xref: /qemu/linux-user/elfload.c (revision 14322bad88c46e41b962ff8f4a6f524dd883670c)
131e31b8aSbellard /* This is the Linux kernel elf-loading code, ported into user space */
2edf8e2afSMika Westerberg #include <sys/time.h>
3edf8e2afSMika Westerberg #include <sys/param.h>
431e31b8aSbellard 
531e31b8aSbellard #include <stdio.h>
631e31b8aSbellard #include <sys/types.h>
731e31b8aSbellard #include <fcntl.h>
831e31b8aSbellard #include <errno.h>
931e31b8aSbellard #include <unistd.h>
1031e31b8aSbellard #include <sys/mman.h>
11edf8e2afSMika Westerberg #include <sys/resource.h>
1231e31b8aSbellard #include <stdlib.h>
1331e31b8aSbellard #include <string.h>
14edf8e2afSMika Westerberg #include <time.h>
1531e31b8aSbellard 
163ef693a0Sbellard #include "qemu.h"
17689f936fSbellard #include "disas.h"
1831e31b8aSbellard 
19e58ffeb3Smalc #ifdef _ARCH_PPC64
20a6cc84f4Smalc #undef ARCH_DLINFO
21a6cc84f4Smalc #undef ELF_PLATFORM
22a6cc84f4Smalc #undef ELF_HWCAP
23a6cc84f4Smalc #undef ELF_CLASS
24a6cc84f4Smalc #undef ELF_DATA
25a6cc84f4Smalc #undef ELF_ARCH
26a6cc84f4Smalc #endif
27a6cc84f4Smalc 
28edf8e2afSMika Westerberg #define ELF_OSABI   ELFOSABI_SYSV
29edf8e2afSMika Westerberg 
30cb33da57Sblueswir1 /* from personality.h */
31cb33da57Sblueswir1 
32cb33da57Sblueswir1 /*
33cb33da57Sblueswir1  * Flags for bug emulation.
34cb33da57Sblueswir1  *
35cb33da57Sblueswir1  * These occupy the top three bytes.
36cb33da57Sblueswir1  */
37cb33da57Sblueswir1 enum {
38cb33da57Sblueswir1     ADDR_NO_RANDOMIZE = 0x0040000,      /* disable randomization of VA space */
39d97ef72eSRichard Henderson     FDPIC_FUNCPTRS =    0x0080000,      /* userspace function ptrs point to
40d97ef72eSRichard Henderson                                            descriptors (signal handling) */
41cb33da57Sblueswir1     MMAP_PAGE_ZERO =    0x0100000,
42cb33da57Sblueswir1     ADDR_COMPAT_LAYOUT = 0x0200000,
43cb33da57Sblueswir1     READ_IMPLIES_EXEC = 0x0400000,
44cb33da57Sblueswir1     ADDR_LIMIT_32BIT =  0x0800000,
45cb33da57Sblueswir1     SHORT_INODE =       0x1000000,
46cb33da57Sblueswir1     WHOLE_SECONDS =     0x2000000,
47cb33da57Sblueswir1     STICKY_TIMEOUTS =   0x4000000,
48cb33da57Sblueswir1     ADDR_LIMIT_3GB =    0x8000000,
49cb33da57Sblueswir1 };
50cb33da57Sblueswir1 
51cb33da57Sblueswir1 /*
52cb33da57Sblueswir1  * Personality types.
53cb33da57Sblueswir1  *
54cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
55cb33da57Sblueswir1  * conflict with error returns.
56cb33da57Sblueswir1  */
57cb33da57Sblueswir1 enum {
58cb33da57Sblueswir1     PER_LINUX =         0x0000,
59cb33da57Sblueswir1     PER_LINUX_32BIT =   0x0000 | ADDR_LIMIT_32BIT,
60cb33da57Sblueswir1     PER_LINUX_FDPIC =   0x0000 | FDPIC_FUNCPTRS,
61cb33da57Sblueswir1     PER_SVR4 =          0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
62cb33da57Sblueswir1     PER_SVR3 =          0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
63d97ef72eSRichard Henderson     PER_SCOSVR3 =       0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE,
64cb33da57Sblueswir1     PER_OSR5 =          0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
65cb33da57Sblueswir1     PER_WYSEV386 =      0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
66cb33da57Sblueswir1     PER_ISCR4 =         0x0005 | STICKY_TIMEOUTS,
67cb33da57Sblueswir1     PER_BSD =           0x0006,
68cb33da57Sblueswir1     PER_SUNOS =         0x0006 | STICKY_TIMEOUTS,
69cb33da57Sblueswir1     PER_XENIX =         0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
70cb33da57Sblueswir1     PER_LINUX32 =       0x0008,
71cb33da57Sblueswir1     PER_LINUX32_3GB =   0x0008 | ADDR_LIMIT_3GB,
72cb33da57Sblueswir1     PER_IRIX32 =        0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
73cb33da57Sblueswir1     PER_IRIXN32 =       0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
74cb33da57Sblueswir1     PER_IRIX64 =        0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
75cb33da57Sblueswir1     PER_RISCOS =        0x000c,
76cb33da57Sblueswir1     PER_SOLARIS =       0x000d | STICKY_TIMEOUTS,
77cb33da57Sblueswir1     PER_UW7 =           0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
78cb33da57Sblueswir1     PER_OSF4 =          0x000f,                  /* OSF/1 v4 */
79cb33da57Sblueswir1     PER_HPUX =          0x0010,
80cb33da57Sblueswir1     PER_MASK =          0x00ff,
81cb33da57Sblueswir1 };
82cb33da57Sblueswir1 
83cb33da57Sblueswir1 /*
84cb33da57Sblueswir1  * Return the base personality without flags.
85cb33da57Sblueswir1  */
86cb33da57Sblueswir1 #define personality(pers)       (pers & PER_MASK)
87cb33da57Sblueswir1 
8883fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
8983fb7adfSbellard #ifndef MAP_DENYWRITE
9083fb7adfSbellard #define MAP_DENYWRITE 0
9183fb7adfSbellard #endif
9283fb7adfSbellard 
9383fb7adfSbellard /* should probably go in elf.h */
9483fb7adfSbellard #ifndef ELIBBAD
9583fb7adfSbellard #define ELIBBAD 80
9683fb7adfSbellard #endif
9783fb7adfSbellard 
9828490231SRichard Henderson #ifdef TARGET_WORDS_BIGENDIAN
9928490231SRichard Henderson #define ELF_DATA        ELFDATA2MSB
10028490231SRichard Henderson #else
10128490231SRichard Henderson #define ELF_DATA        ELFDATA2LSB
10228490231SRichard Henderson #endif
10328490231SRichard Henderson 
10421e807faSNathan Froyd typedef target_ulong    target_elf_greg_t;
10521e807faSNathan Froyd #ifdef USE_UID16
10680f5ce75SLaurent Vivier typedef target_ushort   target_uid_t;
10780f5ce75SLaurent Vivier typedef target_ushort   target_gid_t;
10821e807faSNathan Froyd #else
10980f5ce75SLaurent Vivier typedef target_uint     target_uid_t;
11080f5ce75SLaurent Vivier typedef target_uint     target_gid_t;
11121e807faSNathan Froyd #endif
11280f5ce75SLaurent Vivier typedef target_int      target_pid_t;
11321e807faSNathan Froyd 
11430ac07d4Sbellard #ifdef TARGET_I386
11530ac07d4Sbellard 
11615338fd7Sbellard #define ELF_PLATFORM get_elf_platform()
11715338fd7Sbellard 
11815338fd7Sbellard static const char *get_elf_platform(void)
11915338fd7Sbellard {
12015338fd7Sbellard     static char elf_platform[] = "i386";
121d5975363Spbrook     int family = (thread_env->cpuid_version >> 8) & 0xff;
12215338fd7Sbellard     if (family > 6)
12315338fd7Sbellard         family = 6;
12415338fd7Sbellard     if (family >= 3)
12515338fd7Sbellard         elf_platform[1] = '0' + family;
12615338fd7Sbellard     return elf_platform;
12715338fd7Sbellard }
12815338fd7Sbellard 
12915338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
13015338fd7Sbellard 
13115338fd7Sbellard static uint32_t get_elf_hwcap(void)
13215338fd7Sbellard {
133d5975363Spbrook     return thread_env->cpuid_features;
13415338fd7Sbellard }
13515338fd7Sbellard 
13684409ddbSj_mayer #ifdef TARGET_X86_64
13784409ddbSj_mayer #define ELF_START_MMAP 0x2aaaaab000ULL
13884409ddbSj_mayer #define elf_check_arch(x) ( ((x) == ELF_ARCH) )
13984409ddbSj_mayer 
14084409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
14184409ddbSj_mayer #define ELF_ARCH       EM_X86_64
14284409ddbSj_mayer 
14384409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
14484409ddbSj_mayer {
14584409ddbSj_mayer     regs->rax = 0;
14684409ddbSj_mayer     regs->rsp = infop->start_stack;
14784409ddbSj_mayer     regs->rip = infop->entry;
14884409ddbSj_mayer }
14984409ddbSj_mayer 
1509edc5d79SMika Westerberg #define ELF_NREG    27
151c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
1529edc5d79SMika Westerberg 
1539edc5d79SMika Westerberg /*
1549edc5d79SMika Westerberg  * Note that ELF_NREG should be 29 as there should be place for
1559edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
1569edc5d79SMika Westerberg  * those.
1579edc5d79SMika Westerberg  *
1589edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
1599edc5d79SMika Westerberg  */
160c227f099SAnthony Liguori static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
1619edc5d79SMika Westerberg {
1629edc5d79SMika Westerberg     (*regs)[0] = env->regs[15];
1639edc5d79SMika Westerberg     (*regs)[1] = env->regs[14];
1649edc5d79SMika Westerberg     (*regs)[2] = env->regs[13];
1659edc5d79SMika Westerberg     (*regs)[3] = env->regs[12];
1669edc5d79SMika Westerberg     (*regs)[4] = env->regs[R_EBP];
1679edc5d79SMika Westerberg     (*regs)[5] = env->regs[R_EBX];
1689edc5d79SMika Westerberg     (*regs)[6] = env->regs[11];
1699edc5d79SMika Westerberg     (*regs)[7] = env->regs[10];
1709edc5d79SMika Westerberg     (*regs)[8] = env->regs[9];
1719edc5d79SMika Westerberg     (*regs)[9] = env->regs[8];
1729edc5d79SMika Westerberg     (*regs)[10] = env->regs[R_EAX];
1739edc5d79SMika Westerberg     (*regs)[11] = env->regs[R_ECX];
1749edc5d79SMika Westerberg     (*regs)[12] = env->regs[R_EDX];
1759edc5d79SMika Westerberg     (*regs)[13] = env->regs[R_ESI];
1769edc5d79SMika Westerberg     (*regs)[14] = env->regs[R_EDI];
1779edc5d79SMika Westerberg     (*regs)[15] = env->regs[R_EAX]; /* XXX */
1789edc5d79SMika Westerberg     (*regs)[16] = env->eip;
1799edc5d79SMika Westerberg     (*regs)[17] = env->segs[R_CS].selector & 0xffff;
1809edc5d79SMika Westerberg     (*regs)[18] = env->eflags;
1819edc5d79SMika Westerberg     (*regs)[19] = env->regs[R_ESP];
1829edc5d79SMika Westerberg     (*regs)[20] = env->segs[R_SS].selector & 0xffff;
1839edc5d79SMika Westerberg     (*regs)[21] = env->segs[R_FS].selector & 0xffff;
1849edc5d79SMika Westerberg     (*regs)[22] = env->segs[R_GS].selector & 0xffff;
1859edc5d79SMika Westerberg     (*regs)[23] = env->segs[R_DS].selector & 0xffff;
1869edc5d79SMika Westerberg     (*regs)[24] = env->segs[R_ES].selector & 0xffff;
1879edc5d79SMika Westerberg     (*regs)[25] = env->segs[R_FS].selector & 0xffff;
1889edc5d79SMika Westerberg     (*regs)[26] = env->segs[R_GS].selector & 0xffff;
1899edc5d79SMika Westerberg }
1909edc5d79SMika Westerberg 
19184409ddbSj_mayer #else
19284409ddbSj_mayer 
19330ac07d4Sbellard #define ELF_START_MMAP 0x80000000
19430ac07d4Sbellard 
19530ac07d4Sbellard /*
19630ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
19730ac07d4Sbellard  */
19830ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
19930ac07d4Sbellard 
20030ac07d4Sbellard /*
20130ac07d4Sbellard  * These are used to set parameters in the core dumps.
20230ac07d4Sbellard  */
20330ac07d4Sbellard #define ELF_CLASS       ELFCLASS32
20430ac07d4Sbellard #define ELF_ARCH        EM_386
20530ac07d4Sbellard 
206d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
207d97ef72eSRichard Henderson                                struct image_info *infop)
208e5fe0c52Spbrook {
209e5fe0c52Spbrook     regs->esp = infop->start_stack;
210e5fe0c52Spbrook     regs->eip = infop->entry;
211e5fe0c52Spbrook 
21230ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
21330ac07d4Sbellard        starts %edx contains a pointer to a function which might be
21430ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
21530ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
21630ac07d4Sbellard        that have been loaded before the code runs.
21730ac07d4Sbellard 
21830ac07d4Sbellard        A value of 0 tells we have no such handler.  */
219e5fe0c52Spbrook     regs->edx = 0;
220b346ff46Sbellard }
2219edc5d79SMika Westerberg 
2229edc5d79SMika Westerberg #define ELF_NREG    17
223c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
2249edc5d79SMika Westerberg 
2259edc5d79SMika Westerberg /*
2269edc5d79SMika Westerberg  * Note that ELF_NREG should be 19 as there should be place for
2279edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
2289edc5d79SMika Westerberg  * those.
2299edc5d79SMika Westerberg  *
2309edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
2319edc5d79SMika Westerberg  */
232c227f099SAnthony Liguori static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
2339edc5d79SMika Westerberg {
2349edc5d79SMika Westerberg     (*regs)[0] = env->regs[R_EBX];
2359edc5d79SMika Westerberg     (*regs)[1] = env->regs[R_ECX];
2369edc5d79SMika Westerberg     (*regs)[2] = env->regs[R_EDX];
2379edc5d79SMika Westerberg     (*regs)[3] = env->regs[R_ESI];
2389edc5d79SMika Westerberg     (*regs)[4] = env->regs[R_EDI];
2399edc5d79SMika Westerberg     (*regs)[5] = env->regs[R_EBP];
2409edc5d79SMika Westerberg     (*regs)[6] = env->regs[R_EAX];
2419edc5d79SMika Westerberg     (*regs)[7] = env->segs[R_DS].selector & 0xffff;
2429edc5d79SMika Westerberg     (*regs)[8] = env->segs[R_ES].selector & 0xffff;
2439edc5d79SMika Westerberg     (*regs)[9] = env->segs[R_FS].selector & 0xffff;
2449edc5d79SMika Westerberg     (*regs)[10] = env->segs[R_GS].selector & 0xffff;
2459edc5d79SMika Westerberg     (*regs)[11] = env->regs[R_EAX]; /* XXX */
2469edc5d79SMika Westerberg     (*regs)[12] = env->eip;
2479edc5d79SMika Westerberg     (*regs)[13] = env->segs[R_CS].selector & 0xffff;
2489edc5d79SMika Westerberg     (*regs)[14] = env->eflags;
2499edc5d79SMika Westerberg     (*regs)[15] = env->regs[R_ESP];
2509edc5d79SMika Westerberg     (*regs)[16] = env->segs[R_SS].selector & 0xffff;
2519edc5d79SMika Westerberg }
25284409ddbSj_mayer #endif
253b346ff46Sbellard 
2549edc5d79SMika Westerberg #define USE_ELF_CORE_DUMP
255b346ff46Sbellard #define ELF_EXEC_PAGESIZE       4096
256b346ff46Sbellard 
257b346ff46Sbellard #endif
258b346ff46Sbellard 
259b346ff46Sbellard #ifdef TARGET_ARM
260b346ff46Sbellard 
261b346ff46Sbellard #define ELF_START_MMAP 0x80000000
262b346ff46Sbellard 
263b346ff46Sbellard #define elf_check_arch(x) ( (x) == EM_ARM )
264b346ff46Sbellard 
265b346ff46Sbellard #define ELF_CLASS       ELFCLASS32
266b346ff46Sbellard #define ELF_ARCH        EM_ARM
267b346ff46Sbellard 
268d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
269d97ef72eSRichard Henderson                                struct image_info *infop)
270b346ff46Sbellard {
271992f48a0Sblueswir1     abi_long stack = infop->start_stack;
272b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
273b346ff46Sbellard     regs->ARM_cpsr = 0x10;
2740240ded8Spbrook     if (infop->entry & 1)
2750240ded8Spbrook         regs->ARM_cpsr |= CPSR_T;
2760240ded8Spbrook     regs->ARM_pc = infop->entry & 0xfffffffe;
277b346ff46Sbellard     regs->ARM_sp = infop->start_stack;
2782f619698Sbellard     /* FIXME - what to for failure of get_user()? */
2792f619698Sbellard     get_user_ual(regs->ARM_r2, stack + 8); /* envp */
2802f619698Sbellard     get_user_ual(regs->ARM_r1, stack + 4); /* envp */
281a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
282e5fe0c52Spbrook     regs->ARM_r0 = 0;
283e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
284863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
285e5fe0c52Spbrook     regs->ARM_r10 = infop->start_data;
286b346ff46Sbellard }
287b346ff46Sbellard 
288edf8e2afSMika Westerberg #define ELF_NREG    18
289c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
290edf8e2afSMika Westerberg 
291c227f099SAnthony Liguori static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
292edf8e2afSMika Westerberg {
293d049e626SNathan Froyd     (*regs)[0] = tswapl(env->regs[0]);
294d049e626SNathan Froyd     (*regs)[1] = tswapl(env->regs[1]);
295d049e626SNathan Froyd     (*regs)[2] = tswapl(env->regs[2]);
296d049e626SNathan Froyd     (*regs)[3] = tswapl(env->regs[3]);
297d049e626SNathan Froyd     (*regs)[4] = tswapl(env->regs[4]);
298d049e626SNathan Froyd     (*regs)[5] = tswapl(env->regs[5]);
299d049e626SNathan Froyd     (*regs)[6] = tswapl(env->regs[6]);
300d049e626SNathan Froyd     (*regs)[7] = tswapl(env->regs[7]);
301d049e626SNathan Froyd     (*regs)[8] = tswapl(env->regs[8]);
302d049e626SNathan Froyd     (*regs)[9] = tswapl(env->regs[9]);
303d049e626SNathan Froyd     (*regs)[10] = tswapl(env->regs[10]);
304d049e626SNathan Froyd     (*regs)[11] = tswapl(env->regs[11]);
305d049e626SNathan Froyd     (*regs)[12] = tswapl(env->regs[12]);
306d049e626SNathan Froyd     (*regs)[13] = tswapl(env->regs[13]);
307d049e626SNathan Froyd     (*regs)[14] = tswapl(env->regs[14]);
308d049e626SNathan Froyd     (*regs)[15] = tswapl(env->regs[15]);
309edf8e2afSMika Westerberg 
310d049e626SNathan Froyd     (*regs)[16] = tswapl(cpsr_read((CPUState *)env));
311d049e626SNathan Froyd     (*regs)[17] = tswapl(env->regs[0]); /* XXX */
312edf8e2afSMika Westerberg }
313edf8e2afSMika Westerberg 
31430ac07d4Sbellard #define USE_ELF_CORE_DUMP
31530ac07d4Sbellard #define ELF_EXEC_PAGESIZE       4096
31630ac07d4Sbellard 
317afce2927Sbellard enum
318afce2927Sbellard {
319afce2927Sbellard     ARM_HWCAP_ARM_SWP       = 1 << 0,
320afce2927Sbellard     ARM_HWCAP_ARM_HALF      = 1 << 1,
321afce2927Sbellard     ARM_HWCAP_ARM_THUMB     = 1 << 2,
322afce2927Sbellard     ARM_HWCAP_ARM_26BIT     = 1 << 3,
323afce2927Sbellard     ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
324afce2927Sbellard     ARM_HWCAP_ARM_FPA       = 1 << 5,
325afce2927Sbellard     ARM_HWCAP_ARM_VFP       = 1 << 6,
326afce2927Sbellard     ARM_HWCAP_ARM_EDSP      = 1 << 7,
327cf6de34aSRiku Voipio     ARM_HWCAP_ARM_JAVA      = 1 << 8,
328cf6de34aSRiku Voipio     ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
329cf6de34aSRiku Voipio     ARM_HWCAP_ARM_THUMBEE   = 1 << 10,
330cf6de34aSRiku Voipio     ARM_HWCAP_ARM_NEON      = 1 << 11,
331cf6de34aSRiku Voipio     ARM_HWCAP_ARM_VFPv3     = 1 << 12,
332cf6de34aSRiku Voipio     ARM_HWCAP_ARM_VFPv3D16  = 1 << 13,
333afce2927Sbellard };
334afce2927Sbellard 
33515338fd7Sbellard #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF               \
336afce2927Sbellard                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT      \
337cf6de34aSRiku Voipio                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP              \
338cf6de34aSRiku Voipio                    | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 )
339afce2927Sbellard 
34030ac07d4Sbellard #endif
34130ac07d4Sbellard 
342d2fbca94SGuan Xuetao #ifdef TARGET_UNICORE32
343d2fbca94SGuan Xuetao 
344d2fbca94SGuan Xuetao #define ELF_START_MMAP          0x80000000
345d2fbca94SGuan Xuetao 
346d2fbca94SGuan Xuetao #define elf_check_arch(x)       ((x) == EM_UNICORE32)
347d2fbca94SGuan Xuetao 
348d2fbca94SGuan Xuetao #define ELF_CLASS               ELFCLASS32
349d2fbca94SGuan Xuetao #define ELF_DATA                ELFDATA2LSB
350d2fbca94SGuan Xuetao #define ELF_ARCH                EM_UNICORE32
351d2fbca94SGuan Xuetao 
352d2fbca94SGuan Xuetao static inline void init_thread(struct target_pt_regs *regs,
353d2fbca94SGuan Xuetao         struct image_info *infop)
354d2fbca94SGuan Xuetao {
355d2fbca94SGuan Xuetao     abi_long stack = infop->start_stack;
356d2fbca94SGuan Xuetao     memset(regs, 0, sizeof(*regs));
357d2fbca94SGuan Xuetao     regs->UC32_REG_asr = 0x10;
358d2fbca94SGuan Xuetao     regs->UC32_REG_pc = infop->entry & 0xfffffffe;
359d2fbca94SGuan Xuetao     regs->UC32_REG_sp = infop->start_stack;
360d2fbca94SGuan Xuetao     /* FIXME - what to for failure of get_user()? */
361d2fbca94SGuan Xuetao     get_user_ual(regs->UC32_REG_02, stack + 8); /* envp */
362d2fbca94SGuan Xuetao     get_user_ual(regs->UC32_REG_01, stack + 4); /* envp */
363d2fbca94SGuan Xuetao     /* XXX: it seems that r0 is zeroed after ! */
364d2fbca94SGuan Xuetao     regs->UC32_REG_00 = 0;
365d2fbca94SGuan Xuetao }
366d2fbca94SGuan Xuetao 
367d2fbca94SGuan Xuetao #define ELF_NREG    34
368d2fbca94SGuan Xuetao typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
369d2fbca94SGuan Xuetao 
370d2fbca94SGuan Xuetao static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
371d2fbca94SGuan Xuetao {
372d2fbca94SGuan Xuetao     (*regs)[0] = env->regs[0];
373d2fbca94SGuan Xuetao     (*regs)[1] = env->regs[1];
374d2fbca94SGuan Xuetao     (*regs)[2] = env->regs[2];
375d2fbca94SGuan Xuetao     (*regs)[3] = env->regs[3];
376d2fbca94SGuan Xuetao     (*regs)[4] = env->regs[4];
377d2fbca94SGuan Xuetao     (*regs)[5] = env->regs[5];
378d2fbca94SGuan Xuetao     (*regs)[6] = env->regs[6];
379d2fbca94SGuan Xuetao     (*regs)[7] = env->regs[7];
380d2fbca94SGuan Xuetao     (*regs)[8] = env->regs[8];
381d2fbca94SGuan Xuetao     (*regs)[9] = env->regs[9];
382d2fbca94SGuan Xuetao     (*regs)[10] = env->regs[10];
383d2fbca94SGuan Xuetao     (*regs)[11] = env->regs[11];
384d2fbca94SGuan Xuetao     (*regs)[12] = env->regs[12];
385d2fbca94SGuan Xuetao     (*regs)[13] = env->regs[13];
386d2fbca94SGuan Xuetao     (*regs)[14] = env->regs[14];
387d2fbca94SGuan Xuetao     (*regs)[15] = env->regs[15];
388d2fbca94SGuan Xuetao     (*regs)[16] = env->regs[16];
389d2fbca94SGuan Xuetao     (*regs)[17] = env->regs[17];
390d2fbca94SGuan Xuetao     (*regs)[18] = env->regs[18];
391d2fbca94SGuan Xuetao     (*regs)[19] = env->regs[19];
392d2fbca94SGuan Xuetao     (*regs)[20] = env->regs[20];
393d2fbca94SGuan Xuetao     (*regs)[21] = env->regs[21];
394d2fbca94SGuan Xuetao     (*regs)[22] = env->regs[22];
395d2fbca94SGuan Xuetao     (*regs)[23] = env->regs[23];
396d2fbca94SGuan Xuetao     (*regs)[24] = env->regs[24];
397d2fbca94SGuan Xuetao     (*regs)[25] = env->regs[25];
398d2fbca94SGuan Xuetao     (*regs)[26] = env->regs[26];
399d2fbca94SGuan Xuetao     (*regs)[27] = env->regs[27];
400d2fbca94SGuan Xuetao     (*regs)[28] = env->regs[28];
401d2fbca94SGuan Xuetao     (*regs)[29] = env->regs[29];
402d2fbca94SGuan Xuetao     (*regs)[30] = env->regs[30];
403d2fbca94SGuan Xuetao     (*regs)[31] = env->regs[31];
404d2fbca94SGuan Xuetao 
405d2fbca94SGuan Xuetao     (*regs)[32] = cpu_asr_read((CPUState *)env);
406d2fbca94SGuan Xuetao     (*regs)[33] = env->regs[0]; /* XXX */
407d2fbca94SGuan Xuetao }
408d2fbca94SGuan Xuetao 
409d2fbca94SGuan Xuetao #define USE_ELF_CORE_DUMP
410d2fbca94SGuan Xuetao #define ELF_EXEC_PAGESIZE               4096
411d2fbca94SGuan Xuetao 
412d2fbca94SGuan Xuetao #define ELF_HWCAP                       (UC32_HWCAP_CMOV | UC32_HWCAP_UCF64)
413d2fbca94SGuan Xuetao 
414d2fbca94SGuan Xuetao #endif
415d2fbca94SGuan Xuetao 
416853d6f7aSbellard #ifdef TARGET_SPARC
417a315a145Sbellard #ifdef TARGET_SPARC64
418853d6f7aSbellard 
419853d6f7aSbellard #define ELF_START_MMAP 0x80000000
420853d6f7aSbellard 
421992f48a0Sblueswir1 #ifndef TARGET_ABI32
422cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
423992f48a0Sblueswir1 #else
424992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
425992f48a0Sblueswir1 #endif
426853d6f7aSbellard 
427a315a145Sbellard #define ELF_CLASS   ELFCLASS64
4285ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
4295ef54116Sbellard 
4305ef54116Sbellard #define STACK_BIAS              2047
431a315a145Sbellard 
432d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
433d97ef72eSRichard Henderson                                struct image_info *infop)
434a315a145Sbellard {
435992f48a0Sblueswir1 #ifndef TARGET_ABI32
436a315a145Sbellard     regs->tstate = 0;
437992f48a0Sblueswir1 #endif
438a315a145Sbellard     regs->pc = infop->entry;
439a315a145Sbellard     regs->npc = regs->pc + 4;
440a315a145Sbellard     regs->y = 0;
441992f48a0Sblueswir1 #ifdef TARGET_ABI32
442992f48a0Sblueswir1     regs->u_regs[14] = infop->start_stack - 16 * 4;
443992f48a0Sblueswir1 #else
444cb33da57Sblueswir1     if (personality(infop->personality) == PER_LINUX32)
445cb33da57Sblueswir1         regs->u_regs[14] = infop->start_stack - 16 * 4;
446cb33da57Sblueswir1     else
4475ef54116Sbellard         regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
448992f48a0Sblueswir1 #endif
449a315a145Sbellard }
450a315a145Sbellard 
451a315a145Sbellard #else
452a315a145Sbellard #define ELF_START_MMAP 0x80000000
453a315a145Sbellard 
454a315a145Sbellard #define elf_check_arch(x) ( (x) == EM_SPARC )
455a315a145Sbellard 
456853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
457853d6f7aSbellard #define ELF_ARCH    EM_SPARC
458853d6f7aSbellard 
459d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
460d97ef72eSRichard Henderson                                struct image_info *infop)
461853d6f7aSbellard {
462f5155289Sbellard     regs->psr = 0;
463f5155289Sbellard     regs->pc = infop->entry;
464f5155289Sbellard     regs->npc = regs->pc + 4;
465f5155289Sbellard     regs->y = 0;
466f5155289Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 4;
467853d6f7aSbellard }
468853d6f7aSbellard 
469853d6f7aSbellard #endif
470a315a145Sbellard #endif
471853d6f7aSbellard 
47267867308Sbellard #ifdef TARGET_PPC
47367867308Sbellard 
47467867308Sbellard #define ELF_START_MMAP 0x80000000
47567867308Sbellard 
476e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
47784409ddbSj_mayer 
47884409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
47984409ddbSj_mayer 
48084409ddbSj_mayer #define ELF_CLASS       ELFCLASS64
48184409ddbSj_mayer 
48284409ddbSj_mayer #else
48384409ddbSj_mayer 
48467867308Sbellard #define elf_check_arch(x) ( (x) == EM_PPC )
48567867308Sbellard 
48667867308Sbellard #define ELF_CLASS       ELFCLASS32
48784409ddbSj_mayer 
48884409ddbSj_mayer #endif
48984409ddbSj_mayer 
49067867308Sbellard #define ELF_ARCH        EM_PPC
49167867308Sbellard 
492df84e4f3SNathan Froyd /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
493df84e4f3SNathan Froyd    See arch/powerpc/include/asm/cputable.h.  */
494df84e4f3SNathan Froyd enum {
4953efa9a67Smalc     QEMU_PPC_FEATURE_32 = 0x80000000,
4963efa9a67Smalc     QEMU_PPC_FEATURE_64 = 0x40000000,
4973efa9a67Smalc     QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
4983efa9a67Smalc     QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
4993efa9a67Smalc     QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
5003efa9a67Smalc     QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
5013efa9a67Smalc     QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
5023efa9a67Smalc     QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
5033efa9a67Smalc     QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
5043efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
5053efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
5063efa9a67Smalc     QEMU_PPC_FEATURE_NO_TB = 0x00100000,
5073efa9a67Smalc     QEMU_PPC_FEATURE_POWER4 = 0x00080000,
5083efa9a67Smalc     QEMU_PPC_FEATURE_POWER5 = 0x00040000,
5093efa9a67Smalc     QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
5103efa9a67Smalc     QEMU_PPC_FEATURE_CELL = 0x00010000,
5113efa9a67Smalc     QEMU_PPC_FEATURE_BOOKE = 0x00008000,
5123efa9a67Smalc     QEMU_PPC_FEATURE_SMT = 0x00004000,
5133efa9a67Smalc     QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
5143efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
5153efa9a67Smalc     QEMU_PPC_FEATURE_PA6T = 0x00000800,
5163efa9a67Smalc     QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
5173efa9a67Smalc     QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
5183efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
5193efa9a67Smalc     QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
5203efa9a67Smalc     QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
521df84e4f3SNathan Froyd 
5223efa9a67Smalc     QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
5233efa9a67Smalc     QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
524df84e4f3SNathan Froyd };
525df84e4f3SNathan Froyd 
526df84e4f3SNathan Froyd #define ELF_HWCAP get_elf_hwcap()
527df84e4f3SNathan Froyd 
528df84e4f3SNathan Froyd static uint32_t get_elf_hwcap(void)
529df84e4f3SNathan Froyd {
530df84e4f3SNathan Froyd     CPUState *e = thread_env;
531df84e4f3SNathan Froyd     uint32_t features = 0;
532df84e4f3SNathan Froyd 
533df84e4f3SNathan Froyd     /* We don't have to be terribly complete here; the high points are
534df84e4f3SNathan Froyd        Altivec/FP/SPE support.  Anything else is just a bonus.  */
535df84e4f3SNathan Froyd #define GET_FEATURE(flag, feature)                                      \
536df84e4f3SNathan Froyd     do {if (e->insns_flags & flag) features |= feature; } while(0)
5373efa9a67Smalc     GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
5383efa9a67Smalc     GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
5393efa9a67Smalc     GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
5403efa9a67Smalc     GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
5413efa9a67Smalc     GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
5423efa9a67Smalc     GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
5433efa9a67Smalc     GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
5443efa9a67Smalc     GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
545df84e4f3SNathan Froyd #undef GET_FEATURE
546df84e4f3SNathan Froyd 
547df84e4f3SNathan Froyd     return features;
548df84e4f3SNathan Froyd }
549df84e4f3SNathan Froyd 
550f5155289Sbellard /*
551f5155289Sbellard  * The requirements here are:
552f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
553f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
554f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
555f5155289Sbellard  *   AT_IGNOREPPC is used for that.
556f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
557f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
558f5155289Sbellard  */
5590bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
560f5155289Sbellard #define ARCH_DLINFO                                     \
561f5155289Sbellard     do {                                                \
5620bccf03dSbellard         NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);              \
5630bccf03dSbellard         NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);              \
5640bccf03dSbellard         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                 \
565f5155289Sbellard         /*                                              \
566f5155289Sbellard          * Now handle glibc compatibility.              \
567f5155289Sbellard          */                                             \
5680bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
5690bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
570f5155289Sbellard     } while (0)
571f5155289Sbellard 
57267867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
57367867308Sbellard {
57467867308Sbellard     _regs->gpr[1] = infop->start_stack;
575e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
5767983f435SRob Landley     _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_addr;
5777983f435SRob Landley     infop->entry = ldq_raw(infop->entry) + infop->load_addr;
57884409ddbSj_mayer #endif
57967867308Sbellard     _regs->nip = infop->entry;
58067867308Sbellard }
58167867308Sbellard 
582e2f3e741SNathan Froyd /* See linux kernel: arch/powerpc/include/asm/elf.h.  */
583e2f3e741SNathan Froyd #define ELF_NREG 48
584e2f3e741SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
585e2f3e741SNathan Froyd 
586e2f3e741SNathan Froyd static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
587e2f3e741SNathan Froyd {
588e2f3e741SNathan Froyd     int i;
589e2f3e741SNathan Froyd     target_ulong ccr = 0;
590e2f3e741SNathan Froyd 
591e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
592e2f3e741SNathan Froyd         (*regs)[i] = tswapl(env->gpr[i]);
593e2f3e741SNathan Froyd     }
594e2f3e741SNathan Froyd 
595e2f3e741SNathan Froyd     (*regs)[32] = tswapl(env->nip);
596e2f3e741SNathan Froyd     (*regs)[33] = tswapl(env->msr);
597e2f3e741SNathan Froyd     (*regs)[35] = tswapl(env->ctr);
598e2f3e741SNathan Froyd     (*regs)[36] = tswapl(env->lr);
599e2f3e741SNathan Froyd     (*regs)[37] = tswapl(env->xer);
600e2f3e741SNathan Froyd 
601e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
602e2f3e741SNathan Froyd         ccr |= env->crf[i] << (32 - ((i + 1) * 4));
603e2f3e741SNathan Froyd     }
604e2f3e741SNathan Froyd     (*regs)[38] = tswapl(ccr);
605e2f3e741SNathan Froyd }
606e2f3e741SNathan Froyd 
607e2f3e741SNathan Froyd #define USE_ELF_CORE_DUMP
60867867308Sbellard #define ELF_EXEC_PAGESIZE       4096
60967867308Sbellard 
61067867308Sbellard #endif
61167867308Sbellard 
612048f6b4dSbellard #ifdef TARGET_MIPS
613048f6b4dSbellard 
614048f6b4dSbellard #define ELF_START_MMAP 0x80000000
615048f6b4dSbellard 
616048f6b4dSbellard #define elf_check_arch(x) ( (x) == EM_MIPS )
617048f6b4dSbellard 
618388bb21aSths #ifdef TARGET_MIPS64
619388bb21aSths #define ELF_CLASS   ELFCLASS64
620388bb21aSths #else
621048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
622388bb21aSths #endif
623048f6b4dSbellard #define ELF_ARCH    EM_MIPS
624048f6b4dSbellard 
625d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
626d97ef72eSRichard Henderson                                struct image_info *infop)
627048f6b4dSbellard {
628623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
629048f6b4dSbellard     regs->cp0_epc = infop->entry;
630048f6b4dSbellard     regs->regs[29] = infop->start_stack;
631048f6b4dSbellard }
632048f6b4dSbellard 
63351e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/elf.h.  */
63451e52606SNathan Froyd #define ELF_NREG 45
63551e52606SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
63651e52606SNathan Froyd 
63751e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/reg.h.  */
63851e52606SNathan Froyd enum {
63951e52606SNathan Froyd #ifdef TARGET_MIPS64
64051e52606SNathan Froyd     TARGET_EF_R0 = 0,
64151e52606SNathan Froyd #else
64251e52606SNathan Froyd     TARGET_EF_R0 = 6,
64351e52606SNathan Froyd #endif
64451e52606SNathan Froyd     TARGET_EF_R26 = TARGET_EF_R0 + 26,
64551e52606SNathan Froyd     TARGET_EF_R27 = TARGET_EF_R0 + 27,
64651e52606SNathan Froyd     TARGET_EF_LO = TARGET_EF_R0 + 32,
64751e52606SNathan Froyd     TARGET_EF_HI = TARGET_EF_R0 + 33,
64851e52606SNathan Froyd     TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
64951e52606SNathan Froyd     TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
65051e52606SNathan Froyd     TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
65151e52606SNathan Froyd     TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
65251e52606SNathan Froyd };
65351e52606SNathan Froyd 
65451e52606SNathan Froyd /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
65551e52606SNathan Froyd static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
65651e52606SNathan Froyd {
65751e52606SNathan Froyd     int i;
65851e52606SNathan Froyd 
65951e52606SNathan Froyd     for (i = 0; i < TARGET_EF_R0; i++) {
66051e52606SNathan Froyd         (*regs)[i] = 0;
66151e52606SNathan Froyd     }
66251e52606SNathan Froyd     (*regs)[TARGET_EF_R0] = 0;
66351e52606SNathan Froyd 
66451e52606SNathan Froyd     for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
66551e52606SNathan Froyd         (*regs)[TARGET_EF_R0 + i] = tswapl(env->active_tc.gpr[i]);
66651e52606SNathan Froyd     }
66751e52606SNathan Froyd 
66851e52606SNathan Froyd     (*regs)[TARGET_EF_R26] = 0;
66951e52606SNathan Froyd     (*regs)[TARGET_EF_R27] = 0;
67051e52606SNathan Froyd     (*regs)[TARGET_EF_LO] = tswapl(env->active_tc.LO[0]);
67151e52606SNathan Froyd     (*regs)[TARGET_EF_HI] = tswapl(env->active_tc.HI[0]);
67251e52606SNathan Froyd     (*regs)[TARGET_EF_CP0_EPC] = tswapl(env->active_tc.PC);
67351e52606SNathan Froyd     (*regs)[TARGET_EF_CP0_BADVADDR] = tswapl(env->CP0_BadVAddr);
67451e52606SNathan Froyd     (*regs)[TARGET_EF_CP0_STATUS] = tswapl(env->CP0_Status);
67551e52606SNathan Froyd     (*regs)[TARGET_EF_CP0_CAUSE] = tswapl(env->CP0_Cause);
67651e52606SNathan Froyd }
67751e52606SNathan Froyd 
67851e52606SNathan Froyd #define USE_ELF_CORE_DUMP
679388bb21aSths #define ELF_EXEC_PAGESIZE        4096
680388bb21aSths 
681048f6b4dSbellard #endif /* TARGET_MIPS */
682048f6b4dSbellard 
683b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
684b779e29eSEdgar E. Iglesias 
685b779e29eSEdgar E. Iglesias #define ELF_START_MMAP 0x80000000
686b779e29eSEdgar E. Iglesias 
6870d5d4699SEdgar E. Iglesias #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
688b779e29eSEdgar E. Iglesias 
689b779e29eSEdgar E. Iglesias #define ELF_CLASS   ELFCLASS32
6900d5d4699SEdgar E. Iglesias #define ELF_ARCH    EM_MICROBLAZE
691b779e29eSEdgar E. Iglesias 
692d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
693d97ef72eSRichard Henderson                                struct image_info *infop)
694b779e29eSEdgar E. Iglesias {
695b779e29eSEdgar E. Iglesias     regs->pc = infop->entry;
696b779e29eSEdgar E. Iglesias     regs->r1 = infop->start_stack;
697b779e29eSEdgar E. Iglesias 
698b779e29eSEdgar E. Iglesias }
699b779e29eSEdgar E. Iglesias 
700b779e29eSEdgar E. Iglesias #define ELF_EXEC_PAGESIZE        4096
701b779e29eSEdgar E. Iglesias 
702e4cbd44dSEdgar E. Iglesias #define USE_ELF_CORE_DUMP
703e4cbd44dSEdgar E. Iglesias #define ELF_NREG 38
704e4cbd44dSEdgar E. Iglesias typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
705e4cbd44dSEdgar E. Iglesias 
706e4cbd44dSEdgar E. Iglesias /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
707e4cbd44dSEdgar E. Iglesias static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
708e4cbd44dSEdgar E. Iglesias {
709e4cbd44dSEdgar E. Iglesias     int i, pos = 0;
710e4cbd44dSEdgar E. Iglesias 
711e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 32; i++) {
712e4cbd44dSEdgar E. Iglesias         (*regs)[pos++] = tswapl(env->regs[i]);
713e4cbd44dSEdgar E. Iglesias     }
714e4cbd44dSEdgar E. Iglesias 
715e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 6; i++) {
716e4cbd44dSEdgar E. Iglesias         (*regs)[pos++] = tswapl(env->sregs[i]);
717e4cbd44dSEdgar E. Iglesias     }
718e4cbd44dSEdgar E. Iglesias }
719e4cbd44dSEdgar E. Iglesias 
720b779e29eSEdgar E. Iglesias #endif /* TARGET_MICROBLAZE */
721b779e29eSEdgar E. Iglesias 
722fdf9b3e8Sbellard #ifdef TARGET_SH4
723fdf9b3e8Sbellard 
724fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000
725fdf9b3e8Sbellard 
726fdf9b3e8Sbellard #define elf_check_arch(x) ( (x) == EM_SH )
727fdf9b3e8Sbellard 
728fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
729fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
730fdf9b3e8Sbellard 
731d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
732d97ef72eSRichard Henderson                                struct image_info *infop)
733fdf9b3e8Sbellard {
734fdf9b3e8Sbellard     /* Check other registers XXXXX */
735fdf9b3e8Sbellard     regs->pc = infop->entry;
736072ae847Sths     regs->regs[15] = infop->start_stack;
737fdf9b3e8Sbellard }
738fdf9b3e8Sbellard 
7397631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/elf.h.  */
7407631c97eSNathan Froyd #define ELF_NREG 23
7417631c97eSNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
7427631c97eSNathan Froyd 
7437631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/ptrace.h.  */
7447631c97eSNathan Froyd enum {
7457631c97eSNathan Froyd     TARGET_REG_PC = 16,
7467631c97eSNathan Froyd     TARGET_REG_PR = 17,
7477631c97eSNathan Froyd     TARGET_REG_SR = 18,
7487631c97eSNathan Froyd     TARGET_REG_GBR = 19,
7497631c97eSNathan Froyd     TARGET_REG_MACH = 20,
7507631c97eSNathan Froyd     TARGET_REG_MACL = 21,
7517631c97eSNathan Froyd     TARGET_REG_SYSCALL = 22
7527631c97eSNathan Froyd };
7537631c97eSNathan Froyd 
754d97ef72eSRichard Henderson static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
755d97ef72eSRichard Henderson                                       const CPUState *env)
7567631c97eSNathan Froyd {
7577631c97eSNathan Froyd     int i;
7587631c97eSNathan Froyd 
7597631c97eSNathan Froyd     for (i = 0; i < 16; i++) {
7607631c97eSNathan Froyd         (*regs[i]) = tswapl(env->gregs[i]);
7617631c97eSNathan Froyd     }
7627631c97eSNathan Froyd 
7637631c97eSNathan Froyd     (*regs)[TARGET_REG_PC] = tswapl(env->pc);
7647631c97eSNathan Froyd     (*regs)[TARGET_REG_PR] = tswapl(env->pr);
7657631c97eSNathan Froyd     (*regs)[TARGET_REG_SR] = tswapl(env->sr);
7667631c97eSNathan Froyd     (*regs)[TARGET_REG_GBR] = tswapl(env->gbr);
7677631c97eSNathan Froyd     (*regs)[TARGET_REG_MACH] = tswapl(env->mach);
7687631c97eSNathan Froyd     (*regs)[TARGET_REG_MACL] = tswapl(env->macl);
7697631c97eSNathan Froyd     (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
7707631c97eSNathan Froyd }
7717631c97eSNathan Froyd 
7727631c97eSNathan Froyd #define USE_ELF_CORE_DUMP
773fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
774fdf9b3e8Sbellard 
775fdf9b3e8Sbellard #endif
776fdf9b3e8Sbellard 
77748733d19Sths #ifdef TARGET_CRIS
77848733d19Sths 
77948733d19Sths #define ELF_START_MMAP 0x80000000
78048733d19Sths 
78148733d19Sths #define elf_check_arch(x) ( (x) == EM_CRIS )
78248733d19Sths 
78348733d19Sths #define ELF_CLASS ELFCLASS32
78448733d19Sths #define ELF_ARCH  EM_CRIS
78548733d19Sths 
786d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
787d97ef72eSRichard Henderson                                struct image_info *infop)
78848733d19Sths {
78948733d19Sths     regs->erp = infop->entry;
79048733d19Sths }
79148733d19Sths 
79248733d19Sths #define ELF_EXEC_PAGESIZE        8192
79348733d19Sths 
79448733d19Sths #endif
79548733d19Sths 
796e6e5906bSpbrook #ifdef TARGET_M68K
797e6e5906bSpbrook 
798e6e5906bSpbrook #define ELF_START_MMAP 0x80000000
799e6e5906bSpbrook 
800e6e5906bSpbrook #define elf_check_arch(x) ( (x) == EM_68K )
801e6e5906bSpbrook 
802e6e5906bSpbrook #define ELF_CLASS       ELFCLASS32
803e6e5906bSpbrook #define ELF_ARCH        EM_68K
804e6e5906bSpbrook 
805e6e5906bSpbrook /* ??? Does this need to do anything?
806e6e5906bSpbrook    #define ELF_PLAT_INIT(_r) */
807e6e5906bSpbrook 
808d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
809d97ef72eSRichard Henderson                                struct image_info *infop)
810e6e5906bSpbrook {
811e6e5906bSpbrook     regs->usp = infop->start_stack;
812e6e5906bSpbrook     regs->sr = 0;
813e6e5906bSpbrook     regs->pc = infop->entry;
814e6e5906bSpbrook }
815e6e5906bSpbrook 
8167a93cc55SNathan Froyd /* See linux kernel: arch/m68k/include/asm/elf.h.  */
8177a93cc55SNathan Froyd #define ELF_NREG 20
8187a93cc55SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
8197a93cc55SNathan Froyd 
8207a93cc55SNathan Froyd static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
8217a93cc55SNathan Froyd {
8227a93cc55SNathan Froyd     (*regs)[0] = tswapl(env->dregs[1]);
8237a93cc55SNathan Froyd     (*regs)[1] = tswapl(env->dregs[2]);
8247a93cc55SNathan Froyd     (*regs)[2] = tswapl(env->dregs[3]);
8257a93cc55SNathan Froyd     (*regs)[3] = tswapl(env->dregs[4]);
8267a93cc55SNathan Froyd     (*regs)[4] = tswapl(env->dregs[5]);
8277a93cc55SNathan Froyd     (*regs)[5] = tswapl(env->dregs[6]);
8287a93cc55SNathan Froyd     (*regs)[6] = tswapl(env->dregs[7]);
8297a93cc55SNathan Froyd     (*regs)[7] = tswapl(env->aregs[0]);
8307a93cc55SNathan Froyd     (*regs)[8] = tswapl(env->aregs[1]);
8317a93cc55SNathan Froyd     (*regs)[9] = tswapl(env->aregs[2]);
8327a93cc55SNathan Froyd     (*regs)[10] = tswapl(env->aregs[3]);
8337a93cc55SNathan Froyd     (*regs)[11] = tswapl(env->aregs[4]);
8347a93cc55SNathan Froyd     (*regs)[12] = tswapl(env->aregs[5]);
8357a93cc55SNathan Froyd     (*regs)[13] = tswapl(env->aregs[6]);
8367a93cc55SNathan Froyd     (*regs)[14] = tswapl(env->dregs[0]);
8377a93cc55SNathan Froyd     (*regs)[15] = tswapl(env->aregs[7]);
8387a93cc55SNathan Froyd     (*regs)[16] = tswapl(env->dregs[0]); /* FIXME: orig_d0 */
8397a93cc55SNathan Froyd     (*regs)[17] = tswapl(env->sr);
8407a93cc55SNathan Froyd     (*regs)[18] = tswapl(env->pc);
8417a93cc55SNathan Froyd     (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
8427a93cc55SNathan Froyd }
8437a93cc55SNathan Froyd 
8447a93cc55SNathan Froyd #define USE_ELF_CORE_DUMP
845e6e5906bSpbrook #define ELF_EXEC_PAGESIZE       8192
846e6e5906bSpbrook 
847e6e5906bSpbrook #endif
848e6e5906bSpbrook 
8497a3148a9Sj_mayer #ifdef TARGET_ALPHA
8507a3148a9Sj_mayer 
8517a3148a9Sj_mayer #define ELF_START_MMAP (0x30000000000ULL)
8527a3148a9Sj_mayer 
8537a3148a9Sj_mayer #define elf_check_arch(x) ( (x) == ELF_ARCH )
8547a3148a9Sj_mayer 
8557a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
8567a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
8577a3148a9Sj_mayer 
858d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
859d97ef72eSRichard Henderson                                struct image_info *infop)
8607a3148a9Sj_mayer {
8617a3148a9Sj_mayer     regs->pc = infop->entry;
8627a3148a9Sj_mayer     regs->ps = 8;
8637a3148a9Sj_mayer     regs->usp = infop->start_stack;
8647a3148a9Sj_mayer }
8657a3148a9Sj_mayer 
8667a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
8677a3148a9Sj_mayer 
8687a3148a9Sj_mayer #endif /* TARGET_ALPHA */
8697a3148a9Sj_mayer 
870a4c075f1SUlrich Hecht #ifdef TARGET_S390X
871a4c075f1SUlrich Hecht 
872a4c075f1SUlrich Hecht #define ELF_START_MMAP (0x20000000000ULL)
873a4c075f1SUlrich Hecht 
874a4c075f1SUlrich Hecht #define elf_check_arch(x) ( (x) == ELF_ARCH )
875a4c075f1SUlrich Hecht 
876a4c075f1SUlrich Hecht #define ELF_CLASS	ELFCLASS64
877a4c075f1SUlrich Hecht #define ELF_DATA	ELFDATA2MSB
878a4c075f1SUlrich Hecht #define ELF_ARCH	EM_S390
879a4c075f1SUlrich Hecht 
880a4c075f1SUlrich Hecht static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
881a4c075f1SUlrich Hecht {
882a4c075f1SUlrich Hecht     regs->psw.addr = infop->entry;
883a4c075f1SUlrich Hecht     regs->psw.mask = PSW_MASK_64 | PSW_MASK_32;
884a4c075f1SUlrich Hecht     regs->gprs[15] = infop->start_stack;
885a4c075f1SUlrich Hecht }
886a4c075f1SUlrich Hecht 
887a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
888a4c075f1SUlrich Hecht 
88915338fd7Sbellard #ifndef ELF_PLATFORM
89015338fd7Sbellard #define ELF_PLATFORM (NULL)
89115338fd7Sbellard #endif
89215338fd7Sbellard 
89315338fd7Sbellard #ifndef ELF_HWCAP
89415338fd7Sbellard #define ELF_HWCAP 0
89515338fd7Sbellard #endif
89615338fd7Sbellard 
897992f48a0Sblueswir1 #ifdef TARGET_ABI32
898cb33da57Sblueswir1 #undef ELF_CLASS
899992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
900cb33da57Sblueswir1 #undef bswaptls
901cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
902cb33da57Sblueswir1 #endif
903cb33da57Sblueswir1 
90431e31b8aSbellard #include "elf.h"
90509bfb054Sbellard 
90609bfb054Sbellard struct exec
90709bfb054Sbellard {
90809bfb054Sbellard     unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
90909bfb054Sbellard     unsigned int a_text;   /* length of text, in bytes */
91009bfb054Sbellard     unsigned int a_data;   /* length of data, in bytes */
91109bfb054Sbellard     unsigned int a_bss;    /* length of uninitialized data area, in bytes */
91209bfb054Sbellard     unsigned int a_syms;   /* length of symbol table data in file, in bytes */
91309bfb054Sbellard     unsigned int a_entry;  /* start address */
91409bfb054Sbellard     unsigned int a_trsize; /* length of relocation info for text, in bytes */
91509bfb054Sbellard     unsigned int a_drsize; /* length of relocation info for data, in bytes */
91609bfb054Sbellard };
91709bfb054Sbellard 
91809bfb054Sbellard 
91909bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
92009bfb054Sbellard #define OMAGIC 0407
92109bfb054Sbellard #define NMAGIC 0410
92209bfb054Sbellard #define ZMAGIC 0413
92309bfb054Sbellard #define QMAGIC 0314
92409bfb054Sbellard 
92531e31b8aSbellard /* Necessary parameters */
92654936004Sbellard #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
92754936004Sbellard #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
92854936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
92931e31b8aSbellard 
930*14322badSLaurent ALFONSI #define DLINFO_ITEMS 13
93131e31b8aSbellard 
93209bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
93309bfb054Sbellard {
93409bfb054Sbellard     memcpy(to, from, n);
93509bfb054Sbellard }
93609bfb054Sbellard 
93731e31b8aSbellard #ifdef BSWAP_NEEDED
93892a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
93931e31b8aSbellard {
94031e31b8aSbellard     bswap16s(&ehdr->e_type);            /* Object file type */
94131e31b8aSbellard     bswap16s(&ehdr->e_machine);         /* Architecture */
94231e31b8aSbellard     bswap32s(&ehdr->e_version);         /* Object file version */
94392a31b1fSbellard     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
94492a31b1fSbellard     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
94592a31b1fSbellard     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
94631e31b8aSbellard     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
94731e31b8aSbellard     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
94831e31b8aSbellard     bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
94931e31b8aSbellard     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
95031e31b8aSbellard     bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
95131e31b8aSbellard     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
95231e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
95331e31b8aSbellard }
95431e31b8aSbellard 
955991f8f0cSRichard Henderson static void bswap_phdr(struct elf_phdr *phdr, int phnum)
95631e31b8aSbellard {
957991f8f0cSRichard Henderson     int i;
958991f8f0cSRichard Henderson     for (i = 0; i < phnum; ++i, ++phdr) {
95931e31b8aSbellard         bswap32s(&phdr->p_type);        /* Segment type */
960991f8f0cSRichard Henderson         bswap32s(&phdr->p_flags);       /* Segment flags */
96192a31b1fSbellard         bswaptls(&phdr->p_offset);      /* Segment file offset */
96292a31b1fSbellard         bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
96392a31b1fSbellard         bswaptls(&phdr->p_paddr);       /* Segment physical address */
96492a31b1fSbellard         bswaptls(&phdr->p_filesz);      /* Segment size in file */
96592a31b1fSbellard         bswaptls(&phdr->p_memsz);       /* Segment size in memory */
96692a31b1fSbellard         bswaptls(&phdr->p_align);       /* Segment alignment */
96731e31b8aSbellard     }
968991f8f0cSRichard Henderson }
969689f936fSbellard 
970991f8f0cSRichard Henderson static void bswap_shdr(struct elf_shdr *shdr, int shnum)
971689f936fSbellard {
972991f8f0cSRichard Henderson     int i;
973991f8f0cSRichard Henderson     for (i = 0; i < shnum; ++i, ++shdr) {
974689f936fSbellard         bswap32s(&shdr->sh_name);
975689f936fSbellard         bswap32s(&shdr->sh_type);
97692a31b1fSbellard         bswaptls(&shdr->sh_flags);
97792a31b1fSbellard         bswaptls(&shdr->sh_addr);
97892a31b1fSbellard         bswaptls(&shdr->sh_offset);
97992a31b1fSbellard         bswaptls(&shdr->sh_size);
980689f936fSbellard         bswap32s(&shdr->sh_link);
981689f936fSbellard         bswap32s(&shdr->sh_info);
98292a31b1fSbellard         bswaptls(&shdr->sh_addralign);
98392a31b1fSbellard         bswaptls(&shdr->sh_entsize);
984689f936fSbellard     }
985991f8f0cSRichard Henderson }
986689f936fSbellard 
9877a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
988689f936fSbellard {
989689f936fSbellard     bswap32s(&sym->st_name);
9907a3148a9Sj_mayer     bswaptls(&sym->st_value);
9917a3148a9Sj_mayer     bswaptls(&sym->st_size);
992689f936fSbellard     bswap16s(&sym->st_shndx);
993689f936fSbellard }
994991f8f0cSRichard Henderson #else
995991f8f0cSRichard Henderson static inline void bswap_ehdr(struct elfhdr *ehdr) { }
996991f8f0cSRichard Henderson static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
997991f8f0cSRichard Henderson static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
998991f8f0cSRichard Henderson static inline void bswap_sym(struct elf_sym *sym) { }
99931e31b8aSbellard #endif
100031e31b8aSbellard 
1001edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
1002edf8e2afSMika Westerberg static int elf_core_dump(int, const CPUState *);
1003edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
1004682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
1005edf8e2afSMika Westerberg 
10069058abddSRichard Henderson /* Verify the portions of EHDR within E_IDENT for the target.
10079058abddSRichard Henderson    This can be performed before bswapping the entire header.  */
10089058abddSRichard Henderson static bool elf_check_ident(struct elfhdr *ehdr)
10099058abddSRichard Henderson {
10109058abddSRichard Henderson     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
10119058abddSRichard Henderson             && ehdr->e_ident[EI_MAG1] == ELFMAG1
10129058abddSRichard Henderson             && ehdr->e_ident[EI_MAG2] == ELFMAG2
10139058abddSRichard Henderson             && ehdr->e_ident[EI_MAG3] == ELFMAG3
10149058abddSRichard Henderson             && ehdr->e_ident[EI_CLASS] == ELF_CLASS
10159058abddSRichard Henderson             && ehdr->e_ident[EI_DATA] == ELF_DATA
10169058abddSRichard Henderson             && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
10179058abddSRichard Henderson }
10189058abddSRichard Henderson 
10199058abddSRichard Henderson /* Verify the portions of EHDR outside of E_IDENT for the target.
10209058abddSRichard Henderson    This has to wait until after bswapping the header.  */
10219058abddSRichard Henderson static bool elf_check_ehdr(struct elfhdr *ehdr)
10229058abddSRichard Henderson {
10239058abddSRichard Henderson     return (elf_check_arch(ehdr->e_machine)
10249058abddSRichard Henderson             && ehdr->e_ehsize == sizeof(struct elfhdr)
10259058abddSRichard Henderson             && ehdr->e_phentsize == sizeof(struct elf_phdr)
10269058abddSRichard Henderson             && ehdr->e_shentsize == sizeof(struct elf_shdr)
10279058abddSRichard Henderson             && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
10289058abddSRichard Henderson }
10299058abddSRichard Henderson 
103031e31b8aSbellard /*
1031e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
103231e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
103331e31b8aSbellard  * to be put directly into the top of new user memory.
103431e31b8aSbellard  *
103531e31b8aSbellard  */
1036992f48a0Sblueswir1 static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
1037992f48a0Sblueswir1                                   abi_ulong p)
103831e31b8aSbellard {
103931e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
104031e31b8aSbellard     int len, offset = 0;
104131e31b8aSbellard 
104231e31b8aSbellard     if (!p) {
104331e31b8aSbellard         return 0;       /* bullet-proofing */
104431e31b8aSbellard     }
104531e31b8aSbellard     while (argc-- > 0) {
1046edf779ffSbellard         tmp = argv[argc];
1047edf779ffSbellard         if (!tmp) {
104831e31b8aSbellard             fprintf(stderr, "VFS: argc is wrong");
104931e31b8aSbellard             exit(-1);
105031e31b8aSbellard         }
1051edf779ffSbellard         tmp1 = tmp;
1052edf779ffSbellard         while (*tmp++);
105331e31b8aSbellard         len = tmp - tmp1;
105431e31b8aSbellard         if (p < len) {  /* this shouldn't happen - 128kB */
105531e31b8aSbellard             return 0;
105631e31b8aSbellard         }
105731e31b8aSbellard         while (len) {
105831e31b8aSbellard             --p; --tmp; --len;
105931e31b8aSbellard             if (--offset < 0) {
106054936004Sbellard                 offset = p % TARGET_PAGE_SIZE;
106144a91caeSbellard                 pag = (char *)page[p/TARGET_PAGE_SIZE];
106244a91caeSbellard                 if (!pag) {
106353a5960aSpbrook                     pag = (char *)malloc(TARGET_PAGE_SIZE);
10644118a970Sj_mayer                     memset(pag, 0, TARGET_PAGE_SIZE);
106553a5960aSpbrook                     page[p/TARGET_PAGE_SIZE] = pag;
106644a91caeSbellard                     if (!pag)
106731e31b8aSbellard                         return 0;
106831e31b8aSbellard                 }
106931e31b8aSbellard             }
107031e31b8aSbellard             if (len == 0 || offset == 0) {
1071edf779ffSbellard                 *(pag + offset) = *tmp;
107231e31b8aSbellard             }
107331e31b8aSbellard             else {
107431e31b8aSbellard                 int bytes_to_copy = (len > offset) ? offset : len;
107531e31b8aSbellard                 tmp -= bytes_to_copy;
107631e31b8aSbellard                 p -= bytes_to_copy;
107731e31b8aSbellard                 offset -= bytes_to_copy;
107831e31b8aSbellard                 len -= bytes_to_copy;
107931e31b8aSbellard                 memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
108031e31b8aSbellard             }
108131e31b8aSbellard         }
108231e31b8aSbellard     }
108331e31b8aSbellard     return p;
108431e31b8aSbellard }
108531e31b8aSbellard 
1086992f48a0Sblueswir1 static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
108731e31b8aSbellard                                  struct image_info *info)
108831e31b8aSbellard {
108960dcbcb5SRichard Henderson     abi_ulong stack_base, size, error, guard;
109031e31b8aSbellard     int i;
109131e31b8aSbellard 
109231e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
109360dcbcb5SRichard Henderson        it for args, we'll use it for something else.  */
1094703e0e89SRichard Henderson     size = guest_stack_size;
109560dcbcb5SRichard Henderson     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) {
109654936004Sbellard         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
109760dcbcb5SRichard Henderson     }
109860dcbcb5SRichard Henderson     guard = TARGET_PAGE_SIZE;
109960dcbcb5SRichard Henderson     if (guard < qemu_real_host_page_size) {
110060dcbcb5SRichard Henderson         guard = qemu_real_host_page_size;
110160dcbcb5SRichard Henderson     }
110260dcbcb5SRichard Henderson 
110360dcbcb5SRichard Henderson     error = target_mmap(0, size + guard, PROT_READ | PROT_WRITE,
110460dcbcb5SRichard Henderson                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
110509bfb054Sbellard     if (error == -1) {
110660dcbcb5SRichard Henderson         perror("mmap stack");
110731e31b8aSbellard         exit(-1);
110831e31b8aSbellard     }
110931e31b8aSbellard 
111060dcbcb5SRichard Henderson     /* We reserve one extra page at the top of the stack as guard.  */
111160dcbcb5SRichard Henderson     target_mprotect(error, guard, PROT_NONE);
111260dcbcb5SRichard Henderson 
111360dcbcb5SRichard Henderson     info->stack_limit = error + guard;
111460dcbcb5SRichard Henderson     stack_base = info->stack_limit + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
111509bfb054Sbellard     p += stack_base;
111609bfb054Sbellard 
111731e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
111831e31b8aSbellard         if (bprm->page[i]) {
111931e31b8aSbellard             info->rss++;
1120579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
112153a5960aSpbrook             memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
112253a5960aSpbrook             free(bprm->page[i]);
112331e31b8aSbellard         }
112454936004Sbellard         stack_base += TARGET_PAGE_SIZE;
112531e31b8aSbellard     }
112631e31b8aSbellard     return p;
112731e31b8aSbellard }
112831e31b8aSbellard 
1129cf129f3aSRichard Henderson /* Map and zero the bss.  We need to explicitly zero any fractional pages
1130cf129f3aSRichard Henderson    after the data section (i.e. bss).  */
1131cf129f3aSRichard Henderson static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
113231e31b8aSbellard {
1133cf129f3aSRichard Henderson     uintptr_t host_start, host_map_start, host_end;
1134cf129f3aSRichard Henderson 
1135cf129f3aSRichard Henderson     last_bss = TARGET_PAGE_ALIGN(last_bss);
1136cf129f3aSRichard Henderson 
1137cf129f3aSRichard Henderson     /* ??? There is confusion between qemu_real_host_page_size and
1138cf129f3aSRichard Henderson        qemu_host_page_size here and elsewhere in target_mmap, which
1139cf129f3aSRichard Henderson        may lead to the end of the data section mapping from the file
1140cf129f3aSRichard Henderson        not being mapped.  At least there was an explicit test and
1141cf129f3aSRichard Henderson        comment for that here, suggesting that "the file size must
1142cf129f3aSRichard Henderson        be known".  The comment probably pre-dates the introduction
1143cf129f3aSRichard Henderson        of the fstat system call in target_mmap which does in fact
1144cf129f3aSRichard Henderson        find out the size.  What isn't clear is if the workaround
1145cf129f3aSRichard Henderson        here is still actually needed.  For now, continue with it,
1146cf129f3aSRichard Henderson        but merge it with the "normal" mmap that would allocate the bss.  */
1147cf129f3aSRichard Henderson 
1148cf129f3aSRichard Henderson     host_start = (uintptr_t) g2h(elf_bss);
1149cf129f3aSRichard Henderson     host_end = (uintptr_t) g2h(last_bss);
1150cf129f3aSRichard Henderson     host_map_start = (host_start + qemu_real_host_page_size - 1);
1151cf129f3aSRichard Henderson     host_map_start &= -qemu_real_host_page_size;
1152cf129f3aSRichard Henderson 
1153cf129f3aSRichard Henderson     if (host_map_start < host_end) {
1154cf129f3aSRichard Henderson         void *p = mmap((void *)host_map_start, host_end - host_map_start,
1155cf129f3aSRichard Henderson                        prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1156cf129f3aSRichard Henderson         if (p == MAP_FAILED) {
115731e31b8aSbellard             perror("cannot mmap brk");
115831e31b8aSbellard             exit(-1);
115931e31b8aSbellard         }
1160cf129f3aSRichard Henderson 
1161cf129f3aSRichard Henderson         /* Since we didn't use target_mmap, make sure to record
1162cf129f3aSRichard Henderson            the validity of the pages with qemu.  */
1163cf129f3aSRichard Henderson         page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot|PAGE_VALID);
116431e31b8aSbellard     }
116531e31b8aSbellard 
1166cf129f3aSRichard Henderson     if (host_start < host_map_start) {
1167cf129f3aSRichard Henderson         memset((void *)host_start, 0, host_map_start - host_start);
1168853d6f7aSbellard     }
1169853d6f7aSbellard }
1170853d6f7aSbellard 
11711af02e83SMike Frysinger #ifdef CONFIG_USE_FDPIC
11721af02e83SMike Frysinger static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
11731af02e83SMike Frysinger {
11741af02e83SMike Frysinger     uint16_t n;
11751af02e83SMike Frysinger     struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
11761af02e83SMike Frysinger 
11771af02e83SMike Frysinger     /* elf32_fdpic_loadseg */
11781af02e83SMike Frysinger     n = info->nsegs;
11791af02e83SMike Frysinger     while (n--) {
11801af02e83SMike Frysinger         sp -= 12;
11811af02e83SMike Frysinger         put_user_u32(loadsegs[n].addr, sp+0);
11821af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_vaddr, sp+4);
11831af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_memsz, sp+8);
11841af02e83SMike Frysinger     }
11851af02e83SMike Frysinger 
11861af02e83SMike Frysinger     /* elf32_fdpic_loadmap */
11871af02e83SMike Frysinger     sp -= 4;
11881af02e83SMike Frysinger     put_user_u16(0, sp+0); /* version */
11891af02e83SMike Frysinger     put_user_u16(info->nsegs, sp+2); /* nsegs */
11901af02e83SMike Frysinger 
11911af02e83SMike Frysinger     info->personality = PER_LINUX_FDPIC;
11921af02e83SMike Frysinger     info->loadmap_addr = sp;
11931af02e83SMike Frysinger 
11941af02e83SMike Frysinger     return sp;
11951af02e83SMike Frysinger }
11961af02e83SMike Frysinger #endif
11971af02e83SMike Frysinger 
1198992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
119931e31b8aSbellard                                    struct elfhdr *exec,
12008e62a717SRichard Henderson                                    struct image_info *info,
12018e62a717SRichard Henderson                                    struct image_info *interp_info)
120231e31b8aSbellard {
1203992f48a0Sblueswir1     abi_ulong sp;
120453a5960aSpbrook     int size;
1205*14322badSLaurent ALFONSI     int i;
1206*14322badSLaurent ALFONSI     abi_ulong u_rand_bytes;
1207*14322badSLaurent ALFONSI     uint8_t k_rand_bytes[16];
1208992f48a0Sblueswir1     abi_ulong u_platform;
120915338fd7Sbellard     const char *k_platform;
1210863cf0b7Sj_mayer     const int n = sizeof(elf_addr_t);
121131e31b8aSbellard 
121253a5960aSpbrook     sp = p;
12131af02e83SMike Frysinger 
12141af02e83SMike Frysinger #ifdef CONFIG_USE_FDPIC
12151af02e83SMike Frysinger     /* Needs to be before we load the env/argc/... */
12161af02e83SMike Frysinger     if (elf_is_fdpic(exec)) {
12171af02e83SMike Frysinger         /* Need 4 byte alignment for these structs */
12181af02e83SMike Frysinger         sp &= ~3;
12191af02e83SMike Frysinger         sp = loader_build_fdpic_loadmap(info, sp);
12201af02e83SMike Frysinger         info->other_info = interp_info;
12211af02e83SMike Frysinger         if (interp_info) {
12221af02e83SMike Frysinger             interp_info->other_info = info;
12231af02e83SMike Frysinger             sp = loader_build_fdpic_loadmap(interp_info, sp);
12241af02e83SMike Frysinger         }
12251af02e83SMike Frysinger     }
12261af02e83SMike Frysinger #endif
12271af02e83SMike Frysinger 
122853a5960aSpbrook     u_platform = 0;
122915338fd7Sbellard     k_platform = ELF_PLATFORM;
123015338fd7Sbellard     if (k_platform) {
123115338fd7Sbellard         size_t len = strlen(k_platform) + 1;
123253a5960aSpbrook         sp -= (len + n - 1) & ~(n - 1);
123353a5960aSpbrook         u_platform = sp;
1234579a97f7Sbellard         /* FIXME - check return value of memcpy_to_target() for failure */
123553a5960aSpbrook         memcpy_to_target(sp, k_platform, len);
123615338fd7Sbellard     }
1237*14322badSLaurent ALFONSI 
1238*14322badSLaurent ALFONSI     /*
1239*14322badSLaurent ALFONSI      * Generate 16 random bytes for userspace PRNG seeding (not
1240*14322badSLaurent ALFONSI      * cryptically secure but it's not the aim of QEMU).
1241*14322badSLaurent ALFONSI      */
1242*14322badSLaurent ALFONSI     srand((unsigned int) time(NULL));
1243*14322badSLaurent ALFONSI     for (i = 0; i < 16; i++) {
1244*14322badSLaurent ALFONSI         k_rand_bytes[i] = rand();
1245*14322badSLaurent ALFONSI     }
1246*14322badSLaurent ALFONSI     sp -= 16;
1247*14322badSLaurent ALFONSI     u_rand_bytes = sp;
1248*14322badSLaurent ALFONSI     /* FIXME - check return value of memcpy_to_target() for failure */
1249*14322badSLaurent ALFONSI     memcpy_to_target(sp, k_rand_bytes, 16);
1250*14322badSLaurent ALFONSI 
125153a5960aSpbrook     /*
125253a5960aSpbrook      * Force 16 byte _final_ alignment here for generality.
125353a5960aSpbrook      */
1254992f48a0Sblueswir1     sp = sp &~ (abi_ulong)15;
125553a5960aSpbrook     size = (DLINFO_ITEMS + 1) * 2;
125615338fd7Sbellard     if (k_platform)
125753a5960aSpbrook         size += 2;
1258f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
125953a5960aSpbrook     size += DLINFO_ARCH_ITEMS * 2;
1260f5155289Sbellard #endif
126153a5960aSpbrook     size += envc + argc + 2;
1262b9329d4bSRichard Henderson     size += 1;  /* argc itself */
126353a5960aSpbrook     size *= n;
126453a5960aSpbrook     if (size & 15)
126553a5960aSpbrook         sp -= 16 - (size & 15);
1266f5155289Sbellard 
1267863cf0b7Sj_mayer     /* This is correct because Linux defines
1268863cf0b7Sj_mayer      * elf_addr_t as Elf32_Off / Elf64_Off
1269863cf0b7Sj_mayer      */
127053a5960aSpbrook #define NEW_AUX_ENT(id, val) do {               \
12712f619698Sbellard         sp -= n; put_user_ual(val, sp);         \
12722f619698Sbellard         sp -= n; put_user_ual(id, sp);          \
127353a5960aSpbrook     } while(0)
12742f619698Sbellard 
12750bccf03dSbellard     NEW_AUX_ENT (AT_NULL, 0);
1276f5155289Sbellard 
12770bccf03dSbellard     /* There must be exactly DLINFO_ITEMS entries here.  */
12788e62a717SRichard Henderson     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
1279992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
1280992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
1281992f48a0Sblueswir1     NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
12828e62a717SRichard Henderson     NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
1283992f48a0Sblueswir1     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
12848e62a717SRichard Henderson     NEW_AUX_ENT(AT_ENTRY, info->entry);
1285992f48a0Sblueswir1     NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
1286992f48a0Sblueswir1     NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
1287992f48a0Sblueswir1     NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
1288992f48a0Sblueswir1     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
1289992f48a0Sblueswir1     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
1290a07c67dfSpbrook     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
1291*14322badSLaurent ALFONSI     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
1292*14322badSLaurent ALFONSI 
129315338fd7Sbellard     if (k_platform)
129453a5960aSpbrook         NEW_AUX_ENT(AT_PLATFORM, u_platform);
1295f5155289Sbellard #ifdef ARCH_DLINFO
1296f5155289Sbellard     /*
1297f5155289Sbellard      * ARCH_DLINFO must come last so platform specific code can enforce
1298f5155289Sbellard      * special alignment requirements on the AUXV if necessary (eg. PPC).
1299f5155289Sbellard      */
1300f5155289Sbellard     ARCH_DLINFO;
1301f5155289Sbellard #endif
1302f5155289Sbellard #undef NEW_AUX_ENT
1303f5155289Sbellard 
1304edf8e2afSMika Westerberg     info->saved_auxv = sp;
1305edf8e2afSMika Westerberg 
1306b9329d4bSRichard Henderson     sp = loader_build_argptr(envc, argc, sp, p, 0);
130731e31b8aSbellard     return sp;
130831e31b8aSbellard }
130931e31b8aSbellard 
1310f3ed1f5dSPeter Maydell static void probe_guest_base(const char *image_name,
1311f3ed1f5dSPeter Maydell                              abi_ulong loaddr, abi_ulong hiaddr)
1312f3ed1f5dSPeter Maydell {
1313f3ed1f5dSPeter Maydell     /* Probe for a suitable guest base address, if the user has not set
1314f3ed1f5dSPeter Maydell      * it explicitly, and set guest_base appropriately.
1315f3ed1f5dSPeter Maydell      * In case of error we will print a suitable message and exit.
1316f3ed1f5dSPeter Maydell      */
1317f3ed1f5dSPeter Maydell #if defined(CONFIG_USE_GUEST_BASE)
1318f3ed1f5dSPeter Maydell     const char *errmsg;
1319f3ed1f5dSPeter Maydell     if (!have_guest_base && !reserved_va) {
1320f3ed1f5dSPeter Maydell         unsigned long host_start, real_start, host_size;
1321f3ed1f5dSPeter Maydell 
1322f3ed1f5dSPeter Maydell         /* Round addresses to page boundaries.  */
1323f3ed1f5dSPeter Maydell         loaddr &= qemu_host_page_mask;
1324f3ed1f5dSPeter Maydell         hiaddr = HOST_PAGE_ALIGN(hiaddr);
1325f3ed1f5dSPeter Maydell 
1326f3ed1f5dSPeter Maydell         if (loaddr < mmap_min_addr) {
1327f3ed1f5dSPeter Maydell             host_start = HOST_PAGE_ALIGN(mmap_min_addr);
1328f3ed1f5dSPeter Maydell         } else {
1329f3ed1f5dSPeter Maydell             host_start = loaddr;
1330f3ed1f5dSPeter Maydell             if (host_start != loaddr) {
1331f3ed1f5dSPeter Maydell                 errmsg = "Address overflow loading ELF binary";
1332f3ed1f5dSPeter Maydell                 goto exit_errmsg;
1333f3ed1f5dSPeter Maydell             }
1334f3ed1f5dSPeter Maydell         }
1335f3ed1f5dSPeter Maydell         host_size = hiaddr - loaddr;
1336f3ed1f5dSPeter Maydell         while (1) {
1337f3ed1f5dSPeter Maydell             /* Do not use mmap_find_vma here because that is limited to the
1338f3ed1f5dSPeter Maydell                guest address space.  We are going to make the
1339f3ed1f5dSPeter Maydell                guest address space fit whatever we're given.  */
1340f3ed1f5dSPeter Maydell             real_start = (unsigned long)
1341f3ed1f5dSPeter Maydell                 mmap((void *)host_start, host_size, PROT_NONE,
1342f3ed1f5dSPeter Maydell                      MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
1343f3ed1f5dSPeter Maydell             if (real_start == (unsigned long)-1) {
1344f3ed1f5dSPeter Maydell                 goto exit_perror;
1345f3ed1f5dSPeter Maydell             }
1346f3ed1f5dSPeter Maydell             if (real_start == host_start) {
1347f3ed1f5dSPeter Maydell                 break;
1348f3ed1f5dSPeter Maydell             }
1349f3ed1f5dSPeter Maydell             /* That address didn't work.  Unmap and try a different one.
1350f3ed1f5dSPeter Maydell                The address the host picked because is typically right at
1351f3ed1f5dSPeter Maydell                the top of the host address space and leaves the guest with
1352f3ed1f5dSPeter Maydell                no usable address space.  Resort to a linear search.  We
1353f3ed1f5dSPeter Maydell                already compensated for mmap_min_addr, so this should not
1354f3ed1f5dSPeter Maydell                happen often.  Probably means we got unlucky and host
1355f3ed1f5dSPeter Maydell                address space randomization put a shared library somewhere
1356f3ed1f5dSPeter Maydell                inconvenient.  */
1357f3ed1f5dSPeter Maydell             munmap((void *)real_start, host_size);
1358f3ed1f5dSPeter Maydell             host_start += qemu_host_page_size;
1359f3ed1f5dSPeter Maydell             if (host_start == loaddr) {
1360f3ed1f5dSPeter Maydell                 /* Theoretically possible if host doesn't have any suitably
1361f3ed1f5dSPeter Maydell                    aligned areas.  Normally the first mmap will fail.  */
1362f3ed1f5dSPeter Maydell                 errmsg = "Unable to find space for application";
1363f3ed1f5dSPeter Maydell                 goto exit_errmsg;
1364f3ed1f5dSPeter Maydell             }
1365f3ed1f5dSPeter Maydell         }
1366f3ed1f5dSPeter Maydell         qemu_log("Relocating guest address space from 0x"
1367f3ed1f5dSPeter Maydell                  TARGET_ABI_FMT_lx " to 0x%lx\n",
1368f3ed1f5dSPeter Maydell                  loaddr, real_start);
1369f3ed1f5dSPeter Maydell         guest_base = real_start - loaddr;
1370f3ed1f5dSPeter Maydell     }
1371f3ed1f5dSPeter Maydell     return;
1372f3ed1f5dSPeter Maydell 
1373f3ed1f5dSPeter Maydell exit_perror:
1374f3ed1f5dSPeter Maydell     errmsg = strerror(errno);
1375f3ed1f5dSPeter Maydell exit_errmsg:
1376f3ed1f5dSPeter Maydell     fprintf(stderr, "%s: %s\n", image_name, errmsg);
1377f3ed1f5dSPeter Maydell     exit(-1);
1378f3ed1f5dSPeter Maydell #endif
1379f3ed1f5dSPeter Maydell }
1380f3ed1f5dSPeter Maydell 
1381f3ed1f5dSPeter Maydell 
13828e62a717SRichard Henderson /* Load an ELF image into the address space.
138331e31b8aSbellard 
13848e62a717SRichard Henderson    IMAGE_NAME is the filename of the image, to use in error messages.
13858e62a717SRichard Henderson    IMAGE_FD is the open file descriptor for the image.
13868e62a717SRichard Henderson 
13878e62a717SRichard Henderson    BPRM_BUF is a copy of the beginning of the file; this of course
13888e62a717SRichard Henderson    contains the elf file header at offset 0.  It is assumed that this
13898e62a717SRichard Henderson    buffer is sufficiently aligned to present no problems to the host
13908e62a717SRichard Henderson    in accessing data at aligned offsets within the buffer.
13918e62a717SRichard Henderson 
13928e62a717SRichard Henderson    On return: INFO values will be filled in, as necessary or available.  */
13938e62a717SRichard Henderson 
13948e62a717SRichard Henderson static void load_elf_image(const char *image_name, int image_fd,
1395bf858897SRichard Henderson                            struct image_info *info, char **pinterp_name,
13969955ffacSRichard Henderson                            char bprm_buf[BPRM_BUF_SIZE])
139731e31b8aSbellard {
13988e62a717SRichard Henderson     struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
13998e62a717SRichard Henderson     struct elf_phdr *phdr;
14008e62a717SRichard Henderson     abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
14018e62a717SRichard Henderson     int i, retval;
14028e62a717SRichard Henderson     const char *errmsg;
140331e31b8aSbellard 
14048e62a717SRichard Henderson     /* First of all, some simple consistency checks */
14058e62a717SRichard Henderson     errmsg = "Invalid ELF image for this architecture";
14068e62a717SRichard Henderson     if (!elf_check_ident(ehdr)) {
14078e62a717SRichard Henderson         goto exit_errmsg;
14088e62a717SRichard Henderson     }
14098e62a717SRichard Henderson     bswap_ehdr(ehdr);
14108e62a717SRichard Henderson     if (!elf_check_ehdr(ehdr)) {
14118e62a717SRichard Henderson         goto exit_errmsg;
141231e31b8aSbellard     }
141331e31b8aSbellard 
14148e62a717SRichard Henderson     i = ehdr->e_phnum * sizeof(struct elf_phdr);
14158e62a717SRichard Henderson     if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
14168e62a717SRichard Henderson         phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
14179955ffacSRichard Henderson     } else {
14188e62a717SRichard Henderson         phdr = (struct elf_phdr *) alloca(i);
14198e62a717SRichard Henderson         retval = pread(image_fd, phdr, i, ehdr->e_phoff);
14209955ffacSRichard Henderson         if (retval != i) {
14218e62a717SRichard Henderson             goto exit_read;
14229955ffacSRichard Henderson         }
142331e31b8aSbellard     }
14248e62a717SRichard Henderson     bswap_phdr(phdr, ehdr->e_phnum);
142509bfb054Sbellard 
14261af02e83SMike Frysinger #ifdef CONFIG_USE_FDPIC
14271af02e83SMike Frysinger     info->nsegs = 0;
14281af02e83SMike Frysinger     info->pt_dynamic_addr = 0;
14291af02e83SMike Frysinger #endif
14301af02e83SMike Frysinger 
1431682674b8SRichard Henderson     /* Find the maximum size of the image and allocate an appropriate
1432682674b8SRichard Henderson        amount of memory to handle that.  */
1433682674b8SRichard Henderson     loaddr = -1, hiaddr = 0;
14348e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; ++i) {
14358e62a717SRichard Henderson         if (phdr[i].p_type == PT_LOAD) {
14368e62a717SRichard Henderson             abi_ulong a = phdr[i].p_vaddr;
1437682674b8SRichard Henderson             if (a < loaddr) {
1438682674b8SRichard Henderson                 loaddr = a;
1439682674b8SRichard Henderson             }
14408e62a717SRichard Henderson             a += phdr[i].p_memsz;
1441682674b8SRichard Henderson             if (a > hiaddr) {
1442682674b8SRichard Henderson                 hiaddr = a;
1443682674b8SRichard Henderson             }
14441af02e83SMike Frysinger #ifdef CONFIG_USE_FDPIC
14451af02e83SMike Frysinger             ++info->nsegs;
14461af02e83SMike Frysinger #endif
1447682674b8SRichard Henderson         }
1448682674b8SRichard Henderson     }
1449682674b8SRichard Henderson 
1450682674b8SRichard Henderson     load_addr = loaddr;
14518e62a717SRichard Henderson     if (ehdr->e_type == ET_DYN) {
1452682674b8SRichard Henderson         /* The image indicates that it can be loaded anywhere.  Find a
1453682674b8SRichard Henderson            location that can hold the memory space required.  If the
1454682674b8SRichard Henderson            image is pre-linked, LOADDR will be non-zero.  Since we do
1455682674b8SRichard Henderson            not supply MAP_FIXED here we'll use that address if and
1456682674b8SRichard Henderson            only if it remains available.  */
1457682674b8SRichard Henderson         load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE,
1458682674b8SRichard Henderson                                 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
145909bfb054Sbellard                                 -1, 0);
1460682674b8SRichard Henderson         if (load_addr == -1) {
14618e62a717SRichard Henderson             goto exit_perror;
146209bfb054Sbellard         }
1463bf858897SRichard Henderson     } else if (pinterp_name != NULL) {
1464bf858897SRichard Henderson         /* This is the main executable.  Make sure that the low
1465bf858897SRichard Henderson            address does not conflict with MMAP_MIN_ADDR or the
1466bf858897SRichard Henderson            QEMU application itself.  */
1467f3ed1f5dSPeter Maydell         probe_guest_base(image_name, loaddr, hiaddr);
146809bfb054Sbellard     }
1469682674b8SRichard Henderson     load_bias = load_addr - loaddr;
147009bfb054Sbellard 
14711af02e83SMike Frysinger #ifdef CONFIG_USE_FDPIC
14721af02e83SMike Frysinger     {
14731af02e83SMike Frysinger         struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
14741af02e83SMike Frysinger             qemu_malloc(sizeof(*loadsegs) * info->nsegs);
14751af02e83SMike Frysinger 
14761af02e83SMike Frysinger         for (i = 0; i < ehdr->e_phnum; ++i) {
14771af02e83SMike Frysinger             switch (phdr[i].p_type) {
14781af02e83SMike Frysinger             case PT_DYNAMIC:
14791af02e83SMike Frysinger                 info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
14801af02e83SMike Frysinger                 break;
14811af02e83SMike Frysinger             case PT_LOAD:
14821af02e83SMike Frysinger                 loadsegs->addr = phdr[i].p_vaddr + load_bias;
14831af02e83SMike Frysinger                 loadsegs->p_vaddr = phdr[i].p_vaddr;
14841af02e83SMike Frysinger                 loadsegs->p_memsz = phdr[i].p_memsz;
14851af02e83SMike Frysinger                 ++loadsegs;
14861af02e83SMike Frysinger                 break;
14871af02e83SMike Frysinger             }
14881af02e83SMike Frysinger         }
14891af02e83SMike Frysinger     }
14901af02e83SMike Frysinger #endif
14911af02e83SMike Frysinger 
14928e62a717SRichard Henderson     info->load_bias = load_bias;
14938e62a717SRichard Henderson     info->load_addr = load_addr;
14948e62a717SRichard Henderson     info->entry = ehdr->e_entry + load_bias;
14958e62a717SRichard Henderson     info->start_code = -1;
14968e62a717SRichard Henderson     info->end_code = 0;
14978e62a717SRichard Henderson     info->start_data = -1;
14988e62a717SRichard Henderson     info->end_data = 0;
14998e62a717SRichard Henderson     info->brk = 0;
15008e62a717SRichard Henderson 
15018e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; i++) {
15028e62a717SRichard Henderson         struct elf_phdr *eppnt = phdr + i;
150331e31b8aSbellard         if (eppnt->p_type == PT_LOAD) {
1504682674b8SRichard Henderson             abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
150531e31b8aSbellard             int elf_prot = 0;
150631e31b8aSbellard 
150731e31b8aSbellard             if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
150831e31b8aSbellard             if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
150931e31b8aSbellard             if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
151031e31b8aSbellard 
1511682674b8SRichard Henderson             vaddr = load_bias + eppnt->p_vaddr;
1512682674b8SRichard Henderson             vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
1513682674b8SRichard Henderson             vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
1514682674b8SRichard Henderson 
1515682674b8SRichard Henderson             error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
1516682674b8SRichard Henderson                                 elf_prot, MAP_PRIVATE | MAP_FIXED,
15178e62a717SRichard Henderson                                 image_fd, eppnt->p_offset - vaddr_po);
1518e89f07d3Spbrook             if (error == -1) {
15198e62a717SRichard Henderson                 goto exit_perror;
152031e31b8aSbellard             }
152131e31b8aSbellard 
1522682674b8SRichard Henderson             vaddr_ef = vaddr + eppnt->p_filesz;
1523682674b8SRichard Henderson             vaddr_em = vaddr + eppnt->p_memsz;
152431e31b8aSbellard 
1525cf129f3aSRichard Henderson             /* If the load segment requests extra zeros (e.g. bss), map it.  */
1526682674b8SRichard Henderson             if (vaddr_ef < vaddr_em) {
1527682674b8SRichard Henderson                 zero_bss(vaddr_ef, vaddr_em, elf_prot);
1528682674b8SRichard Henderson             }
15298e62a717SRichard Henderson 
15308e62a717SRichard Henderson             /* Find the full program boundaries.  */
15318e62a717SRichard Henderson             if (elf_prot & PROT_EXEC) {
15328e62a717SRichard Henderson                 if (vaddr < info->start_code) {
15338e62a717SRichard Henderson                     info->start_code = vaddr;
1534cf129f3aSRichard Henderson                 }
15358e62a717SRichard Henderson                 if (vaddr_ef > info->end_code) {
15368e62a717SRichard Henderson                     info->end_code = vaddr_ef;
15378e62a717SRichard Henderson                 }
15388e62a717SRichard Henderson             }
15398e62a717SRichard Henderson             if (elf_prot & PROT_WRITE) {
15408e62a717SRichard Henderson                 if (vaddr < info->start_data) {
15418e62a717SRichard Henderson                     info->start_data = vaddr;
15428e62a717SRichard Henderson                 }
15438e62a717SRichard Henderson                 if (vaddr_ef > info->end_data) {
15448e62a717SRichard Henderson                     info->end_data = vaddr_ef;
15458e62a717SRichard Henderson                 }
15468e62a717SRichard Henderson                 if (vaddr_em > info->brk) {
15478e62a717SRichard Henderson                     info->brk = vaddr_em;
15488e62a717SRichard Henderson                 }
15498e62a717SRichard Henderson             }
1550bf858897SRichard Henderson         } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
1551bf858897SRichard Henderson             char *interp_name;
1552bf858897SRichard Henderson 
1553bf858897SRichard Henderson             if (*pinterp_name) {
1554bf858897SRichard Henderson                 errmsg = "Multiple PT_INTERP entries";
1555bf858897SRichard Henderson                 goto exit_errmsg;
1556bf858897SRichard Henderson             }
1557bf858897SRichard Henderson             interp_name = malloc(eppnt->p_filesz);
1558bf858897SRichard Henderson             if (!interp_name) {
1559bf858897SRichard Henderson                 goto exit_perror;
1560bf858897SRichard Henderson             }
1561bf858897SRichard Henderson 
1562bf858897SRichard Henderson             if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
1563bf858897SRichard Henderson                 memcpy(interp_name, bprm_buf + eppnt->p_offset,
1564bf858897SRichard Henderson                        eppnt->p_filesz);
1565bf858897SRichard Henderson             } else {
1566bf858897SRichard Henderson                 retval = pread(image_fd, interp_name, eppnt->p_filesz,
1567bf858897SRichard Henderson                                eppnt->p_offset);
1568bf858897SRichard Henderson                 if (retval != eppnt->p_filesz) {
1569bf858897SRichard Henderson                     goto exit_perror;
1570bf858897SRichard Henderson                 }
1571bf858897SRichard Henderson             }
1572bf858897SRichard Henderson             if (interp_name[eppnt->p_filesz - 1] != 0) {
1573bf858897SRichard Henderson                 errmsg = "Invalid PT_INTERP entry";
1574bf858897SRichard Henderson                 goto exit_errmsg;
1575bf858897SRichard Henderson             }
1576bf858897SRichard Henderson             *pinterp_name = interp_name;
15778e62a717SRichard Henderson         }
15788e62a717SRichard Henderson     }
15798e62a717SRichard Henderson 
15808e62a717SRichard Henderson     if (info->end_data == 0) {
15818e62a717SRichard Henderson         info->start_data = info->end_code;
15828e62a717SRichard Henderson         info->end_data = info->end_code;
15838e62a717SRichard Henderson         info->brk = info->end_code;
158431e31b8aSbellard     }
158531e31b8aSbellard 
1586682674b8SRichard Henderson     if (qemu_log_enabled()) {
15878e62a717SRichard Henderson         load_symbols(ehdr, image_fd, load_bias);
1588682674b8SRichard Henderson     }
158931e31b8aSbellard 
15908e62a717SRichard Henderson     close(image_fd);
15918e62a717SRichard Henderson     return;
159231e31b8aSbellard 
15938e62a717SRichard Henderson  exit_read:
15948e62a717SRichard Henderson     if (retval >= 0) {
15958e62a717SRichard Henderson         errmsg = "Incomplete read of file header";
15968e62a717SRichard Henderson         goto exit_errmsg;
15978e62a717SRichard Henderson     }
15988e62a717SRichard Henderson  exit_perror:
15998e62a717SRichard Henderson     errmsg = strerror(errno);
16008e62a717SRichard Henderson  exit_errmsg:
16018e62a717SRichard Henderson     fprintf(stderr, "%s: %s\n", image_name, errmsg);
16028e62a717SRichard Henderson     exit(-1);
16038e62a717SRichard Henderson }
16048e62a717SRichard Henderson 
16058e62a717SRichard Henderson static void load_elf_interp(const char *filename, struct image_info *info,
16068e62a717SRichard Henderson                             char bprm_buf[BPRM_BUF_SIZE])
16078e62a717SRichard Henderson {
16088e62a717SRichard Henderson     int fd, retval;
16098e62a717SRichard Henderson 
16108e62a717SRichard Henderson     fd = open(path(filename), O_RDONLY);
16118e62a717SRichard Henderson     if (fd < 0) {
16128e62a717SRichard Henderson         goto exit_perror;
16138e62a717SRichard Henderson     }
16148e62a717SRichard Henderson 
16158e62a717SRichard Henderson     retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
16168e62a717SRichard Henderson     if (retval < 0) {
16178e62a717SRichard Henderson         goto exit_perror;
16188e62a717SRichard Henderson     }
16198e62a717SRichard Henderson     if (retval < BPRM_BUF_SIZE) {
16208e62a717SRichard Henderson         memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
16218e62a717SRichard Henderson     }
16228e62a717SRichard Henderson 
1623bf858897SRichard Henderson     load_elf_image(filename, fd, info, NULL, bprm_buf);
16248e62a717SRichard Henderson     return;
16258e62a717SRichard Henderson 
16268e62a717SRichard Henderson  exit_perror:
16278e62a717SRichard Henderson     fprintf(stderr, "%s: %s\n", filename, strerror(errno));
16288e62a717SRichard Henderson     exit(-1);
162931e31b8aSbellard }
163031e31b8aSbellard 
163149918a75Spbrook static int symfind(const void *s0, const void *s1)
163249918a75Spbrook {
163349918a75Spbrook     struct elf_sym *key = (struct elf_sym *)s0;
163449918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
163549918a75Spbrook     int result = 0;
163649918a75Spbrook     if (key->st_value < sym->st_value) {
163749918a75Spbrook         result = -1;
1638ec822001SLaurent Desnogues     } else if (key->st_value >= sym->st_value + sym->st_size) {
163949918a75Spbrook         result = 1;
164049918a75Spbrook     }
164149918a75Spbrook     return result;
164249918a75Spbrook }
164349918a75Spbrook 
164449918a75Spbrook static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
164549918a75Spbrook {
164649918a75Spbrook #if ELF_CLASS == ELFCLASS32
164749918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
164849918a75Spbrook #else
164949918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
165049918a75Spbrook #endif
165149918a75Spbrook 
165249918a75Spbrook     // binary search
165349918a75Spbrook     struct elf_sym key;
165449918a75Spbrook     struct elf_sym *sym;
165549918a75Spbrook 
165649918a75Spbrook     key.st_value = orig_addr;
165749918a75Spbrook 
165849918a75Spbrook     sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), symfind);
16597cba04f6SBlue Swirl     if (sym != NULL) {
166049918a75Spbrook         return s->disas_strtab + sym->st_name;
166149918a75Spbrook     }
166249918a75Spbrook 
166349918a75Spbrook     return "";
166449918a75Spbrook }
166549918a75Spbrook 
166649918a75Spbrook /* FIXME: This should use elf_ops.h  */
166749918a75Spbrook static int symcmp(const void *s0, const void *s1)
166849918a75Spbrook {
166949918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
167049918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
167149918a75Spbrook     return (sym0->st_value < sym1->st_value)
167249918a75Spbrook         ? -1
167349918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
167449918a75Spbrook }
167549918a75Spbrook 
1676689f936fSbellard /* Best attempt to load symbols from this ELF object. */
1677682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
1678689f936fSbellard {
1679682674b8SRichard Henderson     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
1680682674b8SRichard Henderson     struct elf_shdr *shdr;
1681b9475279SCédric VINCENT     char *strings = NULL;
1682b9475279SCédric VINCENT     struct syminfo *s = NULL;
1683b9475279SCédric VINCENT     struct elf_sym *new_syms, *syms = NULL;
168431e31b8aSbellard 
1685682674b8SRichard Henderson     shnum = hdr->e_shnum;
1686682674b8SRichard Henderson     i = shnum * sizeof(struct elf_shdr);
1687682674b8SRichard Henderson     shdr = (struct elf_shdr *)alloca(i);
1688682674b8SRichard Henderson     if (pread(fd, shdr, i, hdr->e_shoff) != i) {
1689689f936fSbellard         return;
1690682674b8SRichard Henderson     }
1691682674b8SRichard Henderson 
1692682674b8SRichard Henderson     bswap_shdr(shdr, shnum);
1693682674b8SRichard Henderson     for (i = 0; i < shnum; ++i) {
1694682674b8SRichard Henderson         if (shdr[i].sh_type == SHT_SYMTAB) {
1695682674b8SRichard Henderson             sym_idx = i;
1696682674b8SRichard Henderson             str_idx = shdr[i].sh_link;
1697689f936fSbellard             goto found;
1698689f936fSbellard         }
1699689f936fSbellard     }
1700682674b8SRichard Henderson 
1701682674b8SRichard Henderson     /* There will be no symbol table if the file was stripped.  */
1702682674b8SRichard Henderson     return;
1703689f936fSbellard 
1704689f936fSbellard  found:
1705689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them.  */
1706e80cfcfcSbellard     s = malloc(sizeof(*s));
1707682674b8SRichard Henderson     if (!s) {
1708b9475279SCédric VINCENT         goto give_up;
1709682674b8SRichard Henderson     }
1710682674b8SRichard Henderson 
1711682674b8SRichard Henderson     i = shdr[str_idx].sh_size;
1712682674b8SRichard Henderson     s->disas_strtab = strings = malloc(i);
1713682674b8SRichard Henderson     if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
1714b9475279SCédric VINCENT         goto give_up;
1715682674b8SRichard Henderson     }
1716689f936fSbellard 
1717682674b8SRichard Henderson     i = shdr[sym_idx].sh_size;
1718682674b8SRichard Henderson     syms = malloc(i);
1719682674b8SRichard Henderson     if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
1720b9475279SCédric VINCENT         goto give_up;
1721682674b8SRichard Henderson     }
1722689f936fSbellard 
1723682674b8SRichard Henderson     nsyms = i / sizeof(struct elf_sym);
1724682674b8SRichard Henderson     for (i = 0; i < nsyms; ) {
172549918a75Spbrook         bswap_sym(syms + i);
1726682674b8SRichard Henderson         /* Throw away entries which we do not need.  */
1727682674b8SRichard Henderson         if (syms[i].st_shndx == SHN_UNDEF
1728682674b8SRichard Henderson             || syms[i].st_shndx >= SHN_LORESERVE
1729682674b8SRichard Henderson             || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
1730682674b8SRichard Henderson             if (i < --nsyms) {
173149918a75Spbrook                 syms[i] = syms[nsyms];
173249918a75Spbrook             }
1733682674b8SRichard Henderson         } else {
173449918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
173549918a75Spbrook             /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
173649918a75Spbrook             syms[i].st_value &= ~(target_ulong)1;
173749918a75Spbrook #endif
1738682674b8SRichard Henderson             syms[i].st_value += load_bias;
173949918a75Spbrook             i++;
174049918a75Spbrook         }
1741682674b8SRichard Henderson     }
174249918a75Spbrook 
1743b9475279SCédric VINCENT     /* No "useful" symbol.  */
1744b9475279SCédric VINCENT     if (nsyms == 0) {
1745b9475279SCédric VINCENT         goto give_up;
1746b9475279SCédric VINCENT     }
1747b9475279SCédric VINCENT 
17485d5c9930SRichard Henderson     /* Attempt to free the storage associated with the local symbols
17495d5c9930SRichard Henderson        that we threw away.  Whether or not this has any effect on the
17505d5c9930SRichard Henderson        memory allocation depends on the malloc implementation and how
17515d5c9930SRichard Henderson        many symbols we managed to discard.  */
17528d79de6eSStefan Weil     new_syms = realloc(syms, nsyms * sizeof(*syms));
17538d79de6eSStefan Weil     if (new_syms == NULL) {
1754b9475279SCédric VINCENT         goto give_up;
17555d5c9930SRichard Henderson     }
17568d79de6eSStefan Weil     syms = new_syms;
17575d5c9930SRichard Henderson 
175849918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
175949918a75Spbrook 
176049918a75Spbrook     s->disas_num_syms = nsyms;
176149918a75Spbrook #if ELF_CLASS == ELFCLASS32
176249918a75Spbrook     s->disas_symtab.elf32 = syms;
176349918a75Spbrook #else
176449918a75Spbrook     s->disas_symtab.elf64 = syms;
176549918a75Spbrook #endif
1766682674b8SRichard Henderson     s->lookup_symbol = lookup_symbolxx;
1767e80cfcfcSbellard     s->next = syminfos;
1768e80cfcfcSbellard     syminfos = s;
1769b9475279SCédric VINCENT 
1770b9475279SCédric VINCENT     return;
1771b9475279SCédric VINCENT 
1772b9475279SCédric VINCENT give_up:
1773b9475279SCédric VINCENT     free(s);
1774b9475279SCédric VINCENT     free(strings);
1775b9475279SCédric VINCENT     free(syms);
1776689f936fSbellard }
177731e31b8aSbellard 
1778e5fe0c52Spbrook int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
177931e31b8aSbellard                     struct image_info * info)
178031e31b8aSbellard {
17818e62a717SRichard Henderson     struct image_info interp_info;
178231e31b8aSbellard     struct elfhdr elf_ex;
17838e62a717SRichard Henderson     char *elf_interpreter = NULL;
178431e31b8aSbellard 
1785bf858897SRichard Henderson     info->start_mmap = (abi_ulong)ELF_START_MMAP;
1786bf858897SRichard Henderson     info->mmap = 0;
1787bf858897SRichard Henderson     info->rss = 0;
178831e31b8aSbellard 
1789bf858897SRichard Henderson     load_elf_image(bprm->filename, bprm->fd, info,
1790bf858897SRichard Henderson                    &elf_interpreter, bprm->buf);
1791bf858897SRichard Henderson 
1792bf858897SRichard Henderson     /* ??? We need a copy of the elf header for passing to create_elf_tables.
1793bf858897SRichard Henderson        If we do nothing, we'll have overwritten this when we re-use bprm->buf
1794bf858897SRichard Henderson        when we load the interpreter.  */
1795bf858897SRichard Henderson     elf_ex = *(struct elfhdr *)bprm->buf;
179631e31b8aSbellard 
1797e5fe0c52Spbrook     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
1798e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
1799e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
1800e5fe0c52Spbrook     if (!bprm->p) {
1801bf858897SRichard Henderson         fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
180231e31b8aSbellard         exit(-1);
18039955ffacSRichard Henderson     }
1804379f6698SPaul Brook 
180531e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
180631e31b8aSbellard        change some of these later */
180731e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
180831e31b8aSbellard 
18098e62a717SRichard Henderson     if (elf_interpreter) {
18108e62a717SRichard Henderson         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
181131e31b8aSbellard 
18128e62a717SRichard Henderson         /* If the program interpreter is one of these two, then assume
18138e62a717SRichard Henderson            an iBCS2 image.  Otherwise assume a native linux image.  */
181431e31b8aSbellard 
18158e62a717SRichard Henderson         if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
18168e62a717SRichard Henderson             || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
18178e62a717SRichard Henderson             info->personality = PER_SVR4;
18188e62a717SRichard Henderson 
181931e31b8aSbellard             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
18208e62a717SRichard Henderson                and some applications "depend" upon this behavior.  Since
18218e62a717SRichard Henderson                we do not have the power to recompile these, we emulate
18228e62a717SRichard Henderson                the SVr4 behavior.  Sigh.  */
18238e62a717SRichard Henderson             target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
182431e31b8aSbellard                         MAP_FIXED | MAP_PRIVATE, -1, 0);
182531e31b8aSbellard         }
18268e62a717SRichard Henderson     }
182731e31b8aSbellard 
18288e62a717SRichard Henderson     bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
18298e62a717SRichard Henderson                                 info, (elf_interpreter ? &interp_info : NULL));
18308e62a717SRichard Henderson     info->start_stack = bprm->p;
18318e62a717SRichard Henderson 
18328e62a717SRichard Henderson     /* If we have an interpreter, set that as the program's entry point.
18338e62a717SRichard Henderson        Copy the load_addr as well, to help PPC64 interpret the entry
18348e62a717SRichard Henderson        point as a function descriptor.  Do this after creating elf tables
18358e62a717SRichard Henderson        so that we copy the original program entry point into the AUXV.  */
18368e62a717SRichard Henderson     if (elf_interpreter) {
18378e62a717SRichard Henderson         info->load_addr = interp_info.load_addr;
18388e62a717SRichard Henderson         info->entry = interp_info.entry;
1839bf858897SRichard Henderson         free(elf_interpreter);
18408e62a717SRichard Henderson     }
184131e31b8aSbellard 
1842edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
1843edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
1844edf8e2afSMika Westerberg #endif
1845edf8e2afSMika Westerberg 
184631e31b8aSbellard     return 0;
184731e31b8aSbellard }
184831e31b8aSbellard 
1849edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
1850edf8e2afSMika Westerberg /*
1851edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
1852a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
1853edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
1854edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
1855edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
1856edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
1857edf8e2afSMika Westerberg  *
1858edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
1859edf8e2afSMika Westerberg  * are marked with XXX.
1860edf8e2afSMika Westerberg  *
1861edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
1862edf8e2afSMika Westerberg  *
1863edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
1864dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
1865edf8e2afSMika Westerberg  * the target resides):
1866edf8e2afSMika Westerberg  *
1867edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
1868edf8e2afSMika Westerberg  *
1869edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
1870edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
1871edf8e2afSMika Westerberg  *
1872c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
1873edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
1874c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
1875edf8e2afSMika Westerberg  *
1876edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
1877edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
1878edf8e2afSMika Westerberg  *
1879c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
1880a2547a13SLaurent Desnogues  *                                const CPUState *env);
1881edf8e2afSMika Westerberg  *
1882edf8e2afSMika Westerberg  * Parameters:
1883edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
1884edf8e2afSMika Westerberg  *     env - copy registers from here
1885edf8e2afSMika Westerberg  *
1886edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
1887edf8e2afSMika Westerberg  */
1888edf8e2afSMika Westerberg 
1889edf8e2afSMika Westerberg /* An ELF note in memory */
1890edf8e2afSMika Westerberg struct memelfnote {
1891edf8e2afSMika Westerberg     const char *name;
1892edf8e2afSMika Westerberg     size_t     namesz;
1893edf8e2afSMika Westerberg     size_t     namesz_rounded;
1894edf8e2afSMika Westerberg     int        type;
1895edf8e2afSMika Westerberg     size_t     datasz;
189680f5ce75SLaurent Vivier     size_t     datasz_rounded;
1897edf8e2afSMika Westerberg     void       *data;
1898edf8e2afSMika Westerberg     size_t     notesz;
1899edf8e2afSMika Westerberg };
1900edf8e2afSMika Westerberg 
1901a2547a13SLaurent Desnogues struct target_elf_siginfo {
190280f5ce75SLaurent Vivier     target_int  si_signo; /* signal number */
190380f5ce75SLaurent Vivier     target_int  si_code;  /* extra code */
190480f5ce75SLaurent Vivier     target_int  si_errno; /* errno */
1905edf8e2afSMika Westerberg };
1906edf8e2afSMika Westerberg 
1907a2547a13SLaurent Desnogues struct target_elf_prstatus {
1908a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
190980f5ce75SLaurent Vivier     target_short       pr_cursig;    /* Current signal */
1910edf8e2afSMika Westerberg     target_ulong       pr_sigpend;   /* XXX */
1911edf8e2afSMika Westerberg     target_ulong       pr_sighold;   /* XXX */
1912c227f099SAnthony Liguori     target_pid_t       pr_pid;
1913c227f099SAnthony Liguori     target_pid_t       pr_ppid;
1914c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
1915c227f099SAnthony Liguori     target_pid_t       pr_sid;
1916edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
1917edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
1918edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
1919edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
1920c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
192180f5ce75SLaurent Vivier     target_int         pr_fpvalid;   /* XXX */
1922edf8e2afSMika Westerberg };
1923edf8e2afSMika Westerberg 
1924edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
1925edf8e2afSMika Westerberg 
1926a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
1927edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
1928edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
1929edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
1930edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
1931edf8e2afSMika Westerberg     target_ulong pr_flag;        /* flags */
1932c227f099SAnthony Liguori     target_uid_t pr_uid;
1933c227f099SAnthony Liguori     target_gid_t pr_gid;
1934c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
1935edf8e2afSMika Westerberg     /* Lots missing */
1936edf8e2afSMika Westerberg     char    pr_fname[16];           /* filename of executable */
1937edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
1938edf8e2afSMika Westerberg };
1939edf8e2afSMika Westerberg 
1940edf8e2afSMika Westerberg /* Here is the structure in which status of each thread is captured. */
1941edf8e2afSMika Westerberg struct elf_thread_status {
194272cf2d4fSBlue Swirl     QTAILQ_ENTRY(elf_thread_status)  ets_link;
1943a2547a13SLaurent Desnogues     struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
1944edf8e2afSMika Westerberg #if 0
1945edf8e2afSMika Westerberg     elf_fpregset_t fpu;             /* NT_PRFPREG */
1946edf8e2afSMika Westerberg     struct task_struct *thread;
1947edf8e2afSMika Westerberg     elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
1948edf8e2afSMika Westerberg #endif
1949edf8e2afSMika Westerberg     struct memelfnote notes[1];
1950edf8e2afSMika Westerberg     int num_notes;
1951edf8e2afSMika Westerberg };
1952edf8e2afSMika Westerberg 
1953edf8e2afSMika Westerberg struct elf_note_info {
1954edf8e2afSMika Westerberg     struct memelfnote   *notes;
1955a2547a13SLaurent Desnogues     struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
1956a2547a13SLaurent Desnogues     struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
1957edf8e2afSMika Westerberg 
195872cf2d4fSBlue Swirl     QTAILQ_HEAD(thread_list_head, elf_thread_status) thread_list;
1959edf8e2afSMika Westerberg #if 0
1960edf8e2afSMika Westerberg     /*
1961edf8e2afSMika Westerberg      * Current version of ELF coredump doesn't support
1962edf8e2afSMika Westerberg      * dumping fp regs etc.
1963edf8e2afSMika Westerberg      */
1964edf8e2afSMika Westerberg     elf_fpregset_t *fpu;
1965edf8e2afSMika Westerberg     elf_fpxregset_t *xfpu;
1966edf8e2afSMika Westerberg     int thread_status_size;
1967edf8e2afSMika Westerberg #endif
1968edf8e2afSMika Westerberg     int notes_size;
1969edf8e2afSMika Westerberg     int numnote;
1970edf8e2afSMika Westerberg };
1971edf8e2afSMika Westerberg 
1972edf8e2afSMika Westerberg struct vm_area_struct {
1973edf8e2afSMika Westerberg     abi_ulong   vma_start;  /* start vaddr of memory region */
1974edf8e2afSMika Westerberg     abi_ulong   vma_end;    /* end vaddr of memory region */
1975edf8e2afSMika Westerberg     abi_ulong   vma_flags;  /* protection etc. flags for the region */
197672cf2d4fSBlue Swirl     QTAILQ_ENTRY(vm_area_struct) vma_link;
1977edf8e2afSMika Westerberg };
1978edf8e2afSMika Westerberg 
1979edf8e2afSMika Westerberg struct mm_struct {
198072cf2d4fSBlue Swirl     QTAILQ_HEAD(, vm_area_struct) mm_mmap;
1981edf8e2afSMika Westerberg     int mm_count;           /* number of mappings */
1982edf8e2afSMika Westerberg };
1983edf8e2afSMika Westerberg 
1984edf8e2afSMika Westerberg static struct mm_struct *vma_init(void);
1985edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *);
1986edf8e2afSMika Westerberg static int vma_add_mapping(struct mm_struct *, abi_ulong,
1987edf8e2afSMika Westerberg                            abi_ulong, abi_ulong);
1988edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *);
1989edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *);
1990edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *);
1991edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *);
1992b480d9b7SPaul Brook static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
1993edf8e2afSMika Westerberg                       unsigned long flags);
1994edf8e2afSMika Westerberg 
1995edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
1996edf8e2afSMika Westerberg static void fill_note(struct memelfnote *, const char *, int,
1997edf8e2afSMika Westerberg                       unsigned int, void *);
1998a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
1999a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
2000edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *, const TaskState *);
2001edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
2002edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *);
2003edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *);
2004edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *, long, const CPUState *);
2005edf8e2afSMika Westerberg static void fill_thread_info(struct elf_note_info *, const CPUState *);
2006edf8e2afSMika Westerberg static int core_dump_filename(const TaskState *, char *, size_t);
2007edf8e2afSMika Westerberg 
2008edf8e2afSMika Westerberg static int dump_write(int, const void *, size_t);
2009edf8e2afSMika Westerberg static int write_note(struct memelfnote *, int);
2010edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *, int);
2011edf8e2afSMika Westerberg 
2012edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
2013a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
2014edf8e2afSMika Westerberg {
2015edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo);
2016edf8e2afSMika Westerberg     prstatus->pr_info.si_code = tswapl(prstatus->pr_info.si_code);
2017edf8e2afSMika Westerberg     prstatus->pr_info.si_errno = tswapl(prstatus->pr_info.si_errno);
2018edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
2019edf8e2afSMika Westerberg     prstatus->pr_sigpend = tswapl(prstatus->pr_sigpend);
2020edf8e2afSMika Westerberg     prstatus->pr_sighold = tswapl(prstatus->pr_sighold);
2021edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
2022edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
2023edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
2024edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
2025edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
2026edf8e2afSMika Westerberg     /* regs should be in correct format already */
2027edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
2028edf8e2afSMika Westerberg }
2029edf8e2afSMika Westerberg 
2030a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
2031edf8e2afSMika Westerberg {
2032edf8e2afSMika Westerberg     psinfo->pr_flag = tswapl(psinfo->pr_flag);
2033edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
2034edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
2035edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
2036edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
2037edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
2038edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
2039edf8e2afSMika Westerberg }
2040991f8f0cSRichard Henderson 
2041991f8f0cSRichard Henderson static void bswap_note(struct elf_note *en)
2042991f8f0cSRichard Henderson {
2043991f8f0cSRichard Henderson     bswap32s(&en->n_namesz);
2044991f8f0cSRichard Henderson     bswap32s(&en->n_descsz);
2045991f8f0cSRichard Henderson     bswap32s(&en->n_type);
2046991f8f0cSRichard Henderson }
2047991f8f0cSRichard Henderson #else
2048991f8f0cSRichard Henderson static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
2049991f8f0cSRichard Henderson static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
2050991f8f0cSRichard Henderson static inline void bswap_note(struct elf_note *en) { }
2051edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
2052edf8e2afSMika Westerberg 
2053edf8e2afSMika Westerberg /*
2054edf8e2afSMika Westerberg  * Minimal support for linux memory regions.  These are needed
2055edf8e2afSMika Westerberg  * when we are finding out what memory exactly belongs to
2056edf8e2afSMika Westerberg  * emulated process.  No locks needed here, as long as
2057edf8e2afSMika Westerberg  * thread that received the signal is stopped.
2058edf8e2afSMika Westerberg  */
2059edf8e2afSMika Westerberg 
2060edf8e2afSMika Westerberg static struct mm_struct *vma_init(void)
2061edf8e2afSMika Westerberg {
2062edf8e2afSMika Westerberg     struct mm_struct *mm;
2063edf8e2afSMika Westerberg 
2064edf8e2afSMika Westerberg     if ((mm = qemu_malloc(sizeof (*mm))) == NULL)
2065edf8e2afSMika Westerberg         return (NULL);
2066edf8e2afSMika Westerberg 
2067edf8e2afSMika Westerberg     mm->mm_count = 0;
206872cf2d4fSBlue Swirl     QTAILQ_INIT(&mm->mm_mmap);
2069edf8e2afSMika Westerberg 
2070edf8e2afSMika Westerberg     return (mm);
2071edf8e2afSMika Westerberg }
2072edf8e2afSMika Westerberg 
2073edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *mm)
2074edf8e2afSMika Westerberg {
2075edf8e2afSMika Westerberg     struct vm_area_struct *vma;
2076edf8e2afSMika Westerberg 
2077edf8e2afSMika Westerberg     while ((vma = vma_first(mm)) != NULL) {
207872cf2d4fSBlue Swirl         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
2079edf8e2afSMika Westerberg         qemu_free(vma);
2080edf8e2afSMika Westerberg     }
2081edf8e2afSMika Westerberg     qemu_free(mm);
2082edf8e2afSMika Westerberg }
2083edf8e2afSMika Westerberg 
2084edf8e2afSMika Westerberg static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
2085edf8e2afSMika Westerberg                            abi_ulong end, abi_ulong flags)
2086edf8e2afSMika Westerberg {
2087edf8e2afSMika Westerberg     struct vm_area_struct *vma;
2088edf8e2afSMika Westerberg 
2089edf8e2afSMika Westerberg     if ((vma = qemu_mallocz(sizeof (*vma))) == NULL)
2090edf8e2afSMika Westerberg         return (-1);
2091edf8e2afSMika Westerberg 
2092edf8e2afSMika Westerberg     vma->vma_start = start;
2093edf8e2afSMika Westerberg     vma->vma_end = end;
2094edf8e2afSMika Westerberg     vma->vma_flags = flags;
2095edf8e2afSMika Westerberg 
209672cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
2097edf8e2afSMika Westerberg     mm->mm_count++;
2098edf8e2afSMika Westerberg 
2099edf8e2afSMika Westerberg     return (0);
2100edf8e2afSMika Westerberg }
2101edf8e2afSMika Westerberg 
2102edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *mm)
2103edf8e2afSMika Westerberg {
210472cf2d4fSBlue Swirl     return (QTAILQ_FIRST(&mm->mm_mmap));
2105edf8e2afSMika Westerberg }
2106edf8e2afSMika Westerberg 
2107edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
2108edf8e2afSMika Westerberg {
210972cf2d4fSBlue Swirl     return (QTAILQ_NEXT(vma, vma_link));
2110edf8e2afSMika Westerberg }
2111edf8e2afSMika Westerberg 
2112edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *mm)
2113edf8e2afSMika Westerberg {
2114edf8e2afSMika Westerberg     return (mm->mm_count);
2115edf8e2afSMika Westerberg }
2116edf8e2afSMika Westerberg 
2117edf8e2afSMika Westerberg /*
2118edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
2119edf8e2afSMika Westerberg  */
2120edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
2121edf8e2afSMika Westerberg {
2122edf8e2afSMika Westerberg     /* if we cannot even read the first page, skip it */
2123edf8e2afSMika Westerberg     if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
2124edf8e2afSMika Westerberg         return (0);
2125edf8e2afSMika Westerberg 
2126edf8e2afSMika Westerberg     /*
2127edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
2128edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
2129edf8e2afSMika Westerberg      * target library etc.  However, thread stacks are marked
2130edf8e2afSMika Westerberg      * also executable so we read in first page of given region
2131edf8e2afSMika Westerberg      * and check whether it contains elf header.  If there is
2132edf8e2afSMika Westerberg      * no elf header, we dump it.
2133edf8e2afSMika Westerberg      */
2134edf8e2afSMika Westerberg     if (vma->vma_flags & PROT_EXEC) {
2135edf8e2afSMika Westerberg         char page[TARGET_PAGE_SIZE];
2136edf8e2afSMika Westerberg 
2137edf8e2afSMika Westerberg         copy_from_user(page, vma->vma_start, sizeof (page));
2138edf8e2afSMika Westerberg         if ((page[EI_MAG0] == ELFMAG0) &&
2139edf8e2afSMika Westerberg             (page[EI_MAG1] == ELFMAG1) &&
2140edf8e2afSMika Westerberg             (page[EI_MAG2] == ELFMAG2) &&
2141edf8e2afSMika Westerberg             (page[EI_MAG3] == ELFMAG3)) {
2142edf8e2afSMika Westerberg             /*
2143edf8e2afSMika Westerberg              * Mappings are possibly from ELF binary.  Don't dump
2144edf8e2afSMika Westerberg              * them.
2145edf8e2afSMika Westerberg              */
2146edf8e2afSMika Westerberg             return (0);
2147edf8e2afSMika Westerberg         }
2148edf8e2afSMika Westerberg     }
2149edf8e2afSMika Westerberg 
2150edf8e2afSMika Westerberg     return (vma->vma_end - vma->vma_start);
2151edf8e2afSMika Westerberg }
2152edf8e2afSMika Westerberg 
2153b480d9b7SPaul Brook static int vma_walker(void *priv, abi_ulong start, abi_ulong end,
2154edf8e2afSMika Westerberg                       unsigned long flags)
2155edf8e2afSMika Westerberg {
2156edf8e2afSMika Westerberg     struct mm_struct *mm = (struct mm_struct *)priv;
2157edf8e2afSMika Westerberg 
2158edf8e2afSMika Westerberg     vma_add_mapping(mm, start, end, flags);
2159edf8e2afSMika Westerberg     return (0);
2160edf8e2afSMika Westerberg }
2161edf8e2afSMika Westerberg 
2162edf8e2afSMika Westerberg static void fill_note(struct memelfnote *note, const char *name, int type,
2163edf8e2afSMika Westerberg                       unsigned int sz, void *data)
2164edf8e2afSMika Westerberg {
2165edf8e2afSMika Westerberg     unsigned int namesz;
2166edf8e2afSMika Westerberg 
2167edf8e2afSMika Westerberg     namesz = strlen(name) + 1;
2168edf8e2afSMika Westerberg     note->name = name;
2169edf8e2afSMika Westerberg     note->namesz = namesz;
2170edf8e2afSMika Westerberg     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
2171edf8e2afSMika Westerberg     note->type = type;
217280f5ce75SLaurent Vivier     note->datasz = sz;
217380f5ce75SLaurent Vivier     note->datasz_rounded = roundup(sz, sizeof (int32_t));
217480f5ce75SLaurent Vivier 
2175edf8e2afSMika Westerberg     note->data = data;
2176edf8e2afSMika Westerberg 
2177edf8e2afSMika Westerberg     /*
2178edf8e2afSMika Westerberg      * We calculate rounded up note size here as specified by
2179edf8e2afSMika Westerberg      * ELF document.
2180edf8e2afSMika Westerberg      */
2181edf8e2afSMika Westerberg     note->notesz = sizeof (struct elf_note) +
218280f5ce75SLaurent Vivier         note->namesz_rounded + note->datasz_rounded;
2183edf8e2afSMika Westerberg }
2184edf8e2afSMika Westerberg 
2185edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
2186edf8e2afSMika Westerberg                             uint32_t flags)
2187edf8e2afSMika Westerberg {
2188edf8e2afSMika Westerberg     (void) memset(elf, 0, sizeof(*elf));
2189edf8e2afSMika Westerberg 
2190edf8e2afSMika Westerberg     (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
2191edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
2192edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
2193edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
2194edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
2195edf8e2afSMika Westerberg 
2196edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
2197edf8e2afSMika Westerberg     elf->e_machine = machine;
2198edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
2199edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
2200edf8e2afSMika Westerberg     elf->e_flags = flags;
2201edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
2202edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
2203edf8e2afSMika Westerberg     elf->e_phnum = segs;
2204edf8e2afSMika Westerberg 
2205edf8e2afSMika Westerberg     bswap_ehdr(elf);
2206edf8e2afSMika Westerberg }
2207edf8e2afSMika Westerberg 
2208edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
2209edf8e2afSMika Westerberg {
2210edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
2211edf8e2afSMika Westerberg     phdr->p_offset = offset;
2212edf8e2afSMika Westerberg     phdr->p_vaddr = 0;
2213edf8e2afSMika Westerberg     phdr->p_paddr = 0;
2214edf8e2afSMika Westerberg     phdr->p_filesz = sz;
2215edf8e2afSMika Westerberg     phdr->p_memsz = 0;
2216edf8e2afSMika Westerberg     phdr->p_flags = 0;
2217edf8e2afSMika Westerberg     phdr->p_align = 0;
2218edf8e2afSMika Westerberg 
2219991f8f0cSRichard Henderson     bswap_phdr(phdr, 1);
2220edf8e2afSMika Westerberg }
2221edf8e2afSMika Westerberg 
2222edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *note)
2223edf8e2afSMika Westerberg {
2224edf8e2afSMika Westerberg     return (note->notesz);
2225edf8e2afSMika Westerberg }
2226edf8e2afSMika Westerberg 
2227a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *prstatus,
2228edf8e2afSMika Westerberg                           const TaskState *ts, int signr)
2229edf8e2afSMika Westerberg {
2230edf8e2afSMika Westerberg     (void) memset(prstatus, 0, sizeof (*prstatus));
2231edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
2232edf8e2afSMika Westerberg     prstatus->pr_pid = ts->ts_tid;
2233edf8e2afSMika Westerberg     prstatus->pr_ppid = getppid();
2234edf8e2afSMika Westerberg     prstatus->pr_pgrp = getpgrp();
2235edf8e2afSMika Westerberg     prstatus->pr_sid = getsid(0);
2236edf8e2afSMika Westerberg 
2237edf8e2afSMika Westerberg     bswap_prstatus(prstatus);
2238edf8e2afSMika Westerberg }
2239edf8e2afSMika Westerberg 
2240a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
2241edf8e2afSMika Westerberg {
2242edf8e2afSMika Westerberg     char *filename, *base_filename;
2243edf8e2afSMika Westerberg     unsigned int i, len;
2244edf8e2afSMika Westerberg 
2245edf8e2afSMika Westerberg     (void) memset(psinfo, 0, sizeof (*psinfo));
2246edf8e2afSMika Westerberg 
2247edf8e2afSMika Westerberg     len = ts->info->arg_end - ts->info->arg_start;
2248edf8e2afSMika Westerberg     if (len >= ELF_PRARGSZ)
2249edf8e2afSMika Westerberg         len = ELF_PRARGSZ - 1;
2250edf8e2afSMika Westerberg     if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len))
2251edf8e2afSMika Westerberg         return -EFAULT;
2252edf8e2afSMika Westerberg     for (i = 0; i < len; i++)
2253edf8e2afSMika Westerberg         if (psinfo->pr_psargs[i] == 0)
2254edf8e2afSMika Westerberg             psinfo->pr_psargs[i] = ' ';
2255edf8e2afSMika Westerberg     psinfo->pr_psargs[len] = 0;
2256edf8e2afSMika Westerberg 
2257edf8e2afSMika Westerberg     psinfo->pr_pid = getpid();
2258edf8e2afSMika Westerberg     psinfo->pr_ppid = getppid();
2259edf8e2afSMika Westerberg     psinfo->pr_pgrp = getpgrp();
2260edf8e2afSMika Westerberg     psinfo->pr_sid = getsid(0);
2261edf8e2afSMika Westerberg     psinfo->pr_uid = getuid();
2262edf8e2afSMika Westerberg     psinfo->pr_gid = getgid();
2263edf8e2afSMika Westerberg 
2264edf8e2afSMika Westerberg     filename = strdup(ts->bprm->filename);
2265edf8e2afSMika Westerberg     base_filename = strdup(basename(filename));
2266edf8e2afSMika Westerberg     (void) strncpy(psinfo->pr_fname, base_filename,
2267edf8e2afSMika Westerberg                    sizeof(psinfo->pr_fname));
2268edf8e2afSMika Westerberg     free(base_filename);
2269edf8e2afSMika Westerberg     free(filename);
2270edf8e2afSMika Westerberg 
2271edf8e2afSMika Westerberg     bswap_psinfo(psinfo);
2272edf8e2afSMika Westerberg     return (0);
2273edf8e2afSMika Westerberg }
2274edf8e2afSMika Westerberg 
2275edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
2276edf8e2afSMika Westerberg {
2277edf8e2afSMika Westerberg     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
2278edf8e2afSMika Westerberg     elf_addr_t orig_auxv = auxv;
2279edf8e2afSMika Westerberg     abi_ulong val;
2280edf8e2afSMika Westerberg     void *ptr;
2281edf8e2afSMika Westerberg     int i, len;
2282edf8e2afSMika Westerberg 
2283edf8e2afSMika Westerberg     /*
2284edf8e2afSMika Westerberg      * Auxiliary vector is stored in target process stack.  It contains
2285edf8e2afSMika Westerberg      * {type, value} pairs that we need to dump into note.  This is not
2286edf8e2afSMika Westerberg      * strictly necessary but we do it here for sake of completeness.
2287edf8e2afSMika Westerberg      */
2288edf8e2afSMika Westerberg 
2289edf8e2afSMika Westerberg     /* find out lenght of the vector, AT_NULL is terminator */
2290edf8e2afSMika Westerberg     i = len = 0;
2291edf8e2afSMika Westerberg     do {
2292edf8e2afSMika Westerberg         get_user_ual(val, auxv);
2293edf8e2afSMika Westerberg         i += 2;
2294edf8e2afSMika Westerberg         auxv += 2 * sizeof (elf_addr_t);
2295edf8e2afSMika Westerberg     } while (val != AT_NULL);
2296edf8e2afSMika Westerberg     len = i * sizeof (elf_addr_t);
2297edf8e2afSMika Westerberg 
2298edf8e2afSMika Westerberg     /* read in whole auxv vector and copy it to memelfnote */
2299edf8e2afSMika Westerberg     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
2300edf8e2afSMika Westerberg     if (ptr != NULL) {
2301edf8e2afSMika Westerberg         fill_note(note, "CORE", NT_AUXV, len, ptr);
2302edf8e2afSMika Westerberg         unlock_user(ptr, auxv, len);
2303edf8e2afSMika Westerberg     }
2304edf8e2afSMika Westerberg }
2305edf8e2afSMika Westerberg 
2306edf8e2afSMika Westerberg /*
2307edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
2308edf8e2afSMika Westerberg  * for the name:
2309edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
2310edf8e2afSMika Westerberg  *
2311edf8e2afSMika Westerberg  * Returns 0 in case of success, -1 otherwise (errno is set).
2312edf8e2afSMika Westerberg  */
2313edf8e2afSMika Westerberg static int core_dump_filename(const TaskState *ts, char *buf,
2314edf8e2afSMika Westerberg                               size_t bufsize)
2315edf8e2afSMika Westerberg {
2316edf8e2afSMika Westerberg     char timestamp[64];
2317edf8e2afSMika Westerberg     char *filename = NULL;
2318edf8e2afSMika Westerberg     char *base_filename = NULL;
2319edf8e2afSMika Westerberg     struct timeval tv;
2320edf8e2afSMika Westerberg     struct tm tm;
2321edf8e2afSMika Westerberg 
2322edf8e2afSMika Westerberg     assert(bufsize >= PATH_MAX);
2323edf8e2afSMika Westerberg 
2324edf8e2afSMika Westerberg     if (gettimeofday(&tv, NULL) < 0) {
2325edf8e2afSMika Westerberg         (void) fprintf(stderr, "unable to get current timestamp: %s",
2326edf8e2afSMika Westerberg                        strerror(errno));
2327edf8e2afSMika Westerberg         return (-1);
2328edf8e2afSMika Westerberg     }
2329edf8e2afSMika Westerberg 
2330edf8e2afSMika Westerberg     filename = strdup(ts->bprm->filename);
2331edf8e2afSMika Westerberg     base_filename = strdup(basename(filename));
2332edf8e2afSMika Westerberg     (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
2333edf8e2afSMika Westerberg                     localtime_r(&tv.tv_sec, &tm));
2334edf8e2afSMika Westerberg     (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
2335edf8e2afSMika Westerberg                     base_filename, timestamp, (int)getpid());
2336edf8e2afSMika Westerberg     free(base_filename);
2337edf8e2afSMika Westerberg     free(filename);
2338edf8e2afSMika Westerberg 
2339edf8e2afSMika Westerberg     return (0);
2340edf8e2afSMika Westerberg }
2341edf8e2afSMika Westerberg 
2342edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
2343edf8e2afSMika Westerberg {
2344edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
2345edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
2346edf8e2afSMika Westerberg     struct rlimit dumpsize;
2347edf8e2afSMika Westerberg     off_t pos;
2348edf8e2afSMika Westerberg 
2349edf8e2afSMika Westerberg     bytes_written = 0;
2350edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
2351edf8e2afSMika Westerberg     if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
2352edf8e2afSMika Westerberg         if (errno == ESPIPE) { /* not a seekable stream */
2353edf8e2afSMika Westerberg             bytes_left = size;
2354edf8e2afSMika Westerberg         } else {
2355edf8e2afSMika Westerberg             return pos;
2356edf8e2afSMika Westerberg         }
2357edf8e2afSMika Westerberg     } else {
2358edf8e2afSMika Westerberg         if (dumpsize.rlim_cur <= pos) {
2359edf8e2afSMika Westerberg             return -1;
2360edf8e2afSMika Westerberg         } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
2361edf8e2afSMika Westerberg             bytes_left = size;
2362edf8e2afSMika Westerberg         } else {
2363edf8e2afSMika Westerberg             size_t limit_left=dumpsize.rlim_cur - pos;
2364edf8e2afSMika Westerberg             bytes_left = limit_left >= size ? size : limit_left ;
2365edf8e2afSMika Westerberg         }
2366edf8e2afSMika Westerberg     }
2367edf8e2afSMika Westerberg 
2368edf8e2afSMika Westerberg     /*
2369edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
2370edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
2371edf8e2afSMika Westerberg      */
2372edf8e2afSMika Westerberg     do {
2373edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
2374edf8e2afSMika Westerberg         if (bytes_written < 0) {
2375edf8e2afSMika Westerberg             if (errno == EINTR)
2376edf8e2afSMika Westerberg                 continue;
2377edf8e2afSMika Westerberg             return (-1);
2378edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
2379edf8e2afSMika Westerberg             return (-1);
2380edf8e2afSMika Westerberg         }
2381edf8e2afSMika Westerberg         bufp += bytes_written;
2382edf8e2afSMika Westerberg         bytes_left -= bytes_written;
2383edf8e2afSMika Westerberg     } while (bytes_left > 0);
2384edf8e2afSMika Westerberg 
2385edf8e2afSMika Westerberg     return (0);
2386edf8e2afSMika Westerberg }
2387edf8e2afSMika Westerberg 
2388edf8e2afSMika Westerberg static int write_note(struct memelfnote *men, int fd)
2389edf8e2afSMika Westerberg {
2390edf8e2afSMika Westerberg     struct elf_note en;
2391edf8e2afSMika Westerberg 
2392edf8e2afSMika Westerberg     en.n_namesz = men->namesz;
2393edf8e2afSMika Westerberg     en.n_type = men->type;
2394edf8e2afSMika Westerberg     en.n_descsz = men->datasz;
2395edf8e2afSMika Westerberg 
2396edf8e2afSMika Westerberg     bswap_note(&en);
2397edf8e2afSMika Westerberg 
2398edf8e2afSMika Westerberg     if (dump_write(fd, &en, sizeof(en)) != 0)
2399edf8e2afSMika Westerberg         return (-1);
2400edf8e2afSMika Westerberg     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
2401edf8e2afSMika Westerberg         return (-1);
240280f5ce75SLaurent Vivier     if (dump_write(fd, men->data, men->datasz_rounded) != 0)
2403edf8e2afSMika Westerberg         return (-1);
2404edf8e2afSMika Westerberg 
2405edf8e2afSMika Westerberg     return (0);
2406edf8e2afSMika Westerberg }
2407edf8e2afSMika Westerberg 
2408edf8e2afSMika Westerberg static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
2409edf8e2afSMika Westerberg {
2410edf8e2afSMika Westerberg     TaskState *ts = (TaskState *)env->opaque;
2411edf8e2afSMika Westerberg     struct elf_thread_status *ets;
2412edf8e2afSMika Westerberg 
2413edf8e2afSMika Westerberg     ets = qemu_mallocz(sizeof (*ets));
2414edf8e2afSMika Westerberg     ets->num_notes = 1; /* only prstatus is dumped */
2415edf8e2afSMika Westerberg     fill_prstatus(&ets->prstatus, ts, 0);
2416edf8e2afSMika Westerberg     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
2417edf8e2afSMika Westerberg     fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
2418edf8e2afSMika Westerberg               &ets->prstatus);
2419edf8e2afSMika Westerberg 
242072cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
2421edf8e2afSMika Westerberg 
2422edf8e2afSMika Westerberg     info->notes_size += note_size(&ets->notes[0]);
2423edf8e2afSMika Westerberg }
2424edf8e2afSMika Westerberg 
2425edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *info,
2426edf8e2afSMika Westerberg                           long signr, const CPUState *env)
2427edf8e2afSMika Westerberg {
2428edf8e2afSMika Westerberg #define NUMNOTES 3
2429edf8e2afSMika Westerberg     CPUState *cpu = NULL;
2430edf8e2afSMika Westerberg     TaskState *ts = (TaskState *)env->opaque;
2431edf8e2afSMika Westerberg     int i;
2432edf8e2afSMika Westerberg 
2433edf8e2afSMika Westerberg     (void) memset(info, 0, sizeof (*info));
2434edf8e2afSMika Westerberg 
243572cf2d4fSBlue Swirl     QTAILQ_INIT(&info->thread_list);
2436edf8e2afSMika Westerberg 
2437edf8e2afSMika Westerberg     info->notes = qemu_mallocz(NUMNOTES * sizeof (struct memelfnote));
2438edf8e2afSMika Westerberg     if (info->notes == NULL)
2439edf8e2afSMika Westerberg         return (-ENOMEM);
2440edf8e2afSMika Westerberg     info->prstatus = qemu_mallocz(sizeof (*info->prstatus));
2441edf8e2afSMika Westerberg     if (info->prstatus == NULL)
2442edf8e2afSMika Westerberg         return (-ENOMEM);
2443edf8e2afSMika Westerberg     info->psinfo = qemu_mallocz(sizeof (*info->psinfo));
2444edf8e2afSMika Westerberg     if (info->prstatus == NULL)
2445edf8e2afSMika Westerberg         return (-ENOMEM);
2446edf8e2afSMika Westerberg 
2447edf8e2afSMika Westerberg     /*
2448edf8e2afSMika Westerberg      * First fill in status (and registers) of current thread
2449edf8e2afSMika Westerberg      * including process info & aux vector.
2450edf8e2afSMika Westerberg      */
2451edf8e2afSMika Westerberg     fill_prstatus(info->prstatus, ts, signr);
2452edf8e2afSMika Westerberg     elf_core_copy_regs(&info->prstatus->pr_reg, env);
2453edf8e2afSMika Westerberg     fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
2454edf8e2afSMika Westerberg               sizeof (*info->prstatus), info->prstatus);
2455edf8e2afSMika Westerberg     fill_psinfo(info->psinfo, ts);
2456edf8e2afSMika Westerberg     fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
2457edf8e2afSMika Westerberg               sizeof (*info->psinfo), info->psinfo);
2458edf8e2afSMika Westerberg     fill_auxv_note(&info->notes[2], ts);
2459edf8e2afSMika Westerberg     info->numnote = 3;
2460edf8e2afSMika Westerberg 
2461edf8e2afSMika Westerberg     info->notes_size = 0;
2462edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
2463edf8e2afSMika Westerberg         info->notes_size += note_size(&info->notes[i]);
2464edf8e2afSMika Westerberg 
2465edf8e2afSMika Westerberg     /* read and fill status of all threads */
2466edf8e2afSMika Westerberg     cpu_list_lock();
2467edf8e2afSMika Westerberg     for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
2468edf8e2afSMika Westerberg         if (cpu == thread_env)
2469edf8e2afSMika Westerberg             continue;
2470edf8e2afSMika Westerberg         fill_thread_info(info, cpu);
2471edf8e2afSMika Westerberg     }
2472edf8e2afSMika Westerberg     cpu_list_unlock();
2473edf8e2afSMika Westerberg 
2474edf8e2afSMika Westerberg     return (0);
2475edf8e2afSMika Westerberg }
2476edf8e2afSMika Westerberg 
2477edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *info)
2478edf8e2afSMika Westerberg {
2479edf8e2afSMika Westerberg     struct elf_thread_status *ets;
2480edf8e2afSMika Westerberg 
248172cf2d4fSBlue Swirl     while (!QTAILQ_EMPTY(&info->thread_list)) {
248272cf2d4fSBlue Swirl         ets = QTAILQ_FIRST(&info->thread_list);
248372cf2d4fSBlue Swirl         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
2484edf8e2afSMika Westerberg         qemu_free(ets);
2485edf8e2afSMika Westerberg     }
2486edf8e2afSMika Westerberg 
2487edf8e2afSMika Westerberg     qemu_free(info->prstatus);
2488edf8e2afSMika Westerberg     qemu_free(info->psinfo);
2489edf8e2afSMika Westerberg     qemu_free(info->notes);
2490edf8e2afSMika Westerberg }
2491edf8e2afSMika Westerberg 
2492edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *info, int fd)
2493edf8e2afSMika Westerberg {
2494edf8e2afSMika Westerberg     struct elf_thread_status *ets;
2495edf8e2afSMika Westerberg     int i, error = 0;
2496edf8e2afSMika Westerberg 
2497edf8e2afSMika Westerberg     /* write prstatus, psinfo and auxv for current thread */
2498edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
2499edf8e2afSMika Westerberg         if ((error = write_note(&info->notes[i], fd)) != 0)
2500edf8e2afSMika Westerberg             return (error);
2501edf8e2afSMika Westerberg 
2502edf8e2afSMika Westerberg     /* write prstatus for each thread */
2503edf8e2afSMika Westerberg     for (ets = info->thread_list.tqh_first; ets != NULL;
2504edf8e2afSMika Westerberg          ets = ets->ets_link.tqe_next) {
2505edf8e2afSMika Westerberg         if ((error = write_note(&ets->notes[0], fd)) != 0)
2506edf8e2afSMika Westerberg             return (error);
2507edf8e2afSMika Westerberg     }
2508edf8e2afSMika Westerberg 
2509edf8e2afSMika Westerberg     return (0);
2510edf8e2afSMika Westerberg }
2511edf8e2afSMika Westerberg 
2512edf8e2afSMika Westerberg /*
2513edf8e2afSMika Westerberg  * Write out ELF coredump.
2514edf8e2afSMika Westerberg  *
2515edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
2516edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
2517edf8e2afSMika Westerberg  *
2518edf8e2afSMika Westerberg  * Coredump format in linux is following:
2519edf8e2afSMika Westerberg  *
2520edf8e2afSMika Westerberg  * 0   +----------------------+         \
2521edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
2522edf8e2afSMika Westerberg  *     +----------------------+          |
2523edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
2524edf8e2afSMika Westerberg  *     | - NOTE section       |          |
2525edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
2526edf8e2afSMika Westerberg  *     +----------------------+         /
2527edf8e2afSMika Westerberg  *     | NOTEs:               |
2528edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
2529edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
2530edf8e2afSMika Westerberg  *     | - NT_AUXV            |
2531edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
2532edf8e2afSMika Westerberg  *     | Process memory dump  |
2533edf8e2afSMika Westerberg  *     :                      :
2534edf8e2afSMika Westerberg  *     .                      .
2535edf8e2afSMika Westerberg  *     :                      :
2536edf8e2afSMika Westerberg  *     |                      |
2537edf8e2afSMika Westerberg  *     +----------------------+
2538edf8e2afSMika Westerberg  *
2539edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
2540edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
2541edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
2542edf8e2afSMika Westerberg  *
2543edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
2544edf8e2afSMika Westerberg  * version limitations are as follows:
2545edf8e2afSMika Westerberg  *     - no floating point registers are dumped
2546edf8e2afSMika Westerberg  *
2547edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
2548edf8e2afSMika Westerberg  *
2549edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
2550edf8e2afSMika Westerberg  * possible to force coredump from running process and then
2551edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
2552edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
2553edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
2554edf8e2afSMika Westerberg  */
2555edf8e2afSMika Westerberg static int elf_core_dump(int signr, const CPUState *env)
2556edf8e2afSMika Westerberg {
2557edf8e2afSMika Westerberg     const TaskState *ts = (const TaskState *)env->opaque;
2558edf8e2afSMika Westerberg     struct vm_area_struct *vma = NULL;
2559edf8e2afSMika Westerberg     char corefile[PATH_MAX];
2560edf8e2afSMika Westerberg     struct elf_note_info info;
2561edf8e2afSMika Westerberg     struct elfhdr elf;
2562edf8e2afSMika Westerberg     struct elf_phdr phdr;
2563edf8e2afSMika Westerberg     struct rlimit dumpsize;
2564edf8e2afSMika Westerberg     struct mm_struct *mm = NULL;
2565edf8e2afSMika Westerberg     off_t offset = 0, data_offset = 0;
2566edf8e2afSMika Westerberg     int segs = 0;
2567edf8e2afSMika Westerberg     int fd = -1;
2568edf8e2afSMika Westerberg 
2569edf8e2afSMika Westerberg     errno = 0;
2570edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
2571edf8e2afSMika Westerberg     if (dumpsize.rlim_cur == 0)
2572edf8e2afSMika Westerberg         return 0;
2573edf8e2afSMika Westerberg 
2574edf8e2afSMika Westerberg     if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
2575edf8e2afSMika Westerberg         return (-errno);
2576edf8e2afSMika Westerberg 
2577edf8e2afSMika Westerberg     if ((fd = open(corefile, O_WRONLY | O_CREAT,
2578edf8e2afSMika Westerberg                    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
2579edf8e2afSMika Westerberg         return (-errno);
2580edf8e2afSMika Westerberg 
2581edf8e2afSMika Westerberg     /*
2582edf8e2afSMika Westerberg      * Walk through target process memory mappings and
2583edf8e2afSMika Westerberg      * set up structure containing this information.  After
2584edf8e2afSMika Westerberg      * this point vma_xxx functions can be used.
2585edf8e2afSMika Westerberg      */
2586edf8e2afSMika Westerberg     if ((mm = vma_init()) == NULL)
2587edf8e2afSMika Westerberg         goto out;
2588edf8e2afSMika Westerberg 
2589edf8e2afSMika Westerberg     walk_memory_regions(mm, vma_walker);
2590edf8e2afSMika Westerberg     segs = vma_get_mapping_count(mm);
2591edf8e2afSMika Westerberg 
2592edf8e2afSMika Westerberg     /*
2593edf8e2afSMika Westerberg      * Construct valid coredump ELF header.  We also
2594edf8e2afSMika Westerberg      * add one more segment for notes.
2595edf8e2afSMika Westerberg      */
2596edf8e2afSMika Westerberg     fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
2597edf8e2afSMika Westerberg     if (dump_write(fd, &elf, sizeof (elf)) != 0)
2598edf8e2afSMika Westerberg         goto out;
2599edf8e2afSMika Westerberg 
2600edf8e2afSMika Westerberg     /* fill in in-memory version of notes */
2601edf8e2afSMika Westerberg     if (fill_note_info(&info, signr, env) < 0)
2602edf8e2afSMika Westerberg         goto out;
2603edf8e2afSMika Westerberg 
2604edf8e2afSMika Westerberg     offset += sizeof (elf);                             /* elf header */
2605edf8e2afSMika Westerberg     offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
2606edf8e2afSMika Westerberg 
2607edf8e2afSMika Westerberg     /* write out notes program header */
2608edf8e2afSMika Westerberg     fill_elf_note_phdr(&phdr, info.notes_size, offset);
2609edf8e2afSMika Westerberg 
2610edf8e2afSMika Westerberg     offset += info.notes_size;
2611edf8e2afSMika Westerberg     if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
2612edf8e2afSMika Westerberg         goto out;
2613edf8e2afSMika Westerberg 
2614edf8e2afSMika Westerberg     /*
2615edf8e2afSMika Westerberg      * ELF specification wants data to start at page boundary so
2616edf8e2afSMika Westerberg      * we align it here.
2617edf8e2afSMika Westerberg      */
261880f5ce75SLaurent Vivier     data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
2619edf8e2afSMika Westerberg 
2620edf8e2afSMika Westerberg     /*
2621edf8e2afSMika Westerberg      * Write program headers for memory regions mapped in
2622edf8e2afSMika Westerberg      * the target process.
2623edf8e2afSMika Westerberg      */
2624edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
2625edf8e2afSMika Westerberg         (void) memset(&phdr, 0, sizeof (phdr));
2626edf8e2afSMika Westerberg 
2627edf8e2afSMika Westerberg         phdr.p_type = PT_LOAD;
2628edf8e2afSMika Westerberg         phdr.p_offset = offset;
2629edf8e2afSMika Westerberg         phdr.p_vaddr = vma->vma_start;
2630edf8e2afSMika Westerberg         phdr.p_paddr = 0;
2631edf8e2afSMika Westerberg         phdr.p_filesz = vma_dump_size(vma);
2632edf8e2afSMika Westerberg         offset += phdr.p_filesz;
2633edf8e2afSMika Westerberg         phdr.p_memsz = vma->vma_end - vma->vma_start;
2634edf8e2afSMika Westerberg         phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
2635edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_WRITE)
2636edf8e2afSMika Westerberg             phdr.p_flags |= PF_W;
2637edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_EXEC)
2638edf8e2afSMika Westerberg             phdr.p_flags |= PF_X;
2639edf8e2afSMika Westerberg         phdr.p_align = ELF_EXEC_PAGESIZE;
2640edf8e2afSMika Westerberg 
264180f5ce75SLaurent Vivier         bswap_phdr(&phdr, 1);
2642edf8e2afSMika Westerberg         dump_write(fd, &phdr, sizeof (phdr));
2643edf8e2afSMika Westerberg     }
2644edf8e2afSMika Westerberg 
2645edf8e2afSMika Westerberg     /*
2646edf8e2afSMika Westerberg      * Next we write notes just after program headers.  No
2647edf8e2afSMika Westerberg      * alignment needed here.
2648edf8e2afSMika Westerberg      */
2649edf8e2afSMika Westerberg     if (write_note_info(&info, fd) < 0)
2650edf8e2afSMika Westerberg         goto out;
2651edf8e2afSMika Westerberg 
2652edf8e2afSMika Westerberg     /* align data to page boundary */
2653edf8e2afSMika Westerberg     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
2654edf8e2afSMika Westerberg         goto out;
2655edf8e2afSMika Westerberg 
2656edf8e2afSMika Westerberg     /*
2657edf8e2afSMika Westerberg      * Finally we can dump process memory into corefile as well.
2658edf8e2afSMika Westerberg      */
2659edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
2660edf8e2afSMika Westerberg         abi_ulong addr;
2661edf8e2afSMika Westerberg         abi_ulong end;
2662edf8e2afSMika Westerberg 
2663edf8e2afSMika Westerberg         end = vma->vma_start + vma_dump_size(vma);
2664edf8e2afSMika Westerberg 
2665edf8e2afSMika Westerberg         for (addr = vma->vma_start; addr < end;
2666edf8e2afSMika Westerberg              addr += TARGET_PAGE_SIZE) {
2667edf8e2afSMika Westerberg             char page[TARGET_PAGE_SIZE];
2668edf8e2afSMika Westerberg             int error;
2669edf8e2afSMika Westerberg 
2670edf8e2afSMika Westerberg             /*
2671edf8e2afSMika Westerberg              *  Read in page from target process memory and
2672edf8e2afSMika Westerberg              *  write it to coredump file.
2673edf8e2afSMika Westerberg              */
2674edf8e2afSMika Westerberg             error = copy_from_user(page, addr, sizeof (page));
2675edf8e2afSMika Westerberg             if (error != 0) {
267649995e17SAurelien Jarno                 (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
2677edf8e2afSMika Westerberg                                addr);
2678edf8e2afSMika Westerberg                 errno = -error;
2679edf8e2afSMika Westerberg                 goto out;
2680edf8e2afSMika Westerberg             }
2681edf8e2afSMika Westerberg             if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
2682edf8e2afSMika Westerberg                 goto out;
2683edf8e2afSMika Westerberg         }
2684edf8e2afSMika Westerberg     }
2685edf8e2afSMika Westerberg 
2686edf8e2afSMika Westerberg  out:
2687edf8e2afSMika Westerberg     free_note_info(&info);
2688edf8e2afSMika Westerberg     if (mm != NULL)
2689edf8e2afSMika Westerberg         vma_delete(mm);
2690edf8e2afSMika Westerberg     (void) close(fd);
2691edf8e2afSMika Westerberg 
2692edf8e2afSMika Westerberg     if (errno != 0)
2693edf8e2afSMika Westerberg         return (-errno);
2694edf8e2afSMika Westerberg     return (0);
2695edf8e2afSMika Westerberg }
2696edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
2697edf8e2afSMika Westerberg 
2698e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
2699e5fe0c52Spbrook {
2700e5fe0c52Spbrook     init_thread(regs, infop);
2701e5fe0c52Spbrook }
2702