xref: /qemu/linux-user/elfload.c (revision 2677cf9f92a5319bb995927f9225940414ce879d)
131e31b8aSbellard /* This is the Linux kernel elf-loading code, ported into user space */
2d39594e9SPeter Maydell #include "qemu/osdep.h"
3edf8e2afSMika Westerberg #include <sys/param.h>
431e31b8aSbellard 
5edf8e2afSMika Westerberg #include <sys/resource.h>
630ab9ef2SRichard Henderson #include <sys/shm.h>
731e31b8aSbellard 
83ef693a0Sbellard #include "qemu.h"
976cad711SPaolo Bonzini #include "disas/disas.h"
10f348b6d1SVeronia Bahaa #include "qemu/path.h"
11dc5e9ac7SMarkus Armbruster #include "qemu/queue.h"
12c6a2377fSRichard Henderson #include "qemu/guest-random.h"
136fd59449SRichard Henderson #include "qemu/units.h"
1431e31b8aSbellard 
15e58ffeb3Smalc #ifdef _ARCH_PPC64
16a6cc84f4Smalc #undef ARCH_DLINFO
17a6cc84f4Smalc #undef ELF_PLATFORM
18a6cc84f4Smalc #undef ELF_HWCAP
19ad6919dcSPeter Maydell #undef ELF_HWCAP2
20a6cc84f4Smalc #undef ELF_CLASS
21a6cc84f4Smalc #undef ELF_DATA
22a6cc84f4Smalc #undef ELF_ARCH
23a6cc84f4Smalc #endif
24a6cc84f4Smalc 
25edf8e2afSMika Westerberg #define ELF_OSABI   ELFOSABI_SYSV
26edf8e2afSMika Westerberg 
27cb33da57Sblueswir1 /* from personality.h */
28cb33da57Sblueswir1 
29cb33da57Sblueswir1 /*
30cb33da57Sblueswir1  * Flags for bug emulation.
31cb33da57Sblueswir1  *
32cb33da57Sblueswir1  * These occupy the top three bytes.
33cb33da57Sblueswir1  */
34cb33da57Sblueswir1 enum {
35cb33da57Sblueswir1     ADDR_NO_RANDOMIZE = 0x0040000,      /* disable randomization of VA space */
36d97ef72eSRichard Henderson     FDPIC_FUNCPTRS =    0x0080000,      /* userspace function ptrs point to
37d97ef72eSRichard Henderson                                            descriptors (signal handling) */
38cb33da57Sblueswir1     MMAP_PAGE_ZERO =    0x0100000,
39cb33da57Sblueswir1     ADDR_COMPAT_LAYOUT = 0x0200000,
40cb33da57Sblueswir1     READ_IMPLIES_EXEC = 0x0400000,
41cb33da57Sblueswir1     ADDR_LIMIT_32BIT =  0x0800000,
42cb33da57Sblueswir1     SHORT_INODE =       0x1000000,
43cb33da57Sblueswir1     WHOLE_SECONDS =     0x2000000,
44cb33da57Sblueswir1     STICKY_TIMEOUTS =   0x4000000,
45cb33da57Sblueswir1     ADDR_LIMIT_3GB =    0x8000000,
46cb33da57Sblueswir1 };
47cb33da57Sblueswir1 
48cb33da57Sblueswir1 /*
49cb33da57Sblueswir1  * Personality types.
50cb33da57Sblueswir1  *
51cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
52cb33da57Sblueswir1  * conflict with error returns.
53cb33da57Sblueswir1  */
54cb33da57Sblueswir1 enum {
55cb33da57Sblueswir1     PER_LINUX =         0x0000,
56cb33da57Sblueswir1     PER_LINUX_32BIT =   0x0000 | ADDR_LIMIT_32BIT,
57cb33da57Sblueswir1     PER_LINUX_FDPIC =   0x0000 | FDPIC_FUNCPTRS,
58cb33da57Sblueswir1     PER_SVR4 =          0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
59cb33da57Sblueswir1     PER_SVR3 =          0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
60d97ef72eSRichard Henderson     PER_SCOSVR3 =       0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE,
61cb33da57Sblueswir1     PER_OSR5 =          0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
62cb33da57Sblueswir1     PER_WYSEV386 =      0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
63cb33da57Sblueswir1     PER_ISCR4 =         0x0005 | STICKY_TIMEOUTS,
64cb33da57Sblueswir1     PER_BSD =           0x0006,
65cb33da57Sblueswir1     PER_SUNOS =         0x0006 | STICKY_TIMEOUTS,
66cb33da57Sblueswir1     PER_XENIX =         0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
67cb33da57Sblueswir1     PER_LINUX32 =       0x0008,
68cb33da57Sblueswir1     PER_LINUX32_3GB =   0x0008 | ADDR_LIMIT_3GB,
69cb33da57Sblueswir1     PER_IRIX32 =        0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
70cb33da57Sblueswir1     PER_IRIXN32 =       0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
71cb33da57Sblueswir1     PER_IRIX64 =        0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
72cb33da57Sblueswir1     PER_RISCOS =        0x000c,
73cb33da57Sblueswir1     PER_SOLARIS =       0x000d | STICKY_TIMEOUTS,
74cb33da57Sblueswir1     PER_UW7 =           0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
75cb33da57Sblueswir1     PER_OSF4 =          0x000f,                  /* OSF/1 v4 */
76cb33da57Sblueswir1     PER_HPUX =          0x0010,
77cb33da57Sblueswir1     PER_MASK =          0x00ff,
78cb33da57Sblueswir1 };
79cb33da57Sblueswir1 
80cb33da57Sblueswir1 /*
81cb33da57Sblueswir1  * Return the base personality without flags.
82cb33da57Sblueswir1  */
83cb33da57Sblueswir1 #define personality(pers)       (pers & PER_MASK)
84cb33da57Sblueswir1 
853cb10cfaSChristophe Lyon int info_is_fdpic(struct image_info *info)
863cb10cfaSChristophe Lyon {
873cb10cfaSChristophe Lyon     return info->personality == PER_LINUX_FDPIC;
883cb10cfaSChristophe Lyon }
893cb10cfaSChristophe Lyon 
9083fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
9183fb7adfSbellard #ifndef MAP_DENYWRITE
9283fb7adfSbellard #define MAP_DENYWRITE 0
9383fb7adfSbellard #endif
9483fb7adfSbellard 
9583fb7adfSbellard /* should probably go in elf.h */
9683fb7adfSbellard #ifndef ELIBBAD
9783fb7adfSbellard #define ELIBBAD 80
9883fb7adfSbellard #endif
9983fb7adfSbellard 
10028490231SRichard Henderson #ifdef TARGET_WORDS_BIGENDIAN
10128490231SRichard Henderson #define ELF_DATA        ELFDATA2MSB
10228490231SRichard Henderson #else
10328490231SRichard Henderson #define ELF_DATA        ELFDATA2LSB
10428490231SRichard Henderson #endif
10528490231SRichard Henderson 
106a29f998dSPaolo Bonzini #ifdef TARGET_ABI_MIPSN32
107918fc54cSPaolo Bonzini typedef abi_ullong      target_elf_greg_t;
108918fc54cSPaolo Bonzini #define tswapreg(ptr)   tswap64(ptr)
109a29f998dSPaolo Bonzini #else
110a29f998dSPaolo Bonzini typedef abi_ulong       target_elf_greg_t;
111a29f998dSPaolo Bonzini #define tswapreg(ptr)   tswapal(ptr)
112a29f998dSPaolo Bonzini #endif
113a29f998dSPaolo Bonzini 
11421e807faSNathan Froyd #ifdef USE_UID16
1151ddd592fSPaolo Bonzini typedef abi_ushort      target_uid_t;
1161ddd592fSPaolo Bonzini typedef abi_ushort      target_gid_t;
11721e807faSNathan Froyd #else
118f8fd4fc4SPaolo Bonzini typedef abi_uint        target_uid_t;
119f8fd4fc4SPaolo Bonzini typedef abi_uint        target_gid_t;
12021e807faSNathan Froyd #endif
121f8fd4fc4SPaolo Bonzini typedef abi_int         target_pid_t;
12221e807faSNathan Froyd 
12330ac07d4Sbellard #ifdef TARGET_I386
12430ac07d4Sbellard 
12515338fd7Sbellard #define ELF_PLATFORM get_elf_platform()
12615338fd7Sbellard 
12715338fd7Sbellard static const char *get_elf_platform(void)
12815338fd7Sbellard {
12915338fd7Sbellard     static char elf_platform[] = "i386";
130a2247f8eSAndreas Färber     int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
13115338fd7Sbellard     if (family > 6)
13215338fd7Sbellard         family = 6;
13315338fd7Sbellard     if (family >= 3)
13415338fd7Sbellard         elf_platform[1] = '0' + family;
13515338fd7Sbellard     return elf_platform;
13615338fd7Sbellard }
13715338fd7Sbellard 
13815338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
13915338fd7Sbellard 
14015338fd7Sbellard static uint32_t get_elf_hwcap(void)
14115338fd7Sbellard {
142a2247f8eSAndreas Färber     X86CPU *cpu = X86_CPU(thread_cpu);
143a2247f8eSAndreas Färber 
144a2247f8eSAndreas Färber     return cpu->env.features[FEAT_1_EDX];
14515338fd7Sbellard }
14615338fd7Sbellard 
14784409ddbSj_mayer #ifdef TARGET_X86_64
14884409ddbSj_mayer #define ELF_START_MMAP 0x2aaaaab000ULL
14984409ddbSj_mayer 
15084409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
15184409ddbSj_mayer #define ELF_ARCH       EM_X86_64
15284409ddbSj_mayer 
15384409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
15484409ddbSj_mayer {
15584409ddbSj_mayer     regs->rax = 0;
15684409ddbSj_mayer     regs->rsp = infop->start_stack;
15784409ddbSj_mayer     regs->rip = infop->entry;
15884409ddbSj_mayer }
15984409ddbSj_mayer 
1609edc5d79SMika Westerberg #define ELF_NREG    27
161c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
1629edc5d79SMika Westerberg 
1639edc5d79SMika Westerberg /*
1649edc5d79SMika Westerberg  * Note that ELF_NREG should be 29 as there should be place for
1659edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
1669edc5d79SMika Westerberg  * those.
1679edc5d79SMika Westerberg  *
1689edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
1699edc5d79SMika Westerberg  */
17005390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
1719edc5d79SMika Westerberg {
1729edc5d79SMika Westerberg     (*regs)[0] = env->regs[15];
1739edc5d79SMika Westerberg     (*regs)[1] = env->regs[14];
1749edc5d79SMika Westerberg     (*regs)[2] = env->regs[13];
1759edc5d79SMika Westerberg     (*regs)[3] = env->regs[12];
1769edc5d79SMika Westerberg     (*regs)[4] = env->regs[R_EBP];
1779edc5d79SMika Westerberg     (*regs)[5] = env->regs[R_EBX];
1789edc5d79SMika Westerberg     (*regs)[6] = env->regs[11];
1799edc5d79SMika Westerberg     (*regs)[7] = env->regs[10];
1809edc5d79SMika Westerberg     (*regs)[8] = env->regs[9];
1819edc5d79SMika Westerberg     (*regs)[9] = env->regs[8];
1829edc5d79SMika Westerberg     (*regs)[10] = env->regs[R_EAX];
1839edc5d79SMika Westerberg     (*regs)[11] = env->regs[R_ECX];
1849edc5d79SMika Westerberg     (*regs)[12] = env->regs[R_EDX];
1859edc5d79SMika Westerberg     (*regs)[13] = env->regs[R_ESI];
1869edc5d79SMika Westerberg     (*regs)[14] = env->regs[R_EDI];
1879edc5d79SMika Westerberg     (*regs)[15] = env->regs[R_EAX]; /* XXX */
1889edc5d79SMika Westerberg     (*regs)[16] = env->eip;
1899edc5d79SMika Westerberg     (*regs)[17] = env->segs[R_CS].selector & 0xffff;
1909edc5d79SMika Westerberg     (*regs)[18] = env->eflags;
1919edc5d79SMika Westerberg     (*regs)[19] = env->regs[R_ESP];
1929edc5d79SMika Westerberg     (*regs)[20] = env->segs[R_SS].selector & 0xffff;
1939edc5d79SMika Westerberg     (*regs)[21] = env->segs[R_FS].selector & 0xffff;
1949edc5d79SMika Westerberg     (*regs)[22] = env->segs[R_GS].selector & 0xffff;
1959edc5d79SMika Westerberg     (*regs)[23] = env->segs[R_DS].selector & 0xffff;
1969edc5d79SMika Westerberg     (*regs)[24] = env->segs[R_ES].selector & 0xffff;
1979edc5d79SMika Westerberg     (*regs)[25] = env->segs[R_FS].selector & 0xffff;
1989edc5d79SMika Westerberg     (*regs)[26] = env->segs[R_GS].selector & 0xffff;
1999edc5d79SMika Westerberg }
2009edc5d79SMika Westerberg 
20184409ddbSj_mayer #else
20284409ddbSj_mayer 
20330ac07d4Sbellard #define ELF_START_MMAP 0x80000000
20430ac07d4Sbellard 
20530ac07d4Sbellard /*
20630ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
20730ac07d4Sbellard  */
20830ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
20930ac07d4Sbellard 
21030ac07d4Sbellard /*
21130ac07d4Sbellard  * These are used to set parameters in the core dumps.
21230ac07d4Sbellard  */
21330ac07d4Sbellard #define ELF_CLASS       ELFCLASS32
21430ac07d4Sbellard #define ELF_ARCH        EM_386
21530ac07d4Sbellard 
216d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
217d97ef72eSRichard Henderson                                struct image_info *infop)
218e5fe0c52Spbrook {
219e5fe0c52Spbrook     regs->esp = infop->start_stack;
220e5fe0c52Spbrook     regs->eip = infop->entry;
221e5fe0c52Spbrook 
22230ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
22330ac07d4Sbellard        starts %edx contains a pointer to a function which might be
22430ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
22530ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
22630ac07d4Sbellard        that have been loaded before the code runs.
22730ac07d4Sbellard 
22830ac07d4Sbellard        A value of 0 tells we have no such handler.  */
229e5fe0c52Spbrook     regs->edx = 0;
230b346ff46Sbellard }
2319edc5d79SMika Westerberg 
2329edc5d79SMika Westerberg #define ELF_NREG    17
233c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
2349edc5d79SMika Westerberg 
2359edc5d79SMika Westerberg /*
2369edc5d79SMika Westerberg  * Note that ELF_NREG should be 19 as there should be place for
2379edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
2389edc5d79SMika Westerberg  * those.
2399edc5d79SMika Westerberg  *
2409edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
2419edc5d79SMika Westerberg  */
24205390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
2439edc5d79SMika Westerberg {
2449edc5d79SMika Westerberg     (*regs)[0] = env->regs[R_EBX];
2459edc5d79SMika Westerberg     (*regs)[1] = env->regs[R_ECX];
2469edc5d79SMika Westerberg     (*regs)[2] = env->regs[R_EDX];
2479edc5d79SMika Westerberg     (*regs)[3] = env->regs[R_ESI];
2489edc5d79SMika Westerberg     (*regs)[4] = env->regs[R_EDI];
2499edc5d79SMika Westerberg     (*regs)[5] = env->regs[R_EBP];
2509edc5d79SMika Westerberg     (*regs)[6] = env->regs[R_EAX];
2519edc5d79SMika Westerberg     (*regs)[7] = env->segs[R_DS].selector & 0xffff;
2529edc5d79SMika Westerberg     (*regs)[8] = env->segs[R_ES].selector & 0xffff;
2539edc5d79SMika Westerberg     (*regs)[9] = env->segs[R_FS].selector & 0xffff;
2549edc5d79SMika Westerberg     (*regs)[10] = env->segs[R_GS].selector & 0xffff;
2559edc5d79SMika Westerberg     (*regs)[11] = env->regs[R_EAX]; /* XXX */
2569edc5d79SMika Westerberg     (*regs)[12] = env->eip;
2579edc5d79SMika Westerberg     (*regs)[13] = env->segs[R_CS].selector & 0xffff;
2589edc5d79SMika Westerberg     (*regs)[14] = env->eflags;
2599edc5d79SMika Westerberg     (*regs)[15] = env->regs[R_ESP];
2609edc5d79SMika Westerberg     (*regs)[16] = env->segs[R_SS].selector & 0xffff;
2619edc5d79SMika Westerberg }
26284409ddbSj_mayer #endif
263b346ff46Sbellard 
2649edc5d79SMika Westerberg #define USE_ELF_CORE_DUMP
265b346ff46Sbellard #define ELF_EXEC_PAGESIZE       4096
266b346ff46Sbellard 
267b346ff46Sbellard #endif
268b346ff46Sbellard 
269b346ff46Sbellard #ifdef TARGET_ARM
270b346ff46Sbellard 
27124e76ff0SPeter Maydell #ifndef TARGET_AARCH64
27224e76ff0SPeter Maydell /* 32 bit ARM definitions */
27324e76ff0SPeter Maydell 
274b346ff46Sbellard #define ELF_START_MMAP 0x80000000
275b346ff46Sbellard 
276b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_ARM
277b346ff46Sbellard #define ELF_CLASS       ELFCLASS32
278b346ff46Sbellard 
279d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
280d97ef72eSRichard Henderson                                struct image_info *infop)
281b346ff46Sbellard {
282992f48a0Sblueswir1     abi_long stack = infop->start_stack;
283b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
28499033caeSAlexander Graf 
285167e4cdcSPeter Maydell     regs->uregs[16] = ARM_CPU_MODE_USR;
286167e4cdcSPeter Maydell     if (infop->entry & 1) {
287167e4cdcSPeter Maydell         regs->uregs[16] |= CPSR_T;
288167e4cdcSPeter Maydell     }
289167e4cdcSPeter Maydell     regs->uregs[15] = infop->entry & 0xfffffffe;
290167e4cdcSPeter Maydell     regs->uregs[13] = infop->start_stack;
2912f619698Sbellard     /* FIXME - what to for failure of get_user()? */
292167e4cdcSPeter Maydell     get_user_ual(regs->uregs[2], stack + 8); /* envp */
293167e4cdcSPeter Maydell     get_user_ual(regs->uregs[1], stack + 4); /* envp */
294a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
295167e4cdcSPeter Maydell     regs->uregs[0] = 0;
296e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
297863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
298167e4cdcSPeter Maydell     regs->uregs[10] = infop->start_data;
2993cb10cfaSChristophe Lyon 
3003cb10cfaSChristophe Lyon     /* Support ARM FDPIC.  */
3013cb10cfaSChristophe Lyon     if (info_is_fdpic(infop)) {
3023cb10cfaSChristophe Lyon         /* As described in the ABI document, r7 points to the loadmap info
3033cb10cfaSChristophe Lyon          * prepared by the kernel. If an interpreter is needed, r8 points
3043cb10cfaSChristophe Lyon          * to the interpreter loadmap and r9 points to the interpreter
3053cb10cfaSChristophe Lyon          * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
3063cb10cfaSChristophe Lyon          * r9 points to the main program PT_DYNAMIC info.
3073cb10cfaSChristophe Lyon          */
3083cb10cfaSChristophe Lyon         regs->uregs[7] = infop->loadmap_addr;
3093cb10cfaSChristophe Lyon         if (infop->interpreter_loadmap_addr) {
3103cb10cfaSChristophe Lyon             /* Executable is dynamically loaded.  */
3113cb10cfaSChristophe Lyon             regs->uregs[8] = infop->interpreter_loadmap_addr;
3123cb10cfaSChristophe Lyon             regs->uregs[9] = infop->interpreter_pt_dynamic_addr;
3133cb10cfaSChristophe Lyon         } else {
3143cb10cfaSChristophe Lyon             regs->uregs[8] = 0;
3153cb10cfaSChristophe Lyon             regs->uregs[9] = infop->pt_dynamic_addr;
3163cb10cfaSChristophe Lyon         }
3173cb10cfaSChristophe Lyon     }
318b346ff46Sbellard }
319b346ff46Sbellard 
320edf8e2afSMika Westerberg #define ELF_NREG    18
321c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
322edf8e2afSMika Westerberg 
32305390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUARMState *env)
324edf8e2afSMika Westerberg {
32586cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->regs[0]);
32686cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->regs[1]);
32786cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->regs[2]);
32886cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->regs[3]);
32986cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->regs[4]);
33086cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->regs[5]);
33186cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->regs[6]);
33286cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->regs[7]);
33386cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->regs[8]);
33486cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->regs[9]);
33586cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->regs[10]);
33686cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->regs[11]);
33786cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->regs[12]);
33886cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->regs[13]);
33986cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->regs[14]);
34086cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->regs[15]);
341edf8e2afSMika Westerberg 
34286cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(cpsr_read((CPUARMState *)env));
34386cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->regs[0]); /* XXX */
344edf8e2afSMika Westerberg }
345edf8e2afSMika Westerberg 
34630ac07d4Sbellard #define USE_ELF_CORE_DUMP
34730ac07d4Sbellard #define ELF_EXEC_PAGESIZE       4096
34830ac07d4Sbellard 
349afce2927Sbellard enum
350afce2927Sbellard {
351afce2927Sbellard     ARM_HWCAP_ARM_SWP       = 1 << 0,
352afce2927Sbellard     ARM_HWCAP_ARM_HALF      = 1 << 1,
353afce2927Sbellard     ARM_HWCAP_ARM_THUMB     = 1 << 2,
354afce2927Sbellard     ARM_HWCAP_ARM_26BIT     = 1 << 3,
355afce2927Sbellard     ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
356afce2927Sbellard     ARM_HWCAP_ARM_FPA       = 1 << 5,
357afce2927Sbellard     ARM_HWCAP_ARM_VFP       = 1 << 6,
358afce2927Sbellard     ARM_HWCAP_ARM_EDSP      = 1 << 7,
359cf6de34aSRiku Voipio     ARM_HWCAP_ARM_JAVA      = 1 << 8,
360cf6de34aSRiku Voipio     ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
36143ce393eSPeter Maydell     ARM_HWCAP_ARM_CRUNCH    = 1 << 10,
36243ce393eSPeter Maydell     ARM_HWCAP_ARM_THUMBEE   = 1 << 11,
36343ce393eSPeter Maydell     ARM_HWCAP_ARM_NEON      = 1 << 12,
36443ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3     = 1 << 13,
36543ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3D16  = 1 << 14,
36624682654SPeter Maydell     ARM_HWCAP_ARM_TLS       = 1 << 15,
36724682654SPeter Maydell     ARM_HWCAP_ARM_VFPv4     = 1 << 16,
36824682654SPeter Maydell     ARM_HWCAP_ARM_IDIVA     = 1 << 17,
36924682654SPeter Maydell     ARM_HWCAP_ARM_IDIVT     = 1 << 18,
37024682654SPeter Maydell     ARM_HWCAP_ARM_VFPD32    = 1 << 19,
37124682654SPeter Maydell     ARM_HWCAP_ARM_LPAE      = 1 << 20,
37224682654SPeter Maydell     ARM_HWCAP_ARM_EVTSTRM   = 1 << 21,
373afce2927Sbellard };
374afce2927Sbellard 
375ad6919dcSPeter Maydell enum {
376ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_AES      = 1 << 0,
377ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_PMULL    = 1 << 1,
378ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA1     = 1 << 2,
379ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA2     = 1 << 3,
380ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_CRC32    = 1 << 4,
381ad6919dcSPeter Maydell };
382ad6919dcSPeter Maydell 
3836b1275ffSPeter Maydell /* The commpage only exists for 32 bit kernels */
3846b1275ffSPeter Maydell 
385806d1021SMeador Inge /* Return 1 if the proposed guest space is suitable for the guest.
386806d1021SMeador Inge  * Return 0 if the proposed guest space isn't suitable, but another
387806d1021SMeador Inge  * address space should be tried.
388806d1021SMeador Inge  * Return -1 if there is no way the proposed guest space can be
389806d1021SMeador Inge  * valid regardless of the base.
390806d1021SMeador Inge  * The guest code may leave a page mapped and populate it if the
391806d1021SMeador Inge  * address is suitable.
392806d1021SMeador Inge  */
393c3637eafSLuke Shumaker static int init_guest_commpage(unsigned long guest_base,
394806d1021SMeador Inge                                unsigned long guest_size)
39597cc7560SDr. David Alan Gilbert {
39697cc7560SDr. David Alan Gilbert     unsigned long real_start, test_page_addr;
39797cc7560SDr. David Alan Gilbert 
39897cc7560SDr. David Alan Gilbert     /* We need to check that we can force a fault on access to the
39997cc7560SDr. David Alan Gilbert      * commpage at 0xffff0fxx
40097cc7560SDr. David Alan Gilbert      */
40197cc7560SDr. David Alan Gilbert     test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask);
402806d1021SMeador Inge 
403806d1021SMeador Inge     /* If the commpage lies within the already allocated guest space,
404806d1021SMeador Inge      * then there is no way we can allocate it.
405955e304fSLuke Shumaker      *
406955e304fSLuke Shumaker      * You may be thinking that that this check is redundant because
407955e304fSLuke Shumaker      * we already validated the guest size against MAX_RESERVED_VA;
408955e304fSLuke Shumaker      * but if qemu_host_page_mask is unusually large, then
409955e304fSLuke Shumaker      * test_page_addr may be lower.
410806d1021SMeador Inge      */
411806d1021SMeador Inge     if (test_page_addr >= guest_base
412e568f9dfSPeter Maydell         && test_page_addr < (guest_base + guest_size)) {
413806d1021SMeador Inge         return -1;
414806d1021SMeador Inge     }
415806d1021SMeador Inge 
41697cc7560SDr. David Alan Gilbert     /* Note it needs to be writeable to let us initialise it */
41797cc7560SDr. David Alan Gilbert     real_start = (unsigned long)
41897cc7560SDr. David Alan Gilbert                  mmap((void *)test_page_addr, qemu_host_page_size,
41997cc7560SDr. David Alan Gilbert                      PROT_READ | PROT_WRITE,
42097cc7560SDr. David Alan Gilbert                      MAP_ANONYMOUS | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
42197cc7560SDr. David Alan Gilbert 
42297cc7560SDr. David Alan Gilbert     /* If we can't map it then try another address */
42397cc7560SDr. David Alan Gilbert     if (real_start == -1ul) {
42497cc7560SDr. David Alan Gilbert         return 0;
42597cc7560SDr. David Alan Gilbert     }
42697cc7560SDr. David Alan Gilbert 
42797cc7560SDr. David Alan Gilbert     if (real_start != test_page_addr) {
42897cc7560SDr. David Alan Gilbert         /* OS didn't put the page where we asked - unmap and reject */
42997cc7560SDr. David Alan Gilbert         munmap((void *)real_start, qemu_host_page_size);
43097cc7560SDr. David Alan Gilbert         return 0;
43197cc7560SDr. David Alan Gilbert     }
43297cc7560SDr. David Alan Gilbert 
43397cc7560SDr. David Alan Gilbert     /* Leave the page mapped
43497cc7560SDr. David Alan Gilbert      * Populate it (mmap should have left it all 0'd)
43597cc7560SDr. David Alan Gilbert      */
43697cc7560SDr. David Alan Gilbert 
43797cc7560SDr. David Alan Gilbert     /* Kernel helper versions */
43897cc7560SDr. David Alan Gilbert     __put_user(5, (uint32_t *)g2h(0xffff0ffcul));
43997cc7560SDr. David Alan Gilbert 
44097cc7560SDr. David Alan Gilbert     /* Now it's populated make it RO */
44197cc7560SDr. David Alan Gilbert     if (mprotect((void *)test_page_addr, qemu_host_page_size, PROT_READ)) {
44297cc7560SDr. David Alan Gilbert         perror("Protecting guest commpage");
44397cc7560SDr. David Alan Gilbert         exit(-1);
44497cc7560SDr. David Alan Gilbert     }
44597cc7560SDr. David Alan Gilbert 
44697cc7560SDr. David Alan Gilbert     return 1; /* All good */
44797cc7560SDr. David Alan Gilbert }
448adf050b1SBenoit Canet 
449adf050b1SBenoit Canet #define ELF_HWCAP get_elf_hwcap()
450ad6919dcSPeter Maydell #define ELF_HWCAP2 get_elf_hwcap2()
451adf050b1SBenoit Canet 
452adf050b1SBenoit Canet static uint32_t get_elf_hwcap(void)
453adf050b1SBenoit Canet {
454a2247f8eSAndreas Färber     ARMCPU *cpu = ARM_CPU(thread_cpu);
455adf050b1SBenoit Canet     uint32_t hwcaps = 0;
456adf050b1SBenoit Canet 
457adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_SWP;
458adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_HALF;
459adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_THUMB;
460adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
461adf050b1SBenoit Canet 
462adf050b1SBenoit Canet     /* probe for the extra features */
463adf050b1SBenoit Canet #define GET_FEATURE(feat, hwcap) \
464a2247f8eSAndreas Färber     do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
465962fcbf2SRichard Henderson 
466962fcbf2SRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
467962fcbf2SRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
468962fcbf2SRichard Henderson 
46924682654SPeter Maydell     /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
47024682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
471adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
472adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
473adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
47424682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
475bfa8a370SRichard Henderson     GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
476873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
477873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
478bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
479bfa8a370SRichard Henderson 
480bfa8a370SRichard Henderson     if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
481bfa8a370SRichard Henderson         cpu_isar_feature(aa32_fpdp_v3, cpu)) {
482bfa8a370SRichard Henderson         hwcaps |= ARM_HWCAP_ARM_VFPv3;
483bfa8a370SRichard Henderson         if (cpu_isar_feature(aa32_simd_r32, cpu)) {
484bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPD32;
485bfa8a370SRichard Henderson         } else {
486bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
487bfa8a370SRichard Henderson         }
488bfa8a370SRichard Henderson     }
489bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
490adf050b1SBenoit Canet 
491adf050b1SBenoit Canet     return hwcaps;
492adf050b1SBenoit Canet }
493afce2927Sbellard 
494ad6919dcSPeter Maydell static uint32_t get_elf_hwcap2(void)
495ad6919dcSPeter Maydell {
496ad6919dcSPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
497ad6919dcSPeter Maydell     uint32_t hwcaps = 0;
498ad6919dcSPeter Maydell 
499962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES);
500962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL);
501962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1);
502962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2);
503962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32);
504ad6919dcSPeter Maydell     return hwcaps;
505ad6919dcSPeter Maydell }
506ad6919dcSPeter Maydell 
507ad6919dcSPeter Maydell #undef GET_FEATURE
508962fcbf2SRichard Henderson #undef GET_FEATURE_ID
509ad6919dcSPeter Maydell 
51013ec4ec3SRichard Henderson #define ELF_PLATFORM get_elf_platform()
51113ec4ec3SRichard Henderson 
51213ec4ec3SRichard Henderson static const char *get_elf_platform(void)
51313ec4ec3SRichard Henderson {
51413ec4ec3SRichard Henderson     CPUARMState *env = thread_cpu->env_ptr;
51513ec4ec3SRichard Henderson 
51613ec4ec3SRichard Henderson #ifdef TARGET_WORDS_BIGENDIAN
51713ec4ec3SRichard Henderson # define END  "b"
51813ec4ec3SRichard Henderson #else
51913ec4ec3SRichard Henderson # define END  "l"
52013ec4ec3SRichard Henderson #endif
52113ec4ec3SRichard Henderson 
52213ec4ec3SRichard Henderson     if (arm_feature(env, ARM_FEATURE_V8)) {
52313ec4ec3SRichard Henderson         return "v8" END;
52413ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V7)) {
52513ec4ec3SRichard Henderson         if (arm_feature(env, ARM_FEATURE_M)) {
52613ec4ec3SRichard Henderson             return "v7m" END;
52713ec4ec3SRichard Henderson         } else {
52813ec4ec3SRichard Henderson             return "v7" END;
52913ec4ec3SRichard Henderson         }
53013ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V6)) {
53113ec4ec3SRichard Henderson         return "v6" END;
53213ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V5)) {
53313ec4ec3SRichard Henderson         return "v5" END;
53413ec4ec3SRichard Henderson     } else {
53513ec4ec3SRichard Henderson         return "v4" END;
53613ec4ec3SRichard Henderson     }
53713ec4ec3SRichard Henderson 
53813ec4ec3SRichard Henderson #undef END
53913ec4ec3SRichard Henderson }
54013ec4ec3SRichard Henderson 
54124e76ff0SPeter Maydell #else
54224e76ff0SPeter Maydell /* 64 bit ARM definitions */
54324e76ff0SPeter Maydell #define ELF_START_MMAP 0x80000000
54424e76ff0SPeter Maydell 
545b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_AARCH64
54624e76ff0SPeter Maydell #define ELF_CLASS       ELFCLASS64
547e20e3ec9SRichard Henderson #ifdef TARGET_WORDS_BIGENDIAN
548e20e3ec9SRichard Henderson # define ELF_PLATFORM    "aarch64_be"
549e20e3ec9SRichard Henderson #else
55024e76ff0SPeter Maydell # define ELF_PLATFORM    "aarch64"
551e20e3ec9SRichard Henderson #endif
55224e76ff0SPeter Maydell 
55324e76ff0SPeter Maydell static inline void init_thread(struct target_pt_regs *regs,
55424e76ff0SPeter Maydell                                struct image_info *infop)
55524e76ff0SPeter Maydell {
55624e76ff0SPeter Maydell     abi_long stack = infop->start_stack;
55724e76ff0SPeter Maydell     memset(regs, 0, sizeof(*regs));
55824e76ff0SPeter Maydell 
55924e76ff0SPeter Maydell     regs->pc = infop->entry & ~0x3ULL;
56024e76ff0SPeter Maydell     regs->sp = stack;
56124e76ff0SPeter Maydell }
56224e76ff0SPeter Maydell 
56324e76ff0SPeter Maydell #define ELF_NREG    34
56424e76ff0SPeter Maydell typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
56524e76ff0SPeter Maydell 
56624e76ff0SPeter Maydell static void elf_core_copy_regs(target_elf_gregset_t *regs,
56724e76ff0SPeter Maydell                                const CPUARMState *env)
56824e76ff0SPeter Maydell {
56924e76ff0SPeter Maydell     int i;
57024e76ff0SPeter Maydell 
57124e76ff0SPeter Maydell     for (i = 0; i < 32; i++) {
57224e76ff0SPeter Maydell         (*regs)[i] = tswapreg(env->xregs[i]);
57324e76ff0SPeter Maydell     }
57424e76ff0SPeter Maydell     (*regs)[32] = tswapreg(env->pc);
57524e76ff0SPeter Maydell     (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env));
57624e76ff0SPeter Maydell }
57724e76ff0SPeter Maydell 
57824e76ff0SPeter Maydell #define USE_ELF_CORE_DUMP
57924e76ff0SPeter Maydell #define ELF_EXEC_PAGESIZE       4096
58024e76ff0SPeter Maydell 
58124e76ff0SPeter Maydell enum {
58224e76ff0SPeter Maydell     ARM_HWCAP_A64_FP            = 1 << 0,
58324e76ff0SPeter Maydell     ARM_HWCAP_A64_ASIMD         = 1 << 1,
58424e76ff0SPeter Maydell     ARM_HWCAP_A64_EVTSTRM       = 1 << 2,
58524e76ff0SPeter Maydell     ARM_HWCAP_A64_AES           = 1 << 3,
58624e76ff0SPeter Maydell     ARM_HWCAP_A64_PMULL         = 1 << 4,
58724e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA1          = 1 << 5,
58824e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA2          = 1 << 6,
58924e76ff0SPeter Maydell     ARM_HWCAP_A64_CRC32         = 1 << 7,
590955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ATOMICS       = 1 << 8,
591955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FPHP          = 1 << 9,
592955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDHP       = 1 << 10,
593955f56d4SArd Biesheuvel     ARM_HWCAP_A64_CPUID         = 1 << 11,
594955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDRDM      = 1 << 12,
595955f56d4SArd Biesheuvel     ARM_HWCAP_A64_JSCVT         = 1 << 13,
596955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FCMA          = 1 << 14,
597955f56d4SArd Biesheuvel     ARM_HWCAP_A64_LRCPC         = 1 << 15,
598955f56d4SArd Biesheuvel     ARM_HWCAP_A64_DCPOP         = 1 << 16,
599955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA3          = 1 << 17,
600955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM3           = 1 << 18,
601955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM4           = 1 << 19,
602955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDDP       = 1 << 20,
603955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA512        = 1 << 21,
604955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SVE           = 1 << 22,
6050083a1faSRichard Henderson     ARM_HWCAP_A64_ASIMDFHM      = 1 << 23,
6060083a1faSRichard Henderson     ARM_HWCAP_A64_DIT           = 1 << 24,
6070083a1faSRichard Henderson     ARM_HWCAP_A64_USCAT         = 1 << 25,
6080083a1faSRichard Henderson     ARM_HWCAP_A64_ILRCPC        = 1 << 26,
6090083a1faSRichard Henderson     ARM_HWCAP_A64_FLAGM         = 1 << 27,
6100083a1faSRichard Henderson     ARM_HWCAP_A64_SSBS          = 1 << 28,
6110083a1faSRichard Henderson     ARM_HWCAP_A64_SB            = 1 << 29,
6120083a1faSRichard Henderson     ARM_HWCAP_A64_PACA          = 1 << 30,
6130083a1faSRichard Henderson     ARM_HWCAP_A64_PACG          = 1UL << 31,
6142041df4aSRichard Henderson 
6152041df4aSRichard Henderson     ARM_HWCAP2_A64_DCPODP       = 1 << 0,
6162041df4aSRichard Henderson     ARM_HWCAP2_A64_SVE2         = 1 << 1,
6172041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEAES       = 1 << 2,
6182041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEPMULL     = 1 << 3,
6192041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEBITPERM   = 1 << 4,
6202041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESHA3      = 1 << 5,
6212041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESM4       = 1 << 6,
6222041df4aSRichard Henderson     ARM_HWCAP2_A64_FLAGM2       = 1 << 7,
6232041df4aSRichard Henderson     ARM_HWCAP2_A64_FRINT        = 1 << 8,
62424e76ff0SPeter Maydell };
62524e76ff0SPeter Maydell 
62624e76ff0SPeter Maydell #define ELF_HWCAP   get_elf_hwcap()
6272041df4aSRichard Henderson #define ELF_HWCAP2  get_elf_hwcap2()
6282041df4aSRichard Henderson 
6292041df4aSRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
6302041df4aSRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
63124e76ff0SPeter Maydell 
63224e76ff0SPeter Maydell static uint32_t get_elf_hwcap(void)
63324e76ff0SPeter Maydell {
63424e76ff0SPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
63524e76ff0SPeter Maydell     uint32_t hwcaps = 0;
63624e76ff0SPeter Maydell 
63724e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_FP;
63824e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_ASIMD;
63937020ff1SAlex Bennée     hwcaps |= ARM_HWCAP_A64_CPUID;
64024e76ff0SPeter Maydell 
64124e76ff0SPeter Maydell     /* probe for the extra features */
642962fcbf2SRichard Henderson 
643962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
644962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
645962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1);
646962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2);
647962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512);
648962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32);
649962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3);
650962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3);
651962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4);
6525763190fSRichard Henderson     GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP);
653962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_atomics, ARM_HWCAP_A64_ATOMICS);
654962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM);
655962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP);
656962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA);
657cd208a1cSRichard Henderson     GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE);
65829d26ab2SRichard Henderson     GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
6591c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
6601c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
6619888bd1eSRichard Henderson     GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
662b89d9c98SRichard Henderson     GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
6630d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
664*2677cf9fSPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
665962fcbf2SRichard Henderson 
6662041df4aSRichard Henderson     return hwcaps;
6672041df4aSRichard Henderson }
6682041df4aSRichard Henderson 
6692041df4aSRichard Henderson static uint32_t get_elf_hwcap2(void)
6702041df4aSRichard Henderson {
6712041df4aSRichard Henderson     ARMCPU *cpu = ARM_CPU(thread_cpu);
6722041df4aSRichard Henderson     uint32_t hwcaps = 0;
6732041df4aSRichard Henderson 
6740d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
6752041df4aSRichard Henderson     GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
6762041df4aSRichard Henderson     GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
67724e76ff0SPeter Maydell 
67824e76ff0SPeter Maydell     return hwcaps;
67924e76ff0SPeter Maydell }
68024e76ff0SPeter Maydell 
6812041df4aSRichard Henderson #undef GET_FEATURE_ID
6822041df4aSRichard Henderson 
68324e76ff0SPeter Maydell #endif /* not TARGET_AARCH64 */
68424e76ff0SPeter Maydell #endif /* TARGET_ARM */
68530ac07d4Sbellard 
686853d6f7aSbellard #ifdef TARGET_SPARC
687a315a145Sbellard #ifdef TARGET_SPARC64
688853d6f7aSbellard 
689853d6f7aSbellard #define ELF_START_MMAP 0x80000000
690cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
691cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV | HWCAP_SPARC_V9)
692992f48a0Sblueswir1 #ifndef TARGET_ABI32
693cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
694992f48a0Sblueswir1 #else
695992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
696992f48a0Sblueswir1 #endif
697853d6f7aSbellard 
698a315a145Sbellard #define ELF_CLASS   ELFCLASS64
6995ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
7005ef54116Sbellard 
7015ef54116Sbellard #define STACK_BIAS              2047
702a315a145Sbellard 
703d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
704d97ef72eSRichard Henderson                                struct image_info *infop)
705a315a145Sbellard {
706992f48a0Sblueswir1 #ifndef TARGET_ABI32
707a315a145Sbellard     regs->tstate = 0;
708992f48a0Sblueswir1 #endif
709a315a145Sbellard     regs->pc = infop->entry;
710a315a145Sbellard     regs->npc = regs->pc + 4;
711a315a145Sbellard     regs->y = 0;
712992f48a0Sblueswir1 #ifdef TARGET_ABI32
713992f48a0Sblueswir1     regs->u_regs[14] = infop->start_stack - 16 * 4;
714992f48a0Sblueswir1 #else
715cb33da57Sblueswir1     if (personality(infop->personality) == PER_LINUX32)
716cb33da57Sblueswir1         regs->u_regs[14] = infop->start_stack - 16 * 4;
717cb33da57Sblueswir1     else
7185ef54116Sbellard         regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
719992f48a0Sblueswir1 #endif
720a315a145Sbellard }
721a315a145Sbellard 
722a315a145Sbellard #else
723a315a145Sbellard #define ELF_START_MMAP 0x80000000
724cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
725cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV)
726a315a145Sbellard 
727853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
728853d6f7aSbellard #define ELF_ARCH    EM_SPARC
729853d6f7aSbellard 
730d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
731d97ef72eSRichard Henderson                                struct image_info *infop)
732853d6f7aSbellard {
733f5155289Sbellard     regs->psr = 0;
734f5155289Sbellard     regs->pc = infop->entry;
735f5155289Sbellard     regs->npc = regs->pc + 4;
736f5155289Sbellard     regs->y = 0;
737f5155289Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 4;
738853d6f7aSbellard }
739853d6f7aSbellard 
740853d6f7aSbellard #endif
741a315a145Sbellard #endif
742853d6f7aSbellard 
74367867308Sbellard #ifdef TARGET_PPC
74467867308Sbellard 
7454ecd4d16SPeter Crosthwaite #define ELF_MACHINE    PPC_ELF_MACHINE
74667867308Sbellard #define ELF_START_MMAP 0x80000000
74767867308Sbellard 
748e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
74984409ddbSj_mayer 
75084409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
75184409ddbSj_mayer 
75284409ddbSj_mayer #define ELF_CLASS       ELFCLASS64
75384409ddbSj_mayer 
75484409ddbSj_mayer #else
75584409ddbSj_mayer 
75667867308Sbellard #define ELF_CLASS       ELFCLASS32
75784409ddbSj_mayer 
75884409ddbSj_mayer #endif
75984409ddbSj_mayer 
76067867308Sbellard #define ELF_ARCH        EM_PPC
76167867308Sbellard 
762df84e4f3SNathan Froyd /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
763df84e4f3SNathan Froyd    See arch/powerpc/include/asm/cputable.h.  */
764df84e4f3SNathan Froyd enum {
7653efa9a67Smalc     QEMU_PPC_FEATURE_32 = 0x80000000,
7663efa9a67Smalc     QEMU_PPC_FEATURE_64 = 0x40000000,
7673efa9a67Smalc     QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
7683efa9a67Smalc     QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
7693efa9a67Smalc     QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
7703efa9a67Smalc     QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
7713efa9a67Smalc     QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
7723efa9a67Smalc     QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
7733efa9a67Smalc     QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
7743efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
7753efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
7763efa9a67Smalc     QEMU_PPC_FEATURE_NO_TB = 0x00100000,
7773efa9a67Smalc     QEMU_PPC_FEATURE_POWER4 = 0x00080000,
7783efa9a67Smalc     QEMU_PPC_FEATURE_POWER5 = 0x00040000,
7793efa9a67Smalc     QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
7803efa9a67Smalc     QEMU_PPC_FEATURE_CELL = 0x00010000,
7813efa9a67Smalc     QEMU_PPC_FEATURE_BOOKE = 0x00008000,
7823efa9a67Smalc     QEMU_PPC_FEATURE_SMT = 0x00004000,
7833efa9a67Smalc     QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
7843efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
7853efa9a67Smalc     QEMU_PPC_FEATURE_PA6T = 0x00000800,
7863efa9a67Smalc     QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
7873efa9a67Smalc     QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
7883efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
7893efa9a67Smalc     QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
7903efa9a67Smalc     QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
791df84e4f3SNathan Froyd 
7923efa9a67Smalc     QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
7933efa9a67Smalc     QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
794a60438ddSTom Musta 
795a60438ddSTom Musta     /* Feature definitions in AT_HWCAP2.  */
796a60438ddSTom Musta     QEMU_PPC_FEATURE2_ARCH_2_07 = 0x80000000, /* ISA 2.07 */
797a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_HTM = 0x40000000, /* Hardware Transactional Memory */
798a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_DSCR = 0x20000000, /* Data Stream Control Register */
799a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
800a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
801a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
80224c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000,
80324c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000,
804be0c46d4SSandipan Das     QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */
80524c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */
80624c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */
80724c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */
80824c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */
809df84e4f3SNathan Froyd };
810df84e4f3SNathan Froyd 
811df84e4f3SNathan Froyd #define ELF_HWCAP get_elf_hwcap()
812df84e4f3SNathan Froyd 
813df84e4f3SNathan Froyd static uint32_t get_elf_hwcap(void)
814df84e4f3SNathan Froyd {
815a2247f8eSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
816df84e4f3SNathan Froyd     uint32_t features = 0;
817df84e4f3SNathan Froyd 
818df84e4f3SNathan Froyd     /* We don't have to be terribly complete here; the high points are
819df84e4f3SNathan Froyd        Altivec/FP/SPE support.  Anything else is just a bonus.  */
820df84e4f3SNathan Froyd #define GET_FEATURE(flag, feature)                                      \
821a2247f8eSAndreas Färber     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
82258eb5308SMichael Walle #define GET_FEATURE2(flags, feature) \
82358eb5308SMichael Walle     do { \
82458eb5308SMichael Walle         if ((cpu->env.insns_flags2 & flags) == flags) { \
82558eb5308SMichael Walle             features |= feature; \
82658eb5308SMichael Walle         } \
82758eb5308SMichael Walle     } while (0)
8283efa9a67Smalc     GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
8293efa9a67Smalc     GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
8303efa9a67Smalc     GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
8313efa9a67Smalc     GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
8323efa9a67Smalc     GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
8333efa9a67Smalc     GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
8343efa9a67Smalc     GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
8353efa9a67Smalc     GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
8360e019746STom Musta     GET_FEATURE2(PPC2_DFP, QEMU_PPC_FEATURE_HAS_DFP);
8370e019746STom Musta     GET_FEATURE2(PPC2_VSX, QEMU_PPC_FEATURE_HAS_VSX);
8380e019746STom Musta     GET_FEATURE2((PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 |
8390e019746STom Musta                   PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206),
8400e019746STom Musta                   QEMU_PPC_FEATURE_ARCH_2_06);
841df84e4f3SNathan Froyd #undef GET_FEATURE
8420e019746STom Musta #undef GET_FEATURE2
843df84e4f3SNathan Froyd 
844df84e4f3SNathan Froyd     return features;
845df84e4f3SNathan Froyd }
846df84e4f3SNathan Froyd 
847a60438ddSTom Musta #define ELF_HWCAP2 get_elf_hwcap2()
848a60438ddSTom Musta 
849a60438ddSTom Musta static uint32_t get_elf_hwcap2(void)
850a60438ddSTom Musta {
851a60438ddSTom Musta     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
852a60438ddSTom Musta     uint32_t features = 0;
853a60438ddSTom Musta 
854a60438ddSTom Musta #define GET_FEATURE(flag, feature)                                      \
855a60438ddSTom Musta     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
856a60438ddSTom Musta #define GET_FEATURE2(flag, feature)                                      \
857a60438ddSTom Musta     do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
858a60438ddSTom Musta 
859a60438ddSTom Musta     GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
860a60438ddSTom Musta     GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
861a60438ddSTom Musta     GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
86224c373ecSLaurent Vivier                   PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 |
86324c373ecSLaurent Vivier                   QEMU_PPC_FEATURE2_VEC_CRYPTO);
86424c373ecSLaurent Vivier     GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 |
86524c373ecSLaurent Vivier                  QEMU_PPC_FEATURE2_DARN);
866a60438ddSTom Musta 
867a60438ddSTom Musta #undef GET_FEATURE
868a60438ddSTom Musta #undef GET_FEATURE2
869a60438ddSTom Musta 
870a60438ddSTom Musta     return features;
871a60438ddSTom Musta }
872a60438ddSTom Musta 
873f5155289Sbellard /*
874f5155289Sbellard  * The requirements here are:
875f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
876f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
877f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
878f5155289Sbellard  *   AT_IGNOREPPC is used for that.
879f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
880f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
881f5155289Sbellard  */
8820bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
883f5155289Sbellard #define ARCH_DLINFO                                     \
884f5155289Sbellard     do {                                                \
885623e250aSTom Musta         PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);              \
886f5155289Sbellard         /*                                              \
88782991bedSPeter Maydell          * Handle glibc compatibility: these magic entries must \
88882991bedSPeter Maydell          * be at the lowest addresses in the final auxv.        \
889f5155289Sbellard          */                                             \
8900bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
8910bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
89282991bedSPeter Maydell         NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
89382991bedSPeter Maydell         NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
89482991bedSPeter Maydell         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                 \
895f5155289Sbellard     } while (0)
896f5155289Sbellard 
89767867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
89867867308Sbellard {
89967867308Sbellard     _regs->gpr[1] = infop->start_stack;
900e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
901d90b94cdSDoug Kwan     if (get_ppc64_abi(infop) < 2) {
9022ccf97ecSPeter Maydell         uint64_t val;
9032ccf97ecSPeter Maydell         get_user_u64(val, infop->entry + 8);
9042ccf97ecSPeter Maydell         _regs->gpr[2] = val + infop->load_bias;
9052ccf97ecSPeter Maydell         get_user_u64(val, infop->entry);
9062ccf97ecSPeter Maydell         infop->entry = val + infop->load_bias;
907d90b94cdSDoug Kwan     } else {
908d90b94cdSDoug Kwan         _regs->gpr[12] = infop->entry;  /* r12 set to global entry address */
909d90b94cdSDoug Kwan     }
91084409ddbSj_mayer #endif
91167867308Sbellard     _regs->nip = infop->entry;
91267867308Sbellard }
91367867308Sbellard 
914e2f3e741SNathan Froyd /* See linux kernel: arch/powerpc/include/asm/elf.h.  */
915e2f3e741SNathan Froyd #define ELF_NREG 48
916e2f3e741SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
917e2f3e741SNathan Froyd 
91805390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *env)
919e2f3e741SNathan Froyd {
920e2f3e741SNathan Froyd     int i;
921e2f3e741SNathan Froyd     target_ulong ccr = 0;
922e2f3e741SNathan Froyd 
923e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
92486cd7b2dSPaolo Bonzini         (*regs)[i] = tswapreg(env->gpr[i]);
925e2f3e741SNathan Froyd     }
926e2f3e741SNathan Froyd 
92786cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->nip);
92886cd7b2dSPaolo Bonzini     (*regs)[33] = tswapreg(env->msr);
92986cd7b2dSPaolo Bonzini     (*regs)[35] = tswapreg(env->ctr);
93086cd7b2dSPaolo Bonzini     (*regs)[36] = tswapreg(env->lr);
93186cd7b2dSPaolo Bonzini     (*regs)[37] = tswapreg(env->xer);
932e2f3e741SNathan Froyd 
933e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
934e2f3e741SNathan Froyd         ccr |= env->crf[i] << (32 - ((i + 1) * 4));
935e2f3e741SNathan Froyd     }
93686cd7b2dSPaolo Bonzini     (*regs)[38] = tswapreg(ccr);
937e2f3e741SNathan Froyd }
938e2f3e741SNathan Froyd 
939e2f3e741SNathan Froyd #define USE_ELF_CORE_DUMP
94067867308Sbellard #define ELF_EXEC_PAGESIZE       4096
94167867308Sbellard 
94267867308Sbellard #endif
94367867308Sbellard 
944048f6b4dSbellard #ifdef TARGET_MIPS
945048f6b4dSbellard 
946048f6b4dSbellard #define ELF_START_MMAP 0x80000000
947048f6b4dSbellard 
948388bb21aSths #ifdef TARGET_MIPS64
949388bb21aSths #define ELF_CLASS   ELFCLASS64
950388bb21aSths #else
951048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
952388bb21aSths #endif
953048f6b4dSbellard #define ELF_ARCH    EM_MIPS
954048f6b4dSbellard 
955f72541f3SAleksandar Markovic #define elf_check_arch(x) ((x) == EM_MIPS || (x) == EM_NANOMIPS)
956f72541f3SAleksandar Markovic 
957d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
958d97ef72eSRichard Henderson                                struct image_info *infop)
959048f6b4dSbellard {
960623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
961048f6b4dSbellard     regs->cp0_epc = infop->entry;
962048f6b4dSbellard     regs->regs[29] = infop->start_stack;
963048f6b4dSbellard }
964048f6b4dSbellard 
96551e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/elf.h.  */
96651e52606SNathan Froyd #define ELF_NREG 45
96751e52606SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
96851e52606SNathan Froyd 
96951e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/reg.h.  */
97051e52606SNathan Froyd enum {
97151e52606SNathan Froyd #ifdef TARGET_MIPS64
97251e52606SNathan Froyd     TARGET_EF_R0 = 0,
97351e52606SNathan Froyd #else
97451e52606SNathan Froyd     TARGET_EF_R0 = 6,
97551e52606SNathan Froyd #endif
97651e52606SNathan Froyd     TARGET_EF_R26 = TARGET_EF_R0 + 26,
97751e52606SNathan Froyd     TARGET_EF_R27 = TARGET_EF_R0 + 27,
97851e52606SNathan Froyd     TARGET_EF_LO = TARGET_EF_R0 + 32,
97951e52606SNathan Froyd     TARGET_EF_HI = TARGET_EF_R0 + 33,
98051e52606SNathan Froyd     TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
98151e52606SNathan Froyd     TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
98251e52606SNathan Froyd     TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
98351e52606SNathan Froyd     TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
98451e52606SNathan Froyd };
98551e52606SNathan Froyd 
98651e52606SNathan Froyd /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
98705390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *env)
98851e52606SNathan Froyd {
98951e52606SNathan Froyd     int i;
99051e52606SNathan Froyd 
99151e52606SNathan Froyd     for (i = 0; i < TARGET_EF_R0; i++) {
99251e52606SNathan Froyd         (*regs)[i] = 0;
99351e52606SNathan Froyd     }
99451e52606SNathan Froyd     (*regs)[TARGET_EF_R0] = 0;
99551e52606SNathan Froyd 
99651e52606SNathan Froyd     for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
997a29f998dSPaolo Bonzini         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]);
99851e52606SNathan Froyd     }
99951e52606SNathan Froyd 
100051e52606SNathan Froyd     (*regs)[TARGET_EF_R26] = 0;
100151e52606SNathan Froyd     (*regs)[TARGET_EF_R27] = 0;
1002a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_LO] = tswapreg(env->active_tc.LO[0]);
1003a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_HI] = tswapreg(env->active_tc.HI[0]);
1004a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_EPC] = tswapreg(env->active_tc.PC);
1005a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_BADVADDR] = tswapreg(env->CP0_BadVAddr);
1006a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_STATUS] = tswapreg(env->CP0_Status);
1007a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_CAUSE] = tswapreg(env->CP0_Cause);
100851e52606SNathan Froyd }
100951e52606SNathan Froyd 
101051e52606SNathan Froyd #define USE_ELF_CORE_DUMP
1011388bb21aSths #define ELF_EXEC_PAGESIZE        4096
1012388bb21aSths 
101346a1ee4fSJames Cowgill /* See arch/mips/include/uapi/asm/hwcap.h.  */
101446a1ee4fSJames Cowgill enum {
101546a1ee4fSJames Cowgill     HWCAP_MIPS_R6           = (1 << 0),
101646a1ee4fSJames Cowgill     HWCAP_MIPS_MSA          = (1 << 1),
101746a1ee4fSJames Cowgill };
101846a1ee4fSJames Cowgill 
101946a1ee4fSJames Cowgill #define ELF_HWCAP get_elf_hwcap()
102046a1ee4fSJames Cowgill 
102146a1ee4fSJames Cowgill static uint32_t get_elf_hwcap(void)
102246a1ee4fSJames Cowgill {
102346a1ee4fSJames Cowgill     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
102446a1ee4fSJames Cowgill     uint32_t hwcaps = 0;
102546a1ee4fSJames Cowgill 
102646a1ee4fSJames Cowgill #define GET_FEATURE(flag, hwcap) \
102746a1ee4fSJames Cowgill     do { if (cpu->env.insn_flags & (flag)) { hwcaps |= hwcap; } } while (0)
102846a1ee4fSJames Cowgill 
102946a1ee4fSJames Cowgill     GET_FEATURE(ISA_MIPS32R6 | ISA_MIPS64R6, HWCAP_MIPS_R6);
103046a1ee4fSJames Cowgill     GET_FEATURE(ASE_MSA, HWCAP_MIPS_MSA);
103146a1ee4fSJames Cowgill 
103246a1ee4fSJames Cowgill #undef GET_FEATURE
103346a1ee4fSJames Cowgill 
103446a1ee4fSJames Cowgill     return hwcaps;
103546a1ee4fSJames Cowgill }
103646a1ee4fSJames Cowgill 
1037048f6b4dSbellard #endif /* TARGET_MIPS */
1038048f6b4dSbellard 
1039b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
1040b779e29eSEdgar E. Iglesias 
1041b779e29eSEdgar E. Iglesias #define ELF_START_MMAP 0x80000000
1042b779e29eSEdgar E. Iglesias 
10430d5d4699SEdgar E. Iglesias #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
1044b779e29eSEdgar E. Iglesias 
1045b779e29eSEdgar E. Iglesias #define ELF_CLASS   ELFCLASS32
10460d5d4699SEdgar E. Iglesias #define ELF_ARCH    EM_MICROBLAZE
1047b779e29eSEdgar E. Iglesias 
1048d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1049d97ef72eSRichard Henderson                                struct image_info *infop)
1050b779e29eSEdgar E. Iglesias {
1051b779e29eSEdgar E. Iglesias     regs->pc = infop->entry;
1052b779e29eSEdgar E. Iglesias     regs->r1 = infop->start_stack;
1053b779e29eSEdgar E. Iglesias 
1054b779e29eSEdgar E. Iglesias }
1055b779e29eSEdgar E. Iglesias 
1056b779e29eSEdgar E. Iglesias #define ELF_EXEC_PAGESIZE        4096
1057b779e29eSEdgar E. Iglesias 
1058e4cbd44dSEdgar E. Iglesias #define USE_ELF_CORE_DUMP
1059e4cbd44dSEdgar E. Iglesias #define ELF_NREG 38
1060e4cbd44dSEdgar E. Iglesias typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1061e4cbd44dSEdgar E. Iglesias 
1062e4cbd44dSEdgar E. Iglesias /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
106305390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env)
1064e4cbd44dSEdgar E. Iglesias {
1065e4cbd44dSEdgar E. Iglesias     int i, pos = 0;
1066e4cbd44dSEdgar E. Iglesias 
1067e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 32; i++) {
106886cd7b2dSPaolo Bonzini         (*regs)[pos++] = tswapreg(env->regs[i]);
1069e4cbd44dSEdgar E. Iglesias     }
1070e4cbd44dSEdgar E. Iglesias 
1071e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 6; i++) {
107286cd7b2dSPaolo Bonzini         (*regs)[pos++] = tswapreg(env->sregs[i]);
1073e4cbd44dSEdgar E. Iglesias     }
1074e4cbd44dSEdgar E. Iglesias }
1075e4cbd44dSEdgar E. Iglesias 
1076b779e29eSEdgar E. Iglesias #endif /* TARGET_MICROBLAZE */
1077b779e29eSEdgar E. Iglesias 
1078a0a839b6SMarek Vasut #ifdef TARGET_NIOS2
1079a0a839b6SMarek Vasut 
1080a0a839b6SMarek Vasut #define ELF_START_MMAP 0x80000000
1081a0a839b6SMarek Vasut 
1082a0a839b6SMarek Vasut #define elf_check_arch(x) ((x) == EM_ALTERA_NIOS2)
1083a0a839b6SMarek Vasut 
1084a0a839b6SMarek Vasut #define ELF_CLASS   ELFCLASS32
1085a0a839b6SMarek Vasut #define ELF_ARCH    EM_ALTERA_NIOS2
1086a0a839b6SMarek Vasut 
1087a0a839b6SMarek Vasut static void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1088a0a839b6SMarek Vasut {
1089a0a839b6SMarek Vasut     regs->ea = infop->entry;
1090a0a839b6SMarek Vasut     regs->sp = infop->start_stack;
1091a0a839b6SMarek Vasut     regs->estatus = 0x3;
1092a0a839b6SMarek Vasut }
1093a0a839b6SMarek Vasut 
1094a0a839b6SMarek Vasut #define ELF_EXEC_PAGESIZE        4096
1095a0a839b6SMarek Vasut 
1096a0a839b6SMarek Vasut #define USE_ELF_CORE_DUMP
1097a0a839b6SMarek Vasut #define ELF_NREG 49
1098a0a839b6SMarek Vasut typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1099a0a839b6SMarek Vasut 
1100a0a839b6SMarek Vasut /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
1101a0a839b6SMarek Vasut static void elf_core_copy_regs(target_elf_gregset_t *regs,
1102a0a839b6SMarek Vasut                                const CPUNios2State *env)
1103a0a839b6SMarek Vasut {
1104a0a839b6SMarek Vasut     int i;
1105a0a839b6SMarek Vasut 
1106a0a839b6SMarek Vasut     (*regs)[0] = -1;
1107a0a839b6SMarek Vasut     for (i = 1; i < 8; i++)    /* r0-r7 */
1108a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1109a0a839b6SMarek Vasut 
1110a0a839b6SMarek Vasut     for (i = 8; i < 16; i++)   /* r8-r15 */
1111a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i - 8]);
1112a0a839b6SMarek Vasut 
1113a0a839b6SMarek Vasut     for (i = 16; i < 24; i++)  /* r16-r23 */
1114a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1115a0a839b6SMarek Vasut     (*regs)[24] = -1;    /* R_ET */
1116a0a839b6SMarek Vasut     (*regs)[25] = -1;    /* R_BT */
1117a0a839b6SMarek Vasut     (*regs)[26] = tswapreg(env->regs[R_GP]);
1118a0a839b6SMarek Vasut     (*regs)[27] = tswapreg(env->regs[R_SP]);
1119a0a839b6SMarek Vasut     (*regs)[28] = tswapreg(env->regs[R_FP]);
1120a0a839b6SMarek Vasut     (*regs)[29] = tswapreg(env->regs[R_EA]);
1121a0a839b6SMarek Vasut     (*regs)[30] = -1;    /* R_SSTATUS */
1122a0a839b6SMarek Vasut     (*regs)[31] = tswapreg(env->regs[R_RA]);
1123a0a839b6SMarek Vasut 
1124a0a839b6SMarek Vasut     (*regs)[32] = tswapreg(env->regs[R_PC]);
1125a0a839b6SMarek Vasut 
1126a0a839b6SMarek Vasut     (*regs)[33] = -1; /* R_STATUS */
1127a0a839b6SMarek Vasut     (*regs)[34] = tswapreg(env->regs[CR_ESTATUS]);
1128a0a839b6SMarek Vasut 
1129a0a839b6SMarek Vasut     for (i = 35; i < 49; i++)    /* ... */
1130a0a839b6SMarek Vasut         (*regs)[i] = -1;
1131a0a839b6SMarek Vasut }
1132a0a839b6SMarek Vasut 
1133a0a839b6SMarek Vasut #endif /* TARGET_NIOS2 */
1134a0a839b6SMarek Vasut 
1135d962783eSJia Liu #ifdef TARGET_OPENRISC
1136d962783eSJia Liu 
1137d962783eSJia Liu #define ELF_START_MMAP 0x08000000
1138d962783eSJia Liu 
1139d962783eSJia Liu #define ELF_ARCH EM_OPENRISC
1140d962783eSJia Liu #define ELF_CLASS ELFCLASS32
1141d962783eSJia Liu #define ELF_DATA  ELFDATA2MSB
1142d962783eSJia Liu 
1143d962783eSJia Liu static inline void init_thread(struct target_pt_regs *regs,
1144d962783eSJia Liu                                struct image_info *infop)
1145d962783eSJia Liu {
1146d962783eSJia Liu     regs->pc = infop->entry;
1147d962783eSJia Liu     regs->gpr[1] = infop->start_stack;
1148d962783eSJia Liu }
1149d962783eSJia Liu 
1150d962783eSJia Liu #define USE_ELF_CORE_DUMP
1151d962783eSJia Liu #define ELF_EXEC_PAGESIZE 8192
1152d962783eSJia Liu 
1153d962783eSJia Liu /* See linux kernel arch/openrisc/include/asm/elf.h.  */
1154d962783eSJia Liu #define ELF_NREG 34 /* gprs and pc, sr */
1155d962783eSJia Liu typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1156d962783eSJia Liu 
1157d962783eSJia Liu static void elf_core_copy_regs(target_elf_gregset_t *regs,
1158d962783eSJia Liu                                const CPUOpenRISCState *env)
1159d962783eSJia Liu {
1160d962783eSJia Liu     int i;
1161d962783eSJia Liu 
1162d962783eSJia Liu     for (i = 0; i < 32; i++) {
1163d89e71e8SStafford Horne         (*regs)[i] = tswapreg(cpu_get_gpr(env, i));
1164d962783eSJia Liu     }
116586cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->pc);
116684775c43SRichard Henderson     (*regs)[33] = tswapreg(cpu_get_sr(env));
1167d962783eSJia Liu }
1168d962783eSJia Liu #define ELF_HWCAP 0
1169d962783eSJia Liu #define ELF_PLATFORM NULL
1170d962783eSJia Liu 
1171d962783eSJia Liu #endif /* TARGET_OPENRISC */
1172d962783eSJia Liu 
1173fdf9b3e8Sbellard #ifdef TARGET_SH4
1174fdf9b3e8Sbellard 
1175fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000
1176fdf9b3e8Sbellard 
1177fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
1178fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
1179fdf9b3e8Sbellard 
1180d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1181d97ef72eSRichard Henderson                                struct image_info *infop)
1182fdf9b3e8Sbellard {
1183fdf9b3e8Sbellard     /* Check other registers XXXXX */
1184fdf9b3e8Sbellard     regs->pc = infop->entry;
1185072ae847Sths     regs->regs[15] = infop->start_stack;
1186fdf9b3e8Sbellard }
1187fdf9b3e8Sbellard 
11887631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/elf.h.  */
11897631c97eSNathan Froyd #define ELF_NREG 23
11907631c97eSNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
11917631c97eSNathan Froyd 
11927631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/ptrace.h.  */
11937631c97eSNathan Froyd enum {
11947631c97eSNathan Froyd     TARGET_REG_PC = 16,
11957631c97eSNathan Froyd     TARGET_REG_PR = 17,
11967631c97eSNathan Froyd     TARGET_REG_SR = 18,
11977631c97eSNathan Froyd     TARGET_REG_GBR = 19,
11987631c97eSNathan Froyd     TARGET_REG_MACH = 20,
11997631c97eSNathan Froyd     TARGET_REG_MACL = 21,
12007631c97eSNathan Froyd     TARGET_REG_SYSCALL = 22
12017631c97eSNathan Froyd };
12027631c97eSNathan Froyd 
1203d97ef72eSRichard Henderson static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
120405390248SAndreas Färber                                       const CPUSH4State *env)
12057631c97eSNathan Froyd {
12067631c97eSNathan Froyd     int i;
12077631c97eSNathan Froyd 
12087631c97eSNathan Froyd     for (i = 0; i < 16; i++) {
120972cd500bSPhilippe Mathieu-Daudé         (*regs)[i] = tswapreg(env->gregs[i]);
12107631c97eSNathan Froyd     }
12117631c97eSNathan Froyd 
121286cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
121386cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PR] = tswapreg(env->pr);
121486cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_SR] = tswapreg(env->sr);
121586cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_GBR] = tswapreg(env->gbr);
121686cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACH] = tswapreg(env->mach);
121786cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACL] = tswapreg(env->macl);
12187631c97eSNathan Froyd     (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
12197631c97eSNathan Froyd }
12207631c97eSNathan Froyd 
12217631c97eSNathan Froyd #define USE_ELF_CORE_DUMP
1222fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
1223fdf9b3e8Sbellard 
1224e42fd944SRichard Henderson enum {
1225e42fd944SRichard Henderson     SH_CPU_HAS_FPU            = 0x0001, /* Hardware FPU support */
1226e42fd944SRichard Henderson     SH_CPU_HAS_P2_FLUSH_BUG   = 0x0002, /* Need to flush the cache in P2 area */
1227e42fd944SRichard Henderson     SH_CPU_HAS_MMU_PAGE_ASSOC = 0x0004, /* SH3: TLB way selection bit support */
1228e42fd944SRichard Henderson     SH_CPU_HAS_DSP            = 0x0008, /* SH-DSP: DSP support */
1229e42fd944SRichard Henderson     SH_CPU_HAS_PERF_COUNTER   = 0x0010, /* Hardware performance counters */
1230e42fd944SRichard Henderson     SH_CPU_HAS_PTEA           = 0x0020, /* PTEA register */
1231e42fd944SRichard Henderson     SH_CPU_HAS_LLSC           = 0x0040, /* movli.l/movco.l */
1232e42fd944SRichard Henderson     SH_CPU_HAS_L2_CACHE       = 0x0080, /* Secondary cache / URAM */
1233e42fd944SRichard Henderson     SH_CPU_HAS_OP32           = 0x0100, /* 32-bit instruction support */
1234e42fd944SRichard Henderson     SH_CPU_HAS_PTEAEX         = 0x0200, /* PTE ASID Extension support */
1235e42fd944SRichard Henderson };
1236e42fd944SRichard Henderson 
1237e42fd944SRichard Henderson #define ELF_HWCAP get_elf_hwcap()
1238e42fd944SRichard Henderson 
1239e42fd944SRichard Henderson static uint32_t get_elf_hwcap(void)
1240e42fd944SRichard Henderson {
1241e42fd944SRichard Henderson     SuperHCPU *cpu = SUPERH_CPU(thread_cpu);
1242e42fd944SRichard Henderson     uint32_t hwcap = 0;
1243e42fd944SRichard Henderson 
1244e42fd944SRichard Henderson     hwcap |= SH_CPU_HAS_FPU;
1245e42fd944SRichard Henderson 
1246e42fd944SRichard Henderson     if (cpu->env.features & SH_FEATURE_SH4A) {
1247e42fd944SRichard Henderson         hwcap |= SH_CPU_HAS_LLSC;
1248e42fd944SRichard Henderson     }
1249e42fd944SRichard Henderson 
1250e42fd944SRichard Henderson     return hwcap;
1251e42fd944SRichard Henderson }
1252e42fd944SRichard Henderson 
1253fdf9b3e8Sbellard #endif
1254fdf9b3e8Sbellard 
125548733d19Sths #ifdef TARGET_CRIS
125648733d19Sths 
125748733d19Sths #define ELF_START_MMAP 0x80000000
125848733d19Sths 
125948733d19Sths #define ELF_CLASS ELFCLASS32
126048733d19Sths #define ELF_ARCH  EM_CRIS
126148733d19Sths 
1262d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1263d97ef72eSRichard Henderson                                struct image_info *infop)
126448733d19Sths {
126548733d19Sths     regs->erp = infop->entry;
126648733d19Sths }
126748733d19Sths 
126848733d19Sths #define ELF_EXEC_PAGESIZE        8192
126948733d19Sths 
127048733d19Sths #endif
127148733d19Sths 
1272e6e5906bSpbrook #ifdef TARGET_M68K
1273e6e5906bSpbrook 
1274e6e5906bSpbrook #define ELF_START_MMAP 0x80000000
1275e6e5906bSpbrook 
1276e6e5906bSpbrook #define ELF_CLASS       ELFCLASS32
1277e6e5906bSpbrook #define ELF_ARCH        EM_68K
1278e6e5906bSpbrook 
1279e6e5906bSpbrook /* ??? Does this need to do anything?
1280e6e5906bSpbrook    #define ELF_PLAT_INIT(_r) */
1281e6e5906bSpbrook 
1282d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1283d97ef72eSRichard Henderson                                struct image_info *infop)
1284e6e5906bSpbrook {
1285e6e5906bSpbrook     regs->usp = infop->start_stack;
1286e6e5906bSpbrook     regs->sr = 0;
1287e6e5906bSpbrook     regs->pc = infop->entry;
1288e6e5906bSpbrook }
1289e6e5906bSpbrook 
12907a93cc55SNathan Froyd /* See linux kernel: arch/m68k/include/asm/elf.h.  */
12917a93cc55SNathan Froyd #define ELF_NREG 20
12927a93cc55SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
12937a93cc55SNathan Froyd 
129405390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUM68KState *env)
12957a93cc55SNathan Froyd {
129686cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->dregs[1]);
129786cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->dregs[2]);
129886cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->dregs[3]);
129986cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->dregs[4]);
130086cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->dregs[5]);
130186cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->dregs[6]);
130286cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->dregs[7]);
130386cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->aregs[0]);
130486cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->aregs[1]);
130586cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->aregs[2]);
130686cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->aregs[3]);
130786cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->aregs[4]);
130886cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->aregs[5]);
130986cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->aregs[6]);
131086cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->dregs[0]);
131186cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->aregs[7]);
131286cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(env->dregs[0]); /* FIXME: orig_d0 */
131386cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->sr);
131486cd7b2dSPaolo Bonzini     (*regs)[18] = tswapreg(env->pc);
13157a93cc55SNathan Froyd     (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
13167a93cc55SNathan Froyd }
13177a93cc55SNathan Froyd 
13187a93cc55SNathan Froyd #define USE_ELF_CORE_DUMP
1319e6e5906bSpbrook #define ELF_EXEC_PAGESIZE       8192
1320e6e5906bSpbrook 
1321e6e5906bSpbrook #endif
1322e6e5906bSpbrook 
13237a3148a9Sj_mayer #ifdef TARGET_ALPHA
13247a3148a9Sj_mayer 
13257a3148a9Sj_mayer #define ELF_START_MMAP (0x30000000000ULL)
13267a3148a9Sj_mayer 
13277a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
13287a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
13297a3148a9Sj_mayer 
1330d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1331d97ef72eSRichard Henderson                                struct image_info *infop)
13327a3148a9Sj_mayer {
13337a3148a9Sj_mayer     regs->pc = infop->entry;
13347a3148a9Sj_mayer     regs->ps = 8;
13357a3148a9Sj_mayer     regs->usp = infop->start_stack;
13367a3148a9Sj_mayer }
13377a3148a9Sj_mayer 
13387a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
13397a3148a9Sj_mayer 
13407a3148a9Sj_mayer #endif /* TARGET_ALPHA */
13417a3148a9Sj_mayer 
1342a4c075f1SUlrich Hecht #ifdef TARGET_S390X
1343a4c075f1SUlrich Hecht 
1344a4c075f1SUlrich Hecht #define ELF_START_MMAP (0x20000000000ULL)
1345a4c075f1SUlrich Hecht 
1346a4c075f1SUlrich Hecht #define ELF_CLASS	ELFCLASS64
1347a4c075f1SUlrich Hecht #define ELF_DATA	ELFDATA2MSB
1348a4c075f1SUlrich Hecht #define ELF_ARCH	EM_S390
1349a4c075f1SUlrich Hecht 
13506d88baf1SDavid Hildenbrand #include "elf.h"
13516d88baf1SDavid Hildenbrand 
13526d88baf1SDavid Hildenbrand #define ELF_HWCAP get_elf_hwcap()
13536d88baf1SDavid Hildenbrand 
13546d88baf1SDavid Hildenbrand #define GET_FEATURE(_feat, _hwcap) \
13556d88baf1SDavid Hildenbrand     do { if (s390_has_feat(_feat)) { hwcap |= _hwcap; } } while (0)
13566d88baf1SDavid Hildenbrand 
13576d88baf1SDavid Hildenbrand static uint32_t get_elf_hwcap(void)
13586d88baf1SDavid Hildenbrand {
13596d88baf1SDavid Hildenbrand     /*
13606d88baf1SDavid Hildenbrand      * Let's assume we always have esan3 and zarch.
13616d88baf1SDavid Hildenbrand      * 31-bit processes can use 64-bit registers (high gprs).
13626d88baf1SDavid Hildenbrand      */
13636d88baf1SDavid Hildenbrand     uint32_t hwcap = HWCAP_S390_ESAN3 | HWCAP_S390_ZARCH | HWCAP_S390_HIGH_GPRS;
13646d88baf1SDavid Hildenbrand 
13656d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_STFLE, HWCAP_S390_STFLE);
13666d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_MSA, HWCAP_S390_MSA);
13676d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_LONG_DISPLACEMENT, HWCAP_S390_LDISP);
13686d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_EXTENDED_IMMEDIATE, HWCAP_S390_EIMM);
13696d88baf1SDavid Hildenbrand     if (s390_has_feat(S390_FEAT_EXTENDED_TRANSLATION_3) &&
13706d88baf1SDavid Hildenbrand         s390_has_feat(S390_FEAT_ETF3_ENH)) {
13716d88baf1SDavid Hildenbrand         hwcap |= HWCAP_S390_ETF3EH;
13726d88baf1SDavid Hildenbrand     }
13736d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
13746d88baf1SDavid Hildenbrand 
13756d88baf1SDavid Hildenbrand     return hwcap;
13766d88baf1SDavid Hildenbrand }
13776d88baf1SDavid Hildenbrand 
1378a4c075f1SUlrich Hecht static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1379a4c075f1SUlrich Hecht {
1380a4c075f1SUlrich Hecht     regs->psw.addr = infop->entry;
1381a4c075f1SUlrich Hecht     regs->psw.mask = PSW_MASK_64 | PSW_MASK_32;
1382a4c075f1SUlrich Hecht     regs->gprs[15] = infop->start_stack;
1383a4c075f1SUlrich Hecht }
1384a4c075f1SUlrich Hecht 
1385a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
1386a4c075f1SUlrich Hecht 
1387b16189b2SChen Gang #ifdef TARGET_TILEGX
1388b16189b2SChen Gang 
1389b16189b2SChen Gang /* 42 bits real used address, a half for user mode */
1390b16189b2SChen Gang #define ELF_START_MMAP (0x00000020000000000ULL)
1391b16189b2SChen Gang 
1392b16189b2SChen Gang #define elf_check_arch(x) ((x) == EM_TILEGX)
1393b16189b2SChen Gang 
1394b16189b2SChen Gang #define ELF_CLASS   ELFCLASS64
1395b16189b2SChen Gang #define ELF_DATA    ELFDATA2LSB
1396b16189b2SChen Gang #define ELF_ARCH    EM_TILEGX
1397b16189b2SChen Gang 
1398b16189b2SChen Gang static inline void init_thread(struct target_pt_regs *regs,
1399b16189b2SChen Gang                                struct image_info *infop)
1400b16189b2SChen Gang {
1401b16189b2SChen Gang     regs->pc = infop->entry;
1402b16189b2SChen Gang     regs->sp = infop->start_stack;
1403b16189b2SChen Gang 
1404b16189b2SChen Gang }
1405b16189b2SChen Gang 
1406b16189b2SChen Gang #define ELF_EXEC_PAGESIZE        65536 /* TILE-Gx page size is 64KB */
1407b16189b2SChen Gang 
1408b16189b2SChen Gang #endif /* TARGET_TILEGX */
1409b16189b2SChen Gang 
141047ae93cdSMichael Clark #ifdef TARGET_RISCV
141147ae93cdSMichael Clark 
141247ae93cdSMichael Clark #define ELF_START_MMAP 0x80000000
141347ae93cdSMichael Clark #define ELF_ARCH  EM_RISCV
141447ae93cdSMichael Clark 
141547ae93cdSMichael Clark #ifdef TARGET_RISCV32
141647ae93cdSMichael Clark #define ELF_CLASS ELFCLASS32
141747ae93cdSMichael Clark #else
141847ae93cdSMichael Clark #define ELF_CLASS ELFCLASS64
141947ae93cdSMichael Clark #endif
142047ae93cdSMichael Clark 
142147ae93cdSMichael Clark static inline void init_thread(struct target_pt_regs *regs,
142247ae93cdSMichael Clark                                struct image_info *infop)
142347ae93cdSMichael Clark {
142447ae93cdSMichael Clark     regs->sepc = infop->entry;
142547ae93cdSMichael Clark     regs->sp = infop->start_stack;
142647ae93cdSMichael Clark }
142747ae93cdSMichael Clark 
142847ae93cdSMichael Clark #define ELF_EXEC_PAGESIZE 4096
142947ae93cdSMichael Clark 
143047ae93cdSMichael Clark #endif /* TARGET_RISCV */
143147ae93cdSMichael Clark 
14327c248bcdSRichard Henderson #ifdef TARGET_HPPA
14337c248bcdSRichard Henderson 
14347c248bcdSRichard Henderson #define ELF_START_MMAP  0x80000000
14357c248bcdSRichard Henderson #define ELF_CLASS       ELFCLASS32
14367c248bcdSRichard Henderson #define ELF_ARCH        EM_PARISC
14377c248bcdSRichard Henderson #define ELF_PLATFORM    "PARISC"
14387c248bcdSRichard Henderson #define STACK_GROWS_DOWN 0
14397c248bcdSRichard Henderson #define STACK_ALIGNMENT  64
14407c248bcdSRichard Henderson 
14417c248bcdSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
14427c248bcdSRichard Henderson                                struct image_info *infop)
14437c248bcdSRichard Henderson {
14447c248bcdSRichard Henderson     regs->iaoq[0] = infop->entry;
14457c248bcdSRichard Henderson     regs->iaoq[1] = infop->entry + 4;
14467c248bcdSRichard Henderson     regs->gr[23] = 0;
14477c248bcdSRichard Henderson     regs->gr[24] = infop->arg_start;
14487c248bcdSRichard Henderson     regs->gr[25] = (infop->arg_end - infop->arg_start) / sizeof(abi_ulong);
14497c248bcdSRichard Henderson     /* The top-of-stack contains a linkage buffer.  */
14507c248bcdSRichard Henderson     regs->gr[30] = infop->start_stack + 64;
14517c248bcdSRichard Henderson     regs->gr[31] = infop->entry;
14527c248bcdSRichard Henderson }
14537c248bcdSRichard Henderson 
14547c248bcdSRichard Henderson #endif /* TARGET_HPPA */
14557c248bcdSRichard Henderson 
1456ba7651fbSMax Filippov #ifdef TARGET_XTENSA
1457ba7651fbSMax Filippov 
1458ba7651fbSMax Filippov #define ELF_START_MMAP 0x20000000
1459ba7651fbSMax Filippov 
1460ba7651fbSMax Filippov #define ELF_CLASS       ELFCLASS32
1461ba7651fbSMax Filippov #define ELF_ARCH        EM_XTENSA
1462ba7651fbSMax Filippov 
1463ba7651fbSMax Filippov static inline void init_thread(struct target_pt_regs *regs,
1464ba7651fbSMax Filippov                                struct image_info *infop)
1465ba7651fbSMax Filippov {
1466ba7651fbSMax Filippov     regs->windowbase = 0;
1467ba7651fbSMax Filippov     regs->windowstart = 1;
1468ba7651fbSMax Filippov     regs->areg[1] = infop->start_stack;
1469ba7651fbSMax Filippov     regs->pc = infop->entry;
1470ba7651fbSMax Filippov }
1471ba7651fbSMax Filippov 
1472ba7651fbSMax Filippov /* See linux kernel: arch/xtensa/include/asm/elf.h.  */
1473ba7651fbSMax Filippov #define ELF_NREG 128
1474ba7651fbSMax Filippov typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1475ba7651fbSMax Filippov 
1476ba7651fbSMax Filippov enum {
1477ba7651fbSMax Filippov     TARGET_REG_PC,
1478ba7651fbSMax Filippov     TARGET_REG_PS,
1479ba7651fbSMax Filippov     TARGET_REG_LBEG,
1480ba7651fbSMax Filippov     TARGET_REG_LEND,
1481ba7651fbSMax Filippov     TARGET_REG_LCOUNT,
1482ba7651fbSMax Filippov     TARGET_REG_SAR,
1483ba7651fbSMax Filippov     TARGET_REG_WINDOWSTART,
1484ba7651fbSMax Filippov     TARGET_REG_WINDOWBASE,
1485ba7651fbSMax Filippov     TARGET_REG_THREADPTR,
1486ba7651fbSMax Filippov     TARGET_REG_AR0 = 64,
1487ba7651fbSMax Filippov };
1488ba7651fbSMax Filippov 
1489ba7651fbSMax Filippov static void elf_core_copy_regs(target_elf_gregset_t *regs,
1490ba7651fbSMax Filippov                                const CPUXtensaState *env)
1491ba7651fbSMax Filippov {
1492ba7651fbSMax Filippov     unsigned i;
1493ba7651fbSMax Filippov 
1494ba7651fbSMax Filippov     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
1495ba7651fbSMax Filippov     (*regs)[TARGET_REG_PS] = tswapreg(env->sregs[PS] & ~PS_EXCM);
1496ba7651fbSMax Filippov     (*regs)[TARGET_REG_LBEG] = tswapreg(env->sregs[LBEG]);
1497ba7651fbSMax Filippov     (*regs)[TARGET_REG_LEND] = tswapreg(env->sregs[LEND]);
1498ba7651fbSMax Filippov     (*regs)[TARGET_REG_LCOUNT] = tswapreg(env->sregs[LCOUNT]);
1499ba7651fbSMax Filippov     (*regs)[TARGET_REG_SAR] = tswapreg(env->sregs[SAR]);
1500ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWSTART] = tswapreg(env->sregs[WINDOW_START]);
1501ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWBASE] = tswapreg(env->sregs[WINDOW_BASE]);
1502ba7651fbSMax Filippov     (*regs)[TARGET_REG_THREADPTR] = tswapreg(env->uregs[THREADPTR]);
1503ba7651fbSMax Filippov     xtensa_sync_phys_from_window((CPUXtensaState *)env);
1504ba7651fbSMax Filippov     for (i = 0; i < env->config->nareg; ++i) {
1505ba7651fbSMax Filippov         (*regs)[TARGET_REG_AR0 + i] = tswapreg(env->phys_regs[i]);
1506ba7651fbSMax Filippov     }
1507ba7651fbSMax Filippov }
1508ba7651fbSMax Filippov 
1509ba7651fbSMax Filippov #define USE_ELF_CORE_DUMP
1510ba7651fbSMax Filippov #define ELF_EXEC_PAGESIZE       4096
1511ba7651fbSMax Filippov 
1512ba7651fbSMax Filippov #endif /* TARGET_XTENSA */
1513ba7651fbSMax Filippov 
151415338fd7Sbellard #ifndef ELF_PLATFORM
151515338fd7Sbellard #define ELF_PLATFORM (NULL)
151615338fd7Sbellard #endif
151715338fd7Sbellard 
151875be901cSPeter Crosthwaite #ifndef ELF_MACHINE
151975be901cSPeter Crosthwaite #define ELF_MACHINE ELF_ARCH
152075be901cSPeter Crosthwaite #endif
152175be901cSPeter Crosthwaite 
1522d276a604SPeter Crosthwaite #ifndef elf_check_arch
1523d276a604SPeter Crosthwaite #define elf_check_arch(x) ((x) == ELF_ARCH)
1524d276a604SPeter Crosthwaite #endif
1525d276a604SPeter Crosthwaite 
152615338fd7Sbellard #ifndef ELF_HWCAP
152715338fd7Sbellard #define ELF_HWCAP 0
152815338fd7Sbellard #endif
152915338fd7Sbellard 
15307c4ee5bcSRichard Henderson #ifndef STACK_GROWS_DOWN
15317c4ee5bcSRichard Henderson #define STACK_GROWS_DOWN 1
15327c4ee5bcSRichard Henderson #endif
15337c4ee5bcSRichard Henderson 
15347c4ee5bcSRichard Henderson #ifndef STACK_ALIGNMENT
15357c4ee5bcSRichard Henderson #define STACK_ALIGNMENT 16
15367c4ee5bcSRichard Henderson #endif
15377c4ee5bcSRichard Henderson 
1538992f48a0Sblueswir1 #ifdef TARGET_ABI32
1539cb33da57Sblueswir1 #undef ELF_CLASS
1540992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
1541cb33da57Sblueswir1 #undef bswaptls
1542cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
1543cb33da57Sblueswir1 #endif
1544cb33da57Sblueswir1 
154531e31b8aSbellard #include "elf.h"
154609bfb054Sbellard 
154709bfb054Sbellard struct exec
154809bfb054Sbellard {
154909bfb054Sbellard     unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
155009bfb054Sbellard     unsigned int a_text;   /* length of text, in bytes */
155109bfb054Sbellard     unsigned int a_data;   /* length of data, in bytes */
155209bfb054Sbellard     unsigned int a_bss;    /* length of uninitialized data area, in bytes */
155309bfb054Sbellard     unsigned int a_syms;   /* length of symbol table data in file, in bytes */
155409bfb054Sbellard     unsigned int a_entry;  /* start address */
155509bfb054Sbellard     unsigned int a_trsize; /* length of relocation info for text, in bytes */
155609bfb054Sbellard     unsigned int a_drsize; /* length of relocation info for data, in bytes */
155709bfb054Sbellard };
155809bfb054Sbellard 
155909bfb054Sbellard 
156009bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
156109bfb054Sbellard #define OMAGIC 0407
156209bfb054Sbellard #define NMAGIC 0410
156309bfb054Sbellard #define ZMAGIC 0413
156409bfb054Sbellard #define QMAGIC 0314
156509bfb054Sbellard 
156631e31b8aSbellard /* Necessary parameters */
156794894ff2SShivaprasad G Bhat #define TARGET_ELF_EXEC_PAGESIZE \
156894894ff2SShivaprasad G Bhat         (((eppnt->p_align & ~qemu_host_page_mask) != 0) ? \
156994894ff2SShivaprasad G Bhat          TARGET_PAGE_SIZE : MAX(qemu_host_page_size, TARGET_PAGE_SIZE))
157094894ff2SShivaprasad G Bhat #define TARGET_ELF_PAGELENGTH(_v) ROUND_UP((_v), TARGET_ELF_EXEC_PAGESIZE)
157179cb1f1dSYongbok Kim #define TARGET_ELF_PAGESTART(_v) ((_v) & \
157279cb1f1dSYongbok Kim                                  ~(abi_ulong)(TARGET_ELF_EXEC_PAGESIZE-1))
157354936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
157431e31b8aSbellard 
1575444cd5c3SMarco A L Barbosa #define DLINFO_ITEMS 15
157631e31b8aSbellard 
157709bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
157809bfb054Sbellard {
157909bfb054Sbellard     memcpy(to, from, n);
158009bfb054Sbellard }
158109bfb054Sbellard 
158231e31b8aSbellard #ifdef BSWAP_NEEDED
158392a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
158431e31b8aSbellard {
158531e31b8aSbellard     bswap16s(&ehdr->e_type);            /* Object file type */
158631e31b8aSbellard     bswap16s(&ehdr->e_machine);         /* Architecture */
158731e31b8aSbellard     bswap32s(&ehdr->e_version);         /* Object file version */
158892a31b1fSbellard     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
158992a31b1fSbellard     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
159092a31b1fSbellard     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
159131e31b8aSbellard     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
159231e31b8aSbellard     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
159331e31b8aSbellard     bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
159431e31b8aSbellard     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
159531e31b8aSbellard     bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
159631e31b8aSbellard     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
159731e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
159831e31b8aSbellard }
159931e31b8aSbellard 
1600991f8f0cSRichard Henderson static void bswap_phdr(struct elf_phdr *phdr, int phnum)
160131e31b8aSbellard {
1602991f8f0cSRichard Henderson     int i;
1603991f8f0cSRichard Henderson     for (i = 0; i < phnum; ++i, ++phdr) {
160431e31b8aSbellard         bswap32s(&phdr->p_type);        /* Segment type */
1605991f8f0cSRichard Henderson         bswap32s(&phdr->p_flags);       /* Segment flags */
160692a31b1fSbellard         bswaptls(&phdr->p_offset);      /* Segment file offset */
160792a31b1fSbellard         bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
160892a31b1fSbellard         bswaptls(&phdr->p_paddr);       /* Segment physical address */
160992a31b1fSbellard         bswaptls(&phdr->p_filesz);      /* Segment size in file */
161092a31b1fSbellard         bswaptls(&phdr->p_memsz);       /* Segment size in memory */
161192a31b1fSbellard         bswaptls(&phdr->p_align);       /* Segment alignment */
161231e31b8aSbellard     }
1613991f8f0cSRichard Henderson }
1614689f936fSbellard 
1615991f8f0cSRichard Henderson static void bswap_shdr(struct elf_shdr *shdr, int shnum)
1616689f936fSbellard {
1617991f8f0cSRichard Henderson     int i;
1618991f8f0cSRichard Henderson     for (i = 0; i < shnum; ++i, ++shdr) {
1619689f936fSbellard         bswap32s(&shdr->sh_name);
1620689f936fSbellard         bswap32s(&shdr->sh_type);
162192a31b1fSbellard         bswaptls(&shdr->sh_flags);
162292a31b1fSbellard         bswaptls(&shdr->sh_addr);
162392a31b1fSbellard         bswaptls(&shdr->sh_offset);
162492a31b1fSbellard         bswaptls(&shdr->sh_size);
1625689f936fSbellard         bswap32s(&shdr->sh_link);
1626689f936fSbellard         bswap32s(&shdr->sh_info);
162792a31b1fSbellard         bswaptls(&shdr->sh_addralign);
162892a31b1fSbellard         bswaptls(&shdr->sh_entsize);
1629689f936fSbellard     }
1630991f8f0cSRichard Henderson }
1631689f936fSbellard 
16327a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
1633689f936fSbellard {
1634689f936fSbellard     bswap32s(&sym->st_name);
16357a3148a9Sj_mayer     bswaptls(&sym->st_value);
16367a3148a9Sj_mayer     bswaptls(&sym->st_size);
1637689f936fSbellard     bswap16s(&sym->st_shndx);
1638689f936fSbellard }
16395dd0db52SStefan Markovic 
16405dd0db52SStefan Markovic #ifdef TARGET_MIPS
16415dd0db52SStefan Markovic static void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags)
16425dd0db52SStefan Markovic {
16435dd0db52SStefan Markovic     bswap16s(&abiflags->version);
16445dd0db52SStefan Markovic     bswap32s(&abiflags->ases);
16455dd0db52SStefan Markovic     bswap32s(&abiflags->isa_ext);
16465dd0db52SStefan Markovic     bswap32s(&abiflags->flags1);
16475dd0db52SStefan Markovic     bswap32s(&abiflags->flags2);
16485dd0db52SStefan Markovic }
16495dd0db52SStefan Markovic #endif
1650991f8f0cSRichard Henderson #else
1651991f8f0cSRichard Henderson static inline void bswap_ehdr(struct elfhdr *ehdr) { }
1652991f8f0cSRichard Henderson static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
1653991f8f0cSRichard Henderson static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
1654991f8f0cSRichard Henderson static inline void bswap_sym(struct elf_sym *sym) { }
16555dd0db52SStefan Markovic #ifdef TARGET_MIPS
16565dd0db52SStefan Markovic static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
16575dd0db52SStefan Markovic #endif
165831e31b8aSbellard #endif
165931e31b8aSbellard 
1660edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
16619349b4f9SAndreas Färber static int elf_core_dump(int, const CPUArchState *);
1662edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
1663682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
1664edf8e2afSMika Westerberg 
16659058abddSRichard Henderson /* Verify the portions of EHDR within E_IDENT for the target.
16669058abddSRichard Henderson    This can be performed before bswapping the entire header.  */
16679058abddSRichard Henderson static bool elf_check_ident(struct elfhdr *ehdr)
16689058abddSRichard Henderson {
16699058abddSRichard Henderson     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
16709058abddSRichard Henderson             && ehdr->e_ident[EI_MAG1] == ELFMAG1
16719058abddSRichard Henderson             && ehdr->e_ident[EI_MAG2] == ELFMAG2
16729058abddSRichard Henderson             && ehdr->e_ident[EI_MAG3] == ELFMAG3
16739058abddSRichard Henderson             && ehdr->e_ident[EI_CLASS] == ELF_CLASS
16749058abddSRichard Henderson             && ehdr->e_ident[EI_DATA] == ELF_DATA
16759058abddSRichard Henderson             && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
16769058abddSRichard Henderson }
16779058abddSRichard Henderson 
16789058abddSRichard Henderson /* Verify the portions of EHDR outside of E_IDENT for the target.
16799058abddSRichard Henderson    This has to wait until after bswapping the header.  */
16809058abddSRichard Henderson static bool elf_check_ehdr(struct elfhdr *ehdr)
16819058abddSRichard Henderson {
16829058abddSRichard Henderson     return (elf_check_arch(ehdr->e_machine)
16839058abddSRichard Henderson             && ehdr->e_ehsize == sizeof(struct elfhdr)
16849058abddSRichard Henderson             && ehdr->e_phentsize == sizeof(struct elf_phdr)
16859058abddSRichard Henderson             && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
16869058abddSRichard Henderson }
16879058abddSRichard Henderson 
168831e31b8aSbellard /*
1689e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
169031e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
169131e31b8aSbellard  * to be put directly into the top of new user memory.
169231e31b8aSbellard  *
169331e31b8aSbellard  */
169459baae9aSStefan Brüns static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
169559baae9aSStefan Brüns                                   abi_ulong p, abi_ulong stack_limit)
169631e31b8aSbellard {
169759baae9aSStefan Brüns     char *tmp;
16987c4ee5bcSRichard Henderson     int len, i;
169959baae9aSStefan Brüns     abi_ulong top = p;
170031e31b8aSbellard 
170131e31b8aSbellard     if (!p) {
170231e31b8aSbellard         return 0;       /* bullet-proofing */
170331e31b8aSbellard     }
170459baae9aSStefan Brüns 
17057c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
17067c4ee5bcSRichard Henderson         int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
17077c4ee5bcSRichard Henderson         for (i = argc - 1; i >= 0; --i) {
17087c4ee5bcSRichard Henderson             tmp = argv[i];
1709edf779ffSbellard             if (!tmp) {
171031e31b8aSbellard                 fprintf(stderr, "VFS: argc is wrong");
171131e31b8aSbellard                 exit(-1);
171231e31b8aSbellard             }
171359baae9aSStefan Brüns             len = strlen(tmp) + 1;
171459baae9aSStefan Brüns             tmp += len;
171559baae9aSStefan Brüns 
171659baae9aSStefan Brüns             if (len > (p - stack_limit)) {
171731e31b8aSbellard                 return 0;
171831e31b8aSbellard             }
171931e31b8aSbellard             while (len) {
172031e31b8aSbellard                 int bytes_to_copy = (len > offset) ? offset : len;
172131e31b8aSbellard                 tmp -= bytes_to_copy;
172231e31b8aSbellard                 p -= bytes_to_copy;
172331e31b8aSbellard                 offset -= bytes_to_copy;
172431e31b8aSbellard                 len -= bytes_to_copy;
172559baae9aSStefan Brüns 
172659baae9aSStefan Brüns                 memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
172759baae9aSStefan Brüns 
172859baae9aSStefan Brüns                 if (offset == 0) {
172959baae9aSStefan Brüns                     memcpy_to_target(p, scratch, top - p);
173059baae9aSStefan Brüns                     top = p;
173159baae9aSStefan Brüns                     offset = TARGET_PAGE_SIZE;
173231e31b8aSbellard                 }
173331e31b8aSbellard             }
173431e31b8aSbellard         }
17357c4ee5bcSRichard Henderson         if (p != top) {
173659baae9aSStefan Brüns             memcpy_to_target(p, scratch + offset, top - p);
173759baae9aSStefan Brüns         }
17387c4ee5bcSRichard Henderson     } else {
17397c4ee5bcSRichard Henderson         int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE);
17407c4ee5bcSRichard Henderson         for (i = 0; i < argc; ++i) {
17417c4ee5bcSRichard Henderson             tmp = argv[i];
17427c4ee5bcSRichard Henderson             if (!tmp) {
17437c4ee5bcSRichard Henderson                 fprintf(stderr, "VFS: argc is wrong");
17447c4ee5bcSRichard Henderson                 exit(-1);
17457c4ee5bcSRichard Henderson             }
17467c4ee5bcSRichard Henderson             len = strlen(tmp) + 1;
17477c4ee5bcSRichard Henderson             if (len > (stack_limit - p)) {
17487c4ee5bcSRichard Henderson                 return 0;
17497c4ee5bcSRichard Henderson             }
17507c4ee5bcSRichard Henderson             while (len) {
17517c4ee5bcSRichard Henderson                 int bytes_to_copy = (len > remaining) ? remaining : len;
17527c4ee5bcSRichard Henderson 
17537c4ee5bcSRichard Henderson                 memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy);
17547c4ee5bcSRichard Henderson 
17557c4ee5bcSRichard Henderson                 tmp += bytes_to_copy;
17567c4ee5bcSRichard Henderson                 remaining -= bytes_to_copy;
17577c4ee5bcSRichard Henderson                 p += bytes_to_copy;
17587c4ee5bcSRichard Henderson                 len -= bytes_to_copy;
17597c4ee5bcSRichard Henderson 
17607c4ee5bcSRichard Henderson                 if (remaining == 0) {
17617c4ee5bcSRichard Henderson                     memcpy_to_target(top, scratch, p - top);
17627c4ee5bcSRichard Henderson                     top = p;
17637c4ee5bcSRichard Henderson                     remaining = TARGET_PAGE_SIZE;
17647c4ee5bcSRichard Henderson                 }
17657c4ee5bcSRichard Henderson             }
17667c4ee5bcSRichard Henderson         }
17677c4ee5bcSRichard Henderson         if (p != top) {
17687c4ee5bcSRichard Henderson             memcpy_to_target(top, scratch, p - top);
17697c4ee5bcSRichard Henderson         }
17707c4ee5bcSRichard Henderson     }
177159baae9aSStefan Brüns 
177231e31b8aSbellard     return p;
177331e31b8aSbellard }
177431e31b8aSbellard 
177559baae9aSStefan Brüns /* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of
177659baae9aSStefan Brüns  * argument/environment space. Newer kernels (>2.6.33) allow more,
177759baae9aSStefan Brüns  * dependent on stack size, but guarantee at least 32 pages for
177859baae9aSStefan Brüns  * backwards compatibility.
177959baae9aSStefan Brüns  */
178059baae9aSStefan Brüns #define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE)
178159baae9aSStefan Brüns 
178259baae9aSStefan Brüns static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
178331e31b8aSbellard                                  struct image_info *info)
178431e31b8aSbellard {
178559baae9aSStefan Brüns     abi_ulong size, error, guard;
178631e31b8aSbellard 
1787703e0e89SRichard Henderson     size = guest_stack_size;
178859baae9aSStefan Brüns     if (size < STACK_LOWER_LIMIT) {
178959baae9aSStefan Brüns         size = STACK_LOWER_LIMIT;
179060dcbcb5SRichard Henderson     }
179160dcbcb5SRichard Henderson     guard = TARGET_PAGE_SIZE;
179260dcbcb5SRichard Henderson     if (guard < qemu_real_host_page_size) {
179360dcbcb5SRichard Henderson         guard = qemu_real_host_page_size;
179460dcbcb5SRichard Henderson     }
179560dcbcb5SRichard Henderson 
179660dcbcb5SRichard Henderson     error = target_mmap(0, size + guard, PROT_READ | PROT_WRITE,
179760dcbcb5SRichard Henderson                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
179809bfb054Sbellard     if (error == -1) {
179960dcbcb5SRichard Henderson         perror("mmap stack");
180031e31b8aSbellard         exit(-1);
180131e31b8aSbellard     }
180231e31b8aSbellard 
180360dcbcb5SRichard Henderson     /* We reserve one extra page at the top of the stack as guard.  */
18047c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
180560dcbcb5SRichard Henderson         target_mprotect(error, guard, PROT_NONE);
180660dcbcb5SRichard Henderson         info->stack_limit = error + guard;
180759baae9aSStefan Brüns         return info->stack_limit + size - sizeof(void *);
18087c4ee5bcSRichard Henderson     } else {
18097c4ee5bcSRichard Henderson         target_mprotect(error + size, guard, PROT_NONE);
18107c4ee5bcSRichard Henderson         info->stack_limit = error + size;
18117c4ee5bcSRichard Henderson         return error;
18127c4ee5bcSRichard Henderson     }
181331e31b8aSbellard }
181431e31b8aSbellard 
1815cf129f3aSRichard Henderson /* Map and zero the bss.  We need to explicitly zero any fractional pages
1816cf129f3aSRichard Henderson    after the data section (i.e. bss).  */
1817cf129f3aSRichard Henderson static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
181831e31b8aSbellard {
1819cf129f3aSRichard Henderson     uintptr_t host_start, host_map_start, host_end;
1820cf129f3aSRichard Henderson 
1821cf129f3aSRichard Henderson     last_bss = TARGET_PAGE_ALIGN(last_bss);
1822cf129f3aSRichard Henderson 
1823cf129f3aSRichard Henderson     /* ??? There is confusion between qemu_real_host_page_size and
1824cf129f3aSRichard Henderson        qemu_host_page_size here and elsewhere in target_mmap, which
1825cf129f3aSRichard Henderson        may lead to the end of the data section mapping from the file
1826cf129f3aSRichard Henderson        not being mapped.  At least there was an explicit test and
1827cf129f3aSRichard Henderson        comment for that here, suggesting that "the file size must
1828cf129f3aSRichard Henderson        be known".  The comment probably pre-dates the introduction
1829cf129f3aSRichard Henderson        of the fstat system call in target_mmap which does in fact
1830cf129f3aSRichard Henderson        find out the size.  What isn't clear is if the workaround
1831cf129f3aSRichard Henderson        here is still actually needed.  For now, continue with it,
1832cf129f3aSRichard Henderson        but merge it with the "normal" mmap that would allocate the bss.  */
1833cf129f3aSRichard Henderson 
1834cf129f3aSRichard Henderson     host_start = (uintptr_t) g2h(elf_bss);
1835cf129f3aSRichard Henderson     host_end = (uintptr_t) g2h(last_bss);
18360c2d70c4SPaolo Bonzini     host_map_start = REAL_HOST_PAGE_ALIGN(host_start);
1837cf129f3aSRichard Henderson 
1838cf129f3aSRichard Henderson     if (host_map_start < host_end) {
1839cf129f3aSRichard Henderson         void *p = mmap((void *)host_map_start, host_end - host_map_start,
1840cf129f3aSRichard Henderson                        prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1841cf129f3aSRichard Henderson         if (p == MAP_FAILED) {
184231e31b8aSbellard             perror("cannot mmap brk");
184331e31b8aSbellard             exit(-1);
184431e31b8aSbellard         }
1845f46e9a0bSTom Musta     }
1846cf129f3aSRichard Henderson 
1847f46e9a0bSTom Musta     /* Ensure that the bss page(s) are valid */
1848f46e9a0bSTom Musta     if ((page_get_flags(last_bss-1) & prot) != prot) {
1849cf129f3aSRichard Henderson         page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot | PAGE_VALID);
185031e31b8aSbellard     }
185131e31b8aSbellard 
1852cf129f3aSRichard Henderson     if (host_start < host_map_start) {
1853cf129f3aSRichard Henderson         memset((void *)host_start, 0, host_map_start - host_start);
1854853d6f7aSbellard     }
1855853d6f7aSbellard }
1856853d6f7aSbellard 
1857cf58affeSChristophe Lyon #ifdef TARGET_ARM
1858cf58affeSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
1859cf58affeSChristophe Lyon {
1860cf58affeSChristophe Lyon     return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC;
1861cf58affeSChristophe Lyon }
1862cf58affeSChristophe Lyon #else
1863a99856cdSChristophe Lyon /* Default implementation, always false.  */
1864a99856cdSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
1865a99856cdSChristophe Lyon {
1866a99856cdSChristophe Lyon     return 0;
1867a99856cdSChristophe Lyon }
1868cf58affeSChristophe Lyon #endif
1869a99856cdSChristophe Lyon 
18701af02e83SMike Frysinger static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
18711af02e83SMike Frysinger {
18721af02e83SMike Frysinger     uint16_t n;
18731af02e83SMike Frysinger     struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
18741af02e83SMike Frysinger 
18751af02e83SMike Frysinger     /* elf32_fdpic_loadseg */
18761af02e83SMike Frysinger     n = info->nsegs;
18771af02e83SMike Frysinger     while (n--) {
18781af02e83SMike Frysinger         sp -= 12;
18791af02e83SMike Frysinger         put_user_u32(loadsegs[n].addr, sp+0);
18801af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_vaddr, sp+4);
18811af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_memsz, sp+8);
18821af02e83SMike Frysinger     }
18831af02e83SMike Frysinger 
18841af02e83SMike Frysinger     /* elf32_fdpic_loadmap */
18851af02e83SMike Frysinger     sp -= 4;
18861af02e83SMike Frysinger     put_user_u16(0, sp+0); /* version */
18871af02e83SMike Frysinger     put_user_u16(info->nsegs, sp+2); /* nsegs */
18881af02e83SMike Frysinger 
18891af02e83SMike Frysinger     info->personality = PER_LINUX_FDPIC;
18901af02e83SMike Frysinger     info->loadmap_addr = sp;
18911af02e83SMike Frysinger 
18921af02e83SMike Frysinger     return sp;
18931af02e83SMike Frysinger }
18941af02e83SMike Frysinger 
1895992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
189631e31b8aSbellard                                    struct elfhdr *exec,
18978e62a717SRichard Henderson                                    struct image_info *info,
18988e62a717SRichard Henderson                                    struct image_info *interp_info)
189931e31b8aSbellard {
1900992f48a0Sblueswir1     abi_ulong sp;
19017c4ee5bcSRichard Henderson     abi_ulong u_argc, u_argv, u_envp, u_auxv;
190253a5960aSpbrook     int size;
190314322badSLaurent ALFONSI     int i;
190414322badSLaurent ALFONSI     abi_ulong u_rand_bytes;
190514322badSLaurent ALFONSI     uint8_t k_rand_bytes[16];
1906992f48a0Sblueswir1     abi_ulong u_platform;
190715338fd7Sbellard     const char *k_platform;
1908863cf0b7Sj_mayer     const int n = sizeof(elf_addr_t);
190931e31b8aSbellard 
191053a5960aSpbrook     sp = p;
19111af02e83SMike Frysinger 
19121af02e83SMike Frysinger     /* Needs to be before we load the env/argc/... */
19131af02e83SMike Frysinger     if (elf_is_fdpic(exec)) {
19141af02e83SMike Frysinger         /* Need 4 byte alignment for these structs */
19151af02e83SMike Frysinger         sp &= ~3;
19161af02e83SMike Frysinger         sp = loader_build_fdpic_loadmap(info, sp);
19171af02e83SMike Frysinger         info->other_info = interp_info;
19181af02e83SMike Frysinger         if (interp_info) {
19191af02e83SMike Frysinger             interp_info->other_info = info;
19201af02e83SMike Frysinger             sp = loader_build_fdpic_loadmap(interp_info, sp);
19213cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = interp_info->loadmap_addr;
19223cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = interp_info->pt_dynamic_addr;
19233cb10cfaSChristophe Lyon         } else {
19243cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = 0;
19253cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = 0;
19261af02e83SMike Frysinger         }
19271af02e83SMike Frysinger     }
19281af02e83SMike Frysinger 
192953a5960aSpbrook     u_platform = 0;
193015338fd7Sbellard     k_platform = ELF_PLATFORM;
193115338fd7Sbellard     if (k_platform) {
193215338fd7Sbellard         size_t len = strlen(k_platform) + 1;
19337c4ee5bcSRichard Henderson         if (STACK_GROWS_DOWN) {
193453a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
193553a5960aSpbrook             u_platform = sp;
1936579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
193753a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
19387c4ee5bcSRichard Henderson         } else {
19397c4ee5bcSRichard Henderson             memcpy_to_target(sp, k_platform, len);
19407c4ee5bcSRichard Henderson             u_platform = sp;
19417c4ee5bcSRichard Henderson             sp += len + 1;
19427c4ee5bcSRichard Henderson         }
19437c4ee5bcSRichard Henderson     }
19447c4ee5bcSRichard Henderson 
19457c4ee5bcSRichard Henderson     /* Provide 16 byte alignment for the PRNG, and basic alignment for
19467c4ee5bcSRichard Henderson      * the argv and envp pointers.
19477c4ee5bcSRichard Henderson      */
19487c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
19497c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_DOWN(sp, 16);
19507c4ee5bcSRichard Henderson     } else {
19517c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp, 16);
195215338fd7Sbellard     }
195314322badSLaurent ALFONSI 
195414322badSLaurent ALFONSI     /*
1955c6a2377fSRichard Henderson      * Generate 16 random bytes for userspace PRNG seeding.
195614322badSLaurent ALFONSI      */
1957c6a2377fSRichard Henderson     qemu_guest_getrandom_nofail(k_rand_bytes, sizeof(k_rand_bytes));
19587c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
195914322badSLaurent ALFONSI         sp -= 16;
196014322badSLaurent ALFONSI         u_rand_bytes = sp;
196114322badSLaurent ALFONSI         /* FIXME - check return value of memcpy_to_target() for failure */
196214322badSLaurent ALFONSI         memcpy_to_target(sp, k_rand_bytes, 16);
19637c4ee5bcSRichard Henderson     } else {
19647c4ee5bcSRichard Henderson         memcpy_to_target(sp, k_rand_bytes, 16);
19657c4ee5bcSRichard Henderson         u_rand_bytes = sp;
19667c4ee5bcSRichard Henderson         sp += 16;
19677c4ee5bcSRichard Henderson     }
196814322badSLaurent ALFONSI 
196953a5960aSpbrook     size = (DLINFO_ITEMS + 1) * 2;
197015338fd7Sbellard     if (k_platform)
197153a5960aSpbrook         size += 2;
1972f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
197353a5960aSpbrook     size += DLINFO_ARCH_ITEMS * 2;
1974f5155289Sbellard #endif
1975ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
1976ad6919dcSPeter Maydell     size += 2;
1977ad6919dcSPeter Maydell #endif
1978f516511eSPeter Maydell     info->auxv_len = size * n;
1979f516511eSPeter Maydell 
198053a5960aSpbrook     size += envc + argc + 2;
1981b9329d4bSRichard Henderson     size += 1;  /* argc itself */
198253a5960aSpbrook     size *= n;
19837c4ee5bcSRichard Henderson 
19847c4ee5bcSRichard Henderson     /* Allocate space and finalize stack alignment for entry now.  */
19857c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
19867c4ee5bcSRichard Henderson         u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT);
19877c4ee5bcSRichard Henderson         sp = u_argc;
19887c4ee5bcSRichard Henderson     } else {
19897c4ee5bcSRichard Henderson         u_argc = sp;
19907c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT);
19917c4ee5bcSRichard Henderson     }
19927c4ee5bcSRichard Henderson 
19937c4ee5bcSRichard Henderson     u_argv = u_argc + n;
19947c4ee5bcSRichard Henderson     u_envp = u_argv + (argc + 1) * n;
19957c4ee5bcSRichard Henderson     u_auxv = u_envp + (envc + 1) * n;
19967c4ee5bcSRichard Henderson     info->saved_auxv = u_auxv;
19977c4ee5bcSRichard Henderson     info->arg_start = u_argv;
19987c4ee5bcSRichard Henderson     info->arg_end = u_argv + argc * n;
1999f5155289Sbellard 
2000863cf0b7Sj_mayer     /* This is correct because Linux defines
2001863cf0b7Sj_mayer      * elf_addr_t as Elf32_Off / Elf64_Off
2002863cf0b7Sj_mayer      */
200353a5960aSpbrook #define NEW_AUX_ENT(id, val) do {               \
20047c4ee5bcSRichard Henderson         put_user_ual(id, u_auxv);  u_auxv += n; \
20057c4ee5bcSRichard Henderson         put_user_ual(val, u_auxv); u_auxv += n; \
200653a5960aSpbrook     } while(0)
20072f619698Sbellard 
200882991bedSPeter Maydell #ifdef ARCH_DLINFO
200982991bedSPeter Maydell     /*
201082991bedSPeter Maydell      * ARCH_DLINFO must come first so platform specific code can enforce
201182991bedSPeter Maydell      * special alignment requirements on the AUXV if necessary (eg. PPC).
201282991bedSPeter Maydell      */
201382991bedSPeter Maydell     ARCH_DLINFO;
201482991bedSPeter Maydell #endif
2015f516511eSPeter Maydell     /* There must be exactly DLINFO_ITEMS entries here, or the assert
2016f516511eSPeter Maydell      * on info->auxv_len will trigger.
2017f516511eSPeter Maydell      */
20188e62a717SRichard Henderson     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
2019992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
2020992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
202133143c44SLaurent Vivier     if ((info->alignment & ~qemu_host_page_mask) != 0) {
202233143c44SLaurent Vivier         /* Target doesn't support host page size alignment */
202333143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
202433143c44SLaurent Vivier     } else {
202533143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE,
202633143c44SLaurent Vivier                                                qemu_host_page_size)));
202733143c44SLaurent Vivier     }
20288e62a717SRichard Henderson     NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
2029992f48a0Sblueswir1     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
20308e62a717SRichard Henderson     NEW_AUX_ENT(AT_ENTRY, info->entry);
2031992f48a0Sblueswir1     NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
2032992f48a0Sblueswir1     NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
2033992f48a0Sblueswir1     NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
2034992f48a0Sblueswir1     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
2035992f48a0Sblueswir1     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
2036a07c67dfSpbrook     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
203714322badSLaurent ALFONSI     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
2038444cd5c3SMarco A L Barbosa     NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
203914322badSLaurent ALFONSI 
2040ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2041ad6919dcSPeter Maydell     NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
2042ad6919dcSPeter Maydell #endif
2043ad6919dcSPeter Maydell 
20447c4ee5bcSRichard Henderson     if (u_platform) {
204553a5960aSpbrook         NEW_AUX_ENT(AT_PLATFORM, u_platform);
20467c4ee5bcSRichard Henderson     }
20477c4ee5bcSRichard Henderson     NEW_AUX_ENT (AT_NULL, 0);
2048f5155289Sbellard #undef NEW_AUX_ENT
2049f5155289Sbellard 
2050f516511eSPeter Maydell     /* Check that our initial calculation of the auxv length matches how much
2051f516511eSPeter Maydell      * we actually put into it.
2052f516511eSPeter Maydell      */
2053f516511eSPeter Maydell     assert(info->auxv_len == u_auxv - info->saved_auxv);
2054edf8e2afSMika Westerberg 
20557c4ee5bcSRichard Henderson     put_user_ual(argc, u_argc);
20567c4ee5bcSRichard Henderson 
20577c4ee5bcSRichard Henderson     p = info->arg_strings;
20587c4ee5bcSRichard Henderson     for (i = 0; i < argc; ++i) {
20597c4ee5bcSRichard Henderson         put_user_ual(p, u_argv);
20607c4ee5bcSRichard Henderson         u_argv += n;
20617c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
20627c4ee5bcSRichard Henderson     }
20637c4ee5bcSRichard Henderson     put_user_ual(0, u_argv);
20647c4ee5bcSRichard Henderson 
20657c4ee5bcSRichard Henderson     p = info->env_strings;
20667c4ee5bcSRichard Henderson     for (i = 0; i < envc; ++i) {
20677c4ee5bcSRichard Henderson         put_user_ual(p, u_envp);
20687c4ee5bcSRichard Henderson         u_envp += n;
20697c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
20707c4ee5bcSRichard Henderson     }
20717c4ee5bcSRichard Henderson     put_user_ual(0, u_envp);
20727c4ee5bcSRichard Henderson 
207331e31b8aSbellard     return sp;
207431e31b8aSbellard }
207531e31b8aSbellard 
2076dce10401SMeador Inge unsigned long init_guest_space(unsigned long host_start,
2077dce10401SMeador Inge                                unsigned long host_size,
2078dce10401SMeador Inge                                unsigned long guest_start,
2079dce10401SMeador Inge                                bool fixed)
2080dce10401SMeador Inge {
208130ab9ef2SRichard Henderson     /* In order to use host shmat, we must be able to honor SHMLBA.  */
208230ab9ef2SRichard Henderson     unsigned long align = MAX(SHMLBA, qemu_host_page_size);
2083293f2060SLuke Shumaker     unsigned long current_start, aligned_start;
2084dce10401SMeador Inge     int flags;
2085dce10401SMeador Inge 
2086dce10401SMeador Inge     assert(host_start || host_size);
2087dce10401SMeador Inge 
2088dce10401SMeador Inge     /* If just a starting address is given, then just verify that
2089dce10401SMeador Inge      * address.  */
2090dce10401SMeador Inge     if (host_start && !host_size) {
20918756e136SLuke Shumaker #if defined(TARGET_ARM) && !defined(TARGET_AARCH64)
2092c3637eafSLuke Shumaker         if (init_guest_commpage(host_start, host_size) != 1) {
2093dce10401SMeador Inge             return (unsigned long)-1;
2094dce10401SMeador Inge         }
20958756e136SLuke Shumaker #endif
20968756e136SLuke Shumaker         return host_start;
2097dce10401SMeador Inge     }
2098dce10401SMeador Inge 
2099dce10401SMeador Inge     /* Setup the initial flags and start address.  */
210030ab9ef2SRichard Henderson     current_start = host_start & -align;
2101dce10401SMeador Inge     flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
2102dce10401SMeador Inge     if (fixed) {
2103dce10401SMeador Inge         flags |= MAP_FIXED;
2104dce10401SMeador Inge     }
2105dce10401SMeador Inge 
2106dce10401SMeador Inge     /* Otherwise, a non-zero size region of memory needs to be mapped
2107dce10401SMeador Inge      * and validated.  */
21082a53535aSLuke Shumaker 
21092a53535aSLuke Shumaker #if defined(TARGET_ARM) && !defined(TARGET_AARCH64)
21102a53535aSLuke Shumaker     /* On 32-bit ARM, we need to map not just the usable memory, but
21112a53535aSLuke Shumaker      * also the commpage.  Try to find a suitable place by allocating
21122a53535aSLuke Shumaker      * a big chunk for all of it.  If host_start, then the naive
21132a53535aSLuke Shumaker      * strategy probably does good enough.
21142a53535aSLuke Shumaker      */
21152a53535aSLuke Shumaker     if (!host_start) {
21162a53535aSLuke Shumaker         unsigned long guest_full_size, host_full_size, real_start;
21172a53535aSLuke Shumaker 
21182a53535aSLuke Shumaker         guest_full_size =
21192a53535aSLuke Shumaker             (0xffff0f00 & qemu_host_page_mask) + qemu_host_page_size;
21202a53535aSLuke Shumaker         host_full_size = guest_full_size - guest_start;
21212a53535aSLuke Shumaker         real_start = (unsigned long)
21222a53535aSLuke Shumaker             mmap(NULL, host_full_size, PROT_NONE, flags, -1, 0);
21232a53535aSLuke Shumaker         if (real_start == (unsigned long)-1) {
21242a53535aSLuke Shumaker             if (host_size < host_full_size - qemu_host_page_size) {
21252a53535aSLuke Shumaker                 /* We failed to map a continous segment, but we're
21262a53535aSLuke Shumaker                  * allowed to have a gap between the usable memory and
21272a53535aSLuke Shumaker                  * the commpage where other things can be mapped.
21282a53535aSLuke Shumaker                  * This sparseness gives us more flexibility to find
21292a53535aSLuke Shumaker                  * an address range.
21302a53535aSLuke Shumaker                  */
21312a53535aSLuke Shumaker                 goto naive;
21322a53535aSLuke Shumaker             }
21332a53535aSLuke Shumaker             return (unsigned long)-1;
21342a53535aSLuke Shumaker         }
21352a53535aSLuke Shumaker         munmap((void *)real_start, host_full_size);
213630ab9ef2SRichard Henderson         if (real_start & (align - 1)) {
213730ab9ef2SRichard Henderson             /* The same thing again, but with extra
21382a53535aSLuke Shumaker              * so that we can shift around alignment.
21392a53535aSLuke Shumaker              */
21402a53535aSLuke Shumaker             unsigned long real_size = host_full_size + qemu_host_page_size;
21412a53535aSLuke Shumaker             real_start = (unsigned long)
21422a53535aSLuke Shumaker                 mmap(NULL, real_size, PROT_NONE, flags, -1, 0);
21432a53535aSLuke Shumaker             if (real_start == (unsigned long)-1) {
21442a53535aSLuke Shumaker                 if (host_size < host_full_size - qemu_host_page_size) {
21452a53535aSLuke Shumaker                     goto naive;
21462a53535aSLuke Shumaker                 }
21472a53535aSLuke Shumaker                 return (unsigned long)-1;
21482a53535aSLuke Shumaker             }
21492a53535aSLuke Shumaker             munmap((void *)real_start, real_size);
215030ab9ef2SRichard Henderson             real_start = ROUND_UP(real_start, align);
21512a53535aSLuke Shumaker         }
21522a53535aSLuke Shumaker         current_start = real_start;
21532a53535aSLuke Shumaker     }
21542a53535aSLuke Shumaker  naive:
21552a53535aSLuke Shumaker #endif
21562a53535aSLuke Shumaker 
2157dce10401SMeador Inge     while (1) {
2158293f2060SLuke Shumaker         unsigned long real_start, real_size, aligned_size;
2159293f2060SLuke Shumaker         aligned_size = real_size = host_size;
2160806d1021SMeador Inge 
2161dce10401SMeador Inge         /* Do not use mmap_find_vma here because that is limited to the
2162dce10401SMeador Inge          * guest address space.  We are going to make the
2163dce10401SMeador Inge          * guest address space fit whatever we're given.
2164dce10401SMeador Inge          */
2165dce10401SMeador Inge         real_start = (unsigned long)
2166dce10401SMeador Inge             mmap((void *)current_start, host_size, PROT_NONE, flags, -1, 0);
2167dce10401SMeador Inge         if (real_start == (unsigned long)-1) {
2168dce10401SMeador Inge             return (unsigned long)-1;
2169dce10401SMeador Inge         }
2170dce10401SMeador Inge 
2171aac362e4SLuke Shumaker         /* Check to see if the address is valid.  */
2172aac362e4SLuke Shumaker         if (host_start && real_start != current_start) {
2173aac362e4SLuke Shumaker             goto try_again;
2174aac362e4SLuke Shumaker         }
2175aac362e4SLuke Shumaker 
2176806d1021SMeador Inge         /* Ensure the address is properly aligned.  */
217730ab9ef2SRichard Henderson         if (real_start & (align - 1)) {
2178293f2060SLuke Shumaker             /* Ideally, we adjust like
2179293f2060SLuke Shumaker              *
2180293f2060SLuke Shumaker              *    pages: [  ][  ][  ][  ][  ]
2181293f2060SLuke Shumaker              *      old:   [   real   ]
2182293f2060SLuke Shumaker              *             [ aligned  ]
2183293f2060SLuke Shumaker              *      new:   [     real     ]
2184293f2060SLuke Shumaker              *               [ aligned  ]
2185293f2060SLuke Shumaker              *
2186293f2060SLuke Shumaker              * But if there is something else mapped right after it,
2187293f2060SLuke Shumaker              * then obviously it won't have room to grow, and the
2188293f2060SLuke Shumaker              * kernel will put the new larger real someplace else with
2189293f2060SLuke Shumaker              * unknown alignment (if we made it to here, then
2190293f2060SLuke Shumaker              * fixed=false).  Which is why we grow real by a full page
2191293f2060SLuke Shumaker              * size, instead of by part of one; so that even if we get
2192293f2060SLuke Shumaker              * moved, we can still guarantee alignment.  But this does
2193293f2060SLuke Shumaker              * mean that there is a padding of < 1 page both before
2194293f2060SLuke Shumaker              * and after the aligned range; the "after" could could
2195293f2060SLuke Shumaker              * cause problems for ARM emulation where it could butt in
2196293f2060SLuke Shumaker              * to where we need to put the commpage.
2197293f2060SLuke Shumaker              */
2198806d1021SMeador Inge             munmap((void *)real_start, host_size);
219991c8bdb1SXinyu Li             real_size = aligned_size + align;
2200806d1021SMeador Inge             real_start = (unsigned long)
2201806d1021SMeador Inge                 mmap((void *)real_start, real_size, PROT_NONE, flags, -1, 0);
2202806d1021SMeador Inge             if (real_start == (unsigned long)-1) {
2203806d1021SMeador Inge                 return (unsigned long)-1;
2204806d1021SMeador Inge             }
220530ab9ef2SRichard Henderson             aligned_start = ROUND_UP(real_start, align);
2206293f2060SLuke Shumaker         } else {
2207293f2060SLuke Shumaker             aligned_start = real_start;
2208806d1021SMeador Inge         }
2209806d1021SMeador Inge 
22108756e136SLuke Shumaker #if defined(TARGET_ARM) && !defined(TARGET_AARCH64)
22118756e136SLuke Shumaker         /* On 32-bit ARM, we need to also be able to map the commpage.  */
2212293f2060SLuke Shumaker         int valid = init_guest_commpage(aligned_start - guest_start,
2213293f2060SLuke Shumaker                                         aligned_size + guest_start);
22147ad75eeaSLuke Shumaker         if (valid == -1) {
2215293f2060SLuke Shumaker             munmap((void *)real_start, real_size);
2216806d1021SMeador Inge             return (unsigned long)-1;
22177ad75eeaSLuke Shumaker         } else if (valid == 0) {
22187ad75eeaSLuke Shumaker             goto try_again;
2219806d1021SMeador Inge         }
22208756e136SLuke Shumaker #endif
2221dce10401SMeador Inge 
22227ad75eeaSLuke Shumaker         /* If nothing has said `return -1` or `goto try_again` yet,
22237ad75eeaSLuke Shumaker          * then the address we have is good.
22247ad75eeaSLuke Shumaker          */
22257ad75eeaSLuke Shumaker         break;
22267ad75eeaSLuke Shumaker 
22277ad75eeaSLuke Shumaker     try_again:
2228dce10401SMeador Inge         /* That address didn't work.  Unmap and try a different one.
2229dce10401SMeador Inge          * The address the host picked because is typically right at
2230dce10401SMeador Inge          * the top of the host address space and leaves the guest with
2231dce10401SMeador Inge          * no usable address space.  Resort to a linear search.  We
2232dce10401SMeador Inge          * already compensated for mmap_min_addr, so this should not
2233dce10401SMeador Inge          * happen often.  Probably means we got unlucky and host
2234dce10401SMeador Inge          * address space randomization put a shared library somewhere
2235dce10401SMeador Inge          * inconvenient.
22368c17d862SLuke Shumaker          *
22378c17d862SLuke Shumaker          * This is probably a good strategy if host_start, but is
22388c17d862SLuke Shumaker          * probably a bad strategy if not, which means we got here
22398c17d862SLuke Shumaker          * because of trouble with ARM commpage setup.
2240dce10401SMeador Inge          */
2241293f2060SLuke Shumaker         munmap((void *)real_start, real_size);
224230ab9ef2SRichard Henderson         current_start += align;
2243dce10401SMeador Inge         if (host_start == current_start) {
2244dce10401SMeador Inge             /* Theoretically possible if host doesn't have any suitably
2245dce10401SMeador Inge              * aligned areas.  Normally the first mmap will fail.
2246dce10401SMeador Inge              */
2247dce10401SMeador Inge             return (unsigned long)-1;
2248dce10401SMeador Inge         }
2249dce10401SMeador Inge     }
2250dce10401SMeador Inge 
225113829020SPaolo Bonzini     qemu_log_mask(CPU_LOG_PAGE, "Reserved 0x%lx bytes of guest address space\n", host_size);
2252806d1021SMeador Inge 
2253293f2060SLuke Shumaker     return aligned_start;
2254dce10401SMeador Inge }
2255dce10401SMeador Inge 
2256f3ed1f5dSPeter Maydell static void probe_guest_base(const char *image_name,
2257f3ed1f5dSPeter Maydell                              abi_ulong loaddr, abi_ulong hiaddr)
2258f3ed1f5dSPeter Maydell {
2259f3ed1f5dSPeter Maydell     /* Probe for a suitable guest base address, if the user has not set
2260f3ed1f5dSPeter Maydell      * it explicitly, and set guest_base appropriately.
2261f3ed1f5dSPeter Maydell      * In case of error we will print a suitable message and exit.
2262f3ed1f5dSPeter Maydell      */
2263f3ed1f5dSPeter Maydell     const char *errmsg;
2264f3ed1f5dSPeter Maydell     if (!have_guest_base && !reserved_va) {
2265f3ed1f5dSPeter Maydell         unsigned long host_start, real_start, host_size;
2266f3ed1f5dSPeter Maydell 
2267f3ed1f5dSPeter Maydell         /* Round addresses to page boundaries.  */
2268f3ed1f5dSPeter Maydell         loaddr &= qemu_host_page_mask;
2269f3ed1f5dSPeter Maydell         hiaddr = HOST_PAGE_ALIGN(hiaddr);
2270f3ed1f5dSPeter Maydell 
2271f3ed1f5dSPeter Maydell         if (loaddr < mmap_min_addr) {
2272f3ed1f5dSPeter Maydell             host_start = HOST_PAGE_ALIGN(mmap_min_addr);
2273f3ed1f5dSPeter Maydell         } else {
2274f3ed1f5dSPeter Maydell             host_start = loaddr;
2275f3ed1f5dSPeter Maydell             if (host_start != loaddr) {
2276f3ed1f5dSPeter Maydell                 errmsg = "Address overflow loading ELF binary";
2277f3ed1f5dSPeter Maydell                 goto exit_errmsg;
2278f3ed1f5dSPeter Maydell             }
2279f3ed1f5dSPeter Maydell         }
2280f3ed1f5dSPeter Maydell         host_size = hiaddr - loaddr;
2281dce10401SMeador Inge 
2282dce10401SMeador Inge         /* Setup the initial guest memory space with ranges gleaned from
2283dce10401SMeador Inge          * the ELF image that is being loaded.
2284dce10401SMeador Inge          */
2285dce10401SMeador Inge         real_start = init_guest_space(host_start, host_size, loaddr, false);
2286f3ed1f5dSPeter Maydell         if (real_start == (unsigned long)-1) {
2287f3ed1f5dSPeter Maydell             errmsg = "Unable to find space for application";
2288f3ed1f5dSPeter Maydell             goto exit_errmsg;
2289f3ed1f5dSPeter Maydell         }
2290dce10401SMeador Inge         guest_base = real_start - loaddr;
2291dce10401SMeador Inge 
229213829020SPaolo Bonzini         qemu_log_mask(CPU_LOG_PAGE, "Relocating guest address space from 0x"
2293f3ed1f5dSPeter Maydell                       TARGET_ABI_FMT_lx " to 0x%lx\n",
2294f3ed1f5dSPeter Maydell                       loaddr, real_start);
2295f3ed1f5dSPeter Maydell     }
2296f3ed1f5dSPeter Maydell     return;
2297f3ed1f5dSPeter Maydell 
2298f3ed1f5dSPeter Maydell exit_errmsg:
2299f3ed1f5dSPeter Maydell     fprintf(stderr, "%s: %s\n", image_name, errmsg);
2300f3ed1f5dSPeter Maydell     exit(-1);
2301f3ed1f5dSPeter Maydell }
2302f3ed1f5dSPeter Maydell 
2303f3ed1f5dSPeter Maydell 
23048e62a717SRichard Henderson /* Load an ELF image into the address space.
230531e31b8aSbellard 
23068e62a717SRichard Henderson    IMAGE_NAME is the filename of the image, to use in error messages.
23078e62a717SRichard Henderson    IMAGE_FD is the open file descriptor for the image.
23088e62a717SRichard Henderson 
23098e62a717SRichard Henderson    BPRM_BUF is a copy of the beginning of the file; this of course
23108e62a717SRichard Henderson    contains the elf file header at offset 0.  It is assumed that this
23118e62a717SRichard Henderson    buffer is sufficiently aligned to present no problems to the host
23128e62a717SRichard Henderson    in accessing data at aligned offsets within the buffer.
23138e62a717SRichard Henderson 
23148e62a717SRichard Henderson    On return: INFO values will be filled in, as necessary or available.  */
23158e62a717SRichard Henderson 
23168e62a717SRichard Henderson static void load_elf_image(const char *image_name, int image_fd,
2317bf858897SRichard Henderson                            struct image_info *info, char **pinterp_name,
23189955ffacSRichard Henderson                            char bprm_buf[BPRM_BUF_SIZE])
231931e31b8aSbellard {
23208e62a717SRichard Henderson     struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
23218e62a717SRichard Henderson     struct elf_phdr *phdr;
23228e62a717SRichard Henderson     abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
23238e62a717SRichard Henderson     int i, retval;
23248e62a717SRichard Henderson     const char *errmsg;
232531e31b8aSbellard 
23268e62a717SRichard Henderson     /* First of all, some simple consistency checks */
23278e62a717SRichard Henderson     errmsg = "Invalid ELF image for this architecture";
23288e62a717SRichard Henderson     if (!elf_check_ident(ehdr)) {
23298e62a717SRichard Henderson         goto exit_errmsg;
23308e62a717SRichard Henderson     }
23318e62a717SRichard Henderson     bswap_ehdr(ehdr);
23328e62a717SRichard Henderson     if (!elf_check_ehdr(ehdr)) {
23338e62a717SRichard Henderson         goto exit_errmsg;
233431e31b8aSbellard     }
233531e31b8aSbellard 
23368e62a717SRichard Henderson     i = ehdr->e_phnum * sizeof(struct elf_phdr);
23378e62a717SRichard Henderson     if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
23388e62a717SRichard Henderson         phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
23399955ffacSRichard Henderson     } else {
23408e62a717SRichard Henderson         phdr = (struct elf_phdr *) alloca(i);
23418e62a717SRichard Henderson         retval = pread(image_fd, phdr, i, ehdr->e_phoff);
23429955ffacSRichard Henderson         if (retval != i) {
23438e62a717SRichard Henderson             goto exit_read;
23449955ffacSRichard Henderson         }
234531e31b8aSbellard     }
23468e62a717SRichard Henderson     bswap_phdr(phdr, ehdr->e_phnum);
234709bfb054Sbellard 
23481af02e83SMike Frysinger     info->nsegs = 0;
23491af02e83SMike Frysinger     info->pt_dynamic_addr = 0;
23501af02e83SMike Frysinger 
235198c1076cSAlex Bennée     mmap_lock();
235298c1076cSAlex Bennée 
2353682674b8SRichard Henderson     /* Find the maximum size of the image and allocate an appropriate
2354682674b8SRichard Henderson        amount of memory to handle that.  */
2355682674b8SRichard Henderson     loaddr = -1, hiaddr = 0;
235633143c44SLaurent Vivier     info->alignment = 0;
23578e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; ++i) {
23588e62a717SRichard Henderson         if (phdr[i].p_type == PT_LOAD) {
2359a93934feSJonas Maebe             abi_ulong a = phdr[i].p_vaddr - phdr[i].p_offset;
2360682674b8SRichard Henderson             if (a < loaddr) {
2361682674b8SRichard Henderson                 loaddr = a;
2362682674b8SRichard Henderson             }
2363ccf661f8STom Musta             a = phdr[i].p_vaddr + phdr[i].p_memsz;
2364682674b8SRichard Henderson             if (a > hiaddr) {
2365682674b8SRichard Henderson                 hiaddr = a;
2366682674b8SRichard Henderson             }
23671af02e83SMike Frysinger             ++info->nsegs;
236833143c44SLaurent Vivier             info->alignment |= phdr[i].p_align;
2369682674b8SRichard Henderson         }
2370682674b8SRichard Henderson     }
2371682674b8SRichard Henderson 
23726fd59449SRichard Henderson     if (pinterp_name != NULL) {
23736fd59449SRichard Henderson         /*
23746fd59449SRichard Henderson          * This is the main executable.
23756fd59449SRichard Henderson          *
23766fd59449SRichard Henderson          * Reserve extra space for brk.
23776fd59449SRichard Henderson          * We hold on to this space while placing the interpreter
23786fd59449SRichard Henderson          * and the stack, lest they be placed immediately after
23796fd59449SRichard Henderson          * the data segment and block allocation from the brk.
23806fd59449SRichard Henderson          *
23816fd59449SRichard Henderson          * 16MB is chosen as "large enough" without being so large
23826fd59449SRichard Henderson          * as to allow the result to not fit with a 32-bit guest on
23836fd59449SRichard Henderson          * a 32-bit host.
23846fd59449SRichard Henderson          */
23856fd59449SRichard Henderson         info->reserve_brk = 16 * MiB;
23866fd59449SRichard Henderson         hiaddr += info->reserve_brk;
23876fd59449SRichard Henderson 
23886fd59449SRichard Henderson         if (ehdr->e_type == ET_EXEC) {
23896fd59449SRichard Henderson             /*
23906fd59449SRichard Henderson              * Make sure that the low address does not conflict with
23916fd59449SRichard Henderson              * MMAP_MIN_ADDR or the QEMU application itself.
23926fd59449SRichard Henderson              */
23936fd59449SRichard Henderson             probe_guest_base(image_name, loaddr, hiaddr);
23946fd59449SRichard Henderson         }
23956fd59449SRichard Henderson     }
23966fd59449SRichard Henderson 
23976fd59449SRichard Henderson     /*
23986fd59449SRichard Henderson      * Reserve address space for all of this.
23996fd59449SRichard Henderson      *
24006fd59449SRichard Henderson      * In the case of ET_EXEC, we supply MAP_FIXED so that we get
24016fd59449SRichard Henderson      * exactly the address range that is required.
24026fd59449SRichard Henderson      *
24036fd59449SRichard Henderson      * Otherwise this is ET_DYN, and we are searching for a location
24046fd59449SRichard Henderson      * that can hold the memory space required.  If the image is
24056fd59449SRichard Henderson      * pre-linked, LOADDR will be non-zero, and the kernel should
24066fd59449SRichard Henderson      * honor that address if it happens to be free.
24076fd59449SRichard Henderson      *
24086fd59449SRichard Henderson      * In both cases, we will overwrite pages in this range with mappings
24096fd59449SRichard Henderson      * from the executable.
24106fd59449SRichard Henderson      */
2411682674b8SRichard Henderson     load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE,
24126fd59449SRichard Henderson                             MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
24136fd59449SRichard Henderson                             (ehdr->e_type == ET_EXEC ? MAP_FIXED : 0),
241409bfb054Sbellard                             -1, 0);
2415682674b8SRichard Henderson     if (load_addr == -1) {
24168e62a717SRichard Henderson         goto exit_perror;
241709bfb054Sbellard     }
2418682674b8SRichard Henderson     load_bias = load_addr - loaddr;
241909bfb054Sbellard 
2420a99856cdSChristophe Lyon     if (elf_is_fdpic(ehdr)) {
24211af02e83SMike Frysinger         struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
24227267c094SAnthony Liguori             g_malloc(sizeof(*loadsegs) * info->nsegs);
24231af02e83SMike Frysinger 
24241af02e83SMike Frysinger         for (i = 0; i < ehdr->e_phnum; ++i) {
24251af02e83SMike Frysinger             switch (phdr[i].p_type) {
24261af02e83SMike Frysinger             case PT_DYNAMIC:
24271af02e83SMike Frysinger                 info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
24281af02e83SMike Frysinger                 break;
24291af02e83SMike Frysinger             case PT_LOAD:
24301af02e83SMike Frysinger                 loadsegs->addr = phdr[i].p_vaddr + load_bias;
24311af02e83SMike Frysinger                 loadsegs->p_vaddr = phdr[i].p_vaddr;
24321af02e83SMike Frysinger                 loadsegs->p_memsz = phdr[i].p_memsz;
24331af02e83SMike Frysinger                 ++loadsegs;
24341af02e83SMike Frysinger                 break;
24351af02e83SMike Frysinger             }
24361af02e83SMike Frysinger         }
24371af02e83SMike Frysinger     }
24381af02e83SMike Frysinger 
24398e62a717SRichard Henderson     info->load_bias = load_bias;
2440dc12567aSJosh Kunz     info->code_offset = load_bias;
2441dc12567aSJosh Kunz     info->data_offset = load_bias;
24428e62a717SRichard Henderson     info->load_addr = load_addr;
24438e62a717SRichard Henderson     info->entry = ehdr->e_entry + load_bias;
24448e62a717SRichard Henderson     info->start_code = -1;
24458e62a717SRichard Henderson     info->end_code = 0;
24468e62a717SRichard Henderson     info->start_data = -1;
24478e62a717SRichard Henderson     info->end_data = 0;
24488e62a717SRichard Henderson     info->brk = 0;
2449d8fd2954SPaul Brook     info->elf_flags = ehdr->e_flags;
24508e62a717SRichard Henderson 
24518e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; i++) {
24528e62a717SRichard Henderson         struct elf_phdr *eppnt = phdr + i;
245331e31b8aSbellard         if (eppnt->p_type == PT_LOAD) {
245494894ff2SShivaprasad G Bhat             abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em, vaddr_len;
245531e31b8aSbellard             int elf_prot = 0;
245631e31b8aSbellard 
245731e31b8aSbellard             if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
245831e31b8aSbellard             if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
245931e31b8aSbellard             if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
246031e31b8aSbellard 
2461682674b8SRichard Henderson             vaddr = load_bias + eppnt->p_vaddr;
2462682674b8SRichard Henderson             vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
2463682674b8SRichard Henderson             vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
246494894ff2SShivaprasad G Bhat             vaddr_len = TARGET_ELF_PAGELENGTH(eppnt->p_filesz + vaddr_po);
2465682674b8SRichard Henderson 
2466d87146bcSGiuseppe Musacchio             /*
2467d87146bcSGiuseppe Musacchio              * Some segments may be completely empty without any backing file
2468d87146bcSGiuseppe Musacchio              * segment, in that case just let zero_bss allocate an empty buffer
2469d87146bcSGiuseppe Musacchio              * for it.
2470d87146bcSGiuseppe Musacchio              */
2471d87146bcSGiuseppe Musacchio             if (eppnt->p_filesz != 0) {
2472d87146bcSGiuseppe Musacchio                 error = target_mmap(vaddr_ps, vaddr_len, elf_prot,
2473d87146bcSGiuseppe Musacchio                                     MAP_PRIVATE | MAP_FIXED,
24748e62a717SRichard Henderson                                     image_fd, eppnt->p_offset - vaddr_po);
2475d87146bcSGiuseppe Musacchio 
2476e89f07d3Spbrook                 if (error == -1) {
24778e62a717SRichard Henderson                     goto exit_perror;
247831e31b8aSbellard                 }
2479d87146bcSGiuseppe Musacchio             }
248031e31b8aSbellard 
2481682674b8SRichard Henderson             vaddr_ef = vaddr + eppnt->p_filesz;
2482682674b8SRichard Henderson             vaddr_em = vaddr + eppnt->p_memsz;
248331e31b8aSbellard 
2484cf129f3aSRichard Henderson             /* If the load segment requests extra zeros (e.g. bss), map it.  */
2485682674b8SRichard Henderson             if (vaddr_ef < vaddr_em) {
2486682674b8SRichard Henderson                 zero_bss(vaddr_ef, vaddr_em, elf_prot);
2487682674b8SRichard Henderson             }
24888e62a717SRichard Henderson 
24898e62a717SRichard Henderson             /* Find the full program boundaries.  */
24908e62a717SRichard Henderson             if (elf_prot & PROT_EXEC) {
24918e62a717SRichard Henderson                 if (vaddr < info->start_code) {
24928e62a717SRichard Henderson                     info->start_code = vaddr;
2493cf129f3aSRichard Henderson                 }
24948e62a717SRichard Henderson                 if (vaddr_ef > info->end_code) {
24958e62a717SRichard Henderson                     info->end_code = vaddr_ef;
24968e62a717SRichard Henderson                 }
24978e62a717SRichard Henderson             }
24988e62a717SRichard Henderson             if (elf_prot & PROT_WRITE) {
24998e62a717SRichard Henderson                 if (vaddr < info->start_data) {
25008e62a717SRichard Henderson                     info->start_data = vaddr;
25018e62a717SRichard Henderson                 }
25028e62a717SRichard Henderson                 if (vaddr_ef > info->end_data) {
25038e62a717SRichard Henderson                     info->end_data = vaddr_ef;
25048e62a717SRichard Henderson                 }
25058e62a717SRichard Henderson                 if (vaddr_em > info->brk) {
25068e62a717SRichard Henderson                     info->brk = vaddr_em;
25078e62a717SRichard Henderson                 }
25088e62a717SRichard Henderson             }
2509bf858897SRichard Henderson         } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
2510bf858897SRichard Henderson             char *interp_name;
2511bf858897SRichard Henderson 
2512bf858897SRichard Henderson             if (*pinterp_name) {
2513bf858897SRichard Henderson                 errmsg = "Multiple PT_INTERP entries";
2514bf858897SRichard Henderson                 goto exit_errmsg;
2515bf858897SRichard Henderson             }
2516bf858897SRichard Henderson             interp_name = malloc(eppnt->p_filesz);
2517bf858897SRichard Henderson             if (!interp_name) {
2518bf858897SRichard Henderson                 goto exit_perror;
2519bf858897SRichard Henderson             }
2520bf858897SRichard Henderson 
2521bf858897SRichard Henderson             if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
2522bf858897SRichard Henderson                 memcpy(interp_name, bprm_buf + eppnt->p_offset,
2523bf858897SRichard Henderson                        eppnt->p_filesz);
2524bf858897SRichard Henderson             } else {
2525bf858897SRichard Henderson                 retval = pread(image_fd, interp_name, eppnt->p_filesz,
2526bf858897SRichard Henderson                                eppnt->p_offset);
2527bf858897SRichard Henderson                 if (retval != eppnt->p_filesz) {
2528bf858897SRichard Henderson                     goto exit_perror;
2529bf858897SRichard Henderson                 }
2530bf858897SRichard Henderson             }
2531bf858897SRichard Henderson             if (interp_name[eppnt->p_filesz - 1] != 0) {
2532bf858897SRichard Henderson                 errmsg = "Invalid PT_INTERP entry";
2533bf858897SRichard Henderson                 goto exit_errmsg;
2534bf858897SRichard Henderson             }
2535bf858897SRichard Henderson             *pinterp_name = interp_name;
25365dd0db52SStefan Markovic #ifdef TARGET_MIPS
25375dd0db52SStefan Markovic         } else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
25385dd0db52SStefan Markovic             Mips_elf_abiflags_v0 abiflags;
25395dd0db52SStefan Markovic             if (eppnt->p_filesz < sizeof(Mips_elf_abiflags_v0)) {
25405dd0db52SStefan Markovic                 errmsg = "Invalid PT_MIPS_ABIFLAGS entry";
25415dd0db52SStefan Markovic                 goto exit_errmsg;
25425dd0db52SStefan Markovic             }
25435dd0db52SStefan Markovic             if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
25445dd0db52SStefan Markovic                 memcpy(&abiflags, bprm_buf + eppnt->p_offset,
25455dd0db52SStefan Markovic                        sizeof(Mips_elf_abiflags_v0));
25465dd0db52SStefan Markovic             } else {
25475dd0db52SStefan Markovic                 retval = pread(image_fd, &abiflags, sizeof(Mips_elf_abiflags_v0),
25485dd0db52SStefan Markovic                                eppnt->p_offset);
25495dd0db52SStefan Markovic                 if (retval != sizeof(Mips_elf_abiflags_v0)) {
25505dd0db52SStefan Markovic                     goto exit_perror;
25515dd0db52SStefan Markovic                 }
25525dd0db52SStefan Markovic             }
25535dd0db52SStefan Markovic             bswap_mips_abiflags(&abiflags);
2554c94cb6c9SStefan Markovic             info->fp_abi = abiflags.fp_abi;
25555dd0db52SStefan Markovic #endif
25568e62a717SRichard Henderson         }
25578e62a717SRichard Henderson     }
25588e62a717SRichard Henderson 
25598e62a717SRichard Henderson     if (info->end_data == 0) {
25608e62a717SRichard Henderson         info->start_data = info->end_code;
25618e62a717SRichard Henderson         info->end_data = info->end_code;
25628e62a717SRichard Henderson         info->brk = info->end_code;
256331e31b8aSbellard     }
256431e31b8aSbellard 
2565682674b8SRichard Henderson     if (qemu_log_enabled()) {
25668e62a717SRichard Henderson         load_symbols(ehdr, image_fd, load_bias);
2567682674b8SRichard Henderson     }
256831e31b8aSbellard 
256998c1076cSAlex Bennée     mmap_unlock();
257098c1076cSAlex Bennée 
25718e62a717SRichard Henderson     close(image_fd);
25728e62a717SRichard Henderson     return;
257331e31b8aSbellard 
25748e62a717SRichard Henderson  exit_read:
25758e62a717SRichard Henderson     if (retval >= 0) {
25768e62a717SRichard Henderson         errmsg = "Incomplete read of file header";
25778e62a717SRichard Henderson         goto exit_errmsg;
25788e62a717SRichard Henderson     }
25798e62a717SRichard Henderson  exit_perror:
25808e62a717SRichard Henderson     errmsg = strerror(errno);
25818e62a717SRichard Henderson  exit_errmsg:
25828e62a717SRichard Henderson     fprintf(stderr, "%s: %s\n", image_name, errmsg);
25838e62a717SRichard Henderson     exit(-1);
25848e62a717SRichard Henderson }
25858e62a717SRichard Henderson 
25868e62a717SRichard Henderson static void load_elf_interp(const char *filename, struct image_info *info,
25878e62a717SRichard Henderson                             char bprm_buf[BPRM_BUF_SIZE])
25888e62a717SRichard Henderson {
25898e62a717SRichard Henderson     int fd, retval;
25908e62a717SRichard Henderson 
25918e62a717SRichard Henderson     fd = open(path(filename), O_RDONLY);
25928e62a717SRichard Henderson     if (fd < 0) {
25938e62a717SRichard Henderson         goto exit_perror;
25948e62a717SRichard Henderson     }
25958e62a717SRichard Henderson 
25968e62a717SRichard Henderson     retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
25978e62a717SRichard Henderson     if (retval < 0) {
25988e62a717SRichard Henderson         goto exit_perror;
25998e62a717SRichard Henderson     }
26008e62a717SRichard Henderson     if (retval < BPRM_BUF_SIZE) {
26018e62a717SRichard Henderson         memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
26028e62a717SRichard Henderson     }
26038e62a717SRichard Henderson 
2604bf858897SRichard Henderson     load_elf_image(filename, fd, info, NULL, bprm_buf);
26058e62a717SRichard Henderson     return;
26068e62a717SRichard Henderson 
26078e62a717SRichard Henderson  exit_perror:
26088e62a717SRichard Henderson     fprintf(stderr, "%s: %s\n", filename, strerror(errno));
26098e62a717SRichard Henderson     exit(-1);
261031e31b8aSbellard }
261131e31b8aSbellard 
261249918a75Spbrook static int symfind(const void *s0, const void *s1)
261349918a75Spbrook {
2614c7c530cdSStefan Weil     target_ulong addr = *(target_ulong *)s0;
261549918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
261649918a75Spbrook     int result = 0;
2617c7c530cdSStefan Weil     if (addr < sym->st_value) {
261849918a75Spbrook         result = -1;
2619c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
262049918a75Spbrook         result = 1;
262149918a75Spbrook     }
262249918a75Spbrook     return result;
262349918a75Spbrook }
262449918a75Spbrook 
262549918a75Spbrook static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
262649918a75Spbrook {
262749918a75Spbrook #if ELF_CLASS == ELFCLASS32
262849918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
262949918a75Spbrook #else
263049918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
263149918a75Spbrook #endif
263249918a75Spbrook 
263349918a75Spbrook     // binary search
263449918a75Spbrook     struct elf_sym *sym;
263549918a75Spbrook 
2636c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
26377cba04f6SBlue Swirl     if (sym != NULL) {
263849918a75Spbrook         return s->disas_strtab + sym->st_name;
263949918a75Spbrook     }
264049918a75Spbrook 
264149918a75Spbrook     return "";
264249918a75Spbrook }
264349918a75Spbrook 
264449918a75Spbrook /* FIXME: This should use elf_ops.h  */
264549918a75Spbrook static int symcmp(const void *s0, const void *s1)
264649918a75Spbrook {
264749918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
264849918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
264949918a75Spbrook     return (sym0->st_value < sym1->st_value)
265049918a75Spbrook         ? -1
265149918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
265249918a75Spbrook }
265349918a75Spbrook 
2654689f936fSbellard /* Best attempt to load symbols from this ELF object. */
2655682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
2656689f936fSbellard {
2657682674b8SRichard Henderson     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
26581e06262dSPeter Maydell     uint64_t segsz;
2659682674b8SRichard Henderson     struct elf_shdr *shdr;
2660b9475279SCédric VINCENT     char *strings = NULL;
2661b9475279SCédric VINCENT     struct syminfo *s = NULL;
2662b9475279SCédric VINCENT     struct elf_sym *new_syms, *syms = NULL;
266331e31b8aSbellard 
2664682674b8SRichard Henderson     shnum = hdr->e_shnum;
2665682674b8SRichard Henderson     i = shnum * sizeof(struct elf_shdr);
2666682674b8SRichard Henderson     shdr = (struct elf_shdr *)alloca(i);
2667682674b8SRichard Henderson     if (pread(fd, shdr, i, hdr->e_shoff) != i) {
2668689f936fSbellard         return;
2669682674b8SRichard Henderson     }
2670682674b8SRichard Henderson 
2671682674b8SRichard Henderson     bswap_shdr(shdr, shnum);
2672682674b8SRichard Henderson     for (i = 0; i < shnum; ++i) {
2673682674b8SRichard Henderson         if (shdr[i].sh_type == SHT_SYMTAB) {
2674682674b8SRichard Henderson             sym_idx = i;
2675682674b8SRichard Henderson             str_idx = shdr[i].sh_link;
2676689f936fSbellard             goto found;
2677689f936fSbellard         }
2678689f936fSbellard     }
2679682674b8SRichard Henderson 
2680682674b8SRichard Henderson     /* There will be no symbol table if the file was stripped.  */
2681682674b8SRichard Henderson     return;
2682689f936fSbellard 
2683689f936fSbellard  found:
2684689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them.  */
26850ef9ea29SPeter Maydell     s = g_try_new(struct syminfo, 1);
2686682674b8SRichard Henderson     if (!s) {
2687b9475279SCédric VINCENT         goto give_up;
2688682674b8SRichard Henderson     }
2689682674b8SRichard Henderson 
26901e06262dSPeter Maydell     segsz = shdr[str_idx].sh_size;
26911e06262dSPeter Maydell     s->disas_strtab = strings = g_try_malloc(segsz);
26921e06262dSPeter Maydell     if (!strings ||
26931e06262dSPeter Maydell         pread(fd, strings, segsz, shdr[str_idx].sh_offset) != segsz) {
2694b9475279SCédric VINCENT         goto give_up;
2695682674b8SRichard Henderson     }
2696689f936fSbellard 
26971e06262dSPeter Maydell     segsz = shdr[sym_idx].sh_size;
26981e06262dSPeter Maydell     syms = g_try_malloc(segsz);
26991e06262dSPeter Maydell     if (!syms || pread(fd, syms, segsz, shdr[sym_idx].sh_offset) != segsz) {
2700b9475279SCédric VINCENT         goto give_up;
2701682674b8SRichard Henderson     }
2702689f936fSbellard 
27031e06262dSPeter Maydell     if (segsz / sizeof(struct elf_sym) > INT_MAX) {
27041e06262dSPeter Maydell         /* Implausibly large symbol table: give up rather than ploughing
27051e06262dSPeter Maydell          * on with the number of symbols calculation overflowing
27061e06262dSPeter Maydell          */
27071e06262dSPeter Maydell         goto give_up;
27081e06262dSPeter Maydell     }
27091e06262dSPeter Maydell     nsyms = segsz / sizeof(struct elf_sym);
2710682674b8SRichard Henderson     for (i = 0; i < nsyms; ) {
271149918a75Spbrook         bswap_sym(syms + i);
2712682674b8SRichard Henderson         /* Throw away entries which we do not need.  */
2713682674b8SRichard Henderson         if (syms[i].st_shndx == SHN_UNDEF
2714682674b8SRichard Henderson             || syms[i].st_shndx >= SHN_LORESERVE
2715682674b8SRichard Henderson             || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
2716682674b8SRichard Henderson             if (i < --nsyms) {
271749918a75Spbrook                 syms[i] = syms[nsyms];
271849918a75Spbrook             }
2719682674b8SRichard Henderson         } else {
272049918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
272149918a75Spbrook             /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
272249918a75Spbrook             syms[i].st_value &= ~(target_ulong)1;
272349918a75Spbrook #endif
2724682674b8SRichard Henderson             syms[i].st_value += load_bias;
272549918a75Spbrook             i++;
272649918a75Spbrook         }
2727682674b8SRichard Henderson     }
272849918a75Spbrook 
2729b9475279SCédric VINCENT     /* No "useful" symbol.  */
2730b9475279SCédric VINCENT     if (nsyms == 0) {
2731b9475279SCédric VINCENT         goto give_up;
2732b9475279SCédric VINCENT     }
2733b9475279SCédric VINCENT 
27345d5c9930SRichard Henderson     /* Attempt to free the storage associated with the local symbols
27355d5c9930SRichard Henderson        that we threw away.  Whether or not this has any effect on the
27365d5c9930SRichard Henderson        memory allocation depends on the malloc implementation and how
27375d5c9930SRichard Henderson        many symbols we managed to discard.  */
27380ef9ea29SPeter Maydell     new_syms = g_try_renew(struct elf_sym, syms, nsyms);
27398d79de6eSStefan Weil     if (new_syms == NULL) {
2740b9475279SCédric VINCENT         goto give_up;
27415d5c9930SRichard Henderson     }
27428d79de6eSStefan Weil     syms = new_syms;
27435d5c9930SRichard Henderson 
274449918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
274549918a75Spbrook 
274649918a75Spbrook     s->disas_num_syms = nsyms;
274749918a75Spbrook #if ELF_CLASS == ELFCLASS32
274849918a75Spbrook     s->disas_symtab.elf32 = syms;
274949918a75Spbrook #else
275049918a75Spbrook     s->disas_symtab.elf64 = syms;
275149918a75Spbrook #endif
2752682674b8SRichard Henderson     s->lookup_symbol = lookup_symbolxx;
2753e80cfcfcSbellard     s->next = syminfos;
2754e80cfcfcSbellard     syminfos = s;
2755b9475279SCédric VINCENT 
2756b9475279SCédric VINCENT     return;
2757b9475279SCédric VINCENT 
2758b9475279SCédric VINCENT give_up:
27590ef9ea29SPeter Maydell     g_free(s);
27600ef9ea29SPeter Maydell     g_free(strings);
27610ef9ea29SPeter Maydell     g_free(syms);
2762689f936fSbellard }
276331e31b8aSbellard 
2764768fe76eSYunQiang Su uint32_t get_elf_eflags(int fd)
2765768fe76eSYunQiang Su {
2766768fe76eSYunQiang Su     struct elfhdr ehdr;
2767768fe76eSYunQiang Su     off_t offset;
2768768fe76eSYunQiang Su     int ret;
2769768fe76eSYunQiang Su 
2770768fe76eSYunQiang Su     /* Read ELF header */
2771768fe76eSYunQiang Su     offset = lseek(fd, 0, SEEK_SET);
2772768fe76eSYunQiang Su     if (offset == (off_t) -1) {
2773768fe76eSYunQiang Su         return 0;
2774768fe76eSYunQiang Su     }
2775768fe76eSYunQiang Su     ret = read(fd, &ehdr, sizeof(ehdr));
2776768fe76eSYunQiang Su     if (ret < sizeof(ehdr)) {
2777768fe76eSYunQiang Su         return 0;
2778768fe76eSYunQiang Su     }
2779768fe76eSYunQiang Su     offset = lseek(fd, offset, SEEK_SET);
2780768fe76eSYunQiang Su     if (offset == (off_t) -1) {
2781768fe76eSYunQiang Su         return 0;
2782768fe76eSYunQiang Su     }
2783768fe76eSYunQiang Su 
2784768fe76eSYunQiang Su     /* Check ELF signature */
2785768fe76eSYunQiang Su     if (!elf_check_ident(&ehdr)) {
2786768fe76eSYunQiang Su         return 0;
2787768fe76eSYunQiang Su     }
2788768fe76eSYunQiang Su 
2789768fe76eSYunQiang Su     /* check header */
2790768fe76eSYunQiang Su     bswap_ehdr(&ehdr);
2791768fe76eSYunQiang Su     if (!elf_check_ehdr(&ehdr)) {
2792768fe76eSYunQiang Su         return 0;
2793768fe76eSYunQiang Su     }
2794768fe76eSYunQiang Su 
2795768fe76eSYunQiang Su     /* return architecture id */
2796768fe76eSYunQiang Su     return ehdr.e_flags;
2797768fe76eSYunQiang Su }
2798768fe76eSYunQiang Su 
2799f0116c54SWill Newton int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
280031e31b8aSbellard {
28018e62a717SRichard Henderson     struct image_info interp_info;
280231e31b8aSbellard     struct elfhdr elf_ex;
28038e62a717SRichard Henderson     char *elf_interpreter = NULL;
280459baae9aSStefan Brüns     char *scratch;
280531e31b8aSbellard 
2806abcac736SDaniel Santos     memset(&interp_info, 0, sizeof(interp_info));
2807abcac736SDaniel Santos #ifdef TARGET_MIPS
2808abcac736SDaniel Santos     interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
2809abcac736SDaniel Santos #endif
2810abcac736SDaniel Santos 
2811bf858897SRichard Henderson     info->start_mmap = (abi_ulong)ELF_START_MMAP;
281231e31b8aSbellard 
2813bf858897SRichard Henderson     load_elf_image(bprm->filename, bprm->fd, info,
2814bf858897SRichard Henderson                    &elf_interpreter, bprm->buf);
2815bf858897SRichard Henderson 
2816bf858897SRichard Henderson     /* ??? We need a copy of the elf header for passing to create_elf_tables.
2817bf858897SRichard Henderson        If we do nothing, we'll have overwritten this when we re-use bprm->buf
2818bf858897SRichard Henderson        when we load the interpreter.  */
2819bf858897SRichard Henderson     elf_ex = *(struct elfhdr *)bprm->buf;
282031e31b8aSbellard 
282159baae9aSStefan Brüns     /* Do this so that we can load the interpreter, if need be.  We will
282259baae9aSStefan Brüns        change some of these later */
282359baae9aSStefan Brüns     bprm->p = setup_arg_pages(bprm, info);
282459baae9aSStefan Brüns 
282559baae9aSStefan Brüns     scratch = g_new0(char, TARGET_PAGE_SIZE);
28267c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
282759baae9aSStefan Brüns         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
282859baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
28297c4ee5bcSRichard Henderson         info->file_string = bprm->p;
283059baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
283159baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
28327c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
283359baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
283459baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
28357c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
28367c4ee5bcSRichard Henderson     } else {
28377c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
28387c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
28397c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
28407c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
28417c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
28427c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
28437c4ee5bcSRichard Henderson         info->file_string = bprm->p;
28447c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
28457c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
28467c4ee5bcSRichard Henderson     }
28477c4ee5bcSRichard Henderson 
284859baae9aSStefan Brüns     g_free(scratch);
284959baae9aSStefan Brüns 
2850e5fe0c52Spbrook     if (!bprm->p) {
2851bf858897SRichard Henderson         fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
285231e31b8aSbellard         exit(-1);
28539955ffacSRichard Henderson     }
2854379f6698SPaul Brook 
28558e62a717SRichard Henderson     if (elf_interpreter) {
28568e62a717SRichard Henderson         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
285731e31b8aSbellard 
28588e62a717SRichard Henderson         /* If the program interpreter is one of these two, then assume
28598e62a717SRichard Henderson            an iBCS2 image.  Otherwise assume a native linux image.  */
286031e31b8aSbellard 
28618e62a717SRichard Henderson         if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
28628e62a717SRichard Henderson             || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
28638e62a717SRichard Henderson             info->personality = PER_SVR4;
28648e62a717SRichard Henderson 
286531e31b8aSbellard             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
28668e62a717SRichard Henderson                and some applications "depend" upon this behavior.  Since
28678e62a717SRichard Henderson                we do not have the power to recompile these, we emulate
28688e62a717SRichard Henderson                the SVr4 behavior.  Sigh.  */
28698e62a717SRichard Henderson             target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
287068754b44SPeter Maydell                         MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
287131e31b8aSbellard         }
2872c94cb6c9SStefan Markovic #ifdef TARGET_MIPS
2873c94cb6c9SStefan Markovic         info->interp_fp_abi = interp_info.fp_abi;
2874c94cb6c9SStefan Markovic #endif
28758e62a717SRichard Henderson     }
287631e31b8aSbellard 
28778e62a717SRichard Henderson     bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
28788e62a717SRichard Henderson                                 info, (elf_interpreter ? &interp_info : NULL));
28798e62a717SRichard Henderson     info->start_stack = bprm->p;
28808e62a717SRichard Henderson 
28818e62a717SRichard Henderson     /* If we have an interpreter, set that as the program's entry point.
28828e78064eSRichard Henderson        Copy the load_bias as well, to help PPC64 interpret the entry
28838e62a717SRichard Henderson        point as a function descriptor.  Do this after creating elf tables
28848e62a717SRichard Henderson        so that we copy the original program entry point into the AUXV.  */
28858e62a717SRichard Henderson     if (elf_interpreter) {
28868e78064eSRichard Henderson         info->load_bias = interp_info.load_bias;
28878e62a717SRichard Henderson         info->entry = interp_info.entry;
2888bf858897SRichard Henderson         free(elf_interpreter);
28898e62a717SRichard Henderson     }
289031e31b8aSbellard 
2891edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
2892edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
2893edf8e2afSMika Westerberg #endif
2894edf8e2afSMika Westerberg 
28956fd59449SRichard Henderson     /*
28966fd59449SRichard Henderson      * If we reserved extra space for brk, release it now.
28976fd59449SRichard Henderson      * The implementation of do_brk in syscalls.c expects to be able
28986fd59449SRichard Henderson      * to mmap pages in this space.
28996fd59449SRichard Henderson      */
29006fd59449SRichard Henderson     if (info->reserve_brk) {
29016fd59449SRichard Henderson         abi_ulong start_brk = HOST_PAGE_ALIGN(info->brk);
29026fd59449SRichard Henderson         abi_ulong end_brk = HOST_PAGE_ALIGN(info->brk + info->reserve_brk);
29036fd59449SRichard Henderson         target_munmap(start_brk, end_brk - start_brk);
29046fd59449SRichard Henderson     }
29056fd59449SRichard Henderson 
290631e31b8aSbellard     return 0;
290731e31b8aSbellard }
290831e31b8aSbellard 
2909edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
2910edf8e2afSMika Westerberg /*
2911edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
2912a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
2913edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
2914edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
2915edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
2916edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
2917edf8e2afSMika Westerberg  *
2918edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
2919edf8e2afSMika Westerberg  * are marked with XXX.
2920edf8e2afSMika Westerberg  *
2921edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
2922edf8e2afSMika Westerberg  *
2923edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
2924dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
2925edf8e2afSMika Westerberg  * the target resides):
2926edf8e2afSMika Westerberg  *
2927edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
2928edf8e2afSMika Westerberg  *
2929edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
2930edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
2931edf8e2afSMika Westerberg  *
2932c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
2933edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
2934c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
2935edf8e2afSMika Westerberg  *
2936edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
2937edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
2938edf8e2afSMika Westerberg  *
2939c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
29409349b4f9SAndreas Färber  *                                const CPUArchState *env);
2941edf8e2afSMika Westerberg  *
2942edf8e2afSMika Westerberg  * Parameters:
2943edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
2944edf8e2afSMika Westerberg  *     env - copy registers from here
2945edf8e2afSMika Westerberg  *
2946edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
2947edf8e2afSMika Westerberg  */
2948edf8e2afSMika Westerberg 
2949edf8e2afSMika Westerberg /* An ELF note in memory */
2950edf8e2afSMika Westerberg struct memelfnote {
2951edf8e2afSMika Westerberg     const char *name;
2952edf8e2afSMika Westerberg     size_t     namesz;
2953edf8e2afSMika Westerberg     size_t     namesz_rounded;
2954edf8e2afSMika Westerberg     int        type;
2955edf8e2afSMika Westerberg     size_t     datasz;
295680f5ce75SLaurent Vivier     size_t     datasz_rounded;
2957edf8e2afSMika Westerberg     void       *data;
2958edf8e2afSMika Westerberg     size_t     notesz;
2959edf8e2afSMika Westerberg };
2960edf8e2afSMika Westerberg 
2961a2547a13SLaurent Desnogues struct target_elf_siginfo {
2962f8fd4fc4SPaolo Bonzini     abi_int    si_signo; /* signal number */
2963f8fd4fc4SPaolo Bonzini     abi_int    si_code;  /* extra code */
2964f8fd4fc4SPaolo Bonzini     abi_int    si_errno; /* errno */
2965edf8e2afSMika Westerberg };
2966edf8e2afSMika Westerberg 
2967a2547a13SLaurent Desnogues struct target_elf_prstatus {
2968a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
29691ddd592fSPaolo Bonzini     abi_short          pr_cursig;    /* Current signal */
2970ca98ac83SPaolo Bonzini     abi_ulong          pr_sigpend;   /* XXX */
2971ca98ac83SPaolo Bonzini     abi_ulong          pr_sighold;   /* XXX */
2972c227f099SAnthony Liguori     target_pid_t       pr_pid;
2973c227f099SAnthony Liguori     target_pid_t       pr_ppid;
2974c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
2975c227f099SAnthony Liguori     target_pid_t       pr_sid;
2976edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
2977edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
2978edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
2979edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
2980c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
2981f8fd4fc4SPaolo Bonzini     abi_int            pr_fpvalid;   /* XXX */
2982edf8e2afSMika Westerberg };
2983edf8e2afSMika Westerberg 
2984edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
2985edf8e2afSMika Westerberg 
2986a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
2987edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
2988edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
2989edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
2990edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
2991ca98ac83SPaolo Bonzini     abi_ulong    pr_flag;        /* flags */
2992c227f099SAnthony Liguori     target_uid_t pr_uid;
2993c227f099SAnthony Liguori     target_gid_t pr_gid;
2994c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
2995edf8e2afSMika Westerberg     /* Lots missing */
2996d7eb2b92SAlistair Francis     char    pr_fname[16] QEMU_NONSTRING; /* filename of executable */
2997edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
2998edf8e2afSMika Westerberg };
2999edf8e2afSMika Westerberg 
3000edf8e2afSMika Westerberg /* Here is the structure in which status of each thread is captured. */
3001edf8e2afSMika Westerberg struct elf_thread_status {
300272cf2d4fSBlue Swirl     QTAILQ_ENTRY(elf_thread_status)  ets_link;
3003a2547a13SLaurent Desnogues     struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
3004edf8e2afSMika Westerberg #if 0
3005edf8e2afSMika Westerberg     elf_fpregset_t fpu;             /* NT_PRFPREG */
3006edf8e2afSMika Westerberg     struct task_struct *thread;
3007edf8e2afSMika Westerberg     elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
3008edf8e2afSMika Westerberg #endif
3009edf8e2afSMika Westerberg     struct memelfnote notes[1];
3010edf8e2afSMika Westerberg     int num_notes;
3011edf8e2afSMika Westerberg };
3012edf8e2afSMika Westerberg 
3013edf8e2afSMika Westerberg struct elf_note_info {
3014edf8e2afSMika Westerberg     struct memelfnote   *notes;
3015a2547a13SLaurent Desnogues     struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
3016a2547a13SLaurent Desnogues     struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
3017edf8e2afSMika Westerberg 
3018b58deb34SPaolo Bonzini     QTAILQ_HEAD(, elf_thread_status) thread_list;
3019edf8e2afSMika Westerberg #if 0
3020edf8e2afSMika Westerberg     /*
3021edf8e2afSMika Westerberg      * Current version of ELF coredump doesn't support
3022edf8e2afSMika Westerberg      * dumping fp regs etc.
3023edf8e2afSMika Westerberg      */
3024edf8e2afSMika Westerberg     elf_fpregset_t *fpu;
3025edf8e2afSMika Westerberg     elf_fpxregset_t *xfpu;
3026edf8e2afSMika Westerberg     int thread_status_size;
3027edf8e2afSMika Westerberg #endif
3028edf8e2afSMika Westerberg     int notes_size;
3029edf8e2afSMika Westerberg     int numnote;
3030edf8e2afSMika Westerberg };
3031edf8e2afSMika Westerberg 
3032edf8e2afSMika Westerberg struct vm_area_struct {
30331a1c4db9SMikhail Ilyin     target_ulong   vma_start;  /* start vaddr of memory region */
30341a1c4db9SMikhail Ilyin     target_ulong   vma_end;    /* end vaddr of memory region */
3035edf8e2afSMika Westerberg     abi_ulong      vma_flags;  /* protection etc. flags for the region */
303672cf2d4fSBlue Swirl     QTAILQ_ENTRY(vm_area_struct) vma_link;
3037edf8e2afSMika Westerberg };
3038edf8e2afSMika Westerberg 
3039edf8e2afSMika Westerberg struct mm_struct {
304072cf2d4fSBlue Swirl     QTAILQ_HEAD(, vm_area_struct) mm_mmap;
3041edf8e2afSMika Westerberg     int mm_count;           /* number of mappings */
3042edf8e2afSMika Westerberg };
3043edf8e2afSMika Westerberg 
3044edf8e2afSMika Westerberg static struct mm_struct *vma_init(void);
3045edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *);
30461a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *, target_ulong,
30471a1c4db9SMikhail Ilyin                            target_ulong, abi_ulong);
3048edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *);
3049edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *);
3050edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *);
3051edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *);
30521a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
3053edf8e2afSMika Westerberg                       unsigned long flags);
3054edf8e2afSMika Westerberg 
3055edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
3056edf8e2afSMika Westerberg static void fill_note(struct memelfnote *, const char *, int,
3057edf8e2afSMika Westerberg                       unsigned int, void *);
3058a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
3059a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
3060edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *, const TaskState *);
3061edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
3062edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *);
3063edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *);
30649349b4f9SAndreas Färber static int fill_note_info(struct elf_note_info *, long, const CPUArchState *);
30659349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *, const CPUArchState *);
3066edf8e2afSMika Westerberg static int core_dump_filename(const TaskState *, char *, size_t);
3067edf8e2afSMika Westerberg 
3068edf8e2afSMika Westerberg static int dump_write(int, const void *, size_t);
3069edf8e2afSMika Westerberg static int write_note(struct memelfnote *, int);
3070edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *, int);
3071edf8e2afSMika Westerberg 
3072edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
3073a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
3074edf8e2afSMika Westerberg {
3075ca98ac83SPaolo Bonzini     prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo);
3076ca98ac83SPaolo Bonzini     prstatus->pr_info.si_code = tswap32(prstatus->pr_info.si_code);
3077ca98ac83SPaolo Bonzini     prstatus->pr_info.si_errno = tswap32(prstatus->pr_info.si_errno);
3078edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
3079ca98ac83SPaolo Bonzini     prstatus->pr_sigpend = tswapal(prstatus->pr_sigpend);
3080ca98ac83SPaolo Bonzini     prstatus->pr_sighold = tswapal(prstatus->pr_sighold);
3081edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
3082edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
3083edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
3084edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
3085edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
3086edf8e2afSMika Westerberg     /* regs should be in correct format already */
3087edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
3088edf8e2afSMika Westerberg }
3089edf8e2afSMika Westerberg 
3090a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
3091edf8e2afSMika Westerberg {
3092ca98ac83SPaolo Bonzini     psinfo->pr_flag = tswapal(psinfo->pr_flag);
3093edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
3094edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
3095edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
3096edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
3097edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
3098edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
3099edf8e2afSMika Westerberg }
3100991f8f0cSRichard Henderson 
3101991f8f0cSRichard Henderson static void bswap_note(struct elf_note *en)
3102991f8f0cSRichard Henderson {
3103991f8f0cSRichard Henderson     bswap32s(&en->n_namesz);
3104991f8f0cSRichard Henderson     bswap32s(&en->n_descsz);
3105991f8f0cSRichard Henderson     bswap32s(&en->n_type);
3106991f8f0cSRichard Henderson }
3107991f8f0cSRichard Henderson #else
3108991f8f0cSRichard Henderson static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
3109991f8f0cSRichard Henderson static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
3110991f8f0cSRichard Henderson static inline void bswap_note(struct elf_note *en) { }
3111edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
3112edf8e2afSMika Westerberg 
3113edf8e2afSMika Westerberg /*
3114edf8e2afSMika Westerberg  * Minimal support for linux memory regions.  These are needed
3115edf8e2afSMika Westerberg  * when we are finding out what memory exactly belongs to
3116edf8e2afSMika Westerberg  * emulated process.  No locks needed here, as long as
3117edf8e2afSMika Westerberg  * thread that received the signal is stopped.
3118edf8e2afSMika Westerberg  */
3119edf8e2afSMika Westerberg 
3120edf8e2afSMika Westerberg static struct mm_struct *vma_init(void)
3121edf8e2afSMika Westerberg {
3122edf8e2afSMika Westerberg     struct mm_struct *mm;
3123edf8e2afSMika Westerberg 
31247267c094SAnthony Liguori     if ((mm = g_malloc(sizeof (*mm))) == NULL)
3125edf8e2afSMika Westerberg         return (NULL);
3126edf8e2afSMika Westerberg 
3127edf8e2afSMika Westerberg     mm->mm_count = 0;
312872cf2d4fSBlue Swirl     QTAILQ_INIT(&mm->mm_mmap);
3129edf8e2afSMika Westerberg 
3130edf8e2afSMika Westerberg     return (mm);
3131edf8e2afSMika Westerberg }
3132edf8e2afSMika Westerberg 
3133edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *mm)
3134edf8e2afSMika Westerberg {
3135edf8e2afSMika Westerberg     struct vm_area_struct *vma;
3136edf8e2afSMika Westerberg 
3137edf8e2afSMika Westerberg     while ((vma = vma_first(mm)) != NULL) {
313872cf2d4fSBlue Swirl         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
31397267c094SAnthony Liguori         g_free(vma);
3140edf8e2afSMika Westerberg     }
31417267c094SAnthony Liguori     g_free(mm);
3142edf8e2afSMika Westerberg }
3143edf8e2afSMika Westerberg 
31441a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *mm, target_ulong start,
31451a1c4db9SMikhail Ilyin                            target_ulong end, abi_ulong flags)
3146edf8e2afSMika Westerberg {
3147edf8e2afSMika Westerberg     struct vm_area_struct *vma;
3148edf8e2afSMika Westerberg 
31497267c094SAnthony Liguori     if ((vma = g_malloc0(sizeof (*vma))) == NULL)
3150edf8e2afSMika Westerberg         return (-1);
3151edf8e2afSMika Westerberg 
3152edf8e2afSMika Westerberg     vma->vma_start = start;
3153edf8e2afSMika Westerberg     vma->vma_end = end;
3154edf8e2afSMika Westerberg     vma->vma_flags = flags;
3155edf8e2afSMika Westerberg 
315672cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
3157edf8e2afSMika Westerberg     mm->mm_count++;
3158edf8e2afSMika Westerberg 
3159edf8e2afSMika Westerberg     return (0);
3160edf8e2afSMika Westerberg }
3161edf8e2afSMika Westerberg 
3162edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *mm)
3163edf8e2afSMika Westerberg {
316472cf2d4fSBlue Swirl     return (QTAILQ_FIRST(&mm->mm_mmap));
3165edf8e2afSMika Westerberg }
3166edf8e2afSMika Westerberg 
3167edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
3168edf8e2afSMika Westerberg {
316972cf2d4fSBlue Swirl     return (QTAILQ_NEXT(vma, vma_link));
3170edf8e2afSMika Westerberg }
3171edf8e2afSMika Westerberg 
3172edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *mm)
3173edf8e2afSMika Westerberg {
3174edf8e2afSMika Westerberg     return (mm->mm_count);
3175edf8e2afSMika Westerberg }
3176edf8e2afSMika Westerberg 
3177edf8e2afSMika Westerberg /*
3178edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
3179edf8e2afSMika Westerberg  */
3180edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
3181edf8e2afSMika Westerberg {
3182edf8e2afSMika Westerberg     /* if we cannot even read the first page, skip it */
3183edf8e2afSMika Westerberg     if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
3184edf8e2afSMika Westerberg         return (0);
3185edf8e2afSMika Westerberg 
3186edf8e2afSMika Westerberg     /*
3187edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
3188edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
3189edf8e2afSMika Westerberg      * target library etc.  However, thread stacks are marked
3190edf8e2afSMika Westerberg      * also executable so we read in first page of given region
3191edf8e2afSMika Westerberg      * and check whether it contains elf header.  If there is
3192edf8e2afSMika Westerberg      * no elf header, we dump it.
3193edf8e2afSMika Westerberg      */
3194edf8e2afSMika Westerberg     if (vma->vma_flags & PROT_EXEC) {
3195edf8e2afSMika Westerberg         char page[TARGET_PAGE_SIZE];
3196edf8e2afSMika Westerberg 
3197edf8e2afSMika Westerberg         copy_from_user(page, vma->vma_start, sizeof (page));
3198edf8e2afSMika Westerberg         if ((page[EI_MAG0] == ELFMAG0) &&
3199edf8e2afSMika Westerberg             (page[EI_MAG1] == ELFMAG1) &&
3200edf8e2afSMika Westerberg             (page[EI_MAG2] == ELFMAG2) &&
3201edf8e2afSMika Westerberg             (page[EI_MAG3] == ELFMAG3)) {
3202edf8e2afSMika Westerberg             /*
3203edf8e2afSMika Westerberg              * Mappings are possibly from ELF binary.  Don't dump
3204edf8e2afSMika Westerberg              * them.
3205edf8e2afSMika Westerberg              */
3206edf8e2afSMika Westerberg             return (0);
3207edf8e2afSMika Westerberg         }
3208edf8e2afSMika Westerberg     }
3209edf8e2afSMika Westerberg 
3210edf8e2afSMika Westerberg     return (vma->vma_end - vma->vma_start);
3211edf8e2afSMika Westerberg }
3212edf8e2afSMika Westerberg 
32131a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
3214edf8e2afSMika Westerberg                       unsigned long flags)
3215edf8e2afSMika Westerberg {
3216edf8e2afSMika Westerberg     struct mm_struct *mm = (struct mm_struct *)priv;
3217edf8e2afSMika Westerberg 
3218edf8e2afSMika Westerberg     vma_add_mapping(mm, start, end, flags);
3219edf8e2afSMika Westerberg     return (0);
3220edf8e2afSMika Westerberg }
3221edf8e2afSMika Westerberg 
3222edf8e2afSMika Westerberg static void fill_note(struct memelfnote *note, const char *name, int type,
3223edf8e2afSMika Westerberg                       unsigned int sz, void *data)
3224edf8e2afSMika Westerberg {
3225edf8e2afSMika Westerberg     unsigned int namesz;
3226edf8e2afSMika Westerberg 
3227edf8e2afSMika Westerberg     namesz = strlen(name) + 1;
3228edf8e2afSMika Westerberg     note->name = name;
3229edf8e2afSMika Westerberg     note->namesz = namesz;
3230edf8e2afSMika Westerberg     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
3231edf8e2afSMika Westerberg     note->type = type;
323280f5ce75SLaurent Vivier     note->datasz = sz;
323380f5ce75SLaurent Vivier     note->datasz_rounded = roundup(sz, sizeof (int32_t));
323480f5ce75SLaurent Vivier 
3235edf8e2afSMika Westerberg     note->data = data;
3236edf8e2afSMika Westerberg 
3237edf8e2afSMika Westerberg     /*
3238edf8e2afSMika Westerberg      * We calculate rounded up note size here as specified by
3239edf8e2afSMika Westerberg      * ELF document.
3240edf8e2afSMika Westerberg      */
3241edf8e2afSMika Westerberg     note->notesz = sizeof (struct elf_note) +
324280f5ce75SLaurent Vivier         note->namesz_rounded + note->datasz_rounded;
3243edf8e2afSMika Westerberg }
3244edf8e2afSMika Westerberg 
3245edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
3246edf8e2afSMika Westerberg                             uint32_t flags)
3247edf8e2afSMika Westerberg {
3248edf8e2afSMika Westerberg     (void) memset(elf, 0, sizeof(*elf));
3249edf8e2afSMika Westerberg 
3250edf8e2afSMika Westerberg     (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
3251edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
3252edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
3253edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
3254edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
3255edf8e2afSMika Westerberg 
3256edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
3257edf8e2afSMika Westerberg     elf->e_machine = machine;
3258edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
3259edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
3260edf8e2afSMika Westerberg     elf->e_flags = flags;
3261edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
3262edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
3263edf8e2afSMika Westerberg     elf->e_phnum = segs;
3264edf8e2afSMika Westerberg 
3265edf8e2afSMika Westerberg     bswap_ehdr(elf);
3266edf8e2afSMika Westerberg }
3267edf8e2afSMika Westerberg 
3268edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
3269edf8e2afSMika Westerberg {
3270edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
3271edf8e2afSMika Westerberg     phdr->p_offset = offset;
3272edf8e2afSMika Westerberg     phdr->p_vaddr = 0;
3273edf8e2afSMika Westerberg     phdr->p_paddr = 0;
3274edf8e2afSMika Westerberg     phdr->p_filesz = sz;
3275edf8e2afSMika Westerberg     phdr->p_memsz = 0;
3276edf8e2afSMika Westerberg     phdr->p_flags = 0;
3277edf8e2afSMika Westerberg     phdr->p_align = 0;
3278edf8e2afSMika Westerberg 
3279991f8f0cSRichard Henderson     bswap_phdr(phdr, 1);
3280edf8e2afSMika Westerberg }
3281edf8e2afSMika Westerberg 
3282edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *note)
3283edf8e2afSMika Westerberg {
3284edf8e2afSMika Westerberg     return (note->notesz);
3285edf8e2afSMika Westerberg }
3286edf8e2afSMika Westerberg 
3287a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *prstatus,
3288edf8e2afSMika Westerberg                           const TaskState *ts, int signr)
3289edf8e2afSMika Westerberg {
3290edf8e2afSMika Westerberg     (void) memset(prstatus, 0, sizeof (*prstatus));
3291edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
3292edf8e2afSMika Westerberg     prstatus->pr_pid = ts->ts_tid;
3293edf8e2afSMika Westerberg     prstatus->pr_ppid = getppid();
3294edf8e2afSMika Westerberg     prstatus->pr_pgrp = getpgrp();
3295edf8e2afSMika Westerberg     prstatus->pr_sid = getsid(0);
3296edf8e2afSMika Westerberg 
3297edf8e2afSMika Westerberg     bswap_prstatus(prstatus);
3298edf8e2afSMika Westerberg }
3299edf8e2afSMika Westerberg 
3300a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
3301edf8e2afSMika Westerberg {
3302900cfbcaSJim Meyering     char *base_filename;
3303edf8e2afSMika Westerberg     unsigned int i, len;
3304edf8e2afSMika Westerberg 
3305edf8e2afSMika Westerberg     (void) memset(psinfo, 0, sizeof (*psinfo));
3306edf8e2afSMika Westerberg 
3307edf8e2afSMika Westerberg     len = ts->info->arg_end - ts->info->arg_start;
3308edf8e2afSMika Westerberg     if (len >= ELF_PRARGSZ)
3309edf8e2afSMika Westerberg         len = ELF_PRARGSZ - 1;
3310edf8e2afSMika Westerberg     if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len))
3311edf8e2afSMika Westerberg         return -EFAULT;
3312edf8e2afSMika Westerberg     for (i = 0; i < len; i++)
3313edf8e2afSMika Westerberg         if (psinfo->pr_psargs[i] == 0)
3314edf8e2afSMika Westerberg             psinfo->pr_psargs[i] = ' ';
3315edf8e2afSMika Westerberg     psinfo->pr_psargs[len] = 0;
3316edf8e2afSMika Westerberg 
3317edf8e2afSMika Westerberg     psinfo->pr_pid = getpid();
3318edf8e2afSMika Westerberg     psinfo->pr_ppid = getppid();
3319edf8e2afSMika Westerberg     psinfo->pr_pgrp = getpgrp();
3320edf8e2afSMika Westerberg     psinfo->pr_sid = getsid(0);
3321edf8e2afSMika Westerberg     psinfo->pr_uid = getuid();
3322edf8e2afSMika Westerberg     psinfo->pr_gid = getgid();
3323edf8e2afSMika Westerberg 
3324900cfbcaSJim Meyering     base_filename = g_path_get_basename(ts->bprm->filename);
3325900cfbcaSJim Meyering     /*
3326900cfbcaSJim Meyering      * Using strncpy here is fine: at max-length,
3327900cfbcaSJim Meyering      * this field is not NUL-terminated.
3328900cfbcaSJim Meyering      */
3329edf8e2afSMika Westerberg     (void) strncpy(psinfo->pr_fname, base_filename,
3330edf8e2afSMika Westerberg                    sizeof(psinfo->pr_fname));
3331edf8e2afSMika Westerberg 
3332900cfbcaSJim Meyering     g_free(base_filename);
3333edf8e2afSMika Westerberg     bswap_psinfo(psinfo);
3334edf8e2afSMika Westerberg     return (0);
3335edf8e2afSMika Westerberg }
3336edf8e2afSMika Westerberg 
3337edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
3338edf8e2afSMika Westerberg {
3339edf8e2afSMika Westerberg     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
3340edf8e2afSMika Westerberg     elf_addr_t orig_auxv = auxv;
3341edf8e2afSMika Westerberg     void *ptr;
3342125b0f55SAlexander Graf     int len = ts->info->auxv_len;
3343edf8e2afSMika Westerberg 
3344edf8e2afSMika Westerberg     /*
3345edf8e2afSMika Westerberg      * Auxiliary vector is stored in target process stack.  It contains
3346edf8e2afSMika Westerberg      * {type, value} pairs that we need to dump into note.  This is not
3347edf8e2afSMika Westerberg      * strictly necessary but we do it here for sake of completeness.
3348edf8e2afSMika Westerberg      */
3349edf8e2afSMika Westerberg 
3350edf8e2afSMika Westerberg     /* read in whole auxv vector and copy it to memelfnote */
3351edf8e2afSMika Westerberg     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
3352edf8e2afSMika Westerberg     if (ptr != NULL) {
3353edf8e2afSMika Westerberg         fill_note(note, "CORE", NT_AUXV, len, ptr);
3354edf8e2afSMika Westerberg         unlock_user(ptr, auxv, len);
3355edf8e2afSMika Westerberg     }
3356edf8e2afSMika Westerberg }
3357edf8e2afSMika Westerberg 
3358edf8e2afSMika Westerberg /*
3359edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
3360edf8e2afSMika Westerberg  * for the name:
3361edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
3362edf8e2afSMika Westerberg  *
3363edf8e2afSMika Westerberg  * Returns 0 in case of success, -1 otherwise (errno is set).
3364edf8e2afSMika Westerberg  */
3365edf8e2afSMika Westerberg static int core_dump_filename(const TaskState *ts, char *buf,
3366edf8e2afSMika Westerberg                               size_t bufsize)
3367edf8e2afSMika Westerberg {
3368edf8e2afSMika Westerberg     char timestamp[64];
3369edf8e2afSMika Westerberg     char *base_filename = NULL;
3370edf8e2afSMika Westerberg     struct timeval tv;
3371edf8e2afSMika Westerberg     struct tm tm;
3372edf8e2afSMika Westerberg 
3373edf8e2afSMika Westerberg     assert(bufsize >= PATH_MAX);
3374edf8e2afSMika Westerberg 
3375edf8e2afSMika Westerberg     if (gettimeofday(&tv, NULL) < 0) {
3376edf8e2afSMika Westerberg         (void) fprintf(stderr, "unable to get current timestamp: %s",
3377edf8e2afSMika Westerberg                        strerror(errno));
3378edf8e2afSMika Westerberg         return (-1);
3379edf8e2afSMika Westerberg     }
3380edf8e2afSMika Westerberg 
3381b8da57faSWei Jiangang     base_filename = g_path_get_basename(ts->bprm->filename);
3382edf8e2afSMika Westerberg     (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
3383edf8e2afSMika Westerberg                     localtime_r(&tv.tv_sec, &tm));
3384edf8e2afSMika Westerberg     (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
3385edf8e2afSMika Westerberg                     base_filename, timestamp, (int)getpid());
3386b8da57faSWei Jiangang     g_free(base_filename);
3387edf8e2afSMika Westerberg 
3388edf8e2afSMika Westerberg     return (0);
3389edf8e2afSMika Westerberg }
3390edf8e2afSMika Westerberg 
3391edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
3392edf8e2afSMika Westerberg {
3393edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
3394edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
3395edf8e2afSMika Westerberg     struct rlimit dumpsize;
3396edf8e2afSMika Westerberg     off_t pos;
3397edf8e2afSMika Westerberg 
3398edf8e2afSMika Westerberg     bytes_written = 0;
3399edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
3400edf8e2afSMika Westerberg     if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
3401edf8e2afSMika Westerberg         if (errno == ESPIPE) { /* not a seekable stream */
3402edf8e2afSMika Westerberg             bytes_left = size;
3403edf8e2afSMika Westerberg         } else {
3404edf8e2afSMika Westerberg             return pos;
3405edf8e2afSMika Westerberg         }
3406edf8e2afSMika Westerberg     } else {
3407edf8e2afSMika Westerberg         if (dumpsize.rlim_cur <= pos) {
3408edf8e2afSMika Westerberg             return -1;
3409edf8e2afSMika Westerberg         } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
3410edf8e2afSMika Westerberg             bytes_left = size;
3411edf8e2afSMika Westerberg         } else {
3412edf8e2afSMika Westerberg             size_t limit_left=dumpsize.rlim_cur - pos;
3413edf8e2afSMika Westerberg             bytes_left = limit_left >= size ? size : limit_left ;
3414edf8e2afSMika Westerberg         }
3415edf8e2afSMika Westerberg     }
3416edf8e2afSMika Westerberg 
3417edf8e2afSMika Westerberg     /*
3418edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
3419edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
3420edf8e2afSMika Westerberg      */
3421edf8e2afSMika Westerberg     do {
3422edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
3423edf8e2afSMika Westerberg         if (bytes_written < 0) {
3424edf8e2afSMika Westerberg             if (errno == EINTR)
3425edf8e2afSMika Westerberg                 continue;
3426edf8e2afSMika Westerberg             return (-1);
3427edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
3428edf8e2afSMika Westerberg             return (-1);
3429edf8e2afSMika Westerberg         }
3430edf8e2afSMika Westerberg         bufp += bytes_written;
3431edf8e2afSMika Westerberg         bytes_left -= bytes_written;
3432edf8e2afSMika Westerberg     } while (bytes_left > 0);
3433edf8e2afSMika Westerberg 
3434edf8e2afSMika Westerberg     return (0);
3435edf8e2afSMika Westerberg }
3436edf8e2afSMika Westerberg 
3437edf8e2afSMika Westerberg static int write_note(struct memelfnote *men, int fd)
3438edf8e2afSMika Westerberg {
3439edf8e2afSMika Westerberg     struct elf_note en;
3440edf8e2afSMika Westerberg 
3441edf8e2afSMika Westerberg     en.n_namesz = men->namesz;
3442edf8e2afSMika Westerberg     en.n_type = men->type;
3443edf8e2afSMika Westerberg     en.n_descsz = men->datasz;
3444edf8e2afSMika Westerberg 
3445edf8e2afSMika Westerberg     bswap_note(&en);
3446edf8e2afSMika Westerberg 
3447edf8e2afSMika Westerberg     if (dump_write(fd, &en, sizeof(en)) != 0)
3448edf8e2afSMika Westerberg         return (-1);
3449edf8e2afSMika Westerberg     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
3450edf8e2afSMika Westerberg         return (-1);
345180f5ce75SLaurent Vivier     if (dump_write(fd, men->data, men->datasz_rounded) != 0)
3452edf8e2afSMika Westerberg         return (-1);
3453edf8e2afSMika Westerberg 
3454edf8e2afSMika Westerberg     return (0);
3455edf8e2afSMika Westerberg }
3456edf8e2afSMika Westerberg 
34579349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
3458edf8e2afSMika Westerberg {
345929a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
34600429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
3461edf8e2afSMika Westerberg     struct elf_thread_status *ets;
3462edf8e2afSMika Westerberg 
34637267c094SAnthony Liguori     ets = g_malloc0(sizeof (*ets));
3464edf8e2afSMika Westerberg     ets->num_notes = 1; /* only prstatus is dumped */
3465edf8e2afSMika Westerberg     fill_prstatus(&ets->prstatus, ts, 0);
3466edf8e2afSMika Westerberg     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
3467edf8e2afSMika Westerberg     fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
3468edf8e2afSMika Westerberg               &ets->prstatus);
3469edf8e2afSMika Westerberg 
347072cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
3471edf8e2afSMika Westerberg 
3472edf8e2afSMika Westerberg     info->notes_size += note_size(&ets->notes[0]);
3473edf8e2afSMika Westerberg }
3474edf8e2afSMika Westerberg 
34756afafa86SPeter Maydell static void init_note_info(struct elf_note_info *info)
34766afafa86SPeter Maydell {
34776afafa86SPeter Maydell     /* Initialize the elf_note_info structure so that it is at
34786afafa86SPeter Maydell      * least safe to call free_note_info() on it. Must be
34796afafa86SPeter Maydell      * called before calling fill_note_info().
34806afafa86SPeter Maydell      */
34816afafa86SPeter Maydell     memset(info, 0, sizeof (*info));
34826afafa86SPeter Maydell     QTAILQ_INIT(&info->thread_list);
34836afafa86SPeter Maydell }
34846afafa86SPeter Maydell 
3485edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *info,
34869349b4f9SAndreas Färber                           long signr, const CPUArchState *env)
3487edf8e2afSMika Westerberg {
3488edf8e2afSMika Westerberg #define NUMNOTES 3
348929a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
34900429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
3491edf8e2afSMika Westerberg     int i;
3492edf8e2afSMika Westerberg 
3493c78d65e8SMarkus Armbruster     info->notes = g_new0(struct memelfnote, NUMNOTES);
3494edf8e2afSMika Westerberg     if (info->notes == NULL)
3495edf8e2afSMika Westerberg         return (-ENOMEM);
34967267c094SAnthony Liguori     info->prstatus = g_malloc0(sizeof (*info->prstatus));
3497edf8e2afSMika Westerberg     if (info->prstatus == NULL)
3498edf8e2afSMika Westerberg         return (-ENOMEM);
34997267c094SAnthony Liguori     info->psinfo = g_malloc0(sizeof (*info->psinfo));
3500edf8e2afSMika Westerberg     if (info->prstatus == NULL)
3501edf8e2afSMika Westerberg         return (-ENOMEM);
3502edf8e2afSMika Westerberg 
3503edf8e2afSMika Westerberg     /*
3504edf8e2afSMika Westerberg      * First fill in status (and registers) of current thread
3505edf8e2afSMika Westerberg      * including process info & aux vector.
3506edf8e2afSMika Westerberg      */
3507edf8e2afSMika Westerberg     fill_prstatus(info->prstatus, ts, signr);
3508edf8e2afSMika Westerberg     elf_core_copy_regs(&info->prstatus->pr_reg, env);
3509edf8e2afSMika Westerberg     fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
3510edf8e2afSMika Westerberg               sizeof (*info->prstatus), info->prstatus);
3511edf8e2afSMika Westerberg     fill_psinfo(info->psinfo, ts);
3512edf8e2afSMika Westerberg     fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
3513edf8e2afSMika Westerberg               sizeof (*info->psinfo), info->psinfo);
3514edf8e2afSMika Westerberg     fill_auxv_note(&info->notes[2], ts);
3515edf8e2afSMika Westerberg     info->numnote = 3;
3516edf8e2afSMika Westerberg 
3517edf8e2afSMika Westerberg     info->notes_size = 0;
3518edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
3519edf8e2afSMika Westerberg         info->notes_size += note_size(&info->notes[i]);
3520edf8e2afSMika Westerberg 
3521edf8e2afSMika Westerberg     /* read and fill status of all threads */
3522edf8e2afSMika Westerberg     cpu_list_lock();
3523bdc44640SAndreas Färber     CPU_FOREACH(cpu) {
3524a2247f8eSAndreas Färber         if (cpu == thread_cpu) {
3525edf8e2afSMika Westerberg             continue;
3526182735efSAndreas Färber         }
3527182735efSAndreas Färber         fill_thread_info(info, (CPUArchState *)cpu->env_ptr);
3528edf8e2afSMika Westerberg     }
3529edf8e2afSMika Westerberg     cpu_list_unlock();
3530edf8e2afSMika Westerberg 
3531edf8e2afSMika Westerberg     return (0);
3532edf8e2afSMika Westerberg }
3533edf8e2afSMika Westerberg 
3534edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *info)
3535edf8e2afSMika Westerberg {
3536edf8e2afSMika Westerberg     struct elf_thread_status *ets;
3537edf8e2afSMika Westerberg 
353872cf2d4fSBlue Swirl     while (!QTAILQ_EMPTY(&info->thread_list)) {
353972cf2d4fSBlue Swirl         ets = QTAILQ_FIRST(&info->thread_list);
354072cf2d4fSBlue Swirl         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
35417267c094SAnthony Liguori         g_free(ets);
3542edf8e2afSMika Westerberg     }
3543edf8e2afSMika Westerberg 
35447267c094SAnthony Liguori     g_free(info->prstatus);
35457267c094SAnthony Liguori     g_free(info->psinfo);
35467267c094SAnthony Liguori     g_free(info->notes);
3547edf8e2afSMika Westerberg }
3548edf8e2afSMika Westerberg 
3549edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *info, int fd)
3550edf8e2afSMika Westerberg {
3551edf8e2afSMika Westerberg     struct elf_thread_status *ets;
3552edf8e2afSMika Westerberg     int i, error = 0;
3553edf8e2afSMika Westerberg 
3554edf8e2afSMika Westerberg     /* write prstatus, psinfo and auxv for current thread */
3555edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
3556edf8e2afSMika Westerberg         if ((error = write_note(&info->notes[i], fd)) != 0)
3557edf8e2afSMika Westerberg             return (error);
3558edf8e2afSMika Westerberg 
3559edf8e2afSMika Westerberg     /* write prstatus for each thread */
356052a53afeSEmilio G. Cota     QTAILQ_FOREACH(ets, &info->thread_list, ets_link) {
3561edf8e2afSMika Westerberg         if ((error = write_note(&ets->notes[0], fd)) != 0)
3562edf8e2afSMika Westerberg             return (error);
3563edf8e2afSMika Westerberg     }
3564edf8e2afSMika Westerberg 
3565edf8e2afSMika Westerberg     return (0);
3566edf8e2afSMika Westerberg }
3567edf8e2afSMika Westerberg 
3568edf8e2afSMika Westerberg /*
3569edf8e2afSMika Westerberg  * Write out ELF coredump.
3570edf8e2afSMika Westerberg  *
3571edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
3572edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
3573edf8e2afSMika Westerberg  *
3574edf8e2afSMika Westerberg  * Coredump format in linux is following:
3575edf8e2afSMika Westerberg  *
3576edf8e2afSMika Westerberg  * 0   +----------------------+         \
3577edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
3578edf8e2afSMika Westerberg  *     +----------------------+          |
3579edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
3580edf8e2afSMika Westerberg  *     | - NOTE section       |          |
3581edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
3582edf8e2afSMika Westerberg  *     +----------------------+         /
3583edf8e2afSMika Westerberg  *     | NOTEs:               |
3584edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
3585edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
3586edf8e2afSMika Westerberg  *     | - NT_AUXV            |
3587edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
3588edf8e2afSMika Westerberg  *     | Process memory dump  |
3589edf8e2afSMika Westerberg  *     :                      :
3590edf8e2afSMika Westerberg  *     .                      .
3591edf8e2afSMika Westerberg  *     :                      :
3592edf8e2afSMika Westerberg  *     |                      |
3593edf8e2afSMika Westerberg  *     +----------------------+
3594edf8e2afSMika Westerberg  *
3595edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
3596edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
3597edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
3598edf8e2afSMika Westerberg  *
3599edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
3600edf8e2afSMika Westerberg  * version limitations are as follows:
3601edf8e2afSMika Westerberg  *     - no floating point registers are dumped
3602edf8e2afSMika Westerberg  *
3603edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
3604edf8e2afSMika Westerberg  *
3605edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
3606edf8e2afSMika Westerberg  * possible to force coredump from running process and then
3607edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
3608edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
3609edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
3610edf8e2afSMika Westerberg  */
36119349b4f9SAndreas Färber static int elf_core_dump(int signr, const CPUArchState *env)
3612edf8e2afSMika Westerberg {
361329a0af61SRichard Henderson     const CPUState *cpu = env_cpu((CPUArchState *)env);
36140429a971SAndreas Färber     const TaskState *ts = (const TaskState *)cpu->opaque;
3615edf8e2afSMika Westerberg     struct vm_area_struct *vma = NULL;
3616edf8e2afSMika Westerberg     char corefile[PATH_MAX];
3617edf8e2afSMika Westerberg     struct elf_note_info info;
3618edf8e2afSMika Westerberg     struct elfhdr elf;
3619edf8e2afSMika Westerberg     struct elf_phdr phdr;
3620edf8e2afSMika Westerberg     struct rlimit dumpsize;
3621edf8e2afSMika Westerberg     struct mm_struct *mm = NULL;
3622edf8e2afSMika Westerberg     off_t offset = 0, data_offset = 0;
3623edf8e2afSMika Westerberg     int segs = 0;
3624edf8e2afSMika Westerberg     int fd = -1;
3625edf8e2afSMika Westerberg 
36266afafa86SPeter Maydell     init_note_info(&info);
36276afafa86SPeter Maydell 
3628edf8e2afSMika Westerberg     errno = 0;
3629edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
3630edf8e2afSMika Westerberg     if (dumpsize.rlim_cur == 0)
3631edf8e2afSMika Westerberg         return 0;
3632edf8e2afSMika Westerberg 
3633edf8e2afSMika Westerberg     if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
3634edf8e2afSMika Westerberg         return (-errno);
3635edf8e2afSMika Westerberg 
3636edf8e2afSMika Westerberg     if ((fd = open(corefile, O_WRONLY | O_CREAT,
3637edf8e2afSMika Westerberg                    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
3638edf8e2afSMika Westerberg         return (-errno);
3639edf8e2afSMika Westerberg 
3640edf8e2afSMika Westerberg     /*
3641edf8e2afSMika Westerberg      * Walk through target process memory mappings and
3642edf8e2afSMika Westerberg      * set up structure containing this information.  After
3643edf8e2afSMika Westerberg      * this point vma_xxx functions can be used.
3644edf8e2afSMika Westerberg      */
3645edf8e2afSMika Westerberg     if ((mm = vma_init()) == NULL)
3646edf8e2afSMika Westerberg         goto out;
3647edf8e2afSMika Westerberg 
3648edf8e2afSMika Westerberg     walk_memory_regions(mm, vma_walker);
3649edf8e2afSMika Westerberg     segs = vma_get_mapping_count(mm);
3650edf8e2afSMika Westerberg 
3651edf8e2afSMika Westerberg     /*
3652edf8e2afSMika Westerberg      * Construct valid coredump ELF header.  We also
3653edf8e2afSMika Westerberg      * add one more segment for notes.
3654edf8e2afSMika Westerberg      */
3655edf8e2afSMika Westerberg     fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
3656edf8e2afSMika Westerberg     if (dump_write(fd, &elf, sizeof (elf)) != 0)
3657edf8e2afSMika Westerberg         goto out;
3658edf8e2afSMika Westerberg 
3659b6af0975SDaniel P. Berrange     /* fill in the in-memory version of notes */
3660edf8e2afSMika Westerberg     if (fill_note_info(&info, signr, env) < 0)
3661edf8e2afSMika Westerberg         goto out;
3662edf8e2afSMika Westerberg 
3663edf8e2afSMika Westerberg     offset += sizeof (elf);                             /* elf header */
3664edf8e2afSMika Westerberg     offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
3665edf8e2afSMika Westerberg 
3666edf8e2afSMika Westerberg     /* write out notes program header */
3667edf8e2afSMika Westerberg     fill_elf_note_phdr(&phdr, info.notes_size, offset);
3668edf8e2afSMika Westerberg 
3669edf8e2afSMika Westerberg     offset += info.notes_size;
3670edf8e2afSMika Westerberg     if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
3671edf8e2afSMika Westerberg         goto out;
3672edf8e2afSMika Westerberg 
3673edf8e2afSMika Westerberg     /*
3674edf8e2afSMika Westerberg      * ELF specification wants data to start at page boundary so
3675edf8e2afSMika Westerberg      * we align it here.
3676edf8e2afSMika Westerberg      */
367780f5ce75SLaurent Vivier     data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
3678edf8e2afSMika Westerberg 
3679edf8e2afSMika Westerberg     /*
3680edf8e2afSMika Westerberg      * Write program headers for memory regions mapped in
3681edf8e2afSMika Westerberg      * the target process.
3682edf8e2afSMika Westerberg      */
3683edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
3684edf8e2afSMika Westerberg         (void) memset(&phdr, 0, sizeof (phdr));
3685edf8e2afSMika Westerberg 
3686edf8e2afSMika Westerberg         phdr.p_type = PT_LOAD;
3687edf8e2afSMika Westerberg         phdr.p_offset = offset;
3688edf8e2afSMika Westerberg         phdr.p_vaddr = vma->vma_start;
3689edf8e2afSMika Westerberg         phdr.p_paddr = 0;
3690edf8e2afSMika Westerberg         phdr.p_filesz = vma_dump_size(vma);
3691edf8e2afSMika Westerberg         offset += phdr.p_filesz;
3692edf8e2afSMika Westerberg         phdr.p_memsz = vma->vma_end - vma->vma_start;
3693edf8e2afSMika Westerberg         phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
3694edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_WRITE)
3695edf8e2afSMika Westerberg             phdr.p_flags |= PF_W;
3696edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_EXEC)
3697edf8e2afSMika Westerberg             phdr.p_flags |= PF_X;
3698edf8e2afSMika Westerberg         phdr.p_align = ELF_EXEC_PAGESIZE;
3699edf8e2afSMika Westerberg 
370080f5ce75SLaurent Vivier         bswap_phdr(&phdr, 1);
3701772034b6SPeter Maydell         if (dump_write(fd, &phdr, sizeof(phdr)) != 0) {
3702772034b6SPeter Maydell             goto out;
3703772034b6SPeter Maydell         }
3704edf8e2afSMika Westerberg     }
3705edf8e2afSMika Westerberg 
3706edf8e2afSMika Westerberg     /*
3707edf8e2afSMika Westerberg      * Next we write notes just after program headers.  No
3708edf8e2afSMika Westerberg      * alignment needed here.
3709edf8e2afSMika Westerberg      */
3710edf8e2afSMika Westerberg     if (write_note_info(&info, fd) < 0)
3711edf8e2afSMika Westerberg         goto out;
3712edf8e2afSMika Westerberg 
3713edf8e2afSMika Westerberg     /* align data to page boundary */
3714edf8e2afSMika Westerberg     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
3715edf8e2afSMika Westerberg         goto out;
3716edf8e2afSMika Westerberg 
3717edf8e2afSMika Westerberg     /*
3718edf8e2afSMika Westerberg      * Finally we can dump process memory into corefile as well.
3719edf8e2afSMika Westerberg      */
3720edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
3721edf8e2afSMika Westerberg         abi_ulong addr;
3722edf8e2afSMika Westerberg         abi_ulong end;
3723edf8e2afSMika Westerberg 
3724edf8e2afSMika Westerberg         end = vma->vma_start + vma_dump_size(vma);
3725edf8e2afSMika Westerberg 
3726edf8e2afSMika Westerberg         for (addr = vma->vma_start; addr < end;
3727edf8e2afSMika Westerberg              addr += TARGET_PAGE_SIZE) {
3728edf8e2afSMika Westerberg             char page[TARGET_PAGE_SIZE];
3729edf8e2afSMika Westerberg             int error;
3730edf8e2afSMika Westerberg 
3731edf8e2afSMika Westerberg             /*
3732edf8e2afSMika Westerberg              *  Read in page from target process memory and
3733edf8e2afSMika Westerberg              *  write it to coredump file.
3734edf8e2afSMika Westerberg              */
3735edf8e2afSMika Westerberg             error = copy_from_user(page, addr, sizeof (page));
3736edf8e2afSMika Westerberg             if (error != 0) {
373749995e17SAurelien Jarno                 (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
3738edf8e2afSMika Westerberg                                addr);
3739edf8e2afSMika Westerberg                 errno = -error;
3740edf8e2afSMika Westerberg                 goto out;
3741edf8e2afSMika Westerberg             }
3742edf8e2afSMika Westerberg             if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
3743edf8e2afSMika Westerberg                 goto out;
3744edf8e2afSMika Westerberg         }
3745edf8e2afSMika Westerberg     }
3746edf8e2afSMika Westerberg 
3747edf8e2afSMika Westerberg  out:
3748edf8e2afSMika Westerberg     free_note_info(&info);
3749edf8e2afSMika Westerberg     if (mm != NULL)
3750edf8e2afSMika Westerberg         vma_delete(mm);
3751edf8e2afSMika Westerberg     (void) close(fd);
3752edf8e2afSMika Westerberg 
3753edf8e2afSMika Westerberg     if (errno != 0)
3754edf8e2afSMika Westerberg         return (-errno);
3755edf8e2afSMika Westerberg     return (0);
3756edf8e2afSMika Westerberg }
3757edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
3758edf8e2afSMika Westerberg 
3759e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
3760e5fe0c52Spbrook {
3761e5fe0c52Spbrook     init_thread(regs, infop);
3762e5fe0c52Spbrook }
3763