xref: /qemu/linux-user/elfload.c (revision 9f9f030928a3d17ea8b87905fafc1e447328df2d)
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 */
39cb33da57Sblueswir1 	FDPIC_FUNCPTRS =	0x0080000,	/* userspace function ptrs point to descriptors
40cb33da57Sblueswir1 						 * (signal handling)
41cb33da57Sblueswir1 						 */
42cb33da57Sblueswir1 	MMAP_PAGE_ZERO =	0x0100000,
43cb33da57Sblueswir1 	ADDR_COMPAT_LAYOUT =	0x0200000,
44cb33da57Sblueswir1 	READ_IMPLIES_EXEC =	0x0400000,
45cb33da57Sblueswir1 	ADDR_LIMIT_32BIT =	0x0800000,
46cb33da57Sblueswir1 	SHORT_INODE =		0x1000000,
47cb33da57Sblueswir1 	WHOLE_SECONDS =		0x2000000,
48cb33da57Sblueswir1 	STICKY_TIMEOUTS	=	0x4000000,
49cb33da57Sblueswir1 	ADDR_LIMIT_3GB = 	0x8000000,
50cb33da57Sblueswir1 };
51cb33da57Sblueswir1 
52cb33da57Sblueswir1 /*
53cb33da57Sblueswir1  * Personality types.
54cb33da57Sblueswir1  *
55cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
56cb33da57Sblueswir1  * conflict with error returns.
57cb33da57Sblueswir1  */
58cb33da57Sblueswir1 enum {
59cb33da57Sblueswir1 	PER_LINUX =		0x0000,
60cb33da57Sblueswir1 	PER_LINUX_32BIT =	0x0000 | ADDR_LIMIT_32BIT,
61cb33da57Sblueswir1 	PER_LINUX_FDPIC =	0x0000 | FDPIC_FUNCPTRS,
62cb33da57Sblueswir1 	PER_SVR4 =		0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
63cb33da57Sblueswir1 	PER_SVR3 =		0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
64cb33da57Sblueswir1 	PER_SCOSVR3 =		0x0003 | STICKY_TIMEOUTS |
65cb33da57Sblueswir1 					 WHOLE_SECONDS | SHORT_INODE,
66cb33da57Sblueswir1 	PER_OSR5 =		0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
67cb33da57Sblueswir1 	PER_WYSEV386 =		0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
68cb33da57Sblueswir1 	PER_ISCR4 =		0x0005 | STICKY_TIMEOUTS,
69cb33da57Sblueswir1 	PER_BSD =		0x0006,
70cb33da57Sblueswir1 	PER_SUNOS =		0x0006 | STICKY_TIMEOUTS,
71cb33da57Sblueswir1 	PER_XENIX =		0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
72cb33da57Sblueswir1 	PER_LINUX32 =		0x0008,
73cb33da57Sblueswir1 	PER_LINUX32_3GB =	0x0008 | ADDR_LIMIT_3GB,
74cb33da57Sblueswir1 	PER_IRIX32 =		0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
75cb33da57Sblueswir1 	PER_IRIXN32 =		0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
76cb33da57Sblueswir1 	PER_IRIX64 =		0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
77cb33da57Sblueswir1 	PER_RISCOS =		0x000c,
78cb33da57Sblueswir1 	PER_SOLARIS =		0x000d | STICKY_TIMEOUTS,
79cb33da57Sblueswir1 	PER_UW7 =		0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
80cb33da57Sblueswir1 	PER_OSF4 =		0x000f,			 /* OSF/1 v4 */
81cb33da57Sblueswir1 	PER_HPUX =		0x0010,
82cb33da57Sblueswir1 	PER_MASK =		0x00ff,
83cb33da57Sblueswir1 };
84cb33da57Sblueswir1 
85cb33da57Sblueswir1 /*
86cb33da57Sblueswir1  * Return the base personality without flags.
87cb33da57Sblueswir1  */
88cb33da57Sblueswir1 #define personality(pers)	(pers & PER_MASK)
89cb33da57Sblueswir1 
9083fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
9183fb7adfSbellard #ifndef MAP_DENYWRITE
9283fb7adfSbellard #define MAP_DENYWRITE 0
9383fb7adfSbellard #endif
9483fb7adfSbellard 
9583fb7adfSbellard /* should probably go in elf.h */
9683fb7adfSbellard #ifndef ELIBBAD
9783fb7adfSbellard #define ELIBBAD 80
9883fb7adfSbellard #endif
9983fb7adfSbellard 
10021e807faSNathan Froyd typedef target_ulong	target_elf_greg_t;
10121e807faSNathan Froyd #ifdef USE_UID16
10221e807faSNathan Froyd typedef uint16_t	target_uid_t;
10321e807faSNathan Froyd typedef uint16_t	target_gid_t;
10421e807faSNathan Froyd #else
10521e807faSNathan Froyd typedef uint32_t	target_uid_t;
10621e807faSNathan Froyd typedef uint32_t	target_gid_t;
10721e807faSNathan Froyd #endif
10821e807faSNathan Froyd typedef int32_t		target_pid_t;
10921e807faSNathan Froyd 
11030ac07d4Sbellard #ifdef TARGET_I386
11130ac07d4Sbellard 
11215338fd7Sbellard #define ELF_PLATFORM get_elf_platform()
11315338fd7Sbellard 
11415338fd7Sbellard static const char *get_elf_platform(void)
11515338fd7Sbellard {
11615338fd7Sbellard     static char elf_platform[] = "i386";
117d5975363Spbrook     int family = (thread_env->cpuid_version >> 8) & 0xff;
11815338fd7Sbellard     if (family > 6)
11915338fd7Sbellard         family = 6;
12015338fd7Sbellard     if (family >= 3)
12115338fd7Sbellard         elf_platform[1] = '0' + family;
12215338fd7Sbellard     return elf_platform;
12315338fd7Sbellard }
12415338fd7Sbellard 
12515338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
12615338fd7Sbellard 
12715338fd7Sbellard static uint32_t get_elf_hwcap(void)
12815338fd7Sbellard {
129d5975363Spbrook   return thread_env->cpuid_features;
13015338fd7Sbellard }
13115338fd7Sbellard 
13284409ddbSj_mayer #ifdef TARGET_X86_64
13384409ddbSj_mayer #define ELF_START_MMAP 0x2aaaaab000ULL
13484409ddbSj_mayer #define elf_check_arch(x) ( ((x) == ELF_ARCH) )
13584409ddbSj_mayer 
13684409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
13784409ddbSj_mayer #define ELF_DATA       ELFDATA2LSB
13884409ddbSj_mayer #define ELF_ARCH       EM_X86_64
13984409ddbSj_mayer 
14084409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
14184409ddbSj_mayer {
14284409ddbSj_mayer     regs->rax = 0;
14384409ddbSj_mayer     regs->rsp = infop->start_stack;
14484409ddbSj_mayer     regs->rip = infop->entry;
14584409ddbSj_mayer }
14684409ddbSj_mayer 
1479edc5d79SMika Westerberg #define ELF_NREG    27
148c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
1499edc5d79SMika Westerberg 
1509edc5d79SMika Westerberg /*
1519edc5d79SMika Westerberg  * Note that ELF_NREG should be 29 as there should be place for
1529edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
1539edc5d79SMika Westerberg  * those.
1549edc5d79SMika Westerberg  *
1559edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
1569edc5d79SMika Westerberg  */
157c227f099SAnthony Liguori static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
1589edc5d79SMika Westerberg {
1599edc5d79SMika Westerberg     (*regs)[0] = env->regs[15];
1609edc5d79SMika Westerberg     (*regs)[1] = env->regs[14];
1619edc5d79SMika Westerberg     (*regs)[2] = env->regs[13];
1629edc5d79SMika Westerberg     (*regs)[3] = env->regs[12];
1639edc5d79SMika Westerberg     (*regs)[4] = env->regs[R_EBP];
1649edc5d79SMika Westerberg     (*regs)[5] = env->regs[R_EBX];
1659edc5d79SMika Westerberg     (*regs)[6] = env->regs[11];
1669edc5d79SMika Westerberg     (*regs)[7] = env->regs[10];
1679edc5d79SMika Westerberg     (*regs)[8] = env->regs[9];
1689edc5d79SMika Westerberg     (*regs)[9] = env->regs[8];
1699edc5d79SMika Westerberg     (*regs)[10] = env->regs[R_EAX];
1709edc5d79SMika Westerberg     (*regs)[11] = env->regs[R_ECX];
1719edc5d79SMika Westerberg     (*regs)[12] = env->regs[R_EDX];
1729edc5d79SMika Westerberg     (*regs)[13] = env->regs[R_ESI];
1739edc5d79SMika Westerberg     (*regs)[14] = env->regs[R_EDI];
1749edc5d79SMika Westerberg     (*regs)[15] = env->regs[R_EAX]; /* XXX */
1759edc5d79SMika Westerberg     (*regs)[16] = env->eip;
1769edc5d79SMika Westerberg     (*regs)[17] = env->segs[R_CS].selector & 0xffff;
1779edc5d79SMika Westerberg     (*regs)[18] = env->eflags;
1789edc5d79SMika Westerberg     (*regs)[19] = env->regs[R_ESP];
1799edc5d79SMika Westerberg     (*regs)[20] = env->segs[R_SS].selector & 0xffff;
1809edc5d79SMika Westerberg     (*regs)[21] = env->segs[R_FS].selector & 0xffff;
1819edc5d79SMika Westerberg     (*regs)[22] = env->segs[R_GS].selector & 0xffff;
1829edc5d79SMika Westerberg     (*regs)[23] = env->segs[R_DS].selector & 0xffff;
1839edc5d79SMika Westerberg     (*regs)[24] = env->segs[R_ES].selector & 0xffff;
1849edc5d79SMika Westerberg     (*regs)[25] = env->segs[R_FS].selector & 0xffff;
1859edc5d79SMika Westerberg     (*regs)[26] = env->segs[R_GS].selector & 0xffff;
1869edc5d79SMika Westerberg }
1879edc5d79SMika Westerberg 
18884409ddbSj_mayer #else
18984409ddbSj_mayer 
19030ac07d4Sbellard #define ELF_START_MMAP 0x80000000
19130ac07d4Sbellard 
19230ac07d4Sbellard /*
19330ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
19430ac07d4Sbellard  */
19530ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
19630ac07d4Sbellard 
19730ac07d4Sbellard /*
19830ac07d4Sbellard  * These are used to set parameters in the core dumps.
19930ac07d4Sbellard  */
20030ac07d4Sbellard #define ELF_CLASS	ELFCLASS32
20130ac07d4Sbellard #define ELF_DATA	ELFDATA2LSB
20230ac07d4Sbellard #define ELF_ARCH	EM_386
20330ac07d4Sbellard 
204e5fe0c52Spbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
205e5fe0c52Spbrook {
206e5fe0c52Spbrook     regs->esp = infop->start_stack;
207e5fe0c52Spbrook     regs->eip = infop->entry;
208e5fe0c52Spbrook 
20930ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
21030ac07d4Sbellard        starts %edx contains a pointer to a function which might be
21130ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
21230ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
21330ac07d4Sbellard        that have been loaded before the code runs.
21430ac07d4Sbellard 
21530ac07d4Sbellard        A value of 0 tells we have no such handler.  */
216e5fe0c52Spbrook     regs->edx = 0;
217b346ff46Sbellard }
2189edc5d79SMika Westerberg 
2199edc5d79SMika Westerberg #define ELF_NREG    17
220c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
2219edc5d79SMika Westerberg 
2229edc5d79SMika Westerberg /*
2239edc5d79SMika Westerberg  * Note that ELF_NREG should be 19 as there should be place for
2249edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
2259edc5d79SMika Westerberg  * those.
2269edc5d79SMika Westerberg  *
2279edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
2289edc5d79SMika Westerberg  */
229c227f099SAnthony Liguori static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
2309edc5d79SMika Westerberg {
2319edc5d79SMika Westerberg     (*regs)[0] = env->regs[R_EBX];
2329edc5d79SMika Westerberg     (*regs)[1] = env->regs[R_ECX];
2339edc5d79SMika Westerberg     (*regs)[2] = env->regs[R_EDX];
2349edc5d79SMika Westerberg     (*regs)[3] = env->regs[R_ESI];
2359edc5d79SMika Westerberg     (*regs)[4] = env->regs[R_EDI];
2369edc5d79SMika Westerberg     (*regs)[5] = env->regs[R_EBP];
2379edc5d79SMika Westerberg     (*regs)[6] = env->regs[R_EAX];
2389edc5d79SMika Westerberg     (*regs)[7] = env->segs[R_DS].selector & 0xffff;
2399edc5d79SMika Westerberg     (*regs)[8] = env->segs[R_ES].selector & 0xffff;
2409edc5d79SMika Westerberg     (*regs)[9] = env->segs[R_FS].selector & 0xffff;
2419edc5d79SMika Westerberg     (*regs)[10] = env->segs[R_GS].selector & 0xffff;
2429edc5d79SMika Westerberg     (*regs)[11] = env->regs[R_EAX]; /* XXX */
2439edc5d79SMika Westerberg     (*regs)[12] = env->eip;
2449edc5d79SMika Westerberg     (*regs)[13] = env->segs[R_CS].selector & 0xffff;
2459edc5d79SMika Westerberg     (*regs)[14] = env->eflags;
2469edc5d79SMika Westerberg     (*regs)[15] = env->regs[R_ESP];
2479edc5d79SMika Westerberg     (*regs)[16] = env->segs[R_SS].selector & 0xffff;
2489edc5d79SMika Westerberg }
24984409ddbSj_mayer #endif
250b346ff46Sbellard 
2519edc5d79SMika Westerberg #define USE_ELF_CORE_DUMP
252b346ff46Sbellard #define ELF_EXEC_PAGESIZE	4096
253b346ff46Sbellard 
254b346ff46Sbellard #endif
255b346ff46Sbellard 
256b346ff46Sbellard #ifdef TARGET_ARM
257b346ff46Sbellard 
258b346ff46Sbellard #define ELF_START_MMAP 0x80000000
259b346ff46Sbellard 
260b346ff46Sbellard #define elf_check_arch(x) ( (x) == EM_ARM )
261b346ff46Sbellard 
262b346ff46Sbellard #define ELF_CLASS	ELFCLASS32
263b346ff46Sbellard #ifdef TARGET_WORDS_BIGENDIAN
264b346ff46Sbellard #define ELF_DATA	ELFDATA2MSB
265b346ff46Sbellard #else
266b346ff46Sbellard #define ELF_DATA	ELFDATA2LSB
267b346ff46Sbellard #endif
268b346ff46Sbellard #define ELF_ARCH	EM_ARM
269b346ff46Sbellard 
270b346ff46Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
271b346ff46Sbellard {
272992f48a0Sblueswir1     abi_long stack = infop->start_stack;
273b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
274b346ff46Sbellard     regs->ARM_cpsr = 0x10;
2750240ded8Spbrook     if (infop->entry & 1)
2760240ded8Spbrook       regs->ARM_cpsr |= CPSR_T;
2770240ded8Spbrook     regs->ARM_pc = infop->entry & 0xfffffffe;
278b346ff46Sbellard     regs->ARM_sp = infop->start_stack;
2792f619698Sbellard     /* FIXME - what to for failure of get_user()? */
2802f619698Sbellard     get_user_ual(regs->ARM_r2, stack + 8); /* envp */
2812f619698Sbellard     get_user_ual(regs->ARM_r1, stack + 4); /* envp */
282a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
283e5fe0c52Spbrook     regs->ARM_r0 = 0;
284e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
285863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
286e5fe0c52Spbrook     regs->ARM_r10 = infop->start_data;
287b346ff46Sbellard }
288b346ff46Sbellard 
289edf8e2afSMika Westerberg #define ELF_NREG    18
290c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
291edf8e2afSMika Westerberg 
292c227f099SAnthony Liguori static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
293edf8e2afSMika Westerberg {
294d049e626SNathan Froyd     (*regs)[0] = tswapl(env->regs[0]);
295d049e626SNathan Froyd     (*regs)[1] = tswapl(env->regs[1]);
296d049e626SNathan Froyd     (*regs)[2] = tswapl(env->regs[2]);
297d049e626SNathan Froyd     (*regs)[3] = tswapl(env->regs[3]);
298d049e626SNathan Froyd     (*regs)[4] = tswapl(env->regs[4]);
299d049e626SNathan Froyd     (*regs)[5] = tswapl(env->regs[5]);
300d049e626SNathan Froyd     (*regs)[6] = tswapl(env->regs[6]);
301d049e626SNathan Froyd     (*regs)[7] = tswapl(env->regs[7]);
302d049e626SNathan Froyd     (*regs)[8] = tswapl(env->regs[8]);
303d049e626SNathan Froyd     (*regs)[9] = tswapl(env->regs[9]);
304d049e626SNathan Froyd     (*regs)[10] = tswapl(env->regs[10]);
305d049e626SNathan Froyd     (*regs)[11] = tswapl(env->regs[11]);
306d049e626SNathan Froyd     (*regs)[12] = tswapl(env->regs[12]);
307d049e626SNathan Froyd     (*regs)[13] = tswapl(env->regs[13]);
308d049e626SNathan Froyd     (*regs)[14] = tswapl(env->regs[14]);
309d049e626SNathan Froyd     (*regs)[15] = tswapl(env->regs[15]);
310edf8e2afSMika Westerberg 
311d049e626SNathan Froyd     (*regs)[16] = tswapl(cpsr_read((CPUState *)env));
312d049e626SNathan Froyd     (*regs)[17] = tswapl(env->regs[0]); /* XXX */
313edf8e2afSMika Westerberg }
314edf8e2afSMika Westerberg 
31530ac07d4Sbellard #define USE_ELF_CORE_DUMP
31630ac07d4Sbellard #define ELF_EXEC_PAGESIZE	4096
31730ac07d4Sbellard 
318afce2927Sbellard enum
319afce2927Sbellard {
320afce2927Sbellard   ARM_HWCAP_ARM_SWP       = 1 << 0,
321afce2927Sbellard   ARM_HWCAP_ARM_HALF      = 1 << 1,
322afce2927Sbellard   ARM_HWCAP_ARM_THUMB     = 1 << 2,
323afce2927Sbellard   ARM_HWCAP_ARM_26BIT     = 1 << 3,
324afce2927Sbellard   ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
325afce2927Sbellard   ARM_HWCAP_ARM_FPA       = 1 << 5,
326afce2927Sbellard   ARM_HWCAP_ARM_VFP       = 1 << 6,
327afce2927Sbellard   ARM_HWCAP_ARM_EDSP      = 1 << 7,
328cf6de34aSRiku Voipio   ARM_HWCAP_ARM_JAVA      = 1 << 8,
329cf6de34aSRiku Voipio   ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
330cf6de34aSRiku Voipio   ARM_HWCAP_ARM_THUMBEE   = 1 << 10,
331cf6de34aSRiku Voipio   ARM_HWCAP_ARM_NEON      = 1 << 11,
332cf6de34aSRiku Voipio   ARM_HWCAP_ARM_VFPv3     = 1 << 12,
333cf6de34aSRiku Voipio   ARM_HWCAP_ARM_VFPv3D16  = 1 << 13,
334afce2927Sbellard };
335afce2927Sbellard 
33615338fd7Sbellard #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
337afce2927Sbellard                     | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
338cf6de34aSRiku Voipio                     | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP \
339cf6de34aSRiku Voipio                     | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 )
340afce2927Sbellard 
34130ac07d4Sbellard #endif
34230ac07d4Sbellard 
343853d6f7aSbellard #ifdef TARGET_SPARC
344a315a145Sbellard #ifdef TARGET_SPARC64
345853d6f7aSbellard 
346853d6f7aSbellard #define ELF_START_MMAP 0x80000000
347853d6f7aSbellard 
348992f48a0Sblueswir1 #ifndef TARGET_ABI32
349cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
350992f48a0Sblueswir1 #else
351992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
352992f48a0Sblueswir1 #endif
353853d6f7aSbellard 
354a315a145Sbellard #define ELF_CLASS   ELFCLASS64
355a315a145Sbellard #define ELF_DATA    ELFDATA2MSB
3565ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
3575ef54116Sbellard 
3585ef54116Sbellard #define STACK_BIAS		2047
359a315a145Sbellard 
360a315a145Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
361a315a145Sbellard {
362992f48a0Sblueswir1 #ifndef TARGET_ABI32
363a315a145Sbellard     regs->tstate = 0;
364992f48a0Sblueswir1 #endif
365a315a145Sbellard     regs->pc = infop->entry;
366a315a145Sbellard     regs->npc = regs->pc + 4;
367a315a145Sbellard     regs->y = 0;
368992f48a0Sblueswir1 #ifdef TARGET_ABI32
369992f48a0Sblueswir1     regs->u_regs[14] = infop->start_stack - 16 * 4;
370992f48a0Sblueswir1 #else
371cb33da57Sblueswir1     if (personality(infop->personality) == PER_LINUX32)
372cb33da57Sblueswir1         regs->u_regs[14] = infop->start_stack - 16 * 4;
373cb33da57Sblueswir1     else
3745ef54116Sbellard         regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
375992f48a0Sblueswir1 #endif
376a315a145Sbellard }
377a315a145Sbellard 
378a315a145Sbellard #else
379a315a145Sbellard #define ELF_START_MMAP 0x80000000
380a315a145Sbellard 
381a315a145Sbellard #define elf_check_arch(x) ( (x) == EM_SPARC )
382a315a145Sbellard 
383853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
384853d6f7aSbellard #define ELF_DATA    ELFDATA2MSB
385853d6f7aSbellard #define ELF_ARCH    EM_SPARC
386853d6f7aSbellard 
387853d6f7aSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
388853d6f7aSbellard {
389f5155289Sbellard     regs->psr = 0;
390f5155289Sbellard     regs->pc = infop->entry;
391f5155289Sbellard     regs->npc = regs->pc + 4;
392f5155289Sbellard     regs->y = 0;
393f5155289Sbellard     regs->u_regs[14] = infop->start_stack - 16 * 4;
394853d6f7aSbellard }
395853d6f7aSbellard 
396853d6f7aSbellard #endif
397a315a145Sbellard #endif
398853d6f7aSbellard 
39967867308Sbellard #ifdef TARGET_PPC
40067867308Sbellard 
40167867308Sbellard #define ELF_START_MMAP 0x80000000
40267867308Sbellard 
403e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
40484409ddbSj_mayer 
40584409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
40684409ddbSj_mayer 
40784409ddbSj_mayer #define ELF_CLASS	ELFCLASS64
40884409ddbSj_mayer 
40984409ddbSj_mayer #else
41084409ddbSj_mayer 
41167867308Sbellard #define elf_check_arch(x) ( (x) == EM_PPC )
41267867308Sbellard 
41367867308Sbellard #define ELF_CLASS	ELFCLASS32
41484409ddbSj_mayer 
41584409ddbSj_mayer #endif
41684409ddbSj_mayer 
41767867308Sbellard #ifdef TARGET_WORDS_BIGENDIAN
41867867308Sbellard #define ELF_DATA	ELFDATA2MSB
41967867308Sbellard #else
42067867308Sbellard #define ELF_DATA	ELFDATA2LSB
42167867308Sbellard #endif
42267867308Sbellard #define ELF_ARCH	EM_PPC
42367867308Sbellard 
424df84e4f3SNathan Froyd /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
425df84e4f3SNathan Froyd    See arch/powerpc/include/asm/cputable.h.  */
426df84e4f3SNathan Froyd enum {
4273efa9a67Smalc     QEMU_PPC_FEATURE_32 = 0x80000000,
4283efa9a67Smalc     QEMU_PPC_FEATURE_64 = 0x40000000,
4293efa9a67Smalc     QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
4303efa9a67Smalc     QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
4313efa9a67Smalc     QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
4323efa9a67Smalc     QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
4333efa9a67Smalc     QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
4343efa9a67Smalc     QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
4353efa9a67Smalc     QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
4363efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
4373efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
4383efa9a67Smalc     QEMU_PPC_FEATURE_NO_TB = 0x00100000,
4393efa9a67Smalc     QEMU_PPC_FEATURE_POWER4 = 0x00080000,
4403efa9a67Smalc     QEMU_PPC_FEATURE_POWER5 = 0x00040000,
4413efa9a67Smalc     QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
4423efa9a67Smalc     QEMU_PPC_FEATURE_CELL = 0x00010000,
4433efa9a67Smalc     QEMU_PPC_FEATURE_BOOKE = 0x00008000,
4443efa9a67Smalc     QEMU_PPC_FEATURE_SMT = 0x00004000,
4453efa9a67Smalc     QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
4463efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
4473efa9a67Smalc     QEMU_PPC_FEATURE_PA6T = 0x00000800,
4483efa9a67Smalc     QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
4493efa9a67Smalc     QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
4503efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
4513efa9a67Smalc     QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
4523efa9a67Smalc     QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
453df84e4f3SNathan Froyd 
4543efa9a67Smalc     QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
4553efa9a67Smalc     QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
456df84e4f3SNathan Froyd };
457df84e4f3SNathan Froyd 
458df84e4f3SNathan Froyd #define ELF_HWCAP get_elf_hwcap()
459df84e4f3SNathan Froyd 
460df84e4f3SNathan Froyd static uint32_t get_elf_hwcap(void)
461df84e4f3SNathan Froyd {
462df84e4f3SNathan Froyd     CPUState *e = thread_env;
463df84e4f3SNathan Froyd     uint32_t features = 0;
464df84e4f3SNathan Froyd 
465df84e4f3SNathan Froyd     /* We don't have to be terribly complete here; the high points are
466df84e4f3SNathan Froyd        Altivec/FP/SPE support.  Anything else is just a bonus.  */
467df84e4f3SNathan Froyd #define GET_FEATURE(flag, feature)              \
468df84e4f3SNathan Froyd     do {if (e->insns_flags & flag) features |= feature; } while(0)
4693efa9a67Smalc     GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
4703efa9a67Smalc     GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
4713efa9a67Smalc     GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
4723efa9a67Smalc     GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
4733efa9a67Smalc     GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
4743efa9a67Smalc     GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
4753efa9a67Smalc     GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
4763efa9a67Smalc     GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
477df84e4f3SNathan Froyd #undef GET_FEATURE
478df84e4f3SNathan Froyd 
479df84e4f3SNathan Froyd     return features;
480df84e4f3SNathan Froyd }
481df84e4f3SNathan Froyd 
482f5155289Sbellard /*
483f5155289Sbellard  * We need to put in some extra aux table entries to tell glibc what
484f5155289Sbellard  * the cache block size is, so it can use the dcbz instruction safely.
485f5155289Sbellard  */
486f5155289Sbellard #define AT_DCACHEBSIZE          19
487f5155289Sbellard #define AT_ICACHEBSIZE          20
488f5155289Sbellard #define AT_UCACHEBSIZE          21
489f5155289Sbellard /* A special ignored type value for PPC, for glibc compatibility.  */
490f5155289Sbellard #define AT_IGNOREPPC            22
491f5155289Sbellard /*
492f5155289Sbellard  * The requirements here are:
493f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
494f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
495f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
496f5155289Sbellard  *   AT_IGNOREPPC is used for that.
497f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
498f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
499f5155289Sbellard  */
5000bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
501f5155289Sbellard #define ARCH_DLINFO                                                     \
502f5155289Sbellard do {                                                                    \
5030bccf03dSbellard         NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
5040bccf03dSbellard         NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
5050bccf03dSbellard         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
506f5155289Sbellard         /*                                                              \
507f5155289Sbellard          * Now handle glibc compatibility.                              \
508f5155289Sbellard          */                                                             \
5090bccf03dSbellard 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
5100bccf03dSbellard 	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
511f5155289Sbellard  } while (0)
512f5155289Sbellard 
51367867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
51467867308Sbellard {
515992f48a0Sblueswir1     abi_ulong pos = infop->start_stack;
516992f48a0Sblueswir1     abi_ulong tmp;
517e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
518992f48a0Sblueswir1     abi_ulong entry, toc;
51984409ddbSj_mayer #endif
520e5fe0c52Spbrook 
52167867308Sbellard     _regs->gpr[1] = infop->start_stack;
522e85e7c6eSj_mayer #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
52384409ddbSj_mayer     entry = ldq_raw(infop->entry) + infop->load_addr;
52484409ddbSj_mayer     toc = ldq_raw(infop->entry + 8) + infop->load_addr;
52584409ddbSj_mayer     _regs->gpr[2] = toc;
52684409ddbSj_mayer     infop->entry = entry;
52784409ddbSj_mayer #endif
52867867308Sbellard     _regs->nip = infop->entry;
529e5fe0c52Spbrook     /* Note that isn't exactly what regular kernel does
530e5fe0c52Spbrook      * but this is what the ABI wants and is needed to allow
531e5fe0c52Spbrook      * execution of PPC BSD programs.
532e5fe0c52Spbrook      */
5332f619698Sbellard     /* FIXME - what to for failure of get_user()? */
5342f619698Sbellard     get_user_ual(_regs->gpr[3], pos);
535992f48a0Sblueswir1     pos += sizeof(abi_ulong);
536e5fe0c52Spbrook     _regs->gpr[4] = pos;
537992f48a0Sblueswir1     for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong))
538e5fe0c52Spbrook         tmp = ldl(pos);
539e5fe0c52Spbrook     _regs->gpr[5] = pos;
54067867308Sbellard }
54167867308Sbellard 
542e2f3e741SNathan Froyd /* See linux kernel: arch/powerpc/include/asm/elf.h.  */
543e2f3e741SNathan Froyd #define ELF_NREG 48
544e2f3e741SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
545e2f3e741SNathan Froyd 
546e2f3e741SNathan Froyd static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
547e2f3e741SNathan Froyd {
548e2f3e741SNathan Froyd     int i;
549e2f3e741SNathan Froyd     target_ulong ccr = 0;
550e2f3e741SNathan Froyd 
551e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
552e2f3e741SNathan Froyd         (*regs)[i] = tswapl(env->gpr[i]);
553e2f3e741SNathan Froyd     }
554e2f3e741SNathan Froyd 
555e2f3e741SNathan Froyd     (*regs)[32] = tswapl(env->nip);
556e2f3e741SNathan Froyd     (*regs)[33] = tswapl(env->msr);
557e2f3e741SNathan Froyd     (*regs)[35] = tswapl(env->ctr);
558e2f3e741SNathan Froyd     (*regs)[36] = tswapl(env->lr);
559e2f3e741SNathan Froyd     (*regs)[37] = tswapl(env->xer);
560e2f3e741SNathan Froyd 
561e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
562e2f3e741SNathan Froyd         ccr |= env->crf[i] << (32 - ((i + 1) * 4));
563e2f3e741SNathan Froyd     }
564e2f3e741SNathan Froyd     (*regs)[38] = tswapl(ccr);
565e2f3e741SNathan Froyd }
566e2f3e741SNathan Froyd 
567e2f3e741SNathan Froyd #define USE_ELF_CORE_DUMP
56867867308Sbellard #define ELF_EXEC_PAGESIZE	4096
56967867308Sbellard 
57067867308Sbellard #endif
57167867308Sbellard 
572048f6b4dSbellard #ifdef TARGET_MIPS
573048f6b4dSbellard 
574048f6b4dSbellard #define ELF_START_MMAP 0x80000000
575048f6b4dSbellard 
576048f6b4dSbellard #define elf_check_arch(x) ( (x) == EM_MIPS )
577048f6b4dSbellard 
578388bb21aSths #ifdef TARGET_MIPS64
579388bb21aSths #define ELF_CLASS   ELFCLASS64
580388bb21aSths #else
581048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
582388bb21aSths #endif
583048f6b4dSbellard #ifdef TARGET_WORDS_BIGENDIAN
584048f6b4dSbellard #define ELF_DATA	ELFDATA2MSB
585048f6b4dSbellard #else
586048f6b4dSbellard #define ELF_DATA	ELFDATA2LSB
587048f6b4dSbellard #endif
588048f6b4dSbellard #define ELF_ARCH    EM_MIPS
589048f6b4dSbellard 
590048f6b4dSbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
591048f6b4dSbellard {
592623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
593048f6b4dSbellard     regs->cp0_epc = infop->entry;
594048f6b4dSbellard     regs->regs[29] = infop->start_stack;
595048f6b4dSbellard }
596048f6b4dSbellard 
59751e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/elf.h.  */
59851e52606SNathan Froyd #define ELF_NREG 45
59951e52606SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
60051e52606SNathan Froyd 
60151e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/reg.h.  */
60251e52606SNathan Froyd enum {
60351e52606SNathan Froyd #ifdef TARGET_MIPS64
60451e52606SNathan Froyd     TARGET_EF_R0 = 0,
60551e52606SNathan Froyd #else
60651e52606SNathan Froyd     TARGET_EF_R0 = 6,
60751e52606SNathan Froyd #endif
60851e52606SNathan Froyd     TARGET_EF_R26 = TARGET_EF_R0 + 26,
60951e52606SNathan Froyd     TARGET_EF_R27 = TARGET_EF_R0 + 27,
61051e52606SNathan Froyd     TARGET_EF_LO = TARGET_EF_R0 + 32,
61151e52606SNathan Froyd     TARGET_EF_HI = TARGET_EF_R0 + 33,
61251e52606SNathan Froyd     TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
61351e52606SNathan Froyd     TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
61451e52606SNathan Froyd     TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
61551e52606SNathan Froyd     TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
61651e52606SNathan Froyd };
61751e52606SNathan Froyd 
61851e52606SNathan Froyd /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
61951e52606SNathan Froyd static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
62051e52606SNathan Froyd {
62151e52606SNathan Froyd     int i;
62251e52606SNathan Froyd 
62351e52606SNathan Froyd     for (i = 0; i < TARGET_EF_R0; i++) {
62451e52606SNathan Froyd         (*regs)[i] = 0;
62551e52606SNathan Froyd     }
62651e52606SNathan Froyd     (*regs)[TARGET_EF_R0] = 0;
62751e52606SNathan Froyd 
62851e52606SNathan Froyd     for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
62951e52606SNathan Froyd         (*regs)[TARGET_EF_R0 + i] = tswapl(env->active_tc.gpr[i]);
63051e52606SNathan Froyd     }
63151e52606SNathan Froyd 
63251e52606SNathan Froyd     (*regs)[TARGET_EF_R26] = 0;
63351e52606SNathan Froyd     (*regs)[TARGET_EF_R27] = 0;
63451e52606SNathan Froyd     (*regs)[TARGET_EF_LO] = tswapl(env->active_tc.LO[0]);
63551e52606SNathan Froyd     (*regs)[TARGET_EF_HI] = tswapl(env->active_tc.HI[0]);
63651e52606SNathan Froyd     (*regs)[TARGET_EF_CP0_EPC] = tswapl(env->active_tc.PC);
63751e52606SNathan Froyd     (*regs)[TARGET_EF_CP0_BADVADDR] = tswapl(env->CP0_BadVAddr);
63851e52606SNathan Froyd     (*regs)[TARGET_EF_CP0_STATUS] = tswapl(env->CP0_Status);
63951e52606SNathan Froyd     (*regs)[TARGET_EF_CP0_CAUSE] = tswapl(env->CP0_Cause);
64051e52606SNathan Froyd }
64151e52606SNathan Froyd 
64251e52606SNathan Froyd #define USE_ELF_CORE_DUMP
643388bb21aSths #define ELF_EXEC_PAGESIZE        4096
644388bb21aSths 
645048f6b4dSbellard #endif /* TARGET_MIPS */
646048f6b4dSbellard 
647b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
648b779e29eSEdgar E. Iglesias 
649b779e29eSEdgar E. Iglesias #define ELF_START_MMAP 0x80000000
650b779e29eSEdgar E. Iglesias 
651b779e29eSEdgar E. Iglesias #define elf_check_arch(x) ( (x) == EM_XILINX_MICROBLAZE )
652b779e29eSEdgar E. Iglesias 
653b779e29eSEdgar E. Iglesias #define ELF_CLASS   ELFCLASS32
654b779e29eSEdgar E. Iglesias #define ELF_DATA	ELFDATA2MSB
6550ddbc96eSMike Frysinger #define ELF_ARCH    EM_XILINX_MICROBLAZE
656b779e29eSEdgar E. Iglesias 
657b779e29eSEdgar E. Iglesias static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
658b779e29eSEdgar E. Iglesias {
659b779e29eSEdgar E. Iglesias     regs->pc = infop->entry;
660b779e29eSEdgar E. Iglesias     regs->r1 = infop->start_stack;
661b779e29eSEdgar E. Iglesias 
662b779e29eSEdgar E. Iglesias }
663b779e29eSEdgar E. Iglesias 
664b779e29eSEdgar E. Iglesias #define ELF_EXEC_PAGESIZE        4096
665b779e29eSEdgar E. Iglesias 
666b779e29eSEdgar E. Iglesias #endif /* TARGET_MICROBLAZE */
667b779e29eSEdgar E. Iglesias 
668fdf9b3e8Sbellard #ifdef TARGET_SH4
669fdf9b3e8Sbellard 
670fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000
671fdf9b3e8Sbellard 
672fdf9b3e8Sbellard #define elf_check_arch(x) ( (x) == EM_SH )
673fdf9b3e8Sbellard 
674fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
675fdf9b3e8Sbellard #define ELF_DATA  ELFDATA2LSB
676fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
677fdf9b3e8Sbellard 
678fdf9b3e8Sbellard static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
679fdf9b3e8Sbellard {
680fdf9b3e8Sbellard   /* Check other registers XXXXX */
681fdf9b3e8Sbellard   regs->pc = infop->entry;
682072ae847Sths   regs->regs[15] = infop->start_stack;
683fdf9b3e8Sbellard }
684fdf9b3e8Sbellard 
6857631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/elf.h.  */
6867631c97eSNathan Froyd #define ELF_NREG 23
6877631c97eSNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
6887631c97eSNathan Froyd 
6897631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/ptrace.h.  */
6907631c97eSNathan Froyd enum {
6917631c97eSNathan Froyd     TARGET_REG_PC = 16,
6927631c97eSNathan Froyd     TARGET_REG_PR = 17,
6937631c97eSNathan Froyd     TARGET_REG_SR = 18,
6947631c97eSNathan Froyd     TARGET_REG_GBR = 19,
6957631c97eSNathan Froyd     TARGET_REG_MACH = 20,
6967631c97eSNathan Froyd     TARGET_REG_MACL = 21,
6977631c97eSNathan Froyd     TARGET_REG_SYSCALL = 22
6987631c97eSNathan Froyd };
6997631c97eSNathan Froyd 
7007631c97eSNathan Froyd static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
7017631c97eSNathan Froyd {
7027631c97eSNathan Froyd     int i;
7037631c97eSNathan Froyd 
7047631c97eSNathan Froyd     for (i = 0; i < 16; i++) {
7057631c97eSNathan Froyd         (*regs[i]) = tswapl(env->gregs[i]);
7067631c97eSNathan Froyd     }
7077631c97eSNathan Froyd 
7087631c97eSNathan Froyd     (*regs)[TARGET_REG_PC] = tswapl(env->pc);
7097631c97eSNathan Froyd     (*regs)[TARGET_REG_PR] = tswapl(env->pr);
7107631c97eSNathan Froyd     (*regs)[TARGET_REG_SR] = tswapl(env->sr);
7117631c97eSNathan Froyd     (*regs)[TARGET_REG_GBR] = tswapl(env->gbr);
7127631c97eSNathan Froyd     (*regs)[TARGET_REG_MACH] = tswapl(env->mach);
7137631c97eSNathan Froyd     (*regs)[TARGET_REG_MACL] = tswapl(env->macl);
7147631c97eSNathan Froyd     (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
7157631c97eSNathan Froyd }
7167631c97eSNathan Froyd 
7177631c97eSNathan Froyd #define USE_ELF_CORE_DUMP
718fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
719fdf9b3e8Sbellard 
720fdf9b3e8Sbellard #endif
721fdf9b3e8Sbellard 
72248733d19Sths #ifdef TARGET_CRIS
72348733d19Sths 
72448733d19Sths #define ELF_START_MMAP 0x80000000
72548733d19Sths 
72648733d19Sths #define elf_check_arch(x) ( (x) == EM_CRIS )
72748733d19Sths 
72848733d19Sths #define ELF_CLASS ELFCLASS32
72948733d19Sths #define ELF_DATA  ELFDATA2LSB
73048733d19Sths #define ELF_ARCH  EM_CRIS
73148733d19Sths 
73248733d19Sths static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
73348733d19Sths {
73448733d19Sths   regs->erp = infop->entry;
73548733d19Sths }
73648733d19Sths 
73748733d19Sths #define ELF_EXEC_PAGESIZE        8192
73848733d19Sths 
73948733d19Sths #endif
74048733d19Sths 
741e6e5906bSpbrook #ifdef TARGET_M68K
742e6e5906bSpbrook 
743e6e5906bSpbrook #define ELF_START_MMAP 0x80000000
744e6e5906bSpbrook 
745e6e5906bSpbrook #define elf_check_arch(x) ( (x) == EM_68K )
746e6e5906bSpbrook 
747e6e5906bSpbrook #define ELF_CLASS	ELFCLASS32
748e6e5906bSpbrook #define ELF_DATA	ELFDATA2MSB
749e6e5906bSpbrook #define ELF_ARCH	EM_68K
750e6e5906bSpbrook 
751e6e5906bSpbrook /* ??? Does this need to do anything?
752e6e5906bSpbrook #define ELF_PLAT_INIT(_r) */
753e6e5906bSpbrook 
754e6e5906bSpbrook static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
755e6e5906bSpbrook {
756e6e5906bSpbrook     regs->usp = infop->start_stack;
757e6e5906bSpbrook     regs->sr = 0;
758e6e5906bSpbrook     regs->pc = infop->entry;
759e6e5906bSpbrook }
760e6e5906bSpbrook 
7617a93cc55SNathan Froyd /* See linux kernel: arch/m68k/include/asm/elf.h.  */
7627a93cc55SNathan Froyd #define ELF_NREG 20
7637a93cc55SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
7647a93cc55SNathan Froyd 
7657a93cc55SNathan Froyd static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env)
7667a93cc55SNathan Froyd {
7677a93cc55SNathan Froyd     (*regs)[0] = tswapl(env->dregs[1]);
7687a93cc55SNathan Froyd     (*regs)[1] = tswapl(env->dregs[2]);
7697a93cc55SNathan Froyd     (*regs)[2] = tswapl(env->dregs[3]);
7707a93cc55SNathan Froyd     (*regs)[3] = tswapl(env->dregs[4]);
7717a93cc55SNathan Froyd     (*regs)[4] = tswapl(env->dregs[5]);
7727a93cc55SNathan Froyd     (*regs)[5] = tswapl(env->dregs[6]);
7737a93cc55SNathan Froyd     (*regs)[6] = tswapl(env->dregs[7]);
7747a93cc55SNathan Froyd     (*regs)[7] = tswapl(env->aregs[0]);
7757a93cc55SNathan Froyd     (*regs)[8] = tswapl(env->aregs[1]);
7767a93cc55SNathan Froyd     (*regs)[9] = tswapl(env->aregs[2]);
7777a93cc55SNathan Froyd     (*regs)[10] = tswapl(env->aregs[3]);
7787a93cc55SNathan Froyd     (*regs)[11] = tswapl(env->aregs[4]);
7797a93cc55SNathan Froyd     (*regs)[12] = tswapl(env->aregs[5]);
7807a93cc55SNathan Froyd     (*regs)[13] = tswapl(env->aregs[6]);
7817a93cc55SNathan Froyd     (*regs)[14] = tswapl(env->dregs[0]);
7827a93cc55SNathan Froyd     (*regs)[15] = tswapl(env->aregs[7]);
7837a93cc55SNathan Froyd     (*regs)[16] = tswapl(env->dregs[0]); /* FIXME: orig_d0 */
7847a93cc55SNathan Froyd     (*regs)[17] = tswapl(env->sr);
7857a93cc55SNathan Froyd     (*regs)[18] = tswapl(env->pc);
7867a93cc55SNathan Froyd     (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
7877a93cc55SNathan Froyd }
7887a93cc55SNathan Froyd 
7897a93cc55SNathan Froyd #define USE_ELF_CORE_DUMP
790e6e5906bSpbrook #define ELF_EXEC_PAGESIZE	8192
791e6e5906bSpbrook 
792e6e5906bSpbrook #endif
793e6e5906bSpbrook 
7947a3148a9Sj_mayer #ifdef TARGET_ALPHA
7957a3148a9Sj_mayer 
7967a3148a9Sj_mayer #define ELF_START_MMAP (0x30000000000ULL)
7977a3148a9Sj_mayer 
7987a3148a9Sj_mayer #define elf_check_arch(x) ( (x) == ELF_ARCH )
7997a3148a9Sj_mayer 
8007a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
8017a3148a9Sj_mayer #define ELF_DATA       ELFDATA2MSB
8027a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
8037a3148a9Sj_mayer 
8047a3148a9Sj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
8057a3148a9Sj_mayer {
8067a3148a9Sj_mayer     regs->pc = infop->entry;
8077a3148a9Sj_mayer     regs->ps = 8;
8087a3148a9Sj_mayer     regs->usp = infop->start_stack;
8097a3148a9Sj_mayer }
8107a3148a9Sj_mayer 
8117a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
8127a3148a9Sj_mayer 
8137a3148a9Sj_mayer #endif /* TARGET_ALPHA */
8147a3148a9Sj_mayer 
81515338fd7Sbellard #ifndef ELF_PLATFORM
81615338fd7Sbellard #define ELF_PLATFORM (NULL)
81715338fd7Sbellard #endif
81815338fd7Sbellard 
81915338fd7Sbellard #ifndef ELF_HWCAP
82015338fd7Sbellard #define ELF_HWCAP 0
82115338fd7Sbellard #endif
82215338fd7Sbellard 
823992f48a0Sblueswir1 #ifdef TARGET_ABI32
824cb33da57Sblueswir1 #undef ELF_CLASS
825992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
826cb33da57Sblueswir1 #undef bswaptls
827cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
828cb33da57Sblueswir1 #endif
829cb33da57Sblueswir1 
83031e31b8aSbellard #include "elf.h"
83109bfb054Sbellard 
83209bfb054Sbellard struct exec
83309bfb054Sbellard {
83409bfb054Sbellard   unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
83509bfb054Sbellard   unsigned int a_text;   /* length of text, in bytes */
83609bfb054Sbellard   unsigned int a_data;   /* length of data, in bytes */
83709bfb054Sbellard   unsigned int a_bss;    /* length of uninitialized data area, in bytes */
83809bfb054Sbellard   unsigned int a_syms;   /* length of symbol table data in file, in bytes */
83909bfb054Sbellard   unsigned int a_entry;  /* start address */
84009bfb054Sbellard   unsigned int a_trsize; /* length of relocation info for text, in bytes */
84109bfb054Sbellard   unsigned int a_drsize; /* length of relocation info for data, in bytes */
84209bfb054Sbellard };
84309bfb054Sbellard 
84409bfb054Sbellard 
84509bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
84609bfb054Sbellard #define OMAGIC 0407
84709bfb054Sbellard #define NMAGIC 0410
84809bfb054Sbellard #define ZMAGIC 0413
84909bfb054Sbellard #define QMAGIC 0314
85009bfb054Sbellard 
85109bfb054Sbellard /* max code+data+bss space allocated to elf interpreter */
85209bfb054Sbellard #define INTERP_MAP_SIZE (32 * 1024 * 1024)
85309bfb054Sbellard 
85409bfb054Sbellard /* max code+data+bss+brk space allocated to ET_DYN executables */
85509bfb054Sbellard #define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
85609bfb054Sbellard 
85731e31b8aSbellard /* Necessary parameters */
85854936004Sbellard #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
85954936004Sbellard #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
86054936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
86131e31b8aSbellard 
86231e31b8aSbellard #define INTERPRETER_NONE 0
86331e31b8aSbellard #define INTERPRETER_AOUT 1
86431e31b8aSbellard #define INTERPRETER_ELF 2
86531e31b8aSbellard 
86615338fd7Sbellard #define DLINFO_ITEMS 12
86731e31b8aSbellard 
86809bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
86909bfb054Sbellard {
87009bfb054Sbellard 	memcpy(to, from, n);
87109bfb054Sbellard }
87209bfb054Sbellard 
87331e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd);
87431e31b8aSbellard 
87531e31b8aSbellard #ifdef BSWAP_NEEDED
87692a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
87731e31b8aSbellard {
87831e31b8aSbellard     bswap16s(&ehdr->e_type);			/* Object file type */
87931e31b8aSbellard     bswap16s(&ehdr->e_machine);		/* Architecture */
88031e31b8aSbellard     bswap32s(&ehdr->e_version);		/* Object file version */
88192a31b1fSbellard     bswaptls(&ehdr->e_entry);		/* Entry point virtual address */
88292a31b1fSbellard     bswaptls(&ehdr->e_phoff);		/* Program header table file offset */
88392a31b1fSbellard     bswaptls(&ehdr->e_shoff);		/* Section header table file offset */
88431e31b8aSbellard     bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
88531e31b8aSbellard     bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
88631e31b8aSbellard     bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
88731e31b8aSbellard     bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
88831e31b8aSbellard     bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
88931e31b8aSbellard     bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
89031e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
89131e31b8aSbellard }
89231e31b8aSbellard 
89392a31b1fSbellard static void bswap_phdr(struct elf_phdr *phdr)
89431e31b8aSbellard {
89531e31b8aSbellard     bswap32s(&phdr->p_type);			/* Segment type */
89692a31b1fSbellard     bswaptls(&phdr->p_offset);		/* Segment file offset */
89792a31b1fSbellard     bswaptls(&phdr->p_vaddr);		/* Segment virtual address */
89892a31b1fSbellard     bswaptls(&phdr->p_paddr);		/* Segment physical address */
89992a31b1fSbellard     bswaptls(&phdr->p_filesz);		/* Segment size in file */
90092a31b1fSbellard     bswaptls(&phdr->p_memsz);		/* Segment size in memory */
90131e31b8aSbellard     bswap32s(&phdr->p_flags);		/* Segment flags */
90292a31b1fSbellard     bswaptls(&phdr->p_align);		/* Segment alignment */
90331e31b8aSbellard }
904689f936fSbellard 
90592a31b1fSbellard static void bswap_shdr(struct elf_shdr *shdr)
906689f936fSbellard {
907689f936fSbellard     bswap32s(&shdr->sh_name);
908689f936fSbellard     bswap32s(&shdr->sh_type);
90992a31b1fSbellard     bswaptls(&shdr->sh_flags);
91092a31b1fSbellard     bswaptls(&shdr->sh_addr);
91192a31b1fSbellard     bswaptls(&shdr->sh_offset);
91292a31b1fSbellard     bswaptls(&shdr->sh_size);
913689f936fSbellard     bswap32s(&shdr->sh_link);
914689f936fSbellard     bswap32s(&shdr->sh_info);
91592a31b1fSbellard     bswaptls(&shdr->sh_addralign);
91692a31b1fSbellard     bswaptls(&shdr->sh_entsize);
917689f936fSbellard }
918689f936fSbellard 
9197a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
920689f936fSbellard {
921689f936fSbellard     bswap32s(&sym->st_name);
9227a3148a9Sj_mayer     bswaptls(&sym->st_value);
9237a3148a9Sj_mayer     bswaptls(&sym->st_size);
924689f936fSbellard     bswap16s(&sym->st_shndx);
925689f936fSbellard }
92631e31b8aSbellard #endif
92731e31b8aSbellard 
928edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
929edf8e2afSMika Westerberg static int elf_core_dump(int, const CPUState *);
930edf8e2afSMika Westerberg 
931edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
932edf8e2afSMika Westerberg static void bswap_note(struct elf_note *en)
933edf8e2afSMika Westerberg {
9349fdca5aaSmalc     bswap32s(&en->n_namesz);
9359fdca5aaSmalc     bswap32s(&en->n_descsz);
9369fdca5aaSmalc     bswap32s(&en->n_type);
937edf8e2afSMika Westerberg }
938edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
939edf8e2afSMika Westerberg 
940edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
941edf8e2afSMika Westerberg 
94231e31b8aSbellard /*
943e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
94431e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
94531e31b8aSbellard  * to be put directly into the top of new user memory.
94631e31b8aSbellard  *
94731e31b8aSbellard  */
948992f48a0Sblueswir1 static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
949992f48a0Sblueswir1                                   abi_ulong p)
95031e31b8aSbellard {
95131e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
95231e31b8aSbellard     int len, offset = 0;
95331e31b8aSbellard 
95431e31b8aSbellard     if (!p) {
95531e31b8aSbellard 	return 0;       /* bullet-proofing */
95631e31b8aSbellard     }
95731e31b8aSbellard     while (argc-- > 0) {
958edf779ffSbellard         tmp = argv[argc];
959edf779ffSbellard         if (!tmp) {
96031e31b8aSbellard 	    fprintf(stderr, "VFS: argc is wrong");
96131e31b8aSbellard 	    exit(-1);
96231e31b8aSbellard 	}
963edf779ffSbellard         tmp1 = tmp;
964edf779ffSbellard 	while (*tmp++);
96531e31b8aSbellard 	len = tmp - tmp1;
96631e31b8aSbellard 	if (p < len) {  /* this shouldn't happen - 128kB */
96731e31b8aSbellard 		return 0;
96831e31b8aSbellard 	}
96931e31b8aSbellard 	while (len) {
97031e31b8aSbellard 	    --p; --tmp; --len;
97131e31b8aSbellard 	    if (--offset < 0) {
97254936004Sbellard 		offset = p % TARGET_PAGE_SIZE;
97344a91caeSbellard                 pag = (char *)page[p/TARGET_PAGE_SIZE];
97444a91caeSbellard                 if (!pag) {
97553a5960aSpbrook                     pag = (char *)malloc(TARGET_PAGE_SIZE);
9764118a970Sj_mayer                     memset(pag, 0, TARGET_PAGE_SIZE);
97753a5960aSpbrook                     page[p/TARGET_PAGE_SIZE] = pag;
97844a91caeSbellard                     if (!pag)
97931e31b8aSbellard                         return 0;
98031e31b8aSbellard 		}
98131e31b8aSbellard 	    }
98231e31b8aSbellard 	    if (len == 0 || offset == 0) {
983edf779ffSbellard 	        *(pag + offset) = *tmp;
98431e31b8aSbellard 	    }
98531e31b8aSbellard 	    else {
98631e31b8aSbellard 	      int bytes_to_copy = (len > offset) ? offset : len;
98731e31b8aSbellard 	      tmp -= bytes_to_copy;
98831e31b8aSbellard 	      p -= bytes_to_copy;
98931e31b8aSbellard 	      offset -= bytes_to_copy;
99031e31b8aSbellard 	      len -= bytes_to_copy;
99131e31b8aSbellard 	      memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
99231e31b8aSbellard 	    }
99331e31b8aSbellard 	}
99431e31b8aSbellard     }
99531e31b8aSbellard     return p;
99631e31b8aSbellard }
99731e31b8aSbellard 
998992f48a0Sblueswir1 static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
99931e31b8aSbellard                                  struct image_info *info)
100031e31b8aSbellard {
1001992f48a0Sblueswir1     abi_ulong stack_base, size, error;
100231e31b8aSbellard     int i;
100331e31b8aSbellard 
100431e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
100531e31b8aSbellard      * it for args, we'll use it for something else...
100631e31b8aSbellard      */
100709bfb054Sbellard     size = x86_stack_size;
100854936004Sbellard     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
100954936004Sbellard         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
101054936004Sbellard     error = target_mmap(0,
101183fb7adfSbellard                         size + qemu_host_page_size,
101231e31b8aSbellard                         PROT_READ | PROT_WRITE,
101309bfb054Sbellard                         MAP_PRIVATE | MAP_ANONYMOUS,
101409bfb054Sbellard                         -1, 0);
101509bfb054Sbellard     if (error == -1) {
101631e31b8aSbellard         perror("stk mmap");
101731e31b8aSbellard         exit(-1);
101831e31b8aSbellard     }
101909bfb054Sbellard     /* we reserve one extra page at the top of the stack as guard */
102083fb7adfSbellard     target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
102131e31b8aSbellard 
102254936004Sbellard     stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
102309bfb054Sbellard     p += stack_base;
102409bfb054Sbellard 
102531e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
102631e31b8aSbellard 	if (bprm->page[i]) {
102731e31b8aSbellard 	    info->rss++;
1028579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
102953a5960aSpbrook 	    memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
103053a5960aSpbrook 	    free(bprm->page[i]);
103131e31b8aSbellard 	}
103254936004Sbellard         stack_base += TARGET_PAGE_SIZE;
103331e31b8aSbellard     }
103431e31b8aSbellard     return p;
103531e31b8aSbellard }
103631e31b8aSbellard 
1037992f48a0Sblueswir1 static void set_brk(abi_ulong start, abi_ulong end)
103831e31b8aSbellard {
103931e31b8aSbellard 	/* page-align the start and end addresses... */
104054936004Sbellard         start = HOST_PAGE_ALIGN(start);
104154936004Sbellard         end = HOST_PAGE_ALIGN(end);
104231e31b8aSbellard         if (end <= start)
104331e31b8aSbellard                 return;
104454936004Sbellard         if(target_mmap(start, end - start,
104531e31b8aSbellard                        PROT_READ | PROT_WRITE | PROT_EXEC,
104631e31b8aSbellard                        MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
104731e31b8aSbellard 	    perror("cannot mmap brk");
104831e31b8aSbellard 	    exit(-1);
104931e31b8aSbellard 	}
105031e31b8aSbellard }
105131e31b8aSbellard 
105231e31b8aSbellard 
1053853d6f7aSbellard /* We need to explicitly zero any fractional pages after the data
1054853d6f7aSbellard    section (i.e. bss).  This would contain the junk from the file that
1055853d6f7aSbellard    should not be in memory. */
1056992f48a0Sblueswir1 static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
105731e31b8aSbellard {
1058992f48a0Sblueswir1         abi_ulong nbyte;
105931e31b8aSbellard 
1060768a4a36Sths 	if (elf_bss >= last_bss)
1061768a4a36Sths 		return;
1062768a4a36Sths 
1063853d6f7aSbellard         /* XXX: this is really a hack : if the real host page size is
1064853d6f7aSbellard            smaller than the target page size, some pages after the end
1065853d6f7aSbellard            of the file may not be mapped. A better fix would be to
1066853d6f7aSbellard            patch target_mmap(), but it is more complicated as the file
1067853d6f7aSbellard            size must be known */
106883fb7adfSbellard         if (qemu_real_host_page_size < qemu_host_page_size) {
1069992f48a0Sblueswir1             abi_ulong end_addr, end_addr1;
107083fb7adfSbellard             end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
107183fb7adfSbellard                 ~(qemu_real_host_page_size - 1);
1072853d6f7aSbellard             end_addr = HOST_PAGE_ALIGN(elf_bss);
1073853d6f7aSbellard             if (end_addr1 < end_addr) {
1074863cf0b7Sj_mayer                 mmap((void *)g2h(end_addr1), end_addr - end_addr1,
1075853d6f7aSbellard                      PROT_READ|PROT_WRITE|PROT_EXEC,
1076853d6f7aSbellard                      MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
1077853d6f7aSbellard             }
1078853d6f7aSbellard         }
1079853d6f7aSbellard 
108083fb7adfSbellard         nbyte = elf_bss & (qemu_host_page_size-1);
108131e31b8aSbellard         if (nbyte) {
108283fb7adfSbellard 	    nbyte = qemu_host_page_size - nbyte;
108331e31b8aSbellard 	    do {
10842f619698Sbellard                 /* FIXME - what to do if put_user() fails? */
10852f619698Sbellard 		put_user_u8(0, elf_bss);
108653a5960aSpbrook                 elf_bss++;
108731e31b8aSbellard 	    } while (--nbyte);
108831e31b8aSbellard         }
108931e31b8aSbellard }
109031e31b8aSbellard 
109153a5960aSpbrook 
1092992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
109331e31b8aSbellard                                    struct elfhdr * exec,
1094992f48a0Sblueswir1                                    abi_ulong load_addr,
1095992f48a0Sblueswir1                                    abi_ulong load_bias,
1096992f48a0Sblueswir1                                    abi_ulong interp_load_addr, int ibcs,
109731e31b8aSbellard                                    struct image_info *info)
109831e31b8aSbellard {
1099992f48a0Sblueswir1         abi_ulong sp;
110053a5960aSpbrook         int size;
1101992f48a0Sblueswir1         abi_ulong u_platform;
110215338fd7Sbellard         const char *k_platform;
1103863cf0b7Sj_mayer         const int n = sizeof(elf_addr_t);
110431e31b8aSbellard 
110553a5960aSpbrook         sp = p;
110653a5960aSpbrook         u_platform = 0;
110715338fd7Sbellard         k_platform = ELF_PLATFORM;
110815338fd7Sbellard         if (k_platform) {
110915338fd7Sbellard             size_t len = strlen(k_platform) + 1;
111053a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
111153a5960aSpbrook             u_platform = sp;
1112579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
111353a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
111415338fd7Sbellard         }
111553a5960aSpbrook 	/*
111653a5960aSpbrook 	 * Force 16 byte _final_ alignment here for generality.
111753a5960aSpbrook 	 */
1118992f48a0Sblueswir1         sp = sp &~ (abi_ulong)15;
111953a5960aSpbrook         size = (DLINFO_ITEMS + 1) * 2;
112015338fd7Sbellard         if (k_platform)
112153a5960aSpbrook           size += 2;
1122f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
112353a5960aSpbrook 	size += DLINFO_ARCH_ITEMS * 2;
1124f5155289Sbellard #endif
112553a5960aSpbrook         size += envc + argc + 2;
112653a5960aSpbrook 	size += (!ibcs ? 3 : 1);	/* argc itself */
112753a5960aSpbrook         size *= n;
112853a5960aSpbrook         if (size & 15)
112953a5960aSpbrook             sp -= 16 - (size & 15);
1130f5155289Sbellard 
1131863cf0b7Sj_mayer         /* This is correct because Linux defines
1132863cf0b7Sj_mayer          * elf_addr_t as Elf32_Off / Elf64_Off
1133863cf0b7Sj_mayer          */
113453a5960aSpbrook #define NEW_AUX_ENT(id, val) do {		\
11352f619698Sbellard             sp -= n; put_user_ual(val, sp);	\
11362f619698Sbellard             sp -= n; put_user_ual(id, sp);	\
113753a5960aSpbrook           } while(0)
11382f619698Sbellard 
11390bccf03dSbellard         NEW_AUX_ENT (AT_NULL, 0);
1140f5155289Sbellard 
11410bccf03dSbellard         /* There must be exactly DLINFO_ITEMS entries here.  */
1142992f48a0Sblueswir1         NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff));
1143992f48a0Sblueswir1         NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
1144992f48a0Sblueswir1         NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
1145992f48a0Sblueswir1         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
1146992f48a0Sblueswir1         NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr));
1147992f48a0Sblueswir1         NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
11480bccf03dSbellard         NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
1149992f48a0Sblueswir1         NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
1150992f48a0Sblueswir1         NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
1151992f48a0Sblueswir1         NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
1152992f48a0Sblueswir1         NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
1153992f48a0Sblueswir1         NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
1154a07c67dfSpbrook         NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
115515338fd7Sbellard         if (k_platform)
115653a5960aSpbrook             NEW_AUX_ENT(AT_PLATFORM, u_platform);
1157f5155289Sbellard #ifdef ARCH_DLINFO
1158f5155289Sbellard 	/*
1159f5155289Sbellard 	 * ARCH_DLINFO must come last so platform specific code can enforce
1160f5155289Sbellard 	 * special alignment requirements on the AUXV if necessary (eg. PPC).
1161f5155289Sbellard 	 */
1162f5155289Sbellard         ARCH_DLINFO;
1163f5155289Sbellard #endif
1164f5155289Sbellard #undef NEW_AUX_ENT
1165f5155289Sbellard 
1166edf8e2afSMika Westerberg         info->saved_auxv = sp;
1167edf8e2afSMika Westerberg 
1168e5fe0c52Spbrook         sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
116931e31b8aSbellard         return sp;
117031e31b8aSbellard }
117131e31b8aSbellard 
117231e31b8aSbellard 
1173992f48a0Sblueswir1 static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
117431e31b8aSbellard                                  int interpreter_fd,
1175992f48a0Sblueswir1                                  abi_ulong *interp_load_addr)
117631e31b8aSbellard {
117731e31b8aSbellard 	struct elf_phdr *elf_phdata  =  NULL;
117831e31b8aSbellard 	struct elf_phdr *eppnt;
1179992f48a0Sblueswir1 	abi_ulong load_addr = 0;
118031e31b8aSbellard 	int load_addr_set = 0;
118131e31b8aSbellard 	int retval;
1182992f48a0Sblueswir1 	abi_ulong last_bss, elf_bss;
1183992f48a0Sblueswir1 	abi_ulong error;
118431e31b8aSbellard 	int i;
118531e31b8aSbellard 
118631e31b8aSbellard 	elf_bss = 0;
118731e31b8aSbellard 	last_bss = 0;
118831e31b8aSbellard 	error = 0;
118931e31b8aSbellard 
1190644c433cSbellard #ifdef BSWAP_NEEDED
1191644c433cSbellard         bswap_ehdr(interp_elf_ex);
1192644c433cSbellard #endif
119331e31b8aSbellard 	/* First of all, some simple consistency checks */
119431e31b8aSbellard 	if ((interp_elf_ex->e_type != ET_EXEC &&
119531e31b8aSbellard              interp_elf_ex->e_type != ET_DYN) ||
119631e31b8aSbellard 	   !elf_check_arch(interp_elf_ex->e_machine)) {
1197992f48a0Sblueswir1 		return ~((abi_ulong)0UL);
119831e31b8aSbellard 	}
119931e31b8aSbellard 
1200644c433cSbellard 
120131e31b8aSbellard 	/* Now read in all of the header information */
120231e31b8aSbellard 
120354936004Sbellard 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
1204992f48a0Sblueswir1 	    return ~(abi_ulong)0UL;
120531e31b8aSbellard 
120631e31b8aSbellard 	elf_phdata =  (struct elf_phdr *)
120731e31b8aSbellard 		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
120831e31b8aSbellard 
120931e31b8aSbellard 	if (!elf_phdata)
1210992f48a0Sblueswir1 	  return ~((abi_ulong)0UL);
121131e31b8aSbellard 
121231e31b8aSbellard 	/*
121331e31b8aSbellard 	 * If the size of this structure has changed, then punt, since
121431e31b8aSbellard 	 * we will be doing the wrong thing.
121531e31b8aSbellard 	 */
121609bfb054Sbellard 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
121731e31b8aSbellard 	    free(elf_phdata);
1218992f48a0Sblueswir1 	    return ~((abi_ulong)0UL);
121931e31b8aSbellard         }
122031e31b8aSbellard 
122131e31b8aSbellard 	retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
122231e31b8aSbellard 	if(retval >= 0) {
122331e31b8aSbellard 	    retval = read(interpreter_fd,
122431e31b8aSbellard 			   (char *) elf_phdata,
122531e31b8aSbellard 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
122631e31b8aSbellard 	}
122731e31b8aSbellard 	if (retval < 0) {
122831e31b8aSbellard 		perror("load_elf_interp");
122931e31b8aSbellard 		exit(-1);
123031e31b8aSbellard 		free (elf_phdata);
123131e31b8aSbellard 		return retval;
123231e31b8aSbellard  	}
123331e31b8aSbellard #ifdef BSWAP_NEEDED
123431e31b8aSbellard 	eppnt = elf_phdata;
123531e31b8aSbellard 	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
123631e31b8aSbellard             bswap_phdr(eppnt);
123731e31b8aSbellard         }
123831e31b8aSbellard #endif
123909bfb054Sbellard 
124009bfb054Sbellard         if (interp_elf_ex->e_type == ET_DYN) {
1241e91c8a77Sths             /* in order to avoid hardcoding the interpreter load
124209bfb054Sbellard                address in qemu, we allocate a big enough memory zone */
124354936004Sbellard             error = target_mmap(0, INTERP_MAP_SIZE,
124409bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
124509bfb054Sbellard                                 -1, 0);
124609bfb054Sbellard             if (error == -1) {
124709bfb054Sbellard                 perror("mmap");
124809bfb054Sbellard                 exit(-1);
124909bfb054Sbellard             }
125009bfb054Sbellard             load_addr = error;
125109bfb054Sbellard             load_addr_set = 1;
125209bfb054Sbellard         }
125309bfb054Sbellard 
125431e31b8aSbellard 	eppnt = elf_phdata;
125531e31b8aSbellard 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
125631e31b8aSbellard 	  if (eppnt->p_type == PT_LOAD) {
125731e31b8aSbellard 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
125831e31b8aSbellard 	    int elf_prot = 0;
1259992f48a0Sblueswir1 	    abi_ulong vaddr = 0;
1260992f48a0Sblueswir1 	    abi_ulong k;
126131e31b8aSbellard 
126231e31b8aSbellard 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
126331e31b8aSbellard 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
126431e31b8aSbellard 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
126531e31b8aSbellard 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
126631e31b8aSbellard 	    	elf_type |= MAP_FIXED;
126731e31b8aSbellard 	    	vaddr = eppnt->p_vaddr;
126831e31b8aSbellard 	    }
126954936004Sbellard 	    error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
127054936004Sbellard 		 eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
127131e31b8aSbellard 		 elf_prot,
127231e31b8aSbellard 		 elf_type,
127331e31b8aSbellard 		 interpreter_fd,
127454936004Sbellard 		 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
127531e31b8aSbellard 
1276e89f07d3Spbrook 	    if (error == -1) {
127731e31b8aSbellard 	      /* Real error */
127831e31b8aSbellard 	      close(interpreter_fd);
127931e31b8aSbellard 	      free(elf_phdata);
1280992f48a0Sblueswir1 	      return ~((abi_ulong)0UL);
128131e31b8aSbellard 	    }
128231e31b8aSbellard 
128331e31b8aSbellard 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
128431e31b8aSbellard 	      load_addr = error;
128531e31b8aSbellard 	      load_addr_set = 1;
128631e31b8aSbellard 	    }
128731e31b8aSbellard 
128831e31b8aSbellard 	    /*
128931e31b8aSbellard 	     * Find the end of the file  mapping for this phdr, and keep
129031e31b8aSbellard 	     * track of the largest address we see for this.
129131e31b8aSbellard 	     */
129231e31b8aSbellard 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
129331e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
129431e31b8aSbellard 
129531e31b8aSbellard 	    /*
129631e31b8aSbellard 	     * Do the same thing for the memory mapping - between
129731e31b8aSbellard 	     * elf_bss and last_bss is the bss section.
129831e31b8aSbellard 	     */
129931e31b8aSbellard 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
130031e31b8aSbellard 	    if (k > last_bss) last_bss = k;
130131e31b8aSbellard 	  }
130231e31b8aSbellard 
130331e31b8aSbellard 	/* Now use mmap to map the library into memory. */
130431e31b8aSbellard 
130531e31b8aSbellard 	close(interpreter_fd);
130631e31b8aSbellard 
130731e31b8aSbellard 	/*
130831e31b8aSbellard 	 * Now fill out the bss section.  First pad the last page up
130931e31b8aSbellard 	 * to the page boundary, and then perform a mmap to make sure
131031e31b8aSbellard 	 * that there are zeromapped pages up to and including the last
131131e31b8aSbellard 	 * bss page.
131231e31b8aSbellard 	 */
1313768a4a36Sths 	padzero(elf_bss, last_bss);
131483fb7adfSbellard 	elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
131531e31b8aSbellard 
131631e31b8aSbellard 	/* Map the last of the bss segment */
131731e31b8aSbellard 	if (last_bss > elf_bss) {
131854936004Sbellard             target_mmap(elf_bss, last_bss-elf_bss,
131931e31b8aSbellard                         PROT_READ|PROT_WRITE|PROT_EXEC,
132031e31b8aSbellard                         MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
132131e31b8aSbellard 	}
132231e31b8aSbellard 	free(elf_phdata);
132331e31b8aSbellard 
132431e31b8aSbellard 	*interp_load_addr = load_addr;
1325992f48a0Sblueswir1 	return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
132631e31b8aSbellard }
132731e31b8aSbellard 
132849918a75Spbrook static int symfind(const void *s0, const void *s1)
132949918a75Spbrook {
133049918a75Spbrook     struct elf_sym *key = (struct elf_sym *)s0;
133149918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
133249918a75Spbrook     int result = 0;
133349918a75Spbrook     if (key->st_value < sym->st_value) {
133449918a75Spbrook         result = -1;
1335ec822001SLaurent Desnogues     } else if (key->st_value >= sym->st_value + sym->st_size) {
133649918a75Spbrook         result = 1;
133749918a75Spbrook     }
133849918a75Spbrook     return result;
133949918a75Spbrook }
134049918a75Spbrook 
134149918a75Spbrook static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
134249918a75Spbrook {
134349918a75Spbrook #if ELF_CLASS == ELFCLASS32
134449918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
134549918a75Spbrook #else
134649918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
134749918a75Spbrook #endif
134849918a75Spbrook 
134949918a75Spbrook     // binary search
135049918a75Spbrook     struct elf_sym key;
135149918a75Spbrook     struct elf_sym *sym;
135249918a75Spbrook 
135349918a75Spbrook     key.st_value = orig_addr;
135449918a75Spbrook 
135549918a75Spbrook     sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), symfind);
13567cba04f6SBlue Swirl     if (sym != NULL) {
135749918a75Spbrook         return s->disas_strtab + sym->st_name;
135849918a75Spbrook     }
135949918a75Spbrook 
136049918a75Spbrook     return "";
136149918a75Spbrook }
136249918a75Spbrook 
136349918a75Spbrook /* FIXME: This should use elf_ops.h  */
136449918a75Spbrook static int symcmp(const void *s0, const void *s1)
136549918a75Spbrook {
136649918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
136749918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
136849918a75Spbrook     return (sym0->st_value < sym1->st_value)
136949918a75Spbrook         ? -1
137049918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
137149918a75Spbrook }
137249918a75Spbrook 
1373689f936fSbellard /* Best attempt to load symbols from this ELF object. */
1374689f936fSbellard static void load_symbols(struct elfhdr *hdr, int fd)
1375689f936fSbellard {
137649918a75Spbrook     unsigned int i, nsyms;
1377689f936fSbellard     struct elf_shdr sechdr, symtab, strtab;
1378689f936fSbellard     char *strings;
1379e80cfcfcSbellard     struct syminfo *s;
138049918a75Spbrook     struct elf_sym *syms;
138131e31b8aSbellard 
1382689f936fSbellard     lseek(fd, hdr->e_shoff, SEEK_SET);
1383689f936fSbellard     for (i = 0; i < hdr->e_shnum; i++) {
1384689f936fSbellard         if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
1385689f936fSbellard             return;
1386689f936fSbellard #ifdef BSWAP_NEEDED
1387689f936fSbellard         bswap_shdr(&sechdr);
1388689f936fSbellard #endif
1389689f936fSbellard         if (sechdr.sh_type == SHT_SYMTAB) {
1390689f936fSbellard             symtab = sechdr;
1391689f936fSbellard             lseek(fd, hdr->e_shoff
1392689f936fSbellard                   + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
1393689f936fSbellard             if (read(fd, &strtab, sizeof(strtab))
1394689f936fSbellard                 != sizeof(strtab))
1395689f936fSbellard                 return;
1396689f936fSbellard #ifdef BSWAP_NEEDED
1397689f936fSbellard             bswap_shdr(&strtab);
1398689f936fSbellard #endif
1399689f936fSbellard             goto found;
1400689f936fSbellard         }
1401689f936fSbellard     }
1402689f936fSbellard     return; /* Shouldn't happen... */
1403689f936fSbellard 
1404689f936fSbellard  found:
1405689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them. */
1406e80cfcfcSbellard     s = malloc(sizeof(*s));
140749918a75Spbrook     syms = malloc(symtab.sh_size);
140849918a75Spbrook     if (!syms)
140949918a75Spbrook         return;
1410e80cfcfcSbellard     s->disas_strtab = strings = malloc(strtab.sh_size);
141149918a75Spbrook     if (!s->disas_strtab)
1412689f936fSbellard         return;
1413689f936fSbellard 
1414689f936fSbellard     lseek(fd, symtab.sh_offset, SEEK_SET);
141549918a75Spbrook     if (read(fd, syms, symtab.sh_size) != symtab.sh_size)
1416689f936fSbellard         return;
1417689f936fSbellard 
141849918a75Spbrook     nsyms = symtab.sh_size / sizeof(struct elf_sym);
1419689f936fSbellard 
142049918a75Spbrook     i = 0;
142149918a75Spbrook     while (i < nsyms) {
142249918a75Spbrook #ifdef BSWAP_NEEDED
142349918a75Spbrook         bswap_sym(syms + i);
14240774bed1Sblueswir1 #endif
142549918a75Spbrook         // Throw away entries which we do not need.
142649918a75Spbrook         if (syms[i].st_shndx == SHN_UNDEF ||
142749918a75Spbrook                 syms[i].st_shndx >= SHN_LORESERVE ||
142849918a75Spbrook                 ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
142949918a75Spbrook             nsyms--;
143049918a75Spbrook             if (i < nsyms) {
143149918a75Spbrook                 syms[i] = syms[nsyms];
143249918a75Spbrook             }
143349918a75Spbrook             continue;
143449918a75Spbrook         }
143549918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
143649918a75Spbrook         /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
143749918a75Spbrook         syms[i].st_value &= ~(target_ulong)1;
143849918a75Spbrook #endif
143949918a75Spbrook         i++;
144049918a75Spbrook     }
144149918a75Spbrook     syms = realloc(syms, nsyms * sizeof(*syms));
144249918a75Spbrook 
144349918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
144449918a75Spbrook 
1445689f936fSbellard     lseek(fd, strtab.sh_offset, SEEK_SET);
1446689f936fSbellard     if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
1447689f936fSbellard         return;
144849918a75Spbrook     s->disas_num_syms = nsyms;
144949918a75Spbrook #if ELF_CLASS == ELFCLASS32
145049918a75Spbrook     s->disas_symtab.elf32 = syms;
1451*9f9f0309SPaul Brook     s->lookup_symbol = lookup_symbolxx;
145249918a75Spbrook #else
145349918a75Spbrook     s->disas_symtab.elf64 = syms;
1454*9f9f0309SPaul Brook     s->lookup_symbol = lookup_symbolxx;
145549918a75Spbrook #endif
1456e80cfcfcSbellard     s->next = syminfos;
1457e80cfcfcSbellard     syminfos = s;
1458689f936fSbellard }
145931e31b8aSbellard 
1460e5fe0c52Spbrook int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
146131e31b8aSbellard                     struct image_info * info)
146231e31b8aSbellard {
146331e31b8aSbellard     struct elfhdr elf_ex;
146431e31b8aSbellard     struct elfhdr interp_elf_ex;
146531e31b8aSbellard     struct exec interp_ex;
146631e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
1467992f48a0Sblueswir1     abi_ulong load_addr, load_bias;
146831e31b8aSbellard     int load_addr_set = 0;
146931e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
147031e31b8aSbellard     unsigned char ibcs2_interpreter;
147131e31b8aSbellard     int i;
1472992f48a0Sblueswir1     abi_ulong mapped_addr;
147331e31b8aSbellard     struct elf_phdr * elf_ppnt;
147431e31b8aSbellard     struct elf_phdr *elf_phdata;
1475992f48a0Sblueswir1     abi_ulong elf_bss, k, elf_brk;
147631e31b8aSbellard     int retval;
147731e31b8aSbellard     char * elf_interpreter;
1478992f48a0Sblueswir1     abi_ulong elf_entry, interp_load_addr = 0;
147931e31b8aSbellard     int status;
1480992f48a0Sblueswir1     abi_ulong start_code, end_code, start_data, end_data;
1481992f48a0Sblueswir1     abi_ulong reloc_func_desc = 0;
1482992f48a0Sblueswir1     abi_ulong elf_stack;
148331e31b8aSbellard     char passed_fileno[6];
148431e31b8aSbellard 
148531e31b8aSbellard     ibcs2_interpreter = 0;
148631e31b8aSbellard     status = 0;
148731e31b8aSbellard     load_addr = 0;
148809bfb054Sbellard     load_bias = 0;
148931e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
149031e31b8aSbellard #ifdef BSWAP_NEEDED
149131e31b8aSbellard     bswap_ehdr(&elf_ex);
149231e31b8aSbellard #endif
149331e31b8aSbellard 
149431e31b8aSbellard     /* First of all, some simple consistency checks */
149531e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
149631e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
149731e31b8aSbellard 	    return -ENOEXEC;
149831e31b8aSbellard     }
149931e31b8aSbellard 
1500e5fe0c52Spbrook     bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
1501e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
1502e5fe0c52Spbrook     bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
1503e5fe0c52Spbrook     if (!bprm->p) {
1504e5fe0c52Spbrook         retval = -E2BIG;
1505e5fe0c52Spbrook     }
1506e5fe0c52Spbrook 
150731e31b8aSbellard     /* Now read in all of the header information */
150831e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
150931e31b8aSbellard     if (elf_phdata == NULL) {
151031e31b8aSbellard 	return -ENOMEM;
151131e31b8aSbellard     }
151231e31b8aSbellard 
151331e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
151431e31b8aSbellard     if(retval > 0) {
151531e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
151631e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
151731e31b8aSbellard     }
151831e31b8aSbellard 
151931e31b8aSbellard     if (retval < 0) {
152031e31b8aSbellard 	perror("load_elf_binary");
152131e31b8aSbellard 	exit(-1);
152231e31b8aSbellard 	free (elf_phdata);
152331e31b8aSbellard 	return -errno;
152431e31b8aSbellard     }
152531e31b8aSbellard 
1526b17780d5Sbellard #ifdef BSWAP_NEEDED
1527b17780d5Sbellard     elf_ppnt = elf_phdata;
1528b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
1529b17780d5Sbellard         bswap_phdr(elf_ppnt);
1530b17780d5Sbellard     }
1531b17780d5Sbellard #endif
153231e31b8aSbellard     elf_ppnt = elf_phdata;
153331e31b8aSbellard 
153431e31b8aSbellard     elf_bss = 0;
153531e31b8aSbellard     elf_brk = 0;
153631e31b8aSbellard 
153731e31b8aSbellard 
1538992f48a0Sblueswir1     elf_stack = ~((abi_ulong)0UL);
153931e31b8aSbellard     elf_interpreter = NULL;
1540992f48a0Sblueswir1     start_code = ~((abi_ulong)0UL);
154131e31b8aSbellard     end_code = 0;
1542863cf0b7Sj_mayer     start_data = 0;
154331e31b8aSbellard     end_data = 0;
154498448f58Sblueswir1     interp_ex.a_info = 0;
154531e31b8aSbellard 
154631e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
154731e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
154831e31b8aSbellard 	    if ( elf_interpreter != NULL )
154931e31b8aSbellard 	    {
155031e31b8aSbellard 		free (elf_phdata);
155131e31b8aSbellard 		free(elf_interpreter);
155231e31b8aSbellard 		close(bprm->fd);
155331e31b8aSbellard 		return -EINVAL;
155431e31b8aSbellard 	    }
155531e31b8aSbellard 
155631e31b8aSbellard 	    /* This is the program interpreter used for
155731e31b8aSbellard 	     * shared libraries - for now assume that this
155831e31b8aSbellard 	     * is an a.out format binary
155931e31b8aSbellard 	     */
156031e31b8aSbellard 
156132ce6337Sbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
156231e31b8aSbellard 
156331e31b8aSbellard 	    if (elf_interpreter == NULL) {
156431e31b8aSbellard 		free (elf_phdata);
156531e31b8aSbellard 		close(bprm->fd);
156631e31b8aSbellard 		return -ENOMEM;
156731e31b8aSbellard 	    }
156831e31b8aSbellard 
156931e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
157031e31b8aSbellard 	    if(retval >= 0) {
157132ce6337Sbellard 		retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
157231e31b8aSbellard 	    }
157331e31b8aSbellard 	    if(retval < 0) {
157431e31b8aSbellard 	 	perror("load_elf_binary2");
157531e31b8aSbellard 		exit(-1);
157631e31b8aSbellard 	    }
157731e31b8aSbellard 
157831e31b8aSbellard 	    /* If the program interpreter is one of these two,
157931e31b8aSbellard 	       then assume an iBCS2 image. Otherwise assume
158031e31b8aSbellard 	       a native linux image. */
158131e31b8aSbellard 
158231e31b8aSbellard 	    /* JRP - Need to add X86 lib dir stuff here... */
158331e31b8aSbellard 
158431e31b8aSbellard 	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
158531e31b8aSbellard 		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
158631e31b8aSbellard 	      ibcs2_interpreter = 1;
158731e31b8aSbellard 	    }
158831e31b8aSbellard 
158931e31b8aSbellard #if 0
15903bc0bdcaSPaul Bolle 	    printf("Using ELF interpreter %s\n", path(elf_interpreter));
159131e31b8aSbellard #endif
159231e31b8aSbellard 	    if (retval >= 0) {
159332ce6337Sbellard 		retval = open(path(elf_interpreter), O_RDONLY);
159431e31b8aSbellard 		if(retval >= 0) {
159531e31b8aSbellard 		    interpreter_fd = retval;
159631e31b8aSbellard 		}
159731e31b8aSbellard 		else {
159831e31b8aSbellard 		    perror(elf_interpreter);
159931e31b8aSbellard 		    exit(-1);
160031e31b8aSbellard 		    /* retval = -errno; */
160131e31b8aSbellard 		}
160231e31b8aSbellard 	    }
160331e31b8aSbellard 
160431e31b8aSbellard 	    if (retval >= 0) {
160531e31b8aSbellard 		retval = lseek(interpreter_fd, 0, SEEK_SET);
160631e31b8aSbellard 		if(retval >= 0) {
160731e31b8aSbellard 		    retval = read(interpreter_fd,bprm->buf,128);
160831e31b8aSbellard 		}
160931e31b8aSbellard 	    }
161031e31b8aSbellard 	    if (retval >= 0) {
161131e31b8aSbellard 		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
161231e31b8aSbellard 		interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
161331e31b8aSbellard 	    }
161431e31b8aSbellard 	    if (retval < 0) {
161531e31b8aSbellard 		perror("load_elf_binary3");
161631e31b8aSbellard 		exit(-1);
161731e31b8aSbellard 		free (elf_phdata);
161831e31b8aSbellard 		free(elf_interpreter);
161931e31b8aSbellard 		close(bprm->fd);
162031e31b8aSbellard 		return retval;
162131e31b8aSbellard 	    }
162231e31b8aSbellard 	}
162331e31b8aSbellard 	elf_ppnt++;
162431e31b8aSbellard     }
162531e31b8aSbellard 
162631e31b8aSbellard     /* Some simple consistency checks for the interpreter */
162731e31b8aSbellard     if (elf_interpreter){
162831e31b8aSbellard 	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
162931e31b8aSbellard 
163031e31b8aSbellard 	/* Now figure out which format our binary is */
163131e31b8aSbellard 	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
163231e31b8aSbellard 	    	(N_MAGIC(interp_ex) != QMAGIC)) {
163331e31b8aSbellard 	  interpreter_type = INTERPRETER_ELF;
163431e31b8aSbellard 	}
163531e31b8aSbellard 
163631e31b8aSbellard 	if (interp_elf_ex.e_ident[0] != 0x7f ||
1637b55266b5Sblueswir1             strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
163831e31b8aSbellard 	    interpreter_type &= ~INTERPRETER_ELF;
163931e31b8aSbellard 	}
164031e31b8aSbellard 
164131e31b8aSbellard 	if (!interpreter_type) {
164231e31b8aSbellard 	    free(elf_interpreter);
164331e31b8aSbellard 	    free(elf_phdata);
164431e31b8aSbellard 	    close(bprm->fd);
164531e31b8aSbellard 	    return -ELIBBAD;
164631e31b8aSbellard 	}
164731e31b8aSbellard     }
164831e31b8aSbellard 
164931e31b8aSbellard     /* OK, we are done with that, now set up the arg stuff,
165031e31b8aSbellard        and then start this sucker up */
165131e31b8aSbellard 
1652e5fe0c52Spbrook     {
165331e31b8aSbellard 	char * passed_p;
165431e31b8aSbellard 
165531e31b8aSbellard 	if (interpreter_type == INTERPRETER_AOUT) {
1656eba2af63Sbellard 	    snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
165731e31b8aSbellard 	    passed_p = passed_fileno;
165831e31b8aSbellard 
165931e31b8aSbellard 	    if (elf_interpreter) {
1660e5fe0c52Spbrook 		bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
166131e31b8aSbellard 		bprm->argc++;
166231e31b8aSbellard 	    }
166331e31b8aSbellard 	}
166431e31b8aSbellard 	if (!bprm->p) {
166531e31b8aSbellard 	    if (elf_interpreter) {
166631e31b8aSbellard 	        free(elf_interpreter);
166731e31b8aSbellard 	    }
166831e31b8aSbellard 	    free (elf_phdata);
166931e31b8aSbellard 	    close(bprm->fd);
167031e31b8aSbellard 	    return -E2BIG;
167131e31b8aSbellard 	}
167231e31b8aSbellard     }
167331e31b8aSbellard 
167431e31b8aSbellard     /* OK, This is the point of no return */
167531e31b8aSbellard     info->end_data = 0;
167631e31b8aSbellard     info->end_code = 0;
1677992f48a0Sblueswir1     info->start_mmap = (abi_ulong)ELF_START_MMAP;
167831e31b8aSbellard     info->mmap = 0;
1679992f48a0Sblueswir1     elf_entry = (abi_ulong) elf_ex.e_entry;
168031e31b8aSbellard 
1681379f6698SPaul Brook #if defined(CONFIG_USE_GUEST_BASE)
1682379f6698SPaul Brook     /*
1683379f6698SPaul Brook      * In case where user has not explicitly set the guest_base, we
1684379f6698SPaul Brook      * probe here that should we set it automatically.
1685379f6698SPaul Brook      */
1686379f6698SPaul Brook     if (!have_guest_base) {
1687379f6698SPaul Brook         /*
1688379f6698SPaul Brook          * Go through ELF program header table and find out whether
1689379f6698SPaul Brook 	 * any of the segments drop below our current mmap_min_addr and
1690379f6698SPaul Brook          * in that case set guest_base to corresponding address.
1691379f6698SPaul Brook          */
1692379f6698SPaul Brook         for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
1693379f6698SPaul Brook             i++, elf_ppnt++) {
1694379f6698SPaul Brook             if (elf_ppnt->p_type != PT_LOAD)
1695379f6698SPaul Brook                 continue;
1696379f6698SPaul Brook             if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) {
1697379f6698SPaul Brook                 guest_base = HOST_PAGE_ALIGN(mmap_min_addr);
1698379f6698SPaul Brook                 break;
1699379f6698SPaul Brook             }
1700379f6698SPaul Brook         }
1701379f6698SPaul Brook     }
1702379f6698SPaul Brook #endif /* CONFIG_USE_GUEST_BASE */
1703379f6698SPaul Brook 
170431e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
170531e31b8aSbellard        change some of these later */
170631e31b8aSbellard     info->rss = 0;
170731e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
170831e31b8aSbellard     info->start_stack = bprm->p;
170931e31b8aSbellard 
171031e31b8aSbellard     /* Now we do a little grungy work by mmaping the ELF image into
171131e31b8aSbellard      * the correct location in memory.  At this point, we assume that
171231e31b8aSbellard      * the image should be loaded at fixed address, not at a variable
171331e31b8aSbellard      * address.
171431e31b8aSbellard      */
171531e31b8aSbellard 
171631e31b8aSbellard     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
171731e31b8aSbellard         int elf_prot = 0;
171809bfb054Sbellard         int elf_flags = 0;
1719992f48a0Sblueswir1         abi_ulong error;
172009bfb054Sbellard 
172109bfb054Sbellard 	if (elf_ppnt->p_type != PT_LOAD)
172209bfb054Sbellard             continue;
172309bfb054Sbellard 
172431e31b8aSbellard         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
172531e31b8aSbellard         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
172631e31b8aSbellard         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
172709bfb054Sbellard         elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
172809bfb054Sbellard         if (elf_ex.e_type == ET_EXEC || load_addr_set) {
172909bfb054Sbellard             elf_flags |= MAP_FIXED;
173009bfb054Sbellard         } else if (elf_ex.e_type == ET_DYN) {
173109bfb054Sbellard             /* Try and get dynamic programs out of the way of the default mmap
173209bfb054Sbellard                base, as well as whatever program they might try to exec.  This
173309bfb054Sbellard                is because the brk will follow the loader, and is not movable.  */
173409bfb054Sbellard             /* NOTE: for qemu, we do a big mmap to get enough space
1735e91c8a77Sths                without hardcoding any address */
173654936004Sbellard             error = target_mmap(0, ET_DYN_MAP_SIZE,
173709bfb054Sbellard                                 PROT_NONE, MAP_PRIVATE | MAP_ANON,
173809bfb054Sbellard                                 -1, 0);
173909bfb054Sbellard             if (error == -1) {
174009bfb054Sbellard                 perror("mmap");
174109bfb054Sbellard                 exit(-1);
174209bfb054Sbellard             }
174354936004Sbellard             load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
174409bfb054Sbellard         }
174531e31b8aSbellard 
174654936004Sbellard         error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
174731e31b8aSbellard                             (elf_ppnt->p_filesz +
174854936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
174931e31b8aSbellard                             elf_prot,
175031e31b8aSbellard                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
175131e31b8aSbellard                             bprm->fd,
175231e31b8aSbellard                             (elf_ppnt->p_offset -
175354936004Sbellard                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
175409bfb054Sbellard         if (error == -1) {
175531e31b8aSbellard             perror("mmap");
175631e31b8aSbellard             exit(-1);
175731e31b8aSbellard         }
175831e31b8aSbellard 
175931e31b8aSbellard #ifdef LOW_ELF_STACK
176054936004Sbellard         if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
176154936004Sbellard             elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
176231e31b8aSbellard #endif
176331e31b8aSbellard 
176431e31b8aSbellard         if (!load_addr_set) {
176531e31b8aSbellard             load_addr_set = 1;
176609bfb054Sbellard             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
176709bfb054Sbellard             if (elf_ex.e_type == ET_DYN) {
176809bfb054Sbellard                 load_bias += error -
176954936004Sbellard                     TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
177009bfb054Sbellard                 load_addr += load_bias;
177184409ddbSj_mayer                 reloc_func_desc = load_bias;
177209bfb054Sbellard             }
177331e31b8aSbellard         }
177431e31b8aSbellard         k = elf_ppnt->p_vaddr;
177509bfb054Sbellard         if (k < start_code)
177609bfb054Sbellard             start_code = k;
1777863cf0b7Sj_mayer         if (start_data < k)
1778863cf0b7Sj_mayer             start_data = k;
177931e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
178009bfb054Sbellard         if (k > elf_bss)
178109bfb054Sbellard             elf_bss = k;
178231e31b8aSbellard         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
178331e31b8aSbellard             end_code = k;
178409bfb054Sbellard         if (end_data < k)
178509bfb054Sbellard             end_data = k;
178631e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
178731e31b8aSbellard         if (k > elf_brk) elf_brk = k;
178831e31b8aSbellard     }
178909bfb054Sbellard 
179009bfb054Sbellard     elf_entry += load_bias;
179109bfb054Sbellard     elf_bss += load_bias;
179209bfb054Sbellard     elf_brk += load_bias;
179309bfb054Sbellard     start_code += load_bias;
179409bfb054Sbellard     end_code += load_bias;
1795863cf0b7Sj_mayer     start_data += load_bias;
179609bfb054Sbellard     end_data += load_bias;
179731e31b8aSbellard 
179831e31b8aSbellard     if (elf_interpreter) {
179931e31b8aSbellard 	if (interpreter_type & 1) {
180031e31b8aSbellard 	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
180131e31b8aSbellard 	}
180231e31b8aSbellard 	else if (interpreter_type & 2) {
180331e31b8aSbellard 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
180431e31b8aSbellard 					    &interp_load_addr);
180531e31b8aSbellard 	}
180684409ddbSj_mayer         reloc_func_desc = interp_load_addr;
180731e31b8aSbellard 
180831e31b8aSbellard 	close(interpreter_fd);
180931e31b8aSbellard 	free(elf_interpreter);
181031e31b8aSbellard 
1811992f48a0Sblueswir1 	if (elf_entry == ~((abi_ulong)0UL)) {
181231e31b8aSbellard 	    printf("Unable to load interpreter\n");
181331e31b8aSbellard 	    free(elf_phdata);
181431e31b8aSbellard 	    exit(-1);
181531e31b8aSbellard 	    return 0;
181631e31b8aSbellard 	}
181731e31b8aSbellard     }
181831e31b8aSbellard 
181931e31b8aSbellard     free(elf_phdata);
182031e31b8aSbellard 
182193fcfe39Saliguori     if (qemu_log_enabled())
1822689f936fSbellard 	load_symbols(&elf_ex, bprm->fd);
1823689f936fSbellard 
182431e31b8aSbellard     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
182531e31b8aSbellard     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
182631e31b8aSbellard 
182731e31b8aSbellard #ifdef LOW_ELF_STACK
182831e31b8aSbellard     info->start_stack = bprm->p = elf_stack - 4;
182931e31b8aSbellard #endif
183053a5960aSpbrook     bprm->p = create_elf_tables(bprm->p,
183131e31b8aSbellard 		    bprm->argc,
183231e31b8aSbellard 		    bprm->envc,
1833a1516e92Sbellard                     &elf_ex,
183409bfb054Sbellard                     load_addr, load_bias,
183531e31b8aSbellard 		    interp_load_addr,
183631e31b8aSbellard 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
183731e31b8aSbellard 		    info);
183892a343daSj_mayer     info->load_addr = reloc_func_desc;
183931e31b8aSbellard     info->start_brk = info->brk = elf_brk;
184031e31b8aSbellard     info->end_code = end_code;
184131e31b8aSbellard     info->start_code = start_code;
1842863cf0b7Sj_mayer     info->start_data = start_data;
184331e31b8aSbellard     info->end_data = end_data;
184431e31b8aSbellard     info->start_stack = bprm->p;
184531e31b8aSbellard 
184631e31b8aSbellard     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
184731e31b8aSbellard        sections */
184831e31b8aSbellard     set_brk(elf_bss, elf_brk);
184931e31b8aSbellard 
1850768a4a36Sths     padzero(elf_bss, elf_brk);
185131e31b8aSbellard 
185231e31b8aSbellard #if 0
185331e31b8aSbellard     printf("(start_brk) %x\n" , info->start_brk);
185431e31b8aSbellard     printf("(end_code) %x\n" , info->end_code);
185531e31b8aSbellard     printf("(start_code) %x\n" , info->start_code);
185631e31b8aSbellard     printf("(end_data) %x\n" , info->end_data);
185731e31b8aSbellard     printf("(start_stack) %x\n" , info->start_stack);
185831e31b8aSbellard     printf("(brk) %x\n" , info->brk);
185931e31b8aSbellard #endif
186031e31b8aSbellard 
186131e31b8aSbellard     if ( info->personality == PER_SVR4 )
186231e31b8aSbellard     {
186331e31b8aSbellard 	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
186431e31b8aSbellard 	       and some applications "depend" upon this behavior.
186531e31b8aSbellard 	       Since we do not have the power to recompile these, we
186631e31b8aSbellard 	       emulate the SVr4 behavior.  Sigh.  */
186783fb7adfSbellard 	    mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
186831e31b8aSbellard                                       MAP_FIXED | MAP_PRIVATE, -1, 0);
186931e31b8aSbellard     }
187031e31b8aSbellard 
187131e31b8aSbellard     info->entry = elf_entry;
187231e31b8aSbellard 
1873edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
1874edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
1875edf8e2afSMika Westerberg #endif
1876edf8e2afSMika Westerberg 
187731e31b8aSbellard     return 0;
187831e31b8aSbellard }
187931e31b8aSbellard 
1880edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
1881edf8e2afSMika Westerberg 
1882edf8e2afSMika Westerberg /*
1883edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
1884a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
1885edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
1886edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
1887edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
1888edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
1889edf8e2afSMika Westerberg  *
1890edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
1891edf8e2afSMika Westerberg  * are marked with XXX.
1892edf8e2afSMika Westerberg  *
1893edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
1894edf8e2afSMika Westerberg  *
1895edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
1896dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
1897edf8e2afSMika Westerberg  * the target resides):
1898edf8e2afSMika Westerberg  *
1899edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
1900edf8e2afSMika Westerberg  *
1901edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
1902edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
1903edf8e2afSMika Westerberg  *
1904c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
1905edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
1906c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
1907edf8e2afSMika Westerberg  *
1908edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
1909edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
1910edf8e2afSMika Westerberg  *
1911c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
1912a2547a13SLaurent Desnogues  *                                const CPUState *env);
1913edf8e2afSMika Westerberg  *
1914edf8e2afSMika Westerberg  * Parameters:
1915edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
1916edf8e2afSMika Westerberg  *     env - copy registers from here
1917edf8e2afSMika Westerberg  *
1918edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
1919edf8e2afSMika Westerberg  */
1920edf8e2afSMika Westerberg 
1921edf8e2afSMika Westerberg /* An ELF note in memory */
1922edf8e2afSMika Westerberg struct memelfnote {
1923edf8e2afSMika Westerberg     const char *name;
1924edf8e2afSMika Westerberg     size_t     namesz;
1925edf8e2afSMika Westerberg     size_t     namesz_rounded;
1926edf8e2afSMika Westerberg     int        type;
1927edf8e2afSMika Westerberg     size_t     datasz;
1928edf8e2afSMika Westerberg     void       *data;
1929edf8e2afSMika Westerberg     size_t     notesz;
1930edf8e2afSMika Westerberg };
1931edf8e2afSMika Westerberg 
1932a2547a13SLaurent Desnogues struct target_elf_siginfo {
1933edf8e2afSMika Westerberg     int  si_signo; /* signal number */
1934edf8e2afSMika Westerberg     int  si_code;  /* extra code */
1935edf8e2afSMika Westerberg     int  si_errno; /* errno */
1936edf8e2afSMika Westerberg };
1937edf8e2afSMika Westerberg 
1938a2547a13SLaurent Desnogues struct target_elf_prstatus {
1939a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
1940edf8e2afSMika Westerberg     short              pr_cursig;    /* Current signal */
1941edf8e2afSMika Westerberg     target_ulong       pr_sigpend;   /* XXX */
1942edf8e2afSMika Westerberg     target_ulong       pr_sighold;   /* XXX */
1943c227f099SAnthony Liguori     target_pid_t       pr_pid;
1944c227f099SAnthony Liguori     target_pid_t       pr_ppid;
1945c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
1946c227f099SAnthony Liguori     target_pid_t       pr_sid;
1947edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
1948edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
1949edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
1950edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
1951c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
1952edf8e2afSMika Westerberg     int                pr_fpvalid;   /* XXX */
1953edf8e2afSMika Westerberg };
1954edf8e2afSMika Westerberg 
1955edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
1956edf8e2afSMika Westerberg 
1957a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
1958edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
1959edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
1960edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
1961edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
1962edf8e2afSMika Westerberg     target_ulong pr_flag;        /* flags */
1963c227f099SAnthony Liguori     target_uid_t pr_uid;
1964c227f099SAnthony Liguori     target_gid_t pr_gid;
1965c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
1966edf8e2afSMika Westerberg     /* Lots missing */
1967edf8e2afSMika Westerberg     char    pr_fname[16];           /* filename of executable */
1968edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
1969edf8e2afSMika Westerberg };
1970edf8e2afSMika Westerberg 
1971edf8e2afSMika Westerberg /* Here is the structure in which status of each thread is captured. */
1972edf8e2afSMika Westerberg struct elf_thread_status {
197372cf2d4fSBlue Swirl     QTAILQ_ENTRY(elf_thread_status)  ets_link;
1974a2547a13SLaurent Desnogues     struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
1975edf8e2afSMika Westerberg #if 0
1976edf8e2afSMika Westerberg     elf_fpregset_t fpu;             /* NT_PRFPREG */
1977edf8e2afSMika Westerberg     struct task_struct *thread;
1978edf8e2afSMika Westerberg     elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
1979edf8e2afSMika Westerberg #endif
1980edf8e2afSMika Westerberg     struct memelfnote notes[1];
1981edf8e2afSMika Westerberg     int num_notes;
1982edf8e2afSMika Westerberg };
1983edf8e2afSMika Westerberg 
1984edf8e2afSMika Westerberg struct elf_note_info {
1985edf8e2afSMika Westerberg     struct memelfnote   *notes;
1986a2547a13SLaurent Desnogues     struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
1987a2547a13SLaurent Desnogues     struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
1988edf8e2afSMika Westerberg 
198972cf2d4fSBlue Swirl     QTAILQ_HEAD(thread_list_head, elf_thread_status) thread_list;
1990edf8e2afSMika Westerberg #if 0
1991edf8e2afSMika Westerberg     /*
1992edf8e2afSMika Westerberg      * Current version of ELF coredump doesn't support
1993edf8e2afSMika Westerberg      * dumping fp regs etc.
1994edf8e2afSMika Westerberg      */
1995edf8e2afSMika Westerberg     elf_fpregset_t *fpu;
1996edf8e2afSMika Westerberg     elf_fpxregset_t *xfpu;
1997edf8e2afSMika Westerberg     int thread_status_size;
1998edf8e2afSMika Westerberg #endif
1999edf8e2afSMika Westerberg     int notes_size;
2000edf8e2afSMika Westerberg     int numnote;
2001edf8e2afSMika Westerberg };
2002edf8e2afSMika Westerberg 
2003edf8e2afSMika Westerberg struct vm_area_struct {
2004edf8e2afSMika Westerberg     abi_ulong   vma_start;  /* start vaddr of memory region */
2005edf8e2afSMika Westerberg     abi_ulong   vma_end;    /* end vaddr of memory region */
2006edf8e2afSMika Westerberg     abi_ulong   vma_flags;  /* protection etc. flags for the region */
200772cf2d4fSBlue Swirl     QTAILQ_ENTRY(vm_area_struct) vma_link;
2008edf8e2afSMika Westerberg };
2009edf8e2afSMika Westerberg 
2010edf8e2afSMika Westerberg struct mm_struct {
201172cf2d4fSBlue Swirl     QTAILQ_HEAD(, vm_area_struct) mm_mmap;
2012edf8e2afSMika Westerberg     int mm_count;           /* number of mappings */
2013edf8e2afSMika Westerberg };
2014edf8e2afSMika Westerberg 
2015edf8e2afSMika Westerberg static struct mm_struct *vma_init(void);
2016edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *);
2017edf8e2afSMika Westerberg static int vma_add_mapping(struct mm_struct *, abi_ulong,
2018edf8e2afSMika Westerberg     abi_ulong, abi_ulong);
2019edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *);
2020edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *);
2021edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *);
2022edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *);
2023edf8e2afSMika Westerberg static int vma_walker(void *priv, unsigned long start, unsigned long end,
2024edf8e2afSMika Westerberg     unsigned long flags);
2025edf8e2afSMika Westerberg 
2026edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
2027edf8e2afSMika Westerberg static void fill_note(struct memelfnote *, const char *, int,
2028edf8e2afSMika Westerberg     unsigned int, void *);
2029a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
2030a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
2031edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *, const TaskState *);
2032edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
2033edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *);
2034edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *);
2035edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *, long, const CPUState *);
2036edf8e2afSMika Westerberg static void fill_thread_info(struct elf_note_info *, const CPUState *);
2037edf8e2afSMika Westerberg static int core_dump_filename(const TaskState *, char *, size_t);
2038edf8e2afSMika Westerberg 
2039edf8e2afSMika Westerberg static int dump_write(int, const void *, size_t);
2040edf8e2afSMika Westerberg static int write_note(struct memelfnote *, int);
2041edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *, int);
2042edf8e2afSMika Westerberg 
2043edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
2044a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *);
2045a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *);
2046edf8e2afSMika Westerberg 
2047a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
2048edf8e2afSMika Westerberg {
2049edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo);
2050edf8e2afSMika Westerberg     prstatus->pr_info.si_code = tswapl(prstatus->pr_info.si_code);
2051edf8e2afSMika Westerberg     prstatus->pr_info.si_errno = tswapl(prstatus->pr_info.si_errno);
2052edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
2053edf8e2afSMika Westerberg     prstatus->pr_sigpend = tswapl(prstatus->pr_sigpend);
2054edf8e2afSMika Westerberg     prstatus->pr_sighold = tswapl(prstatus->pr_sighold);
2055edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
2056edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
2057edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
2058edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
2059edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
2060edf8e2afSMika Westerberg     /* regs should be in correct format already */
2061edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
2062edf8e2afSMika Westerberg }
2063edf8e2afSMika Westerberg 
2064a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
2065edf8e2afSMika Westerberg {
2066edf8e2afSMika Westerberg     psinfo->pr_flag = tswapl(psinfo->pr_flag);
2067edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
2068edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
2069edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
2070edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
2071edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
2072edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
2073edf8e2afSMika Westerberg }
2074edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
2075edf8e2afSMika Westerberg 
2076edf8e2afSMika Westerberg /*
2077edf8e2afSMika Westerberg  * Minimal support for linux memory regions.  These are needed
2078edf8e2afSMika Westerberg  * when we are finding out what memory exactly belongs to
2079edf8e2afSMika Westerberg  * emulated process.  No locks needed here, as long as
2080edf8e2afSMika Westerberg  * thread that received the signal is stopped.
2081edf8e2afSMika Westerberg  */
2082edf8e2afSMika Westerberg 
2083edf8e2afSMika Westerberg static struct mm_struct *vma_init(void)
2084edf8e2afSMika Westerberg {
2085edf8e2afSMika Westerberg     struct mm_struct *mm;
2086edf8e2afSMika Westerberg 
2087edf8e2afSMika Westerberg     if ((mm = qemu_malloc(sizeof (*mm))) == NULL)
2088edf8e2afSMika Westerberg         return (NULL);
2089edf8e2afSMika Westerberg 
2090edf8e2afSMika Westerberg     mm->mm_count = 0;
209172cf2d4fSBlue Swirl     QTAILQ_INIT(&mm->mm_mmap);
2092edf8e2afSMika Westerberg 
2093edf8e2afSMika Westerberg     return (mm);
2094edf8e2afSMika Westerberg }
2095edf8e2afSMika Westerberg 
2096edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *mm)
2097edf8e2afSMika Westerberg {
2098edf8e2afSMika Westerberg     struct vm_area_struct *vma;
2099edf8e2afSMika Westerberg 
2100edf8e2afSMika Westerberg     while ((vma = vma_first(mm)) != NULL) {
210172cf2d4fSBlue Swirl         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
2102edf8e2afSMika Westerberg         qemu_free(vma);
2103edf8e2afSMika Westerberg     }
2104edf8e2afSMika Westerberg     qemu_free(mm);
2105edf8e2afSMika Westerberg }
2106edf8e2afSMika Westerberg 
2107edf8e2afSMika Westerberg static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
2108edf8e2afSMika Westerberg     abi_ulong end, abi_ulong flags)
2109edf8e2afSMika Westerberg {
2110edf8e2afSMika Westerberg     struct vm_area_struct *vma;
2111edf8e2afSMika Westerberg 
2112edf8e2afSMika Westerberg     if ((vma = qemu_mallocz(sizeof (*vma))) == NULL)
2113edf8e2afSMika Westerberg         return (-1);
2114edf8e2afSMika Westerberg 
2115edf8e2afSMika Westerberg     vma->vma_start = start;
2116edf8e2afSMika Westerberg     vma->vma_end = end;
2117edf8e2afSMika Westerberg     vma->vma_flags = flags;
2118edf8e2afSMika Westerberg 
211972cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
2120edf8e2afSMika Westerberg     mm->mm_count++;
2121edf8e2afSMika Westerberg 
2122edf8e2afSMika Westerberg     return (0);
2123edf8e2afSMika Westerberg }
2124edf8e2afSMika Westerberg 
2125edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *mm)
2126edf8e2afSMika Westerberg {
212772cf2d4fSBlue Swirl     return (QTAILQ_FIRST(&mm->mm_mmap));
2128edf8e2afSMika Westerberg }
2129edf8e2afSMika Westerberg 
2130edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
2131edf8e2afSMika Westerberg {
213272cf2d4fSBlue Swirl     return (QTAILQ_NEXT(vma, vma_link));
2133edf8e2afSMika Westerberg }
2134edf8e2afSMika Westerberg 
2135edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *mm)
2136edf8e2afSMika Westerberg {
2137edf8e2afSMika Westerberg     return (mm->mm_count);
2138edf8e2afSMika Westerberg }
2139edf8e2afSMika Westerberg 
2140edf8e2afSMika Westerberg /*
2141edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
2142edf8e2afSMika Westerberg  */
2143edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
2144edf8e2afSMika Westerberg {
2145edf8e2afSMika Westerberg     /* if we cannot even read the first page, skip it */
2146edf8e2afSMika Westerberg     if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
2147edf8e2afSMika Westerberg         return (0);
2148edf8e2afSMika Westerberg 
2149edf8e2afSMika Westerberg     /*
2150edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
2151edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
2152edf8e2afSMika Westerberg      * target library etc.  However, thread stacks are marked
2153edf8e2afSMika Westerberg      * also executable so we read in first page of given region
2154edf8e2afSMika Westerberg      * and check whether it contains elf header.  If there is
2155edf8e2afSMika Westerberg      * no elf header, we dump it.
2156edf8e2afSMika Westerberg      */
2157edf8e2afSMika Westerberg     if (vma->vma_flags & PROT_EXEC) {
2158edf8e2afSMika Westerberg         char page[TARGET_PAGE_SIZE];
2159edf8e2afSMika Westerberg 
2160edf8e2afSMika Westerberg         copy_from_user(page, vma->vma_start, sizeof (page));
2161edf8e2afSMika Westerberg         if ((page[EI_MAG0] == ELFMAG0) &&
2162edf8e2afSMika Westerberg             (page[EI_MAG1] == ELFMAG1) &&
2163edf8e2afSMika Westerberg             (page[EI_MAG2] == ELFMAG2) &&
2164edf8e2afSMika Westerberg             (page[EI_MAG3] == ELFMAG3)) {
2165edf8e2afSMika Westerberg             /*
2166edf8e2afSMika Westerberg              * Mappings are possibly from ELF binary.  Don't dump
2167edf8e2afSMika Westerberg              * them.
2168edf8e2afSMika Westerberg              */
2169edf8e2afSMika Westerberg             return (0);
2170edf8e2afSMika Westerberg         }
2171edf8e2afSMika Westerberg     }
2172edf8e2afSMika Westerberg 
2173edf8e2afSMika Westerberg     return (vma->vma_end - vma->vma_start);
2174edf8e2afSMika Westerberg }
2175edf8e2afSMika Westerberg 
2176edf8e2afSMika Westerberg static int vma_walker(void *priv, unsigned long start, unsigned long end,
2177edf8e2afSMika Westerberg     unsigned long flags)
2178edf8e2afSMika Westerberg {
2179edf8e2afSMika Westerberg     struct mm_struct *mm = (struct mm_struct *)priv;
2180edf8e2afSMika Westerberg 
2181edf8e2afSMika Westerberg     /*
2182edf8e2afSMika Westerberg      * Don't dump anything that qemu has reserved for internal use.
2183edf8e2afSMika Westerberg      */
2184edf8e2afSMika Westerberg     if (flags & PAGE_RESERVED)
2185edf8e2afSMika Westerberg         return (0);
2186edf8e2afSMika Westerberg 
2187edf8e2afSMika Westerberg     vma_add_mapping(mm, start, end, flags);
2188edf8e2afSMika Westerberg     return (0);
2189edf8e2afSMika Westerberg }
2190edf8e2afSMika Westerberg 
2191edf8e2afSMika Westerberg static void fill_note(struct memelfnote *note, const char *name, int type,
2192edf8e2afSMika Westerberg     unsigned int sz, void *data)
2193edf8e2afSMika Westerberg {
2194edf8e2afSMika Westerberg     unsigned int namesz;
2195edf8e2afSMika Westerberg 
2196edf8e2afSMika Westerberg     namesz = strlen(name) + 1;
2197edf8e2afSMika Westerberg     note->name = name;
2198edf8e2afSMika Westerberg     note->namesz = namesz;
2199edf8e2afSMika Westerberg     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
2200edf8e2afSMika Westerberg     note->type = type;
2201edf8e2afSMika Westerberg     note->datasz = roundup(sz, sizeof (int32_t));;
2202edf8e2afSMika Westerberg     note->data = data;
2203edf8e2afSMika Westerberg 
2204edf8e2afSMika Westerberg     /*
2205edf8e2afSMika Westerberg      * We calculate rounded up note size here as specified by
2206edf8e2afSMika Westerberg      * ELF document.
2207edf8e2afSMika Westerberg      */
2208edf8e2afSMika Westerberg     note->notesz = sizeof (struct elf_note) +
2209edf8e2afSMika Westerberg         note->namesz_rounded + note->datasz;
2210edf8e2afSMika Westerberg }
2211edf8e2afSMika Westerberg 
2212edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
2213edf8e2afSMika Westerberg     uint32_t flags)
2214edf8e2afSMika Westerberg {
2215edf8e2afSMika Westerberg     (void) memset(elf, 0, sizeof(*elf));
2216edf8e2afSMika Westerberg 
2217edf8e2afSMika Westerberg     (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
2218edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
2219edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
2220edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
2221edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
2222edf8e2afSMika Westerberg 
2223edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
2224edf8e2afSMika Westerberg     elf->e_machine = machine;
2225edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
2226edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
2227edf8e2afSMika Westerberg     elf->e_flags = flags;
2228edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
2229edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
2230edf8e2afSMika Westerberg     elf->e_phnum = segs;
2231edf8e2afSMika Westerberg 
2232edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
2233edf8e2afSMika Westerberg     bswap_ehdr(elf);
2234edf8e2afSMika Westerberg #endif
2235edf8e2afSMika Westerberg }
2236edf8e2afSMika Westerberg 
2237edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
2238edf8e2afSMika Westerberg {
2239edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
2240edf8e2afSMika Westerberg     phdr->p_offset = offset;
2241edf8e2afSMika Westerberg     phdr->p_vaddr = 0;
2242edf8e2afSMika Westerberg     phdr->p_paddr = 0;
2243edf8e2afSMika Westerberg     phdr->p_filesz = sz;
2244edf8e2afSMika Westerberg     phdr->p_memsz = 0;
2245edf8e2afSMika Westerberg     phdr->p_flags = 0;
2246edf8e2afSMika Westerberg     phdr->p_align = 0;
2247edf8e2afSMika Westerberg 
2248edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
2249edf8e2afSMika Westerberg     bswap_phdr(phdr);
2250edf8e2afSMika Westerberg #endif
2251edf8e2afSMika Westerberg }
2252edf8e2afSMika Westerberg 
2253edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *note)
2254edf8e2afSMika Westerberg {
2255edf8e2afSMika Westerberg     return (note->notesz);
2256edf8e2afSMika Westerberg }
2257edf8e2afSMika Westerberg 
2258a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *prstatus,
2259edf8e2afSMika Westerberg     const TaskState *ts, int signr)
2260edf8e2afSMika Westerberg {
2261edf8e2afSMika Westerberg     (void) memset(prstatus, 0, sizeof (*prstatus));
2262edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
2263edf8e2afSMika Westerberg     prstatus->pr_pid = ts->ts_tid;
2264edf8e2afSMika Westerberg     prstatus->pr_ppid = getppid();
2265edf8e2afSMika Westerberg     prstatus->pr_pgrp = getpgrp();
2266edf8e2afSMika Westerberg     prstatus->pr_sid = getsid(0);
2267edf8e2afSMika Westerberg 
2268edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
2269edf8e2afSMika Westerberg     bswap_prstatus(prstatus);
2270edf8e2afSMika Westerberg #endif
2271edf8e2afSMika Westerberg }
2272edf8e2afSMika Westerberg 
2273a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
2274edf8e2afSMika Westerberg {
2275edf8e2afSMika Westerberg     char *filename, *base_filename;
2276edf8e2afSMika Westerberg     unsigned int i, len;
2277edf8e2afSMika Westerberg 
2278edf8e2afSMika Westerberg     (void) memset(psinfo, 0, sizeof (*psinfo));
2279edf8e2afSMika Westerberg 
2280edf8e2afSMika Westerberg     len = ts->info->arg_end - ts->info->arg_start;
2281edf8e2afSMika Westerberg     if (len >= ELF_PRARGSZ)
2282edf8e2afSMika Westerberg         len = ELF_PRARGSZ - 1;
2283edf8e2afSMika Westerberg     if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len))
2284edf8e2afSMika Westerberg         return -EFAULT;
2285edf8e2afSMika Westerberg     for (i = 0; i < len; i++)
2286edf8e2afSMika Westerberg         if (psinfo->pr_psargs[i] == 0)
2287edf8e2afSMika Westerberg             psinfo->pr_psargs[i] = ' ';
2288edf8e2afSMika Westerberg     psinfo->pr_psargs[len] = 0;
2289edf8e2afSMika Westerberg 
2290edf8e2afSMika Westerberg     psinfo->pr_pid = getpid();
2291edf8e2afSMika Westerberg     psinfo->pr_ppid = getppid();
2292edf8e2afSMika Westerberg     psinfo->pr_pgrp = getpgrp();
2293edf8e2afSMika Westerberg     psinfo->pr_sid = getsid(0);
2294edf8e2afSMika Westerberg     psinfo->pr_uid = getuid();
2295edf8e2afSMika Westerberg     psinfo->pr_gid = getgid();
2296edf8e2afSMika Westerberg 
2297edf8e2afSMika Westerberg     filename = strdup(ts->bprm->filename);
2298edf8e2afSMika Westerberg     base_filename = strdup(basename(filename));
2299edf8e2afSMika Westerberg     (void) strncpy(psinfo->pr_fname, base_filename,
2300edf8e2afSMika Westerberg         sizeof(psinfo->pr_fname));
2301edf8e2afSMika Westerberg     free(base_filename);
2302edf8e2afSMika Westerberg     free(filename);
2303edf8e2afSMika Westerberg 
2304edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
2305edf8e2afSMika Westerberg     bswap_psinfo(psinfo);
2306edf8e2afSMika Westerberg #endif
2307edf8e2afSMika Westerberg     return (0);
2308edf8e2afSMika Westerberg }
2309edf8e2afSMika Westerberg 
2310edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
2311edf8e2afSMika Westerberg {
2312edf8e2afSMika Westerberg     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
2313edf8e2afSMika Westerberg     elf_addr_t orig_auxv = auxv;
2314edf8e2afSMika Westerberg     abi_ulong val;
2315edf8e2afSMika Westerberg     void *ptr;
2316edf8e2afSMika Westerberg     int i, len;
2317edf8e2afSMika Westerberg 
2318edf8e2afSMika Westerberg     /*
2319edf8e2afSMika Westerberg      * Auxiliary vector is stored in target process stack.  It contains
2320edf8e2afSMika Westerberg      * {type, value} pairs that we need to dump into note.  This is not
2321edf8e2afSMika Westerberg      * strictly necessary but we do it here for sake of completeness.
2322edf8e2afSMika Westerberg      */
2323edf8e2afSMika Westerberg 
2324edf8e2afSMika Westerberg     /* find out lenght of the vector, AT_NULL is terminator */
2325edf8e2afSMika Westerberg     i = len = 0;
2326edf8e2afSMika Westerberg     do {
2327edf8e2afSMika Westerberg         get_user_ual(val, auxv);
2328edf8e2afSMika Westerberg         i += 2;
2329edf8e2afSMika Westerberg         auxv += 2 * sizeof (elf_addr_t);
2330edf8e2afSMika Westerberg     } while (val != AT_NULL);
2331edf8e2afSMika Westerberg     len = i * sizeof (elf_addr_t);
2332edf8e2afSMika Westerberg 
2333edf8e2afSMika Westerberg     /* read in whole auxv vector and copy it to memelfnote */
2334edf8e2afSMika Westerberg     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
2335edf8e2afSMika Westerberg     if (ptr != NULL) {
2336edf8e2afSMika Westerberg         fill_note(note, "CORE", NT_AUXV, len, ptr);
2337edf8e2afSMika Westerberg         unlock_user(ptr, auxv, len);
2338edf8e2afSMika Westerberg     }
2339edf8e2afSMika Westerberg }
2340edf8e2afSMika Westerberg 
2341edf8e2afSMika Westerberg /*
2342edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
2343edf8e2afSMika Westerberg  * for the name:
2344edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
2345edf8e2afSMika Westerberg  *
2346edf8e2afSMika Westerberg  * Returns 0 in case of success, -1 otherwise (errno is set).
2347edf8e2afSMika Westerberg  */
2348edf8e2afSMika Westerberg static int core_dump_filename(const TaskState *ts, char *buf,
2349edf8e2afSMika Westerberg     size_t bufsize)
2350edf8e2afSMika Westerberg {
2351edf8e2afSMika Westerberg     char timestamp[64];
2352edf8e2afSMika Westerberg     char *filename = NULL;
2353edf8e2afSMika Westerberg     char *base_filename = NULL;
2354edf8e2afSMika Westerberg     struct timeval tv;
2355edf8e2afSMika Westerberg     struct tm tm;
2356edf8e2afSMika Westerberg 
2357edf8e2afSMika Westerberg     assert(bufsize >= PATH_MAX);
2358edf8e2afSMika Westerberg 
2359edf8e2afSMika Westerberg     if (gettimeofday(&tv, NULL) < 0) {
2360edf8e2afSMika Westerberg         (void) fprintf(stderr, "unable to get current timestamp: %s",
2361edf8e2afSMika Westerberg             strerror(errno));
2362edf8e2afSMika Westerberg         return (-1);
2363edf8e2afSMika Westerberg     }
2364edf8e2afSMika Westerberg 
2365edf8e2afSMika Westerberg     filename = strdup(ts->bprm->filename);
2366edf8e2afSMika Westerberg     base_filename = strdup(basename(filename));
2367edf8e2afSMika Westerberg     (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
2368edf8e2afSMika Westerberg         localtime_r(&tv.tv_sec, &tm));
2369edf8e2afSMika Westerberg     (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
2370edf8e2afSMika Westerberg         base_filename, timestamp, (int)getpid());
2371edf8e2afSMika Westerberg     free(base_filename);
2372edf8e2afSMika Westerberg     free(filename);
2373edf8e2afSMika Westerberg 
2374edf8e2afSMika Westerberg     return (0);
2375edf8e2afSMika Westerberg }
2376edf8e2afSMika Westerberg 
2377edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
2378edf8e2afSMika Westerberg {
2379edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
2380edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
2381edf8e2afSMika Westerberg     struct rlimit dumpsize;
2382edf8e2afSMika Westerberg     off_t pos;
2383edf8e2afSMika Westerberg 
2384edf8e2afSMika Westerberg     bytes_written = 0;
2385edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
2386edf8e2afSMika Westerberg     if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
2387edf8e2afSMika Westerberg         if (errno == ESPIPE) { /* not a seekable stream */
2388edf8e2afSMika Westerberg             bytes_left = size;
2389edf8e2afSMika Westerberg         } else {
2390edf8e2afSMika Westerberg             return pos;
2391edf8e2afSMika Westerberg         }
2392edf8e2afSMika Westerberg     } else {
2393edf8e2afSMika Westerberg         if (dumpsize.rlim_cur <= pos) {
2394edf8e2afSMika Westerberg             return -1;
2395edf8e2afSMika Westerberg         } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
2396edf8e2afSMika Westerberg             bytes_left = size;
2397edf8e2afSMika Westerberg         } else {
2398edf8e2afSMika Westerberg             size_t limit_left=dumpsize.rlim_cur - pos;
2399edf8e2afSMika Westerberg             bytes_left = limit_left >= size ? size : limit_left ;
2400edf8e2afSMika Westerberg         }
2401edf8e2afSMika Westerberg     }
2402edf8e2afSMika Westerberg 
2403edf8e2afSMika Westerberg     /*
2404edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
2405edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
2406edf8e2afSMika Westerberg      */
2407edf8e2afSMika Westerberg     do {
2408edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
2409edf8e2afSMika Westerberg         if (bytes_written < 0) {
2410edf8e2afSMika Westerberg             if (errno == EINTR)
2411edf8e2afSMika Westerberg                 continue;
2412edf8e2afSMika Westerberg             return (-1);
2413edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
2414edf8e2afSMika Westerberg             return (-1);
2415edf8e2afSMika Westerberg         }
2416edf8e2afSMika Westerberg         bufp += bytes_written;
2417edf8e2afSMika Westerberg         bytes_left -= bytes_written;
2418edf8e2afSMika Westerberg     } while (bytes_left > 0);
2419edf8e2afSMika Westerberg 
2420edf8e2afSMika Westerberg     return (0);
2421edf8e2afSMika Westerberg }
2422edf8e2afSMika Westerberg 
2423edf8e2afSMika Westerberg static int write_note(struct memelfnote *men, int fd)
2424edf8e2afSMika Westerberg {
2425edf8e2afSMika Westerberg     struct elf_note en;
2426edf8e2afSMika Westerberg 
2427edf8e2afSMika Westerberg     en.n_namesz = men->namesz;
2428edf8e2afSMika Westerberg     en.n_type = men->type;
2429edf8e2afSMika Westerberg     en.n_descsz = men->datasz;
2430edf8e2afSMika Westerberg 
2431edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
2432edf8e2afSMika Westerberg     bswap_note(&en);
2433edf8e2afSMika Westerberg #endif
2434edf8e2afSMika Westerberg 
2435edf8e2afSMika Westerberg     if (dump_write(fd, &en, sizeof(en)) != 0)
2436edf8e2afSMika Westerberg         return (-1);
2437edf8e2afSMika Westerberg     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
2438edf8e2afSMika Westerberg         return (-1);
2439edf8e2afSMika Westerberg     if (dump_write(fd, men->data, men->datasz) != 0)
2440edf8e2afSMika Westerberg         return (-1);
2441edf8e2afSMika Westerberg 
2442edf8e2afSMika Westerberg     return (0);
2443edf8e2afSMika Westerberg }
2444edf8e2afSMika Westerberg 
2445edf8e2afSMika Westerberg static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
2446edf8e2afSMika Westerberg {
2447edf8e2afSMika Westerberg     TaskState *ts = (TaskState *)env->opaque;
2448edf8e2afSMika Westerberg     struct elf_thread_status *ets;
2449edf8e2afSMika Westerberg 
2450edf8e2afSMika Westerberg     ets = qemu_mallocz(sizeof (*ets));
2451edf8e2afSMika Westerberg     ets->num_notes = 1; /* only prstatus is dumped */
2452edf8e2afSMika Westerberg     fill_prstatus(&ets->prstatus, ts, 0);
2453edf8e2afSMika Westerberg     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
2454edf8e2afSMika Westerberg     fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
2455edf8e2afSMika Westerberg         &ets->prstatus);
2456edf8e2afSMika Westerberg 
245772cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
2458edf8e2afSMika Westerberg 
2459edf8e2afSMika Westerberg     info->notes_size += note_size(&ets->notes[0]);
2460edf8e2afSMika Westerberg }
2461edf8e2afSMika Westerberg 
2462edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *info,
2463edf8e2afSMika Westerberg     long signr, const CPUState *env)
2464edf8e2afSMika Westerberg {
2465edf8e2afSMika Westerberg #define NUMNOTES 3
2466edf8e2afSMika Westerberg     CPUState *cpu = NULL;
2467edf8e2afSMika Westerberg     TaskState *ts = (TaskState *)env->opaque;
2468edf8e2afSMika Westerberg     int i;
2469edf8e2afSMika Westerberg 
2470edf8e2afSMika Westerberg     (void) memset(info, 0, sizeof (*info));
2471edf8e2afSMika Westerberg 
247272cf2d4fSBlue Swirl     QTAILQ_INIT(&info->thread_list);
2473edf8e2afSMika Westerberg 
2474edf8e2afSMika Westerberg     info->notes = qemu_mallocz(NUMNOTES * sizeof (struct memelfnote));
2475edf8e2afSMika Westerberg     if (info->notes == NULL)
2476edf8e2afSMika Westerberg         return (-ENOMEM);
2477edf8e2afSMika Westerberg     info->prstatus = qemu_mallocz(sizeof (*info->prstatus));
2478edf8e2afSMika Westerberg     if (info->prstatus == NULL)
2479edf8e2afSMika Westerberg         return (-ENOMEM);
2480edf8e2afSMika Westerberg     info->psinfo = qemu_mallocz(sizeof (*info->psinfo));
2481edf8e2afSMika Westerberg     if (info->prstatus == NULL)
2482edf8e2afSMika Westerberg         return (-ENOMEM);
2483edf8e2afSMika Westerberg 
2484edf8e2afSMika Westerberg     /*
2485edf8e2afSMika Westerberg      * First fill in status (and registers) of current thread
2486edf8e2afSMika Westerberg      * including process info & aux vector.
2487edf8e2afSMika Westerberg      */
2488edf8e2afSMika Westerberg     fill_prstatus(info->prstatus, ts, signr);
2489edf8e2afSMika Westerberg     elf_core_copy_regs(&info->prstatus->pr_reg, env);
2490edf8e2afSMika Westerberg     fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
2491edf8e2afSMika Westerberg         sizeof (*info->prstatus), info->prstatus);
2492edf8e2afSMika Westerberg     fill_psinfo(info->psinfo, ts);
2493edf8e2afSMika Westerberg     fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
2494edf8e2afSMika Westerberg         sizeof (*info->psinfo), info->psinfo);
2495edf8e2afSMika Westerberg     fill_auxv_note(&info->notes[2], ts);
2496edf8e2afSMika Westerberg     info->numnote = 3;
2497edf8e2afSMika Westerberg 
2498edf8e2afSMika Westerberg     info->notes_size = 0;
2499edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
2500edf8e2afSMika Westerberg         info->notes_size += note_size(&info->notes[i]);
2501edf8e2afSMika Westerberg 
2502edf8e2afSMika Westerberg     /* read and fill status of all threads */
2503edf8e2afSMika Westerberg     cpu_list_lock();
2504edf8e2afSMika Westerberg     for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
2505edf8e2afSMika Westerberg         if (cpu == thread_env)
2506edf8e2afSMika Westerberg             continue;
2507edf8e2afSMika Westerberg         fill_thread_info(info, cpu);
2508edf8e2afSMika Westerberg     }
2509edf8e2afSMika Westerberg     cpu_list_unlock();
2510edf8e2afSMika Westerberg 
2511edf8e2afSMika Westerberg     return (0);
2512edf8e2afSMika Westerberg }
2513edf8e2afSMika Westerberg 
2514edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *info)
2515edf8e2afSMika Westerberg {
2516edf8e2afSMika Westerberg     struct elf_thread_status *ets;
2517edf8e2afSMika Westerberg 
251872cf2d4fSBlue Swirl     while (!QTAILQ_EMPTY(&info->thread_list)) {
251972cf2d4fSBlue Swirl         ets = QTAILQ_FIRST(&info->thread_list);
252072cf2d4fSBlue Swirl         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
2521edf8e2afSMika Westerberg         qemu_free(ets);
2522edf8e2afSMika Westerberg     }
2523edf8e2afSMika Westerberg 
2524edf8e2afSMika Westerberg     qemu_free(info->prstatus);
2525edf8e2afSMika Westerberg     qemu_free(info->psinfo);
2526edf8e2afSMika Westerberg     qemu_free(info->notes);
2527edf8e2afSMika Westerberg }
2528edf8e2afSMika Westerberg 
2529edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *info, int fd)
2530edf8e2afSMika Westerberg {
2531edf8e2afSMika Westerberg     struct elf_thread_status *ets;
2532edf8e2afSMika Westerberg     int i, error = 0;
2533edf8e2afSMika Westerberg 
2534edf8e2afSMika Westerberg     /* write prstatus, psinfo and auxv for current thread */
2535edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
2536edf8e2afSMika Westerberg         if ((error = write_note(&info->notes[i], fd)) != 0)
2537edf8e2afSMika Westerberg             return (error);
2538edf8e2afSMika Westerberg 
2539edf8e2afSMika Westerberg     /* write prstatus for each thread */
2540edf8e2afSMika Westerberg     for (ets = info->thread_list.tqh_first; ets != NULL;
2541edf8e2afSMika Westerberg         ets = ets->ets_link.tqe_next) {
2542edf8e2afSMika Westerberg         if ((error = write_note(&ets->notes[0], fd)) != 0)
2543edf8e2afSMika Westerberg             return (error);
2544edf8e2afSMika Westerberg     }
2545edf8e2afSMika Westerberg 
2546edf8e2afSMika Westerberg     return (0);
2547edf8e2afSMika Westerberg }
2548edf8e2afSMika Westerberg 
2549edf8e2afSMika Westerberg /*
2550edf8e2afSMika Westerberg  * Write out ELF coredump.
2551edf8e2afSMika Westerberg  *
2552edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
2553edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
2554edf8e2afSMika Westerberg  *
2555edf8e2afSMika Westerberg  * Coredump format in linux is following:
2556edf8e2afSMika Westerberg  *
2557edf8e2afSMika Westerberg  * 0   +----------------------+         \
2558edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
2559edf8e2afSMika Westerberg  *     +----------------------+          |
2560edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
2561edf8e2afSMika Westerberg  *     | - NOTE section       |          |
2562edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
2563edf8e2afSMika Westerberg  *     +----------------------+         /
2564edf8e2afSMika Westerberg  *     | NOTEs:               |
2565edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
2566edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
2567edf8e2afSMika Westerberg  *     | - NT_AUXV            |
2568edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
2569edf8e2afSMika Westerberg  *     | Process memory dump  |
2570edf8e2afSMika Westerberg  *     :                      :
2571edf8e2afSMika Westerberg  *     .                      .
2572edf8e2afSMika Westerberg  *     :                      :
2573edf8e2afSMika Westerberg  *     |                      |
2574edf8e2afSMika Westerberg  *     +----------------------+
2575edf8e2afSMika Westerberg  *
2576edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
2577edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
2578edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
2579edf8e2afSMika Westerberg  *
2580edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
2581edf8e2afSMika Westerberg  * version limitations are as follows:
2582edf8e2afSMika Westerberg  *     - no floating point registers are dumped
2583edf8e2afSMika Westerberg  *
2584edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
2585edf8e2afSMika Westerberg  *
2586edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
2587edf8e2afSMika Westerberg  * possible to force coredump from running process and then
2588edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
2589edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
2590edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
2591edf8e2afSMika Westerberg  */
2592edf8e2afSMika Westerberg static int elf_core_dump(int signr, const CPUState *env)
2593edf8e2afSMika Westerberg {
2594edf8e2afSMika Westerberg     const TaskState *ts = (const TaskState *)env->opaque;
2595edf8e2afSMika Westerberg     struct vm_area_struct *vma = NULL;
2596edf8e2afSMika Westerberg     char corefile[PATH_MAX];
2597edf8e2afSMika Westerberg     struct elf_note_info info;
2598edf8e2afSMika Westerberg     struct elfhdr elf;
2599edf8e2afSMika Westerberg     struct elf_phdr phdr;
2600edf8e2afSMika Westerberg     struct rlimit dumpsize;
2601edf8e2afSMika Westerberg     struct mm_struct *mm = NULL;
2602edf8e2afSMika Westerberg     off_t offset = 0, data_offset = 0;
2603edf8e2afSMika Westerberg     int segs = 0;
2604edf8e2afSMika Westerberg     int fd = -1;
2605edf8e2afSMika Westerberg 
2606edf8e2afSMika Westerberg     errno = 0;
2607edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
2608edf8e2afSMika Westerberg     if (dumpsize.rlim_cur == 0)
2609edf8e2afSMika Westerberg        return 0;
2610edf8e2afSMika Westerberg 
2611edf8e2afSMika Westerberg     if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
2612edf8e2afSMika Westerberg         return (-errno);
2613edf8e2afSMika Westerberg 
2614edf8e2afSMika Westerberg     if ((fd = open(corefile, O_WRONLY | O_CREAT,
2615edf8e2afSMika Westerberg         S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
2616edf8e2afSMika Westerberg         return (-errno);
2617edf8e2afSMika Westerberg 
2618edf8e2afSMika Westerberg     /*
2619edf8e2afSMika Westerberg      * Walk through target process memory mappings and
2620edf8e2afSMika Westerberg      * set up structure containing this information.  After
2621edf8e2afSMika Westerberg      * this point vma_xxx functions can be used.
2622edf8e2afSMika Westerberg      */
2623edf8e2afSMika Westerberg     if ((mm = vma_init()) == NULL)
2624edf8e2afSMika Westerberg         goto out;
2625edf8e2afSMika Westerberg 
2626edf8e2afSMika Westerberg     walk_memory_regions(mm, vma_walker);
2627edf8e2afSMika Westerberg     segs = vma_get_mapping_count(mm);
2628edf8e2afSMika Westerberg 
2629edf8e2afSMika Westerberg     /*
2630edf8e2afSMika Westerberg      * Construct valid coredump ELF header.  We also
2631edf8e2afSMika Westerberg      * add one more segment for notes.
2632edf8e2afSMika Westerberg      */
2633edf8e2afSMika Westerberg     fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
2634edf8e2afSMika Westerberg     if (dump_write(fd, &elf, sizeof (elf)) != 0)
2635edf8e2afSMika Westerberg         goto out;
2636edf8e2afSMika Westerberg 
2637edf8e2afSMika Westerberg     /* fill in in-memory version of notes */
2638edf8e2afSMika Westerberg     if (fill_note_info(&info, signr, env) < 0)
2639edf8e2afSMika Westerberg         goto out;
2640edf8e2afSMika Westerberg 
2641edf8e2afSMika Westerberg     offset += sizeof (elf);                             /* elf header */
2642edf8e2afSMika Westerberg     offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
2643edf8e2afSMika Westerberg 
2644edf8e2afSMika Westerberg     /* write out notes program header */
2645edf8e2afSMika Westerberg     fill_elf_note_phdr(&phdr, info.notes_size, offset);
2646edf8e2afSMika Westerberg 
2647edf8e2afSMika Westerberg     offset += info.notes_size;
2648edf8e2afSMika Westerberg     if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
2649edf8e2afSMika Westerberg         goto out;
2650edf8e2afSMika Westerberg 
2651edf8e2afSMika Westerberg     /*
2652edf8e2afSMika Westerberg      * ELF specification wants data to start at page boundary so
2653edf8e2afSMika Westerberg      * we align it here.
2654edf8e2afSMika Westerberg      */
2655edf8e2afSMika Westerberg     offset = roundup(offset, ELF_EXEC_PAGESIZE);
2656edf8e2afSMika Westerberg 
2657edf8e2afSMika Westerberg     /*
2658edf8e2afSMika Westerberg      * Write program headers for memory regions mapped in
2659edf8e2afSMika Westerberg      * the target process.
2660edf8e2afSMika Westerberg      */
2661edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
2662edf8e2afSMika Westerberg         (void) memset(&phdr, 0, sizeof (phdr));
2663edf8e2afSMika Westerberg 
2664edf8e2afSMika Westerberg         phdr.p_type = PT_LOAD;
2665edf8e2afSMika Westerberg         phdr.p_offset = offset;
2666edf8e2afSMika Westerberg         phdr.p_vaddr = vma->vma_start;
2667edf8e2afSMika Westerberg         phdr.p_paddr = 0;
2668edf8e2afSMika Westerberg         phdr.p_filesz = vma_dump_size(vma);
2669edf8e2afSMika Westerberg         offset += phdr.p_filesz;
2670edf8e2afSMika Westerberg         phdr.p_memsz = vma->vma_end - vma->vma_start;
2671edf8e2afSMika Westerberg         phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
2672edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_WRITE)
2673edf8e2afSMika Westerberg             phdr.p_flags |= PF_W;
2674edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_EXEC)
2675edf8e2afSMika Westerberg             phdr.p_flags |= PF_X;
2676edf8e2afSMika Westerberg         phdr.p_align = ELF_EXEC_PAGESIZE;
2677edf8e2afSMika Westerberg 
2678edf8e2afSMika Westerberg         dump_write(fd, &phdr, sizeof (phdr));
2679edf8e2afSMika Westerberg     }
2680edf8e2afSMika Westerberg 
2681edf8e2afSMika Westerberg     /*
2682edf8e2afSMika Westerberg      * Next we write notes just after program headers.  No
2683edf8e2afSMika Westerberg      * alignment needed here.
2684edf8e2afSMika Westerberg      */
2685edf8e2afSMika Westerberg     if (write_note_info(&info, fd) < 0)
2686edf8e2afSMika Westerberg         goto out;
2687edf8e2afSMika Westerberg 
2688edf8e2afSMika Westerberg     /* align data to page boundary */
2689edf8e2afSMika Westerberg     data_offset = lseek(fd, 0, SEEK_CUR);
2690edf8e2afSMika Westerberg     data_offset = TARGET_PAGE_ALIGN(data_offset);
2691edf8e2afSMika Westerberg     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
2692edf8e2afSMika Westerberg         goto out;
2693edf8e2afSMika Westerberg 
2694edf8e2afSMika Westerberg     /*
2695edf8e2afSMika Westerberg      * Finally we can dump process memory into corefile as well.
2696edf8e2afSMika Westerberg      */
2697edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
2698edf8e2afSMika Westerberg         abi_ulong addr;
2699edf8e2afSMika Westerberg         abi_ulong end;
2700edf8e2afSMika Westerberg 
2701edf8e2afSMika Westerberg         end = vma->vma_start + vma_dump_size(vma);
2702edf8e2afSMika Westerberg 
2703edf8e2afSMika Westerberg         for (addr = vma->vma_start; addr < end;
2704edf8e2afSMika Westerberg             addr += TARGET_PAGE_SIZE) {
2705edf8e2afSMika Westerberg             char page[TARGET_PAGE_SIZE];
2706edf8e2afSMika Westerberg             int error;
2707edf8e2afSMika Westerberg 
2708edf8e2afSMika Westerberg             /*
2709edf8e2afSMika Westerberg              *  Read in page from target process memory and
2710edf8e2afSMika Westerberg              *  write it to coredump file.
2711edf8e2afSMika Westerberg              */
2712edf8e2afSMika Westerberg             error = copy_from_user(page, addr, sizeof (page));
2713edf8e2afSMika Westerberg             if (error != 0) {
271449995e17SAurelien Jarno                 (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
2715edf8e2afSMika Westerberg                     addr);
2716edf8e2afSMika Westerberg                 errno = -error;
2717edf8e2afSMika Westerberg                 goto out;
2718edf8e2afSMika Westerberg             }
2719edf8e2afSMika Westerberg             if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
2720edf8e2afSMika Westerberg                 goto out;
2721edf8e2afSMika Westerberg         }
2722edf8e2afSMika Westerberg     }
2723edf8e2afSMika Westerberg 
2724edf8e2afSMika Westerberg out:
2725edf8e2afSMika Westerberg     free_note_info(&info);
2726edf8e2afSMika Westerberg     if (mm != NULL)
2727edf8e2afSMika Westerberg         vma_delete(mm);
2728edf8e2afSMika Westerberg     (void) close(fd);
2729edf8e2afSMika Westerberg 
2730edf8e2afSMika Westerberg     if (errno != 0)
2731edf8e2afSMika Westerberg         return (-errno);
2732edf8e2afSMika Westerberg     return (0);
2733edf8e2afSMika Westerberg }
2734edf8e2afSMika Westerberg 
2735edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
2736edf8e2afSMika Westerberg 
273731e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
273831e31b8aSbellard {
273931e31b8aSbellard     printf("a.out interpreter not yet supported\n");
274031e31b8aSbellard     return(0);
274131e31b8aSbellard }
274231e31b8aSbellard 
2743e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
2744e5fe0c52Spbrook {
2745e5fe0c52Spbrook     init_thread(regs, infop);
2746e5fe0c52Spbrook }
2747