root / linux-user / elfload.c @ 124964b5
History | View | Annotate | Download (81.2 kB)
1 | 31e31b8a | bellard | /* This is the Linux kernel elf-loading code, ported into user space */
|
---|---|---|---|
2 | edf8e2af | Mika Westerberg | #include <sys/time.h> |
3 | edf8e2af | Mika Westerberg | #include <sys/param.h> |
4 | 31e31b8a | bellard | |
5 | 31e31b8a | bellard | #include <stdio.h> |
6 | 31e31b8a | bellard | #include <sys/types.h> |
7 | 31e31b8a | bellard | #include <fcntl.h> |
8 | 31e31b8a | bellard | #include <errno.h> |
9 | 31e31b8a | bellard | #include <unistd.h> |
10 | 31e31b8a | bellard | #include <sys/mman.h> |
11 | edf8e2af | Mika Westerberg | #include <sys/resource.h> |
12 | 31e31b8a | bellard | #include <stdlib.h> |
13 | 31e31b8a | bellard | #include <string.h> |
14 | edf8e2af | Mika Westerberg | #include <time.h> |
15 | 31e31b8a | bellard | |
16 | 3ef693a0 | bellard | #include "qemu.h" |
17 | 689f936f | bellard | #include "disas.h" |
18 | 31e31b8a | bellard | |
19 | e58ffeb3 | malc | #ifdef _ARCH_PPC64
|
20 | a6cc84f4 | malc | #undef ARCH_DLINFO
|
21 | a6cc84f4 | malc | #undef ELF_PLATFORM
|
22 | a6cc84f4 | malc | #undef ELF_HWCAP
|
23 | a6cc84f4 | malc | #undef ELF_CLASS
|
24 | a6cc84f4 | malc | #undef ELF_DATA
|
25 | a6cc84f4 | malc | #undef ELF_ARCH
|
26 | a6cc84f4 | malc | #endif
|
27 | a6cc84f4 | malc | |
28 | edf8e2af | Mika Westerberg | #define ELF_OSABI ELFOSABI_SYSV
|
29 | edf8e2af | Mika Westerberg | |
30 | cb33da57 | blueswir1 | /* from personality.h */
|
31 | cb33da57 | blueswir1 | |
32 | cb33da57 | blueswir1 | /*
|
33 | cb33da57 | blueswir1 | * Flags for bug emulation.
|
34 | cb33da57 | blueswir1 | *
|
35 | cb33da57 | blueswir1 | * These occupy the top three bytes.
|
36 | cb33da57 | blueswir1 | */
|
37 | cb33da57 | blueswir1 | enum {
|
38 | cb33da57 | blueswir1 | ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ |
39 | cb33da57 | blueswir1 | FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors |
40 | cb33da57 | blueswir1 | * (signal handling)
|
41 | cb33da57 | blueswir1 | */
|
42 | cb33da57 | blueswir1 | MMAP_PAGE_ZERO = 0x0100000,
|
43 | cb33da57 | blueswir1 | ADDR_COMPAT_LAYOUT = 0x0200000,
|
44 | cb33da57 | blueswir1 | READ_IMPLIES_EXEC = 0x0400000,
|
45 | cb33da57 | blueswir1 | ADDR_LIMIT_32BIT = 0x0800000,
|
46 | cb33da57 | blueswir1 | SHORT_INODE = 0x1000000,
|
47 | cb33da57 | blueswir1 | WHOLE_SECONDS = 0x2000000,
|
48 | cb33da57 | blueswir1 | STICKY_TIMEOUTS = 0x4000000,
|
49 | cb33da57 | blueswir1 | ADDR_LIMIT_3GB = 0x8000000,
|
50 | cb33da57 | blueswir1 | }; |
51 | cb33da57 | blueswir1 | |
52 | cb33da57 | blueswir1 | /*
|
53 | cb33da57 | blueswir1 | * Personality types.
|
54 | cb33da57 | blueswir1 | *
|
55 | cb33da57 | blueswir1 | * These go in the low byte. Avoid using the top bit, it will
|
56 | cb33da57 | blueswir1 | * conflict with error returns.
|
57 | cb33da57 | blueswir1 | */
|
58 | cb33da57 | blueswir1 | enum {
|
59 | cb33da57 | blueswir1 | PER_LINUX = 0x0000,
|
60 | cb33da57 | blueswir1 | PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT,
|
61 | cb33da57 | blueswir1 | PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS,
|
62 | cb33da57 | blueswir1 | PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
|
63 | cb33da57 | blueswir1 | PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
|
64 | cb33da57 | blueswir1 | PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS |
|
65 | cb33da57 | blueswir1 | WHOLE_SECONDS | SHORT_INODE, |
66 | cb33da57 | blueswir1 | PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
|
67 | cb33da57 | blueswir1 | PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
|
68 | cb33da57 | blueswir1 | PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS,
|
69 | cb33da57 | blueswir1 | PER_BSD = 0x0006,
|
70 | cb33da57 | blueswir1 | PER_SUNOS = 0x0006 | STICKY_TIMEOUTS,
|
71 | cb33da57 | blueswir1 | PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
|
72 | cb33da57 | blueswir1 | PER_LINUX32 = 0x0008,
|
73 | cb33da57 | blueswir1 | PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB,
|
74 | cb33da57 | blueswir1 | PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */ |
75 | cb33da57 | blueswir1 | PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */ |
76 | cb33da57 | blueswir1 | PER_IRIX64 = 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */ |
77 | cb33da57 | blueswir1 | PER_RISCOS = 0x000c,
|
78 | cb33da57 | blueswir1 | PER_SOLARIS = 0x000d | STICKY_TIMEOUTS,
|
79 | cb33da57 | blueswir1 | PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
|
80 | cb33da57 | blueswir1 | PER_OSF4 = 0x000f, /* OSF/1 v4 */ |
81 | cb33da57 | blueswir1 | PER_HPUX = 0x0010,
|
82 | cb33da57 | blueswir1 | PER_MASK = 0x00ff,
|
83 | cb33da57 | blueswir1 | }; |
84 | cb33da57 | blueswir1 | |
85 | cb33da57 | blueswir1 | /*
|
86 | cb33da57 | blueswir1 | * Return the base personality without flags.
|
87 | cb33da57 | blueswir1 | */
|
88 | cb33da57 | blueswir1 | #define personality(pers) (pers & PER_MASK)
|
89 | cb33da57 | blueswir1 | |
90 | 83fb7adf | bellard | /* this flag is uneffective under linux too, should be deleted */
|
91 | 83fb7adf | bellard | #ifndef MAP_DENYWRITE
|
92 | 83fb7adf | bellard | #define MAP_DENYWRITE 0 |
93 | 83fb7adf | bellard | #endif
|
94 | 83fb7adf | bellard | |
95 | 83fb7adf | bellard | /* should probably go in elf.h */
|
96 | 83fb7adf | bellard | #ifndef ELIBBAD
|
97 | 83fb7adf | bellard | #define ELIBBAD 80 |
98 | 83fb7adf | bellard | #endif
|
99 | 83fb7adf | bellard | |
100 | 21e807fa | Nathan Froyd | typedef target_ulong target_elf_greg_t;
|
101 | 21e807fa | Nathan Froyd | #ifdef USE_UID16
|
102 | 21e807fa | Nathan Froyd | typedef uint16_t target_uid_t;
|
103 | 21e807fa | Nathan Froyd | typedef uint16_t target_gid_t;
|
104 | 21e807fa | Nathan Froyd | #else
|
105 | 21e807fa | Nathan Froyd | typedef uint32_t target_uid_t;
|
106 | 21e807fa | Nathan Froyd | typedef uint32_t target_gid_t;
|
107 | 21e807fa | Nathan Froyd | #endif
|
108 | 21e807fa | Nathan Froyd | typedef int32_t target_pid_t;
|
109 | 21e807fa | Nathan Froyd | |
110 | 30ac07d4 | bellard | #ifdef TARGET_I386
|
111 | 30ac07d4 | bellard | |
112 | 15338fd7 | bellard | #define ELF_PLATFORM get_elf_platform()
|
113 | 15338fd7 | bellard | |
114 | 15338fd7 | bellard | static const char *get_elf_platform(void) |
115 | 15338fd7 | bellard | { |
116 | 15338fd7 | bellard | static char elf_platform[] = "i386"; |
117 | d5975363 | pbrook | int family = (thread_env->cpuid_version >> 8) & 0xff; |
118 | 15338fd7 | bellard | if (family > 6) |
119 | 15338fd7 | bellard | family = 6;
|
120 | 15338fd7 | bellard | if (family >= 3) |
121 | 15338fd7 | bellard | elf_platform[1] = '0' + family; |
122 | 15338fd7 | bellard | return elf_platform;
|
123 | 15338fd7 | bellard | } |
124 | 15338fd7 | bellard | |
125 | 15338fd7 | bellard | #define ELF_HWCAP get_elf_hwcap()
|
126 | 15338fd7 | bellard | |
127 | 15338fd7 | bellard | static uint32_t get_elf_hwcap(void) |
128 | 15338fd7 | bellard | { |
129 | d5975363 | pbrook | return thread_env->cpuid_features;
|
130 | 15338fd7 | bellard | } |
131 | 15338fd7 | bellard | |
132 | 84409ddb | j_mayer | #ifdef TARGET_X86_64
|
133 | 84409ddb | j_mayer | #define ELF_START_MMAP 0x2aaaaab000ULL |
134 | 84409ddb | j_mayer | #define elf_check_arch(x) ( ((x) == ELF_ARCH) )
|
135 | 84409ddb | j_mayer | |
136 | 84409ddb | j_mayer | #define ELF_CLASS ELFCLASS64
|
137 | 84409ddb | j_mayer | #define ELF_DATA ELFDATA2LSB
|
138 | 84409ddb | j_mayer | #define ELF_ARCH EM_X86_64
|
139 | 84409ddb | j_mayer | |
140 | 84409ddb | j_mayer | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
141 | 84409ddb | j_mayer | { |
142 | 84409ddb | j_mayer | regs->rax = 0;
|
143 | 84409ddb | j_mayer | regs->rsp = infop->start_stack; |
144 | 84409ddb | j_mayer | regs->rip = infop->entry; |
145 | 84409ddb | j_mayer | } |
146 | 84409ddb | j_mayer | |
147 | 9edc5d79 | Mika Westerberg | #define ELF_NREG 27 |
148 | c227f099 | Anthony Liguori | typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
149 | 9edc5d79 | Mika Westerberg | |
150 | 9edc5d79 | Mika Westerberg | /*
|
151 | 9edc5d79 | Mika Westerberg | * Note that ELF_NREG should be 29 as there should be place for
|
152 | 9edc5d79 | Mika Westerberg | * TRAPNO and ERR "registers" as well but linux doesn't dump
|
153 | 9edc5d79 | Mika Westerberg | * those.
|
154 | 9edc5d79 | Mika Westerberg | *
|
155 | 9edc5d79 | Mika Westerberg | * See linux kernel: arch/x86/include/asm/elf.h
|
156 | 9edc5d79 | Mika Westerberg | */
|
157 | c227f099 | Anthony Liguori | static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) |
158 | 9edc5d79 | Mika Westerberg | { |
159 | 9edc5d79 | Mika Westerberg | (*regs)[0] = env->regs[15]; |
160 | 9edc5d79 | Mika Westerberg | (*regs)[1] = env->regs[14]; |
161 | 9edc5d79 | Mika Westerberg | (*regs)[2] = env->regs[13]; |
162 | 9edc5d79 | Mika Westerberg | (*regs)[3] = env->regs[12]; |
163 | 9edc5d79 | Mika Westerberg | (*regs)[4] = env->regs[R_EBP];
|
164 | 9edc5d79 | Mika Westerberg | (*regs)[5] = env->regs[R_EBX];
|
165 | 9edc5d79 | Mika Westerberg | (*regs)[6] = env->regs[11]; |
166 | 9edc5d79 | Mika Westerberg | (*regs)[7] = env->regs[10]; |
167 | 9edc5d79 | Mika Westerberg | (*regs)[8] = env->regs[9]; |
168 | 9edc5d79 | Mika Westerberg | (*regs)[9] = env->regs[8]; |
169 | 9edc5d79 | Mika Westerberg | (*regs)[10] = env->regs[R_EAX];
|
170 | 9edc5d79 | Mika Westerberg | (*regs)[11] = env->regs[R_ECX];
|
171 | 9edc5d79 | Mika Westerberg | (*regs)[12] = env->regs[R_EDX];
|
172 | 9edc5d79 | Mika Westerberg | (*regs)[13] = env->regs[R_ESI];
|
173 | 9edc5d79 | Mika Westerberg | (*regs)[14] = env->regs[R_EDI];
|
174 | 9edc5d79 | Mika Westerberg | (*regs)[15] = env->regs[R_EAX]; /* XXX */ |
175 | 9edc5d79 | Mika Westerberg | (*regs)[16] = env->eip;
|
176 | 9edc5d79 | Mika Westerberg | (*regs)[17] = env->segs[R_CS].selector & 0xffff; |
177 | 9edc5d79 | Mika Westerberg | (*regs)[18] = env->eflags;
|
178 | 9edc5d79 | Mika Westerberg | (*regs)[19] = env->regs[R_ESP];
|
179 | 9edc5d79 | Mika Westerberg | (*regs)[20] = env->segs[R_SS].selector & 0xffff; |
180 | 9edc5d79 | Mika Westerberg | (*regs)[21] = env->segs[R_FS].selector & 0xffff; |
181 | 9edc5d79 | Mika Westerberg | (*regs)[22] = env->segs[R_GS].selector & 0xffff; |
182 | 9edc5d79 | Mika Westerberg | (*regs)[23] = env->segs[R_DS].selector & 0xffff; |
183 | 9edc5d79 | Mika Westerberg | (*regs)[24] = env->segs[R_ES].selector & 0xffff; |
184 | 9edc5d79 | Mika Westerberg | (*regs)[25] = env->segs[R_FS].selector & 0xffff; |
185 | 9edc5d79 | Mika Westerberg | (*regs)[26] = env->segs[R_GS].selector & 0xffff; |
186 | 9edc5d79 | Mika Westerberg | } |
187 | 9edc5d79 | Mika Westerberg | |
188 | 84409ddb | j_mayer | #else
|
189 | 84409ddb | j_mayer | |
190 | 30ac07d4 | bellard | #define ELF_START_MMAP 0x80000000 |
191 | 30ac07d4 | bellard | |
192 | 30ac07d4 | bellard | /*
|
193 | 30ac07d4 | bellard | * This is used to ensure we don't load something for the wrong architecture.
|
194 | 30ac07d4 | bellard | */
|
195 | 30ac07d4 | bellard | #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
|
196 | 30ac07d4 | bellard | |
197 | 30ac07d4 | bellard | /*
|
198 | 30ac07d4 | bellard | * These are used to set parameters in the core dumps.
|
199 | 30ac07d4 | bellard | */
|
200 | 30ac07d4 | bellard | #define ELF_CLASS ELFCLASS32
|
201 | 30ac07d4 | bellard | #define ELF_DATA ELFDATA2LSB
|
202 | 30ac07d4 | bellard | #define ELF_ARCH EM_386
|
203 | 30ac07d4 | bellard | |
204 | b346ff46 | bellard | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
205 | b346ff46 | bellard | { |
206 | b346ff46 | bellard | regs->esp = infop->start_stack; |
207 | b346ff46 | bellard | regs->eip = infop->entry; |
208 | e5fe0c52 | pbrook | |
209 | e5fe0c52 | pbrook | /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
|
210 | e5fe0c52 | pbrook | starts %edx contains a pointer to a function which might be
|
211 | e5fe0c52 | pbrook | registered using `atexit'. This provides a mean for the
|
212 | e5fe0c52 | pbrook | dynamic linker to call DT_FINI functions for shared libraries
|
213 | e5fe0c52 | pbrook | that have been loaded before the code runs.
|
214 | e5fe0c52 | pbrook | |
215 | e5fe0c52 | pbrook | A value of 0 tells we have no such handler. */
|
216 | e5fe0c52 | pbrook | regs->edx = 0;
|
217 | b346ff46 | bellard | } |
218 | 9edc5d79 | Mika Westerberg | |
219 | 9edc5d79 | Mika Westerberg | #define ELF_NREG 17 |
220 | c227f099 | Anthony Liguori | typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
221 | 9edc5d79 | Mika Westerberg | |
222 | 9edc5d79 | Mika Westerberg | /*
|
223 | 9edc5d79 | Mika Westerberg | * Note that ELF_NREG should be 19 as there should be place for
|
224 | 9edc5d79 | Mika Westerberg | * TRAPNO and ERR "registers" as well but linux doesn't dump
|
225 | 9edc5d79 | Mika Westerberg | * those.
|
226 | 9edc5d79 | Mika Westerberg | *
|
227 | 9edc5d79 | Mika Westerberg | * See linux kernel: arch/x86/include/asm/elf.h
|
228 | 9edc5d79 | Mika Westerberg | */
|
229 | c227f099 | Anthony Liguori | static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) |
230 | 9edc5d79 | Mika Westerberg | { |
231 | 9edc5d79 | Mika Westerberg | (*regs)[0] = env->regs[R_EBX];
|
232 | 9edc5d79 | Mika Westerberg | (*regs)[1] = env->regs[R_ECX];
|
233 | 9edc5d79 | Mika Westerberg | (*regs)[2] = env->regs[R_EDX];
|
234 | 9edc5d79 | Mika Westerberg | (*regs)[3] = env->regs[R_ESI];
|
235 | 9edc5d79 | Mika Westerberg | (*regs)[4] = env->regs[R_EDI];
|
236 | 9edc5d79 | Mika Westerberg | (*regs)[5] = env->regs[R_EBP];
|
237 | 9edc5d79 | Mika Westerberg | (*regs)[6] = env->regs[R_EAX];
|
238 | 9edc5d79 | Mika Westerberg | (*regs)[7] = env->segs[R_DS].selector & 0xffff; |
239 | 9edc5d79 | Mika Westerberg | (*regs)[8] = env->segs[R_ES].selector & 0xffff; |
240 | 9edc5d79 | Mika Westerberg | (*regs)[9] = env->segs[R_FS].selector & 0xffff; |
241 | 9edc5d79 | Mika Westerberg | (*regs)[10] = env->segs[R_GS].selector & 0xffff; |
242 | 9edc5d79 | Mika Westerberg | (*regs)[11] = env->regs[R_EAX]; /* XXX */ |
243 | 9edc5d79 | Mika Westerberg | (*regs)[12] = env->eip;
|
244 | 9edc5d79 | Mika Westerberg | (*regs)[13] = env->segs[R_CS].selector & 0xffff; |
245 | 9edc5d79 | Mika Westerberg | (*regs)[14] = env->eflags;
|
246 | 9edc5d79 | Mika Westerberg | (*regs)[15] = env->regs[R_ESP];
|
247 | 9edc5d79 | Mika Westerberg | (*regs)[16] = env->segs[R_SS].selector & 0xffff; |
248 | 9edc5d79 | Mika Westerberg | } |
249 | 84409ddb | j_mayer | #endif
|
250 | b346ff46 | bellard | |
251 | 9edc5d79 | Mika Westerberg | #define USE_ELF_CORE_DUMP
|
252 | b346ff46 | bellard | #define ELF_EXEC_PAGESIZE 4096 |
253 | b346ff46 | bellard | |
254 | b346ff46 | bellard | #endif
|
255 | b346ff46 | bellard | |
256 | b346ff46 | bellard | #ifdef TARGET_ARM
|
257 | b346ff46 | bellard | |
258 | b346ff46 | bellard | #define ELF_START_MMAP 0x80000000 |
259 | b346ff46 | bellard | |
260 | b346ff46 | bellard | #define elf_check_arch(x) ( (x) == EM_ARM )
|
261 | b346ff46 | bellard | |
262 | b346ff46 | bellard | #define ELF_CLASS ELFCLASS32
|
263 | b346ff46 | bellard | #ifdef TARGET_WORDS_BIGENDIAN
|
264 | b346ff46 | bellard | #define ELF_DATA ELFDATA2MSB
|
265 | b346ff46 | bellard | #else
|
266 | b346ff46 | bellard | #define ELF_DATA ELFDATA2LSB
|
267 | b346ff46 | bellard | #endif
|
268 | b346ff46 | bellard | #define ELF_ARCH EM_ARM
|
269 | b346ff46 | bellard | |
270 | b346ff46 | bellard | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
271 | b346ff46 | bellard | { |
272 | 992f48a0 | blueswir1 | abi_long stack = infop->start_stack; |
273 | b346ff46 | bellard | memset(regs, 0, sizeof(*regs)); |
274 | b346ff46 | bellard | regs->ARM_cpsr = 0x10;
|
275 | 0240ded8 | pbrook | if (infop->entry & 1) |
276 | 0240ded8 | pbrook | regs->ARM_cpsr |= CPSR_T; |
277 | 0240ded8 | pbrook | regs->ARM_pc = infop->entry & 0xfffffffe;
|
278 | b346ff46 | bellard | regs->ARM_sp = infop->start_stack; |
279 | 2f619698 | bellard | /* FIXME - what to for failure of get_user()? */
|
280 | 2f619698 | bellard | get_user_ual(regs->ARM_r2, stack + 8); /* envp */ |
281 | 2f619698 | bellard | get_user_ual(regs->ARM_r1, stack + 4); /* envp */ |
282 | a1516e92 | bellard | /* XXX: it seems that r0 is zeroed after ! */
|
283 | e5fe0c52 | pbrook | regs->ARM_r0 = 0;
|
284 | e5fe0c52 | pbrook | /* For uClinux PIC binaries. */
|
285 | 863cf0b7 | j_mayer | /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
|
286 | e5fe0c52 | pbrook | regs->ARM_r10 = infop->start_data; |
287 | b346ff46 | bellard | } |
288 | b346ff46 | bellard | |
289 | edf8e2af | Mika Westerberg | #define ELF_NREG 18 |
290 | c227f099 | Anthony Liguori | typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
291 | edf8e2af | Mika Westerberg | |
292 | c227f099 | Anthony Liguori | static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) |
293 | edf8e2af | Mika Westerberg | { |
294 | d049e626 | Nathan Froyd | (*regs)[0] = tswapl(env->regs[0]); |
295 | d049e626 | Nathan Froyd | (*regs)[1] = tswapl(env->regs[1]); |
296 | d049e626 | Nathan Froyd | (*regs)[2] = tswapl(env->regs[2]); |
297 | d049e626 | Nathan Froyd | (*regs)[3] = tswapl(env->regs[3]); |
298 | d049e626 | Nathan Froyd | (*regs)[4] = tswapl(env->regs[4]); |
299 | d049e626 | Nathan Froyd | (*regs)[5] = tswapl(env->regs[5]); |
300 | d049e626 | Nathan Froyd | (*regs)[6] = tswapl(env->regs[6]); |
301 | d049e626 | Nathan Froyd | (*regs)[7] = tswapl(env->regs[7]); |
302 | d049e626 | Nathan Froyd | (*regs)[8] = tswapl(env->regs[8]); |
303 | d049e626 | Nathan Froyd | (*regs)[9] = tswapl(env->regs[9]); |
304 | d049e626 | Nathan Froyd | (*regs)[10] = tswapl(env->regs[10]); |
305 | d049e626 | Nathan Froyd | (*regs)[11] = tswapl(env->regs[11]); |
306 | d049e626 | Nathan Froyd | (*regs)[12] = tswapl(env->regs[12]); |
307 | d049e626 | Nathan Froyd | (*regs)[13] = tswapl(env->regs[13]); |
308 | d049e626 | Nathan Froyd | (*regs)[14] = tswapl(env->regs[14]); |
309 | d049e626 | Nathan Froyd | (*regs)[15] = tswapl(env->regs[15]); |
310 | d049e626 | Nathan Froyd | |
311 | d049e626 | Nathan Froyd | (*regs)[16] = tswapl(cpsr_read((CPUState *)env));
|
312 | d049e626 | Nathan Froyd | (*regs)[17] = tswapl(env->regs[0]); /* XXX */ |
313 | edf8e2af | Mika Westerberg | } |
314 | edf8e2af | Mika Westerberg | |
315 | 30ac07d4 | bellard | #define USE_ELF_CORE_DUMP
|
316 | 30ac07d4 | bellard | #define ELF_EXEC_PAGESIZE 4096 |
317 | 30ac07d4 | bellard | |
318 | afce2927 | bellard | enum
|
319 | afce2927 | bellard | { |
320 | afce2927 | bellard | ARM_HWCAP_ARM_SWP = 1 << 0, |
321 | afce2927 | bellard | ARM_HWCAP_ARM_HALF = 1 << 1, |
322 | afce2927 | bellard | ARM_HWCAP_ARM_THUMB = 1 << 2, |
323 | afce2927 | bellard | ARM_HWCAP_ARM_26BIT = 1 << 3, |
324 | afce2927 | bellard | ARM_HWCAP_ARM_FAST_MULT = 1 << 4, |
325 | afce2927 | bellard | ARM_HWCAP_ARM_FPA = 1 << 5, |
326 | afce2927 | bellard | ARM_HWCAP_ARM_VFP = 1 << 6, |
327 | afce2927 | bellard | ARM_HWCAP_ARM_EDSP = 1 << 7, |
328 | cf6de34a | Riku Voipio | ARM_HWCAP_ARM_JAVA = 1 << 8, |
329 | cf6de34a | Riku Voipio | ARM_HWCAP_ARM_IWMMXT = 1 << 9, |
330 | cf6de34a | Riku Voipio | ARM_HWCAP_ARM_THUMBEE = 1 << 10, |
331 | cf6de34a | Riku Voipio | ARM_HWCAP_ARM_NEON = 1 << 11, |
332 | cf6de34a | Riku Voipio | ARM_HWCAP_ARM_VFPv3 = 1 << 12, |
333 | cf6de34a | Riku Voipio | ARM_HWCAP_ARM_VFPv3D16 = 1 << 13, |
334 | afce2927 | bellard | }; |
335 | afce2927 | bellard | |
336 | 15338fd7 | bellard | #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \
|
337 | afce2927 | bellard | | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ |
338 | cf6de34a | Riku Voipio | | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP \ |
339 | cf6de34a | Riku Voipio | | ARM_HWCAP_ARM_NEON | ARM_HWCAP_ARM_VFPv3 ) |
340 | afce2927 | bellard | |
341 | 30ac07d4 | bellard | #endif
|
342 | 30ac07d4 | bellard | |
343 | 853d6f7a | bellard | #ifdef TARGET_SPARC
|
344 | a315a145 | bellard | #ifdef TARGET_SPARC64
|
345 | 853d6f7a | bellard | |
346 | 853d6f7a | bellard | #define ELF_START_MMAP 0x80000000 |
347 | 853d6f7a | bellard | |
348 | 992f48a0 | blueswir1 | #ifndef TARGET_ABI32
|
349 | cb33da57 | blueswir1 | #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
|
350 | 992f48a0 | blueswir1 | #else
|
351 | 992f48a0 | blueswir1 | #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
|
352 | 992f48a0 | blueswir1 | #endif
|
353 | 853d6f7a | bellard | |
354 | a315a145 | bellard | #define ELF_CLASS ELFCLASS64
|
355 | a315a145 | bellard | #define ELF_DATA ELFDATA2MSB
|
356 | 5ef54116 | bellard | #define ELF_ARCH EM_SPARCV9
|
357 | 5ef54116 | bellard | |
358 | 5ef54116 | bellard | #define STACK_BIAS 2047 |
359 | a315a145 | bellard | |
360 | a315a145 | bellard | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
361 | a315a145 | bellard | { |
362 | 992f48a0 | blueswir1 | #ifndef TARGET_ABI32
|
363 | a315a145 | bellard | regs->tstate = 0;
|
364 | 992f48a0 | blueswir1 | #endif
|
365 | a315a145 | bellard | regs->pc = infop->entry; |
366 | a315a145 | bellard | regs->npc = regs->pc + 4;
|
367 | a315a145 | bellard | regs->y = 0;
|
368 | 992f48a0 | blueswir1 | #ifdef TARGET_ABI32
|
369 | 992f48a0 | blueswir1 | regs->u_regs[14] = infop->start_stack - 16 * 4; |
370 | 992f48a0 | blueswir1 | #else
|
371 | cb33da57 | blueswir1 | if (personality(infop->personality) == PER_LINUX32)
|
372 | cb33da57 | blueswir1 | regs->u_regs[14] = infop->start_stack - 16 * 4; |
373 | cb33da57 | blueswir1 | else
|
374 | cb33da57 | blueswir1 | regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; |
375 | 992f48a0 | blueswir1 | #endif
|
376 | a315a145 | bellard | } |
377 | a315a145 | bellard | |
378 | a315a145 | bellard | #else
|
379 | a315a145 | bellard | #define ELF_START_MMAP 0x80000000 |
380 | a315a145 | bellard | |
381 | a315a145 | bellard | #define elf_check_arch(x) ( (x) == EM_SPARC )
|
382 | a315a145 | bellard | |
383 | 853d6f7a | bellard | #define ELF_CLASS ELFCLASS32
|
384 | 853d6f7a | bellard | #define ELF_DATA ELFDATA2MSB
|
385 | 853d6f7a | bellard | #define ELF_ARCH EM_SPARC
|
386 | 853d6f7a | bellard | |
387 | 853d6f7a | bellard | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
388 | 853d6f7a | bellard | { |
389 | f5155289 | bellard | regs->psr = 0;
|
390 | f5155289 | bellard | regs->pc = infop->entry; |
391 | f5155289 | bellard | regs->npc = regs->pc + 4;
|
392 | f5155289 | bellard | regs->y = 0;
|
393 | f5155289 | bellard | regs->u_regs[14] = infop->start_stack - 16 * 4; |
394 | 853d6f7a | bellard | } |
395 | 853d6f7a | bellard | |
396 | 853d6f7a | bellard | #endif
|
397 | a315a145 | bellard | #endif
|
398 | 853d6f7a | bellard | |
399 | 67867308 | bellard | #ifdef TARGET_PPC
|
400 | 67867308 | bellard | |
401 | 67867308 | bellard | #define ELF_START_MMAP 0x80000000 |
402 | 67867308 | bellard | |
403 | e85e7c6e | j_mayer | #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
|
404 | 84409ddb | j_mayer | |
405 | 84409ddb | j_mayer | #define elf_check_arch(x) ( (x) == EM_PPC64 )
|
406 | 84409ddb | j_mayer | |
407 | 84409ddb | j_mayer | #define ELF_CLASS ELFCLASS64
|
408 | 84409ddb | j_mayer | |
409 | 84409ddb | j_mayer | #else
|
410 | 84409ddb | j_mayer | |
411 | 67867308 | bellard | #define elf_check_arch(x) ( (x) == EM_PPC )
|
412 | 67867308 | bellard | |
413 | 67867308 | bellard | #define ELF_CLASS ELFCLASS32
|
414 | 84409ddb | j_mayer | |
415 | 84409ddb | j_mayer | #endif
|
416 | 84409ddb | j_mayer | |
417 | 67867308 | bellard | #ifdef TARGET_WORDS_BIGENDIAN
|
418 | 67867308 | bellard | #define ELF_DATA ELFDATA2MSB
|
419 | 67867308 | bellard | #else
|
420 | 67867308 | bellard | #define ELF_DATA ELFDATA2LSB
|
421 | 67867308 | bellard | #endif
|
422 | 67867308 | bellard | #define ELF_ARCH EM_PPC
|
423 | 67867308 | bellard | |
424 | df84e4f3 | Nathan Froyd | /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
|
425 | df84e4f3 | Nathan Froyd | See arch/powerpc/include/asm/cputable.h. */
|
426 | df84e4f3 | Nathan Froyd | enum {
|
427 | 3efa9a67 | malc | QEMU_PPC_FEATURE_32 = 0x80000000,
|
428 | 3efa9a67 | malc | QEMU_PPC_FEATURE_64 = 0x40000000,
|
429 | 3efa9a67 | malc | QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
|
430 | 3efa9a67 | malc | QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
|
431 | 3efa9a67 | malc | QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
|
432 | 3efa9a67 | malc | QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
|
433 | 3efa9a67 | malc | QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
|
434 | 3efa9a67 | malc | QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
|
435 | 3efa9a67 | malc | QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
|
436 | 3efa9a67 | malc | QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
|
437 | 3efa9a67 | malc | QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
|
438 | 3efa9a67 | malc | QEMU_PPC_FEATURE_NO_TB = 0x00100000,
|
439 | 3efa9a67 | malc | QEMU_PPC_FEATURE_POWER4 = 0x00080000,
|
440 | 3efa9a67 | malc | QEMU_PPC_FEATURE_POWER5 = 0x00040000,
|
441 | 3efa9a67 | malc | QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
|
442 | 3efa9a67 | malc | QEMU_PPC_FEATURE_CELL = 0x00010000,
|
443 | 3efa9a67 | malc | QEMU_PPC_FEATURE_BOOKE = 0x00008000,
|
444 | 3efa9a67 | malc | QEMU_PPC_FEATURE_SMT = 0x00004000,
|
445 | 3efa9a67 | malc | QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
|
446 | 3efa9a67 | malc | QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
|
447 | 3efa9a67 | malc | QEMU_PPC_FEATURE_PA6T = 0x00000800,
|
448 | 3efa9a67 | malc | QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
|
449 | 3efa9a67 | malc | QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
|
450 | 3efa9a67 | malc | QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
|
451 | 3efa9a67 | malc | QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
|
452 | 3efa9a67 | malc | QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
|
453 | 3efa9a67 | malc | |
454 | 3efa9a67 | malc | QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
|
455 | 3efa9a67 | malc | QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
|
456 | df84e4f3 | Nathan Froyd | }; |
457 | df84e4f3 | Nathan Froyd | |
458 | df84e4f3 | Nathan Froyd | #define ELF_HWCAP get_elf_hwcap()
|
459 | df84e4f3 | Nathan Froyd | |
460 | df84e4f3 | Nathan Froyd | static uint32_t get_elf_hwcap(void) |
461 | df84e4f3 | Nathan Froyd | { |
462 | df84e4f3 | Nathan Froyd | CPUState *e = thread_env; |
463 | df84e4f3 | Nathan Froyd | uint32_t features = 0;
|
464 | df84e4f3 | Nathan Froyd | |
465 | df84e4f3 | Nathan Froyd | /* We don't have to be terribly complete here; the high points are
|
466 | df84e4f3 | Nathan Froyd | Altivec/FP/SPE support. Anything else is just a bonus. */
|
467 | df84e4f3 | Nathan Froyd | #define GET_FEATURE(flag, feature) \
|
468 | df84e4f3 | Nathan Froyd | do {if (e->insns_flags & flag) features |= feature; } while(0) |
469 | 3efa9a67 | malc | GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64); |
470 | 3efa9a67 | malc | GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU); |
471 | 3efa9a67 | malc | GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC); |
472 | 3efa9a67 | malc | GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE); |
473 | 3efa9a67 | malc | GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE); |
474 | 3efa9a67 | malc | GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE); |
475 | 3efa9a67 | malc | GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE); |
476 | 3efa9a67 | malc | GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC); |
477 | df84e4f3 | Nathan Froyd | #undef GET_FEATURE
|
478 | df84e4f3 | Nathan Froyd | |
479 | df84e4f3 | Nathan Froyd | return features;
|
480 | df84e4f3 | Nathan Froyd | } |
481 | df84e4f3 | Nathan Froyd | |
482 | f5155289 | bellard | /*
|
483 | f5155289 | bellard | * We need to put in some extra aux table entries to tell glibc what
|
484 | f5155289 | bellard | * the cache block size is, so it can use the dcbz instruction safely.
|
485 | f5155289 | bellard | */
|
486 | f5155289 | bellard | #define AT_DCACHEBSIZE 19 |
487 | f5155289 | bellard | #define AT_ICACHEBSIZE 20 |
488 | f5155289 | bellard | #define AT_UCACHEBSIZE 21 |
489 | f5155289 | bellard | /* A special ignored type value for PPC, for glibc compatibility. */
|
490 | f5155289 | bellard | #define AT_IGNOREPPC 22 |
491 | f5155289 | bellard | /*
|
492 | f5155289 | bellard | * The requirements here are:
|
493 | f5155289 | bellard | * - keep the final alignment of sp (sp & 0xf)
|
494 | f5155289 | bellard | * - make sure the 32-bit value at the first 16 byte aligned position of
|
495 | f5155289 | bellard | * AUXV is greater than 16 for glibc compatibility.
|
496 | f5155289 | bellard | * AT_IGNOREPPC is used for that.
|
497 | f5155289 | bellard | * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
|
498 | f5155289 | bellard | * even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
|
499 | f5155289 | bellard | */
|
500 | 0bccf03d | bellard | #define DLINFO_ARCH_ITEMS 5 |
501 | f5155289 | bellard | #define ARCH_DLINFO \
|
502 | f5155289 | bellard | do { \
|
503 | 0bccf03d | bellard | NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \
|
504 | 0bccf03d | bellard | NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \
|
505 | 0bccf03d | bellard | NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \
|
506 | f5155289 | bellard | /* \
|
507 | f5155289 | bellard | * Now handle glibc compatibility. \
|
508 | f5155289 | bellard | */ \
|
509 | 0bccf03d | bellard | NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ |
510 | 0bccf03d | bellard | NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ |
511 | f5155289 | bellard | } while (0) |
512 | f5155289 | bellard | |
513 | 67867308 | bellard | static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) |
514 | 67867308 | bellard | { |
515 | 67867308 | bellard | _regs->gpr[1] = infop->start_stack;
|
516 | e85e7c6e | j_mayer | #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
|
517 | 7983f435 | Rob Landley | _regs->gpr[2] = ldq_raw(infop->entry + 8) + infop->load_addr; |
518 | 7983f435 | Rob Landley | infop->entry = ldq_raw(infop->entry) + infop->load_addr; |
519 | 84409ddb | j_mayer | #endif
|
520 | 67867308 | bellard | _regs->nip = infop->entry; |
521 | 67867308 | bellard | } |
522 | 67867308 | bellard | |
523 | e2f3e741 | Nathan Froyd | /* See linux kernel: arch/powerpc/include/asm/elf.h. */
|
524 | e2f3e741 | Nathan Froyd | #define ELF_NREG 48 |
525 | e2f3e741 | Nathan Froyd | typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
526 | e2f3e741 | Nathan Froyd | |
527 | e2f3e741 | Nathan Froyd | static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) |
528 | e2f3e741 | Nathan Froyd | { |
529 | e2f3e741 | Nathan Froyd | int i;
|
530 | e2f3e741 | Nathan Froyd | target_ulong ccr = 0;
|
531 | e2f3e741 | Nathan Froyd | |
532 | e2f3e741 | Nathan Froyd | for (i = 0; i < ARRAY_SIZE(env->gpr); i++) { |
533 | e2f3e741 | Nathan Froyd | (*regs)[i] = tswapl(env->gpr[i]); |
534 | e2f3e741 | Nathan Froyd | } |
535 | e2f3e741 | Nathan Froyd | |
536 | e2f3e741 | Nathan Froyd | (*regs)[32] = tswapl(env->nip);
|
537 | e2f3e741 | Nathan Froyd | (*regs)[33] = tswapl(env->msr);
|
538 | e2f3e741 | Nathan Froyd | (*regs)[35] = tswapl(env->ctr);
|
539 | e2f3e741 | Nathan Froyd | (*regs)[36] = tswapl(env->lr);
|
540 | e2f3e741 | Nathan Froyd | (*regs)[37] = tswapl(env->xer);
|
541 | e2f3e741 | Nathan Froyd | |
542 | e2f3e741 | Nathan Froyd | for (i = 0; i < ARRAY_SIZE(env->crf); i++) { |
543 | e2f3e741 | Nathan Froyd | ccr |= env->crf[i] << (32 - ((i + 1) * 4)); |
544 | e2f3e741 | Nathan Froyd | } |
545 | e2f3e741 | Nathan Froyd | (*regs)[38] = tswapl(ccr);
|
546 | e2f3e741 | Nathan Froyd | } |
547 | e2f3e741 | Nathan Froyd | |
548 | e2f3e741 | Nathan Froyd | #define USE_ELF_CORE_DUMP
|
549 | 67867308 | bellard | #define ELF_EXEC_PAGESIZE 4096 |
550 | 67867308 | bellard | |
551 | 67867308 | bellard | #endif
|
552 | 67867308 | bellard | |
553 | 048f6b4d | bellard | #ifdef TARGET_MIPS
|
554 | 048f6b4d | bellard | |
555 | 048f6b4d | bellard | #define ELF_START_MMAP 0x80000000 |
556 | 048f6b4d | bellard | |
557 | 048f6b4d | bellard | #define elf_check_arch(x) ( (x) == EM_MIPS )
|
558 | 048f6b4d | bellard | |
559 | 388bb21a | ths | #ifdef TARGET_MIPS64
|
560 | 388bb21a | ths | #define ELF_CLASS ELFCLASS64
|
561 | 388bb21a | ths | #else
|
562 | 048f6b4d | bellard | #define ELF_CLASS ELFCLASS32
|
563 | 388bb21a | ths | #endif
|
564 | 048f6b4d | bellard | #ifdef TARGET_WORDS_BIGENDIAN
|
565 | 048f6b4d | bellard | #define ELF_DATA ELFDATA2MSB
|
566 | 048f6b4d | bellard | #else
|
567 | 048f6b4d | bellard | #define ELF_DATA ELFDATA2LSB
|
568 | 048f6b4d | bellard | #endif
|
569 | 048f6b4d | bellard | #define ELF_ARCH EM_MIPS
|
570 | 048f6b4d | bellard | |
571 | 048f6b4d | bellard | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
572 | 048f6b4d | bellard | { |
573 | 623a930e | ths | regs->cp0_status = 2 << CP0St_KSU;
|
574 | 048f6b4d | bellard | regs->cp0_epc = infop->entry; |
575 | 048f6b4d | bellard | regs->regs[29] = infop->start_stack;
|
576 | 048f6b4d | bellard | } |
577 | 048f6b4d | bellard | |
578 | 51e52606 | Nathan Froyd | /* See linux kernel: arch/mips/include/asm/elf.h. */
|
579 | 51e52606 | Nathan Froyd | #define ELF_NREG 45 |
580 | 51e52606 | Nathan Froyd | typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
581 | 51e52606 | Nathan Froyd | |
582 | 51e52606 | Nathan Froyd | /* See linux kernel: arch/mips/include/asm/reg.h. */
|
583 | 51e52606 | Nathan Froyd | enum {
|
584 | 51e52606 | Nathan Froyd | #ifdef TARGET_MIPS64
|
585 | 51e52606 | Nathan Froyd | TARGET_EF_R0 = 0,
|
586 | 51e52606 | Nathan Froyd | #else
|
587 | 51e52606 | Nathan Froyd | TARGET_EF_R0 = 6,
|
588 | 51e52606 | Nathan Froyd | #endif
|
589 | 51e52606 | Nathan Froyd | TARGET_EF_R26 = TARGET_EF_R0 + 26,
|
590 | 51e52606 | Nathan Froyd | TARGET_EF_R27 = TARGET_EF_R0 + 27,
|
591 | 51e52606 | Nathan Froyd | TARGET_EF_LO = TARGET_EF_R0 + 32,
|
592 | 51e52606 | Nathan Froyd | TARGET_EF_HI = TARGET_EF_R0 + 33,
|
593 | 51e52606 | Nathan Froyd | TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
|
594 | 51e52606 | Nathan Froyd | TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
|
595 | 51e52606 | Nathan Froyd | TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
|
596 | 51e52606 | Nathan Froyd | TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
|
597 | 51e52606 | Nathan Froyd | }; |
598 | 51e52606 | Nathan Froyd | |
599 | 51e52606 | Nathan Froyd | /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs. */
|
600 | 51e52606 | Nathan Froyd | static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) |
601 | 51e52606 | Nathan Froyd | { |
602 | 51e52606 | Nathan Froyd | int i;
|
603 | 51e52606 | Nathan Froyd | |
604 | 51e52606 | Nathan Froyd | for (i = 0; i < TARGET_EF_R0; i++) { |
605 | 51e52606 | Nathan Froyd | (*regs)[i] = 0;
|
606 | 51e52606 | Nathan Froyd | } |
607 | 51e52606 | Nathan Froyd | (*regs)[TARGET_EF_R0] = 0;
|
608 | 51e52606 | Nathan Froyd | |
609 | 51e52606 | Nathan Froyd | for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) { |
610 | 51e52606 | Nathan Froyd | (*regs)[TARGET_EF_R0 + i] = tswapl(env->active_tc.gpr[i]); |
611 | 51e52606 | Nathan Froyd | } |
612 | 51e52606 | Nathan Froyd | |
613 | 51e52606 | Nathan Froyd | (*regs)[TARGET_EF_R26] = 0;
|
614 | 51e52606 | Nathan Froyd | (*regs)[TARGET_EF_R27] = 0;
|
615 | 51e52606 | Nathan Froyd | (*regs)[TARGET_EF_LO] = tswapl(env->active_tc.LO[0]);
|
616 | 51e52606 | Nathan Froyd | (*regs)[TARGET_EF_HI] = tswapl(env->active_tc.HI[0]);
|
617 | 51e52606 | Nathan Froyd | (*regs)[TARGET_EF_CP0_EPC] = tswapl(env->active_tc.PC); |
618 | 51e52606 | Nathan Froyd | (*regs)[TARGET_EF_CP0_BADVADDR] = tswapl(env->CP0_BadVAddr); |
619 | 51e52606 | Nathan Froyd | (*regs)[TARGET_EF_CP0_STATUS] = tswapl(env->CP0_Status); |
620 | 51e52606 | Nathan Froyd | (*regs)[TARGET_EF_CP0_CAUSE] = tswapl(env->CP0_Cause); |
621 | 51e52606 | Nathan Froyd | } |
622 | 51e52606 | Nathan Froyd | |
623 | 51e52606 | Nathan Froyd | #define USE_ELF_CORE_DUMP
|
624 | 388bb21a | ths | #define ELF_EXEC_PAGESIZE 4096 |
625 | 388bb21a | ths | |
626 | 048f6b4d | bellard | #endif /* TARGET_MIPS */ |
627 | 048f6b4d | bellard | |
628 | b779e29e | Edgar E. Iglesias | #ifdef TARGET_MICROBLAZE
|
629 | b779e29e | Edgar E. Iglesias | |
630 | b779e29e | Edgar E. Iglesias | #define ELF_START_MMAP 0x80000000 |
631 | b779e29e | Edgar E. Iglesias | |
632 | 0d5d4699 | Edgar E. Iglesias | #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
|
633 | b779e29e | Edgar E. Iglesias | |
634 | b779e29e | Edgar E. Iglesias | #define ELF_CLASS ELFCLASS32
|
635 | b779e29e | Edgar E. Iglesias | #define ELF_DATA ELFDATA2MSB
|
636 | 0d5d4699 | Edgar E. Iglesias | #define ELF_ARCH EM_MICROBLAZE
|
637 | b779e29e | Edgar E. Iglesias | |
638 | b779e29e | Edgar E. Iglesias | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
639 | b779e29e | Edgar E. Iglesias | { |
640 | b779e29e | Edgar E. Iglesias | regs->pc = infop->entry; |
641 | b779e29e | Edgar E. Iglesias | regs->r1 = infop->start_stack; |
642 | b779e29e | Edgar E. Iglesias | |
643 | b779e29e | Edgar E. Iglesias | } |
644 | b779e29e | Edgar E. Iglesias | |
645 | b779e29e | Edgar E. Iglesias | #define ELF_EXEC_PAGESIZE 4096 |
646 | b779e29e | Edgar E. Iglesias | |
647 | e4cbd44d | Edgar E. Iglesias | #define USE_ELF_CORE_DUMP
|
648 | e4cbd44d | Edgar E. Iglesias | #define ELF_NREG 38 |
649 | e4cbd44d | Edgar E. Iglesias | typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
650 | e4cbd44d | Edgar E. Iglesias | |
651 | e4cbd44d | Edgar E. Iglesias | /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs. */
|
652 | e4cbd44d | Edgar E. Iglesias | static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) |
653 | e4cbd44d | Edgar E. Iglesias | { |
654 | e4cbd44d | Edgar E. Iglesias | int i, pos = 0; |
655 | e4cbd44d | Edgar E. Iglesias | |
656 | e4cbd44d | Edgar E. Iglesias | for (i = 0; i < 32; i++) { |
657 | e4cbd44d | Edgar E. Iglesias | (*regs)[pos++] = tswapl(env->regs[i]); |
658 | e4cbd44d | Edgar E. Iglesias | } |
659 | e4cbd44d | Edgar E. Iglesias | |
660 | e4cbd44d | Edgar E. Iglesias | for (i = 0; i < 6; i++) { |
661 | e4cbd44d | Edgar E. Iglesias | (*regs)[pos++] = tswapl(env->sregs[i]); |
662 | e4cbd44d | Edgar E. Iglesias | } |
663 | e4cbd44d | Edgar E. Iglesias | } |
664 | e4cbd44d | Edgar E. Iglesias | |
665 | b779e29e | Edgar E. Iglesias | #endif /* TARGET_MICROBLAZE */ |
666 | b779e29e | Edgar E. Iglesias | |
667 | fdf9b3e8 | bellard | #ifdef TARGET_SH4
|
668 | fdf9b3e8 | bellard | |
669 | fdf9b3e8 | bellard | #define ELF_START_MMAP 0x80000000 |
670 | fdf9b3e8 | bellard | |
671 | fdf9b3e8 | bellard | #define elf_check_arch(x) ( (x) == EM_SH )
|
672 | fdf9b3e8 | bellard | |
673 | fdf9b3e8 | bellard | #define ELF_CLASS ELFCLASS32
|
674 | fdf9b3e8 | bellard | #define ELF_DATA ELFDATA2LSB
|
675 | fdf9b3e8 | bellard | #define ELF_ARCH EM_SH
|
676 | fdf9b3e8 | bellard | |
677 | fdf9b3e8 | bellard | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
678 | fdf9b3e8 | bellard | { |
679 | fdf9b3e8 | bellard | /* Check other registers XXXXX */
|
680 | fdf9b3e8 | bellard | regs->pc = infop->entry; |
681 | 072ae847 | ths | regs->regs[15] = infop->start_stack;
|
682 | fdf9b3e8 | bellard | } |
683 | fdf9b3e8 | bellard | |
684 | 7631c97e | Nathan Froyd | /* See linux kernel: arch/sh/include/asm/elf.h. */
|
685 | 7631c97e | Nathan Froyd | #define ELF_NREG 23 |
686 | 7631c97e | Nathan Froyd | typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
687 | 7631c97e | Nathan Froyd | |
688 | 7631c97e | Nathan Froyd | /* See linux kernel: arch/sh/include/asm/ptrace.h. */
|
689 | 7631c97e | Nathan Froyd | enum {
|
690 | 7631c97e | Nathan Froyd | TARGET_REG_PC = 16,
|
691 | 7631c97e | Nathan Froyd | TARGET_REG_PR = 17,
|
692 | 7631c97e | Nathan Froyd | TARGET_REG_SR = 18,
|
693 | 7631c97e | Nathan Froyd | TARGET_REG_GBR = 19,
|
694 | 7631c97e | Nathan Froyd | TARGET_REG_MACH = 20,
|
695 | 7631c97e | Nathan Froyd | TARGET_REG_MACL = 21,
|
696 | 7631c97e | Nathan Froyd | TARGET_REG_SYSCALL = 22
|
697 | 7631c97e | Nathan Froyd | }; |
698 | 7631c97e | Nathan Froyd | |
699 | 7631c97e | Nathan Froyd | static inline void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) |
700 | 7631c97e | Nathan Froyd | { |
701 | 7631c97e | Nathan Froyd | int i;
|
702 | 7631c97e | Nathan Froyd | |
703 | 7631c97e | Nathan Froyd | for (i = 0; i < 16; i++) { |
704 | 7631c97e | Nathan Froyd | (*regs[i]) = tswapl(env->gregs[i]); |
705 | 7631c97e | Nathan Froyd | } |
706 | 7631c97e | Nathan Froyd | |
707 | 7631c97e | Nathan Froyd | (*regs)[TARGET_REG_PC] = tswapl(env->pc); |
708 | 7631c97e | Nathan Froyd | (*regs)[TARGET_REG_PR] = tswapl(env->pr); |
709 | 7631c97e | Nathan Froyd | (*regs)[TARGET_REG_SR] = tswapl(env->sr); |
710 | 7631c97e | Nathan Froyd | (*regs)[TARGET_REG_GBR] = tswapl(env->gbr); |
711 | 7631c97e | Nathan Froyd | (*regs)[TARGET_REG_MACH] = tswapl(env->mach); |
712 | 7631c97e | Nathan Froyd | (*regs)[TARGET_REG_MACL] = tswapl(env->macl); |
713 | 7631c97e | Nathan Froyd | (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */ |
714 | 7631c97e | Nathan Froyd | } |
715 | 7631c97e | Nathan Froyd | |
716 | 7631c97e | Nathan Froyd | #define USE_ELF_CORE_DUMP
|
717 | fdf9b3e8 | bellard | #define ELF_EXEC_PAGESIZE 4096 |
718 | fdf9b3e8 | bellard | |
719 | fdf9b3e8 | bellard | #endif
|
720 | fdf9b3e8 | bellard | |
721 | 48733d19 | ths | #ifdef TARGET_CRIS
|
722 | 48733d19 | ths | |
723 | 48733d19 | ths | #define ELF_START_MMAP 0x80000000 |
724 | 48733d19 | ths | |
725 | 48733d19 | ths | #define elf_check_arch(x) ( (x) == EM_CRIS )
|
726 | 48733d19 | ths | |
727 | 48733d19 | ths | #define ELF_CLASS ELFCLASS32
|
728 | 48733d19 | ths | #define ELF_DATA ELFDATA2LSB
|
729 | 48733d19 | ths | #define ELF_ARCH EM_CRIS
|
730 | 48733d19 | ths | |
731 | 48733d19 | ths | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
732 | 48733d19 | ths | { |
733 | 48733d19 | ths | regs->erp = infop->entry; |
734 | 48733d19 | ths | } |
735 | 48733d19 | ths | |
736 | 48733d19 | ths | #define ELF_EXEC_PAGESIZE 8192 |
737 | 48733d19 | ths | |
738 | 48733d19 | ths | #endif
|
739 | 48733d19 | ths | |
740 | e6e5906b | pbrook | #ifdef TARGET_M68K
|
741 | e6e5906b | pbrook | |
742 | e6e5906b | pbrook | #define ELF_START_MMAP 0x80000000 |
743 | e6e5906b | pbrook | |
744 | e6e5906b | pbrook | #define elf_check_arch(x) ( (x) == EM_68K )
|
745 | e6e5906b | pbrook | |
746 | e6e5906b | pbrook | #define ELF_CLASS ELFCLASS32
|
747 | e6e5906b | pbrook | #define ELF_DATA ELFDATA2MSB
|
748 | e6e5906b | pbrook | #define ELF_ARCH EM_68K
|
749 | e6e5906b | pbrook | |
750 | e6e5906b | pbrook | /* ??? Does this need to do anything?
|
751 | e6e5906b | pbrook | #define ELF_PLAT_INIT(_r) */
|
752 | e6e5906b | pbrook | |
753 | e6e5906b | pbrook | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
754 | e6e5906b | pbrook | { |
755 | e6e5906b | pbrook | regs->usp = infop->start_stack; |
756 | e6e5906b | pbrook | regs->sr = 0;
|
757 | e6e5906b | pbrook | regs->pc = infop->entry; |
758 | e6e5906b | pbrook | } |
759 | e6e5906b | pbrook | |
760 | 7a93cc55 | Nathan Froyd | /* See linux kernel: arch/m68k/include/asm/elf.h. */
|
761 | 7a93cc55 | Nathan Froyd | #define ELF_NREG 20 |
762 | 7a93cc55 | Nathan Froyd | typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
763 | 7a93cc55 | Nathan Froyd | |
764 | 7a93cc55 | Nathan Froyd | static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) |
765 | 7a93cc55 | Nathan Froyd | { |
766 | 7a93cc55 | Nathan Froyd | (*regs)[0] = tswapl(env->dregs[1]); |
767 | 7a93cc55 | Nathan Froyd | (*regs)[1] = tswapl(env->dregs[2]); |
768 | 7a93cc55 | Nathan Froyd | (*regs)[2] = tswapl(env->dregs[3]); |
769 | 7a93cc55 | Nathan Froyd | (*regs)[3] = tswapl(env->dregs[4]); |
770 | 7a93cc55 | Nathan Froyd | (*regs)[4] = tswapl(env->dregs[5]); |
771 | 7a93cc55 | Nathan Froyd | (*regs)[5] = tswapl(env->dregs[6]); |
772 | 7a93cc55 | Nathan Froyd | (*regs)[6] = tswapl(env->dregs[7]); |
773 | 7a93cc55 | Nathan Froyd | (*regs)[7] = tswapl(env->aregs[0]); |
774 | 7a93cc55 | Nathan Froyd | (*regs)[8] = tswapl(env->aregs[1]); |
775 | 7a93cc55 | Nathan Froyd | (*regs)[9] = tswapl(env->aregs[2]); |
776 | 7a93cc55 | Nathan Froyd | (*regs)[10] = tswapl(env->aregs[3]); |
777 | 7a93cc55 | Nathan Froyd | (*regs)[11] = tswapl(env->aregs[4]); |
778 | 7a93cc55 | Nathan Froyd | (*regs)[12] = tswapl(env->aregs[5]); |
779 | 7a93cc55 | Nathan Froyd | (*regs)[13] = tswapl(env->aregs[6]); |
780 | 7a93cc55 | Nathan Froyd | (*regs)[14] = tswapl(env->dregs[0]); |
781 | 7a93cc55 | Nathan Froyd | (*regs)[15] = tswapl(env->aregs[7]); |
782 | 7a93cc55 | Nathan Froyd | (*regs)[16] = tswapl(env->dregs[0]); /* FIXME: orig_d0 */ |
783 | 7a93cc55 | Nathan Froyd | (*regs)[17] = tswapl(env->sr);
|
784 | 7a93cc55 | Nathan Froyd | (*regs)[18] = tswapl(env->pc);
|
785 | 7a93cc55 | Nathan Froyd | (*regs)[19] = 0; /* FIXME: regs->format | regs->vector */ |
786 | 7a93cc55 | Nathan Froyd | } |
787 | 7a93cc55 | Nathan Froyd | |
788 | 7a93cc55 | Nathan Froyd | #define USE_ELF_CORE_DUMP
|
789 | e6e5906b | pbrook | #define ELF_EXEC_PAGESIZE 8192 |
790 | e6e5906b | pbrook | |
791 | e6e5906b | pbrook | #endif
|
792 | e6e5906b | pbrook | |
793 | 7a3148a9 | j_mayer | #ifdef TARGET_ALPHA
|
794 | 7a3148a9 | j_mayer | |
795 | 7a3148a9 | j_mayer | #define ELF_START_MMAP (0x30000000000ULL) |
796 | 7a3148a9 | j_mayer | |
797 | 7a3148a9 | j_mayer | #define elf_check_arch(x) ( (x) == ELF_ARCH )
|
798 | 7a3148a9 | j_mayer | |
799 | 7a3148a9 | j_mayer | #define ELF_CLASS ELFCLASS64
|
800 | 7a3148a9 | j_mayer | #define ELF_DATA ELFDATA2MSB
|
801 | 7a3148a9 | j_mayer | #define ELF_ARCH EM_ALPHA
|
802 | 7a3148a9 | j_mayer | |
803 | 7a3148a9 | j_mayer | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
804 | 7a3148a9 | j_mayer | { |
805 | 7a3148a9 | j_mayer | regs->pc = infop->entry; |
806 | 7a3148a9 | j_mayer | regs->ps = 8;
|
807 | 7a3148a9 | j_mayer | regs->usp = infop->start_stack; |
808 | 7a3148a9 | j_mayer | } |
809 | 7a3148a9 | j_mayer | |
810 | 7a3148a9 | j_mayer | #define ELF_EXEC_PAGESIZE 8192 |
811 | 7a3148a9 | j_mayer | |
812 | 7a3148a9 | j_mayer | #endif /* TARGET_ALPHA */ |
813 | 7a3148a9 | j_mayer | |
814 | 15338fd7 | bellard | #ifndef ELF_PLATFORM
|
815 | 15338fd7 | bellard | #define ELF_PLATFORM (NULL) |
816 | 15338fd7 | bellard | #endif
|
817 | 15338fd7 | bellard | |
818 | 15338fd7 | bellard | #ifndef ELF_HWCAP
|
819 | 15338fd7 | bellard | #define ELF_HWCAP 0 |
820 | 15338fd7 | bellard | #endif
|
821 | 15338fd7 | bellard | |
822 | 992f48a0 | blueswir1 | #ifdef TARGET_ABI32
|
823 | cb33da57 | blueswir1 | #undef ELF_CLASS
|
824 | 992f48a0 | blueswir1 | #define ELF_CLASS ELFCLASS32
|
825 | cb33da57 | blueswir1 | #undef bswaptls
|
826 | cb33da57 | blueswir1 | #define bswaptls(ptr) bswap32s(ptr)
|
827 | cb33da57 | blueswir1 | #endif
|
828 | cb33da57 | blueswir1 | |
829 | 31e31b8a | bellard | #include "elf.h" |
830 | 09bfb054 | bellard | |
831 | 09bfb054 | bellard | struct exec
|
832 | 09bfb054 | bellard | { |
833 | 09bfb054 | bellard | unsigned int a_info; /* Use macros N_MAGIC, etc for access */ |
834 | 09bfb054 | bellard | unsigned int a_text; /* length of text, in bytes */ |
835 | 09bfb054 | bellard | unsigned int a_data; /* length of data, in bytes */ |
836 | 09bfb054 | bellard | unsigned int a_bss; /* length of uninitialized data area, in bytes */ |
837 | 09bfb054 | bellard | unsigned int a_syms; /* length of symbol table data in file, in bytes */ |
838 | 09bfb054 | bellard | unsigned int a_entry; /* start address */ |
839 | 09bfb054 | bellard | unsigned int a_trsize; /* length of relocation info for text, in bytes */ |
840 | 09bfb054 | bellard | unsigned int a_drsize; /* length of relocation info for data, in bytes */ |
841 | 09bfb054 | bellard | }; |
842 | 09bfb054 | bellard | |
843 | 09bfb054 | bellard | |
844 | 09bfb054 | bellard | #define N_MAGIC(exec) ((exec).a_info & 0xffff) |
845 | 09bfb054 | bellard | #define OMAGIC 0407 |
846 | 09bfb054 | bellard | #define NMAGIC 0410 |
847 | 09bfb054 | bellard | #define ZMAGIC 0413 |
848 | 09bfb054 | bellard | #define QMAGIC 0314 |
849 | 09bfb054 | bellard | |
850 | 09bfb054 | bellard | /* max code+data+bss space allocated to elf interpreter */
|
851 | 09bfb054 | bellard | #define INTERP_MAP_SIZE (32 * 1024 * 1024) |
852 | 09bfb054 | bellard | |
853 | 09bfb054 | bellard | /* max code+data+bss+brk space allocated to ET_DYN executables */
|
854 | 09bfb054 | bellard | #define ET_DYN_MAP_SIZE (128 * 1024 * 1024) |
855 | 09bfb054 | bellard | |
856 | 31e31b8a | bellard | /* Necessary parameters */
|
857 | 54936004 | bellard | #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
|
858 | 54936004 | bellard | #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) |
859 | 54936004 | bellard | #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) |
860 | 31e31b8a | bellard | |
861 | 31e31b8a | bellard | #define INTERPRETER_NONE 0 |
862 | 31e31b8a | bellard | #define INTERPRETER_AOUT 1 |
863 | 31e31b8a | bellard | #define INTERPRETER_ELF 2 |
864 | 31e31b8a | bellard | |
865 | 15338fd7 | bellard | #define DLINFO_ITEMS 12 |
866 | 31e31b8a | bellard | |
867 | 09bfb054 | bellard | static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) |
868 | 09bfb054 | bellard | { |
869 | 09bfb054 | bellard | memcpy(to, from, n); |
870 | 09bfb054 | bellard | } |
871 | d691f669 | bellard | |
872 | 31e31b8a | bellard | static int load_aout_interp(void * exptr, int interp_fd); |
873 | 31e31b8a | bellard | |
874 | 31e31b8a | bellard | #ifdef BSWAP_NEEDED
|
875 | 92a31b1f | bellard | static void bswap_ehdr(struct elfhdr *ehdr) |
876 | 31e31b8a | bellard | { |
877 | 31e31b8a | bellard | bswap16s(&ehdr->e_type); /* Object file type */
|
878 | 31e31b8a | bellard | bswap16s(&ehdr->e_machine); /* Architecture */
|
879 | 31e31b8a | bellard | bswap32s(&ehdr->e_version); /* Object file version */
|
880 | 92a31b1f | bellard | bswaptls(&ehdr->e_entry); /* Entry point virtual address */
|
881 | 92a31b1f | bellard | bswaptls(&ehdr->e_phoff); /* Program header table file offset */
|
882 | 92a31b1f | bellard | bswaptls(&ehdr->e_shoff); /* Section header table file offset */
|
883 | 31e31b8a | bellard | bswap32s(&ehdr->e_flags); /* Processor-specific flags */
|
884 | 31e31b8a | bellard | bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
|
885 | 31e31b8a | bellard | bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
|
886 | 31e31b8a | bellard | bswap16s(&ehdr->e_phnum); /* Program header table entry count */
|
887 | 31e31b8a | bellard | bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
|
888 | 31e31b8a | bellard | bswap16s(&ehdr->e_shnum); /* Section header table entry count */
|
889 | 31e31b8a | bellard | bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
|
890 | 31e31b8a | bellard | } |
891 | 31e31b8a | bellard | |
892 | 92a31b1f | bellard | static void bswap_phdr(struct elf_phdr *phdr) |
893 | 31e31b8a | bellard | { |
894 | 31e31b8a | bellard | bswap32s(&phdr->p_type); /* Segment type */
|
895 | 92a31b1f | bellard | bswaptls(&phdr->p_offset); /* Segment file offset */
|
896 | 92a31b1f | bellard | bswaptls(&phdr->p_vaddr); /* Segment virtual address */
|
897 | 92a31b1f | bellard | bswaptls(&phdr->p_paddr); /* Segment physical address */
|
898 | 92a31b1f | bellard | bswaptls(&phdr->p_filesz); /* Segment size in file */
|
899 | 92a31b1f | bellard | bswaptls(&phdr->p_memsz); /* Segment size in memory */
|
900 | 31e31b8a | bellard | bswap32s(&phdr->p_flags); /* Segment flags */
|
901 | 92a31b1f | bellard | bswaptls(&phdr->p_align); /* Segment alignment */
|
902 | 31e31b8a | bellard | } |
903 | 689f936f | bellard | |
904 | 92a31b1f | bellard | static void bswap_shdr(struct elf_shdr *shdr) |
905 | 689f936f | bellard | { |
906 | 689f936f | bellard | bswap32s(&shdr->sh_name); |
907 | 689f936f | bellard | bswap32s(&shdr->sh_type); |
908 | 92a31b1f | bellard | bswaptls(&shdr->sh_flags); |
909 | 92a31b1f | bellard | bswaptls(&shdr->sh_addr); |
910 | 92a31b1f | bellard | bswaptls(&shdr->sh_offset); |
911 | 92a31b1f | bellard | bswaptls(&shdr->sh_size); |
912 | 689f936f | bellard | bswap32s(&shdr->sh_link); |
913 | 689f936f | bellard | bswap32s(&shdr->sh_info); |
914 | 92a31b1f | bellard | bswaptls(&shdr->sh_addralign); |
915 | 92a31b1f | bellard | bswaptls(&shdr->sh_entsize); |
916 | 689f936f | bellard | } |
917 | 689f936f | bellard | |
918 | 7a3148a9 | j_mayer | static void bswap_sym(struct elf_sym *sym) |
919 | 689f936f | bellard | { |
920 | 689f936f | bellard | bswap32s(&sym->st_name); |
921 | 7a3148a9 | j_mayer | bswaptls(&sym->st_value); |
922 | 7a3148a9 | j_mayer | bswaptls(&sym->st_size); |
923 | 689f936f | bellard | bswap16s(&sym->st_shndx); |
924 | 689f936f | bellard | } |
925 | 31e31b8a | bellard | #endif
|
926 | 31e31b8a | bellard | |
927 | edf8e2af | Mika Westerberg | #ifdef USE_ELF_CORE_DUMP
|
928 | edf8e2af | Mika Westerberg | static int elf_core_dump(int, const CPUState *); |
929 | edf8e2af | Mika Westerberg | |
930 | edf8e2af | Mika Westerberg | #ifdef BSWAP_NEEDED
|
931 | edf8e2af | Mika Westerberg | static void bswap_note(struct elf_note *en) |
932 | edf8e2af | Mika Westerberg | { |
933 | 9fdca5aa | malc | bswap32s(&en->n_namesz); |
934 | 9fdca5aa | malc | bswap32s(&en->n_descsz); |
935 | 9fdca5aa | malc | bswap32s(&en->n_type); |
936 | edf8e2af | Mika Westerberg | } |
937 | edf8e2af | Mika Westerberg | #endif /* BSWAP_NEEDED */ |
938 | edf8e2af | Mika Westerberg | |
939 | edf8e2af | Mika Westerberg | #endif /* USE_ELF_CORE_DUMP */ |
940 | edf8e2af | Mika Westerberg | |
941 | 31e31b8a | bellard | /*
|
942 | e5fe0c52 | pbrook | * 'copy_elf_strings()' copies argument/envelope strings from user
|
943 | 31e31b8a | bellard | * memory to free pages in kernel mem. These are in a format ready
|
944 | 31e31b8a | bellard | * to be put directly into the top of new user memory.
|
945 | 31e31b8a | bellard | *
|
946 | 31e31b8a | bellard | */
|
947 | 992f48a0 | blueswir1 | static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, |
948 | 992f48a0 | blueswir1 | abi_ulong p) |
949 | 31e31b8a | bellard | { |
950 | 31e31b8a | bellard | char *tmp, *tmp1, *pag = NULL; |
951 | 31e31b8a | bellard | int len, offset = 0; |
952 | 31e31b8a | bellard | |
953 | 31e31b8a | bellard | if (!p) {
|
954 | 31e31b8a | bellard | return 0; /* bullet-proofing */ |
955 | 31e31b8a | bellard | } |
956 | 31e31b8a | bellard | while (argc-- > 0) { |
957 | edf779ff | bellard | tmp = argv[argc]; |
958 | edf779ff | bellard | if (!tmp) {
|
959 | 31e31b8a | bellard | fprintf(stderr, "VFS: argc is wrong");
|
960 | 31e31b8a | bellard | exit(-1);
|
961 | 31e31b8a | bellard | } |
962 | edf779ff | bellard | tmp1 = tmp; |
963 | edf779ff | bellard | while (*tmp++);
|
964 | 31e31b8a | bellard | len = tmp - tmp1; |
965 | 31e31b8a | bellard | if (p < len) { /* this shouldn't happen - 128kB */ |
966 | 31e31b8a | bellard | return 0; |
967 | 31e31b8a | bellard | } |
968 | 31e31b8a | bellard | while (len) {
|
969 | 31e31b8a | bellard | --p; --tmp; --len; |
970 | 31e31b8a | bellard | if (--offset < 0) { |
971 | 54936004 | bellard | offset = p % TARGET_PAGE_SIZE; |
972 | 53a5960a | pbrook | pag = (char *)page[p/TARGET_PAGE_SIZE];
|
973 | 44a91cae | bellard | if (!pag) {
|
974 | 53a5960a | pbrook | pag = (char *)malloc(TARGET_PAGE_SIZE);
|
975 | 4118a970 | j_mayer | memset(pag, 0, TARGET_PAGE_SIZE);
|
976 | 53a5960a | pbrook | page[p/TARGET_PAGE_SIZE] = pag; |
977 | 44a91cae | bellard | if (!pag)
|
978 | 44a91cae | bellard | return 0; |
979 | 31e31b8a | bellard | } |
980 | 31e31b8a | bellard | } |
981 | 31e31b8a | bellard | if (len == 0 || offset == 0) { |
982 | edf779ff | bellard | *(pag + offset) = *tmp; |
983 | 31e31b8a | bellard | } |
984 | 31e31b8a | bellard | else {
|
985 | 31e31b8a | bellard | int bytes_to_copy = (len > offset) ? offset : len;
|
986 | 31e31b8a | bellard | tmp -= bytes_to_copy; |
987 | 31e31b8a | bellard | p -= bytes_to_copy; |
988 | 31e31b8a | bellard | offset -= bytes_to_copy; |
989 | 31e31b8a | bellard | len -= bytes_to_copy; |
990 | 31e31b8a | bellard | memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
|
991 | 31e31b8a | bellard | } |
992 | 31e31b8a | bellard | } |
993 | 31e31b8a | bellard | } |
994 | 31e31b8a | bellard | return p;
|
995 | 31e31b8a | bellard | } |
996 | 31e31b8a | bellard | |
997 | 992f48a0 | blueswir1 | static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, |
998 | 992f48a0 | blueswir1 | struct image_info *info)
|
999 | 53a5960a | pbrook | { |
1000 | 992f48a0 | blueswir1 | abi_ulong stack_base, size, error; |
1001 | 31e31b8a | bellard | int i;
|
1002 | 31e31b8a | bellard | |
1003 | 09bfb054 | bellard | /* Create enough stack to hold everything. If we don't use
|
1004 | 09bfb054 | bellard | * it for args, we'll use it for something else...
|
1005 | 09bfb054 | bellard | */
|
1006 | 703e0e89 | Richard Henderson | size = guest_stack_size; |
1007 | 54936004 | bellard | if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
|
1008 | 54936004 | bellard | size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; |
1009 | 5fafdf24 | ths | error = target_mmap(0,
|
1010 | 83fb7adf | bellard | size + qemu_host_page_size, |
1011 | 54936004 | bellard | PROT_READ | PROT_WRITE, |
1012 | 54936004 | bellard | MAP_PRIVATE | MAP_ANONYMOUS, |
1013 | 54936004 | bellard | -1, 0); |
1014 | 09bfb054 | bellard | if (error == -1) { |
1015 | 09bfb054 | bellard | perror("stk mmap");
|
1016 | 09bfb054 | bellard | exit(-1);
|
1017 | 09bfb054 | bellard | } |
1018 | 09bfb054 | bellard | /* we reserve one extra page at the top of the stack as guard */
|
1019 | 83fb7adf | bellard | target_mprotect(error + size, qemu_host_page_size, PROT_NONE); |
1020 | 31e31b8a | bellard | |
1021 | 54936004 | bellard | stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; |
1022 | 31e31b8a | bellard | p += stack_base; |
1023 | 09bfb054 | bellard | |
1024 | 31e31b8a | bellard | for (i = 0 ; i < MAX_ARG_PAGES ; i++) { |
1025 | 31e31b8a | bellard | if (bprm->page[i]) {
|
1026 | 31e31b8a | bellard | info->rss++; |
1027 | 579a97f7 | bellard | /* FIXME - check return value of memcpy_to_target() for failure */
|
1028 | 53a5960a | pbrook | memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); |
1029 | 53a5960a | pbrook | free(bprm->page[i]); |
1030 | 31e31b8a | bellard | } |
1031 | 53a5960a | pbrook | stack_base += TARGET_PAGE_SIZE; |
1032 | 31e31b8a | bellard | } |
1033 | 31e31b8a | bellard | return p;
|
1034 | 31e31b8a | bellard | } |
1035 | 31e31b8a | bellard | |
1036 | 992f48a0 | blueswir1 | static void set_brk(abi_ulong start, abi_ulong end) |
1037 | 31e31b8a | bellard | { |
1038 | 31e31b8a | bellard | /* page-align the start and end addresses... */
|
1039 | 54936004 | bellard | start = HOST_PAGE_ALIGN(start); |
1040 | 54936004 | bellard | end = HOST_PAGE_ALIGN(end); |
1041 | 31e31b8a | bellard | if (end <= start)
|
1042 | 31e31b8a | bellard | return;
|
1043 | 54936004 | bellard | if(target_mmap(start, end - start,
|
1044 | 54936004 | bellard | PROT_READ | PROT_WRITE | PROT_EXEC, |
1045 | 54936004 | bellard | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { |
1046 | 31e31b8a | bellard | perror("cannot mmap brk");
|
1047 | 31e31b8a | bellard | exit(-1);
|
1048 | 31e31b8a | bellard | } |
1049 | 31e31b8a | bellard | } |
1050 | 31e31b8a | bellard | |
1051 | 31e31b8a | bellard | |
1052 | 853d6f7a | bellard | /* We need to explicitly zero any fractional pages after the data
|
1053 | 853d6f7a | bellard | section (i.e. bss). This would contain the junk from the file that
|
1054 | 853d6f7a | bellard | should not be in memory. */
|
1055 | 992f48a0 | blueswir1 | static void padzero(abi_ulong elf_bss, abi_ulong last_bss) |
1056 | 31e31b8a | bellard | { |
1057 | 992f48a0 | blueswir1 | abi_ulong nbyte; |
1058 | 31e31b8a | bellard | |
1059 | 768a4a36 | ths | if (elf_bss >= last_bss)
|
1060 | 768a4a36 | ths | return;
|
1061 | 768a4a36 | ths | |
1062 | 853d6f7a | bellard | /* XXX: this is really a hack : if the real host page size is
|
1063 | 853d6f7a | bellard | smaller than the target page size, some pages after the end
|
1064 | 853d6f7a | bellard | of the file may not be mapped. A better fix would be to
|
1065 | 853d6f7a | bellard | patch target_mmap(), but it is more complicated as the file
|
1066 | 853d6f7a | bellard | size must be known */
|
1067 | 83fb7adf | bellard | if (qemu_real_host_page_size < qemu_host_page_size) {
|
1068 | 992f48a0 | blueswir1 | abi_ulong end_addr, end_addr1; |
1069 | 5fafdf24 | ths | end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
|
1070 | 83fb7adf | bellard | ~(qemu_real_host_page_size - 1);
|
1071 | 853d6f7a | bellard | end_addr = HOST_PAGE_ALIGN(elf_bss); |
1072 | 853d6f7a | bellard | if (end_addr1 < end_addr) {
|
1073 | 863cf0b7 | j_mayer | mmap((void *)g2h(end_addr1), end_addr - end_addr1,
|
1074 | 853d6f7a | bellard | PROT_READ|PROT_WRITE|PROT_EXEC, |
1075 | 853d6f7a | bellard | MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
1076 | 853d6f7a | bellard | } |
1077 | 853d6f7a | bellard | } |
1078 | 853d6f7a | bellard | |
1079 | 83fb7adf | bellard | nbyte = elf_bss & (qemu_host_page_size-1);
|
1080 | 31e31b8a | bellard | if (nbyte) {
|
1081 | 83fb7adf | bellard | nbyte = qemu_host_page_size - nbyte; |
1082 | 31e31b8a | bellard | do {
|
1083 | 2f619698 | bellard | /* FIXME - what to do if put_user() fails? */
|
1084 | 2f619698 | bellard | put_user_u8(0, elf_bss);
|
1085 | 53a5960a | pbrook | elf_bss++; |
1086 | 31e31b8a | bellard | } while (--nbyte);
|
1087 | 31e31b8a | bellard | } |
1088 | 31e31b8a | bellard | } |
1089 | 31e31b8a | bellard | |
1090 | 53a5960a | pbrook | |
1091 | 992f48a0 | blueswir1 | static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, |
1092 | 992f48a0 | blueswir1 | struct elfhdr * exec,
|
1093 | 992f48a0 | blueswir1 | abi_ulong load_addr, |
1094 | 992f48a0 | blueswir1 | abi_ulong load_bias, |
1095 | 992f48a0 | blueswir1 | abi_ulong interp_load_addr, int ibcs,
|
1096 | 992f48a0 | blueswir1 | struct image_info *info)
|
1097 | 31e31b8a | bellard | { |
1098 | 992f48a0 | blueswir1 | abi_ulong sp; |
1099 | 53a5960a | pbrook | int size;
|
1100 | 992f48a0 | blueswir1 | abi_ulong u_platform; |
1101 | 15338fd7 | bellard | const char *k_platform; |
1102 | 863cf0b7 | j_mayer | const int n = sizeof(elf_addr_t); |
1103 | edf779ff | bellard | |
1104 | 53a5960a | pbrook | sp = p; |
1105 | 53a5960a | pbrook | u_platform = 0;
|
1106 | 15338fd7 | bellard | k_platform = ELF_PLATFORM; |
1107 | 15338fd7 | bellard | if (k_platform) {
|
1108 | 15338fd7 | bellard | size_t len = strlen(k_platform) + 1;
|
1109 | 53a5960a | pbrook | sp -= (len + n - 1) & ~(n - 1); |
1110 | 53a5960a | pbrook | u_platform = sp; |
1111 | 579a97f7 | bellard | /* FIXME - check return value of memcpy_to_target() for failure */
|
1112 | 53a5960a | pbrook | memcpy_to_target(sp, k_platform, len); |
1113 | 15338fd7 | bellard | } |
1114 | 53a5960a | pbrook | /*
|
1115 | 53a5960a | pbrook | * Force 16 byte _final_ alignment here for generality.
|
1116 | 53a5960a | pbrook | */
|
1117 | 992f48a0 | blueswir1 | sp = sp &~ (abi_ulong)15;
|
1118 | 53a5960a | pbrook | size = (DLINFO_ITEMS + 1) * 2; |
1119 | 15338fd7 | bellard | if (k_platform)
|
1120 | 53a5960a | pbrook | size += 2;
|
1121 | f5155289 | bellard | #ifdef DLINFO_ARCH_ITEMS
|
1122 | 53a5960a | pbrook | size += DLINFO_ARCH_ITEMS * 2;
|
1123 | f5155289 | bellard | #endif
|
1124 | 53a5960a | pbrook | size += envc + argc + 2;
|
1125 | 53a5960a | pbrook | size += (!ibcs ? 3 : 1); /* argc itself */ |
1126 | 53a5960a | pbrook | size *= n; |
1127 | 53a5960a | pbrook | if (size & 15) |
1128 | 53a5960a | pbrook | sp -= 16 - (size & 15); |
1129 | 3b46e624 | ths | |
1130 | 863cf0b7 | j_mayer | /* This is correct because Linux defines
|
1131 | 863cf0b7 | j_mayer | * elf_addr_t as Elf32_Off / Elf64_Off
|
1132 | 863cf0b7 | j_mayer | */
|
1133 | 2f619698 | bellard | #define NEW_AUX_ENT(id, val) do { \ |
1134 | 2f619698 | bellard | sp -= n; put_user_ual(val, sp); \ |
1135 | 2f619698 | bellard | sp -= n; put_user_ual(id, sp); \ |
1136 | 53a5960a | pbrook | } while(0) |
1137 | 2f619698 | bellard | |
1138 | 0bccf03d | bellard | NEW_AUX_ENT (AT_NULL, 0);
|
1139 | 0bccf03d | bellard | |
1140 | 0bccf03d | bellard | /* There must be exactly DLINFO_ITEMS entries here. */
|
1141 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff)); |
1142 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); |
1143 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); |
1144 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); |
1145 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr)); |
1146 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
|
1147 | 0bccf03d | bellard | NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); |
1148 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_UID, (abi_ulong) getuid()); |
1149 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid()); |
1150 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); |
1151 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); |
1152 | 992f48a0 | blueswir1 | NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); |
1153 | a07c67df | pbrook | NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); |
1154 | 15338fd7 | bellard | if (k_platform)
|
1155 | 53a5960a | pbrook | NEW_AUX_ENT(AT_PLATFORM, u_platform); |
1156 | f5155289 | bellard | #ifdef ARCH_DLINFO
|
1157 | 5fafdf24 | ths | /*
|
1158 | f5155289 | bellard | * ARCH_DLINFO must come last so platform specific code can enforce
|
1159 | f5155289 | bellard | * special alignment requirements on the AUXV if necessary (eg. PPC).
|
1160 | f5155289 | bellard | */
|
1161 | f5155289 | bellard | ARCH_DLINFO; |
1162 | f5155289 | bellard | #endif
|
1163 | f5155289 | bellard | #undef NEW_AUX_ENT
|
1164 | f5155289 | bellard | |
1165 | edf8e2af | Mika Westerberg | info->saved_auxv = sp; |
1166 | edf8e2af | Mika Westerberg | |
1167 | e5fe0c52 | pbrook | sp = loader_build_argptr(envc, argc, sp, p, !ibcs); |
1168 | 31e31b8a | bellard | return sp;
|
1169 | 31e31b8a | bellard | } |
1170 | 31e31b8a | bellard | |
1171 | 31e31b8a | bellard | |
1172 | 992f48a0 | blueswir1 | static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, |
1173 | 992f48a0 | blueswir1 | int interpreter_fd,
|
1174 | 992f48a0 | blueswir1 | abi_ulong *interp_load_addr) |
1175 | 31e31b8a | bellard | { |
1176 | 31e31b8a | bellard | struct elf_phdr *elf_phdata = NULL; |
1177 | 31e31b8a | bellard | struct elf_phdr *eppnt;
|
1178 | 992f48a0 | blueswir1 | abi_ulong load_addr = 0;
|
1179 | 31e31b8a | bellard | int load_addr_set = 0; |
1180 | 31e31b8a | bellard | int retval;
|
1181 | 992f48a0 | blueswir1 | abi_ulong last_bss, elf_bss; |
1182 | 992f48a0 | blueswir1 | abi_ulong error; |
1183 | 31e31b8a | bellard | int i;
|
1184 | 5fafdf24 | ths | |
1185 | 31e31b8a | bellard | elf_bss = 0;
|
1186 | 31e31b8a | bellard | last_bss = 0;
|
1187 | 31e31b8a | bellard | error = 0;
|
1188 | 31e31b8a | bellard | |
1189 | 644c433c | bellard | #ifdef BSWAP_NEEDED
|
1190 | 644c433c | bellard | bswap_ehdr(interp_elf_ex); |
1191 | 644c433c | bellard | #endif
|
1192 | 31e31b8a | bellard | /* First of all, some simple consistency checks */
|
1193 | 5fafdf24 | ths | if ((interp_elf_ex->e_type != ET_EXEC &&
|
1194 | 5fafdf24 | ths | interp_elf_ex->e_type != ET_DYN) || |
1195 | 31e31b8a | bellard | !elf_check_arch(interp_elf_ex->e_machine)) { |
1196 | 992f48a0 | blueswir1 | return ~((abi_ulong)0UL); |
1197 | 31e31b8a | bellard | } |
1198 | 5fafdf24 | ths | |
1199 | 644c433c | bellard | |
1200 | 31e31b8a | bellard | /* Now read in all of the header information */
|
1201 | 5fafdf24 | ths | |
1202 | 54936004 | bellard | if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) |
1203 | 992f48a0 | blueswir1 | return ~(abi_ulong)0UL; |
1204 | 5fafdf24 | ths | |
1205 | 5fafdf24 | ths | elf_phdata = (struct elf_phdr *)
|
1206 | 31e31b8a | bellard | malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); |
1207 | 31e31b8a | bellard | |
1208 | 31e31b8a | bellard | if (!elf_phdata)
|
1209 | 992f48a0 | blueswir1 | return ~((abi_ulong)0UL); |
1210 | 5fafdf24 | ths | |
1211 | 31e31b8a | bellard | /*
|
1212 | 31e31b8a | bellard | * If the size of this structure has changed, then punt, since
|
1213 | 31e31b8a | bellard | * we will be doing the wrong thing.
|
1214 | 31e31b8a | bellard | */
|
1215 | 09bfb054 | bellard | if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { |
1216 | 31e31b8a | bellard | free(elf_phdata); |
1217 | 992f48a0 | blueswir1 | return ~((abi_ulong)0UL); |
1218 | 09bfb054 | bellard | } |
1219 | 31e31b8a | bellard | |
1220 | 31e31b8a | bellard | retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); |
1221 | 31e31b8a | bellard | if(retval >= 0) { |
1222 | 31e31b8a | bellard | retval = read(interpreter_fd, |
1223 | 31e31b8a | bellard | (char *) elf_phdata,
|
1224 | 31e31b8a | bellard | sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); |
1225 | 31e31b8a | bellard | } |
1226 | 31e31b8a | bellard | if (retval < 0) { |
1227 | 31e31b8a | bellard | perror("load_elf_interp");
|
1228 | 31e31b8a | bellard | exit(-1);
|
1229 | 31e31b8a | bellard | free (elf_phdata); |
1230 | 31e31b8a | bellard | return retval;
|
1231 | 31e31b8a | bellard | } |
1232 | 31e31b8a | bellard | #ifdef BSWAP_NEEDED
|
1233 | 31e31b8a | bellard | eppnt = elf_phdata; |
1234 | 31e31b8a | bellard | for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { |
1235 | 31e31b8a | bellard | bswap_phdr(eppnt); |
1236 | 31e31b8a | bellard | } |
1237 | 31e31b8a | bellard | #endif
|
1238 | 09bfb054 | bellard | |
1239 | 09bfb054 | bellard | if (interp_elf_ex->e_type == ET_DYN) {
|
1240 | e91c8a77 | ths | /* in order to avoid hardcoding the interpreter load
|
1241 | 09bfb054 | bellard | address in qemu, we allocate a big enough memory zone */
|
1242 | 54936004 | bellard | error = target_mmap(0, INTERP_MAP_SIZE,
|
1243 | 5fafdf24 | ths | PROT_NONE, MAP_PRIVATE | MAP_ANON, |
1244 | 54936004 | bellard | -1, 0); |
1245 | 09bfb054 | bellard | if (error == -1) { |
1246 | 09bfb054 | bellard | perror("mmap");
|
1247 | 09bfb054 | bellard | exit(-1);
|
1248 | 09bfb054 | bellard | } |
1249 | 09bfb054 | bellard | load_addr = error; |
1250 | 09bfb054 | bellard | load_addr_set = 1;
|
1251 | 09bfb054 | bellard | } |
1252 | 09bfb054 | bellard | |
1253 | 31e31b8a | bellard | eppnt = elf_phdata; |
1254 | 31e31b8a | bellard | for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) |
1255 | 31e31b8a | bellard | if (eppnt->p_type == PT_LOAD) {
|
1256 | 31e31b8a | bellard | int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
|
1257 | 31e31b8a | bellard | int elf_prot = 0; |
1258 | 992f48a0 | blueswir1 | abi_ulong vaddr = 0;
|
1259 | 992f48a0 | blueswir1 | abi_ulong k; |
1260 | 31e31b8a | bellard | |
1261 | 31e31b8a | bellard | if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
|
1262 | 31e31b8a | bellard | if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
|
1263 | 31e31b8a | bellard | if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
|
1264 | 31e31b8a | bellard | if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
|
1265 | 31e31b8a | bellard | elf_type |= MAP_FIXED; |
1266 | 31e31b8a | bellard | vaddr = eppnt->p_vaddr; |
1267 | 31e31b8a | bellard | } |
1268 | 54936004 | bellard | error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), |
1269 | 54936004 | bellard | eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), |
1270 | 31e31b8a | bellard | elf_prot, |
1271 | 31e31b8a | bellard | elf_type, |
1272 | 31e31b8a | bellard | interpreter_fd, |
1273 | 54936004 | bellard | eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); |
1274 | 3b46e624 | ths | |
1275 | e89f07d3 | pbrook | if (error == -1) { |
1276 | 31e31b8a | bellard | /* Real error */
|
1277 | 31e31b8a | bellard | close(interpreter_fd); |
1278 | 31e31b8a | bellard | free(elf_phdata); |
1279 | 992f48a0 | blueswir1 | return ~((abi_ulong)0UL); |
1280 | 31e31b8a | bellard | } |
1281 | 31e31b8a | bellard | |
1282 | 31e31b8a | bellard | if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
|
1283 | 31e31b8a | bellard | load_addr = error; |
1284 | 31e31b8a | bellard | load_addr_set = 1;
|
1285 | 31e31b8a | bellard | } |
1286 | 31e31b8a | bellard | |
1287 | 31e31b8a | bellard | /*
|
1288 | 31e31b8a | bellard | * Find the end of the file mapping for this phdr, and keep
|
1289 | 31e31b8a | bellard | * track of the largest address we see for this.
|
1290 | 31e31b8a | bellard | */
|
1291 | 31e31b8a | bellard | k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; |
1292 | 31e31b8a | bellard | if (k > elf_bss) elf_bss = k;
|
1293 | 31e31b8a | bellard | |
1294 | 31e31b8a | bellard | /*
|
1295 | 31e31b8a | bellard | * Do the same thing for the memory mapping - between
|
1296 | 31e31b8a | bellard | * elf_bss and last_bss is the bss section.
|
1297 | 31e31b8a | bellard | */
|
1298 | 31e31b8a | bellard | k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; |
1299 | 31e31b8a | bellard | if (k > last_bss) last_bss = k;
|
1300 | 31e31b8a | bellard | } |
1301 | 5fafdf24 | ths | |
1302 | 31e31b8a | bellard | /* Now use mmap to map the library into memory. */
|
1303 | 31e31b8a | bellard | |
1304 | 31e31b8a | bellard | close(interpreter_fd); |
1305 | 31e31b8a | bellard | |
1306 | 31e31b8a | bellard | /*
|
1307 | 31e31b8a | bellard | * Now fill out the bss section. First pad the last page up
|
1308 | 31e31b8a | bellard | * to the page boundary, and then perform a mmap to make sure
|
1309 | 31e31b8a | bellard | * that there are zeromapped pages up to and including the last
|
1310 | 31e31b8a | bellard | * bss page.
|
1311 | 31e31b8a | bellard | */
|
1312 | 768a4a36 | ths | padzero(elf_bss, last_bss); |
1313 | 83fb7adf | bellard | elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ |
1314 | 31e31b8a | bellard | |
1315 | 31e31b8a | bellard | /* Map the last of the bss segment */
|
1316 | 31e31b8a | bellard | if (last_bss > elf_bss) {
|
1317 | 54936004 | bellard | target_mmap(elf_bss, last_bss-elf_bss, |
1318 | 54936004 | bellard | PROT_READ|PROT_WRITE|PROT_EXEC, |
1319 | 54936004 | bellard | MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
1320 | 31e31b8a | bellard | } |
1321 | 31e31b8a | bellard | free(elf_phdata); |
1322 | 31e31b8a | bellard | |
1323 | 31e31b8a | bellard | *interp_load_addr = load_addr; |
1324 | 992f48a0 | blueswir1 | return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
|
1325 | 31e31b8a | bellard | } |
1326 | 31e31b8a | bellard | |
1327 | 49918a75 | pbrook | static int symfind(const void *s0, const void *s1) |
1328 | 49918a75 | pbrook | { |
1329 | 49918a75 | pbrook | struct elf_sym *key = (struct elf_sym *)s0; |
1330 | 49918a75 | pbrook | struct elf_sym *sym = (struct elf_sym *)s1; |
1331 | 49918a75 | pbrook | int result = 0; |
1332 | 49918a75 | pbrook | if (key->st_value < sym->st_value) {
|
1333 | 49918a75 | pbrook | result = -1;
|
1334 | ec822001 | Laurent Desnogues | } else if (key->st_value >= sym->st_value + sym->st_size) { |
1335 | 49918a75 | pbrook | result = 1;
|
1336 | 49918a75 | pbrook | } |
1337 | 49918a75 | pbrook | return result;
|
1338 | 49918a75 | pbrook | } |
1339 | 49918a75 | pbrook | |
1340 | 49918a75 | pbrook | static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr) |
1341 | 49918a75 | pbrook | { |
1342 | 49918a75 | pbrook | #if ELF_CLASS == ELFCLASS32
|
1343 | 49918a75 | pbrook | struct elf_sym *syms = s->disas_symtab.elf32;
|
1344 | 49918a75 | pbrook | #else
|
1345 | 49918a75 | pbrook | struct elf_sym *syms = s->disas_symtab.elf64;
|
1346 | 49918a75 | pbrook | #endif
|
1347 | 49918a75 | pbrook | |
1348 | 49918a75 | pbrook | // binary search
|
1349 | 49918a75 | pbrook | struct elf_sym key;
|
1350 | 49918a75 | pbrook | struct elf_sym *sym;
|
1351 | 49918a75 | pbrook | |
1352 | 49918a75 | pbrook | key.st_value = orig_addr; |
1353 | 49918a75 | pbrook | |
1354 | 49918a75 | pbrook | sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), symfind);
|
1355 | 7cba04f6 | Blue Swirl | if (sym != NULL) { |
1356 | 49918a75 | pbrook | return s->disas_strtab + sym->st_name;
|
1357 | 49918a75 | pbrook | } |
1358 | 49918a75 | pbrook | |
1359 | 49918a75 | pbrook | return ""; |
1360 | 49918a75 | pbrook | } |
1361 | 49918a75 | pbrook | |
1362 | 49918a75 | pbrook | /* FIXME: This should use elf_ops.h */
|
1363 | 49918a75 | pbrook | static int symcmp(const void *s0, const void *s1) |
1364 | 49918a75 | pbrook | { |
1365 | 49918a75 | pbrook | struct elf_sym *sym0 = (struct elf_sym *)s0; |
1366 | 49918a75 | pbrook | struct elf_sym *sym1 = (struct elf_sym *)s1; |
1367 | 49918a75 | pbrook | return (sym0->st_value < sym1->st_value)
|
1368 | 49918a75 | pbrook | ? -1
|
1369 | 49918a75 | pbrook | : ((sym0->st_value > sym1->st_value) ? 1 : 0); |
1370 | 49918a75 | pbrook | } |
1371 | 49918a75 | pbrook | |
1372 | 689f936f | bellard | /* Best attempt to load symbols from this ELF object. */
|
1373 | 689f936f | bellard | static void load_symbols(struct elfhdr *hdr, int fd) |
1374 | 689f936f | bellard | { |
1375 | 49918a75 | pbrook | unsigned int i, nsyms; |
1376 | 689f936f | bellard | struct elf_shdr sechdr, symtab, strtab;
|
1377 | 689f936f | bellard | char *strings;
|
1378 | e80cfcfc | bellard | struct syminfo *s;
|
1379 | 49918a75 | pbrook | struct elf_sym *syms;
|
1380 | 689f936f | bellard | |
1381 | 689f936f | bellard | lseek(fd, hdr->e_shoff, SEEK_SET); |
1382 | 689f936f | bellard | for (i = 0; i < hdr->e_shnum; i++) { |
1383 | 49918a75 | pbrook | if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) |
1384 | 49918a75 | pbrook | return;
|
1385 | 689f936f | bellard | #ifdef BSWAP_NEEDED
|
1386 | 49918a75 | pbrook | bswap_shdr(&sechdr); |
1387 | 689f936f | bellard | #endif
|
1388 | 49918a75 | pbrook | if (sechdr.sh_type == SHT_SYMTAB) {
|
1389 | 49918a75 | pbrook | symtab = sechdr; |
1390 | 49918a75 | pbrook | lseek(fd, hdr->e_shoff |
1391 | 49918a75 | pbrook | + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
|
1392 | 49918a75 | pbrook | if (read(fd, &strtab, sizeof(strtab)) |
1393 | 49918a75 | pbrook | != sizeof(strtab))
|
1394 | 49918a75 | pbrook | return;
|
1395 | 689f936f | bellard | #ifdef BSWAP_NEEDED
|
1396 | 49918a75 | pbrook | bswap_shdr(&strtab); |
1397 | 689f936f | bellard | #endif
|
1398 | 49918a75 | pbrook | goto found;
|
1399 | 49918a75 | pbrook | } |
1400 | 689f936f | bellard | } |
1401 | 689f936f | bellard | return; /* Shouldn't happen... */ |
1402 | 689f936f | bellard | |
1403 | 689f936f | bellard | found:
|
1404 | 689f936f | bellard | /* Now know where the strtab and symtab are. Snarf them. */
|
1405 | e80cfcfc | bellard | s = malloc(sizeof(*s));
|
1406 | 49918a75 | pbrook | syms = malloc(symtab.sh_size); |
1407 | 49918a75 | pbrook | if (!syms)
|
1408 | 49918a75 | pbrook | return;
|
1409 | e80cfcfc | bellard | s->disas_strtab = strings = malloc(strtab.sh_size); |
1410 | 49918a75 | pbrook | if (!s->disas_strtab)
|
1411 | 49918a75 | pbrook | return;
|
1412 | 5fafdf24 | ths | |
1413 | 689f936f | bellard | lseek(fd, symtab.sh_offset, SEEK_SET); |
1414 | 49918a75 | pbrook | if (read(fd, syms, symtab.sh_size) != symtab.sh_size)
|
1415 | 49918a75 | pbrook | return;
|
1416 | 49918a75 | pbrook | |
1417 | 49918a75 | pbrook | nsyms = symtab.sh_size / sizeof(struct elf_sym); |
1418 | 31e31b8a | bellard | |
1419 | 49918a75 | pbrook | i = 0;
|
1420 | 49918a75 | pbrook | while (i < nsyms) {
|
1421 | 689f936f | bellard | #ifdef BSWAP_NEEDED
|
1422 | 49918a75 | pbrook | bswap_sym(syms + i); |
1423 | 689f936f | bellard | #endif
|
1424 | 49918a75 | pbrook | // Throw away entries which we do not need.
|
1425 | 49918a75 | pbrook | if (syms[i].st_shndx == SHN_UNDEF ||
|
1426 | 49918a75 | pbrook | syms[i].st_shndx >= SHN_LORESERVE || |
1427 | 49918a75 | pbrook | ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { |
1428 | 49918a75 | pbrook | nsyms--; |
1429 | 49918a75 | pbrook | if (i < nsyms) {
|
1430 | 49918a75 | pbrook | syms[i] = syms[nsyms]; |
1431 | 49918a75 | pbrook | } |
1432 | 49918a75 | pbrook | continue;
|
1433 | 49918a75 | pbrook | } |
1434 | 49918a75 | pbrook | #if defined(TARGET_ARM) || defined (TARGET_MIPS)
|
1435 | 49918a75 | pbrook | /* The bottom address bit marks a Thumb or MIPS16 symbol. */
|
1436 | 49918a75 | pbrook | syms[i].st_value &= ~(target_ulong)1;
|
1437 | 0774bed1 | blueswir1 | #endif
|
1438 | 49918a75 | pbrook | i++; |
1439 | 0774bed1 | blueswir1 | } |
1440 | 49918a75 | pbrook | syms = realloc(syms, nsyms * sizeof(*syms));
|
1441 | 49918a75 | pbrook | |
1442 | 49918a75 | pbrook | qsort(syms, nsyms, sizeof(*syms), symcmp);
|
1443 | 689f936f | bellard | |
1444 | 689f936f | bellard | lseek(fd, strtab.sh_offset, SEEK_SET); |
1445 | 689f936f | bellard | if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
|
1446 | 49918a75 | pbrook | return;
|
1447 | 49918a75 | pbrook | s->disas_num_syms = nsyms; |
1448 | 49918a75 | pbrook | #if ELF_CLASS == ELFCLASS32
|
1449 | 49918a75 | pbrook | s->disas_symtab.elf32 = syms; |
1450 | 9f9f0309 | Paul Brook | s->lookup_symbol = lookup_symbolxx; |
1451 | 49918a75 | pbrook | #else
|
1452 | 49918a75 | pbrook | s->disas_symtab.elf64 = syms; |
1453 | 9f9f0309 | Paul Brook | s->lookup_symbol = lookup_symbolxx; |
1454 | 49918a75 | pbrook | #endif
|
1455 | e80cfcfc | bellard | s->next = syminfos; |
1456 | e80cfcfc | bellard | syminfos = s; |
1457 | 689f936f | bellard | } |
1458 | 31e31b8a | bellard | |
1459 | e5fe0c52 | pbrook | int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, |
1460 | e5fe0c52 | pbrook | struct image_info * info)
|
1461 | 31e31b8a | bellard | { |
1462 | 31e31b8a | bellard | struct elfhdr elf_ex;
|
1463 | 31e31b8a | bellard | struct elfhdr interp_elf_ex;
|
1464 | 31e31b8a | bellard | struct exec interp_ex;
|
1465 | 31e31b8a | bellard | int interpreter_fd = -1; /* avoid warning */ |
1466 | 992f48a0 | blueswir1 | abi_ulong load_addr, load_bias; |
1467 | 31e31b8a | bellard | int load_addr_set = 0; |
1468 | 31e31b8a | bellard | unsigned int interpreter_type = INTERPRETER_NONE; |
1469 | 31e31b8a | bellard | unsigned char ibcs2_interpreter; |
1470 | 31e31b8a | bellard | int i;
|
1471 | 992f48a0 | blueswir1 | abi_ulong mapped_addr; |
1472 | 31e31b8a | bellard | struct elf_phdr * elf_ppnt;
|
1473 | 31e31b8a | bellard | struct elf_phdr *elf_phdata;
|
1474 | 992f48a0 | blueswir1 | abi_ulong elf_bss, k, elf_brk; |
1475 | 31e31b8a | bellard | int retval;
|
1476 | 31e31b8a | bellard | char * elf_interpreter;
|
1477 | 992f48a0 | blueswir1 | abi_ulong elf_entry, interp_load_addr = 0;
|
1478 | 31e31b8a | bellard | int status;
|
1479 | 992f48a0 | blueswir1 | abi_ulong start_code, end_code, start_data, end_data; |
1480 | 992f48a0 | blueswir1 | abi_ulong reloc_func_desc = 0;
|
1481 | 992f48a0 | blueswir1 | abi_ulong elf_stack; |
1482 | 31e31b8a | bellard | char passed_fileno[6]; |
1483 | 31e31b8a | bellard | |
1484 | 31e31b8a | bellard | ibcs2_interpreter = 0;
|
1485 | 31e31b8a | bellard | status = 0;
|
1486 | 31e31b8a | bellard | load_addr = 0;
|
1487 | 09bfb054 | bellard | load_bias = 0;
|
1488 | 31e31b8a | bellard | elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ |
1489 | 31e31b8a | bellard | #ifdef BSWAP_NEEDED
|
1490 | 31e31b8a | bellard | bswap_ehdr(&elf_ex); |
1491 | 31e31b8a | bellard | #endif
|
1492 | 31e31b8a | bellard | |
1493 | 31e31b8a | bellard | /* First of all, some simple consistency checks */
|
1494 | 31e31b8a | bellard | if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
|
1495 | 31e31b8a | bellard | (! elf_check_arch(elf_ex.e_machine))) { |
1496 | 31e31b8a | bellard | return -ENOEXEC;
|
1497 | 31e31b8a | bellard | } |
1498 | 31e31b8a | bellard | |
1499 | e5fe0c52 | pbrook | bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
|
1500 | e5fe0c52 | pbrook | bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); |
1501 | e5fe0c52 | pbrook | bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); |
1502 | e5fe0c52 | pbrook | if (!bprm->p) {
|
1503 | e5fe0c52 | pbrook | retval = -E2BIG; |
1504 | e5fe0c52 | pbrook | } |
1505 | e5fe0c52 | pbrook | |
1506 | 31e31b8a | bellard | /* Now read in all of the header information */
|
1507 | 31e31b8a | bellard | elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
|
1508 | 31e31b8a | bellard | if (elf_phdata == NULL) { |
1509 | 31e31b8a | bellard | return -ENOMEM;
|
1510 | 31e31b8a | bellard | } |
1511 | 31e31b8a | bellard | |
1512 | 31e31b8a | bellard | retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); |
1513 | 31e31b8a | bellard | if(retval > 0) { |
1514 | 5fafdf24 | ths | retval = read(bprm->fd, (char *) elf_phdata,
|
1515 | 31e31b8a | bellard | elf_ex.e_phentsize * elf_ex.e_phnum); |
1516 | 31e31b8a | bellard | } |
1517 | 31e31b8a | bellard | |
1518 | 31e31b8a | bellard | if (retval < 0) { |
1519 | 31e31b8a | bellard | perror("load_elf_binary");
|
1520 | 31e31b8a | bellard | exit(-1);
|
1521 | 31e31b8a | bellard | free (elf_phdata); |
1522 | 31e31b8a | bellard | return -errno;
|
1523 | 31e31b8a | bellard | } |
1524 | 31e31b8a | bellard | |
1525 | b17780d5 | bellard | #ifdef BSWAP_NEEDED
|
1526 | b17780d5 | bellard | elf_ppnt = elf_phdata; |
1527 | b17780d5 | bellard | for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { |
1528 | b17780d5 | bellard | bswap_phdr(elf_ppnt); |
1529 | b17780d5 | bellard | } |
1530 | b17780d5 | bellard | #endif
|
1531 | 31e31b8a | bellard | elf_ppnt = elf_phdata; |
1532 | 31e31b8a | bellard | |
1533 | 31e31b8a | bellard | elf_bss = 0;
|
1534 | 31e31b8a | bellard | elf_brk = 0;
|
1535 | 31e31b8a | bellard | |
1536 | 31e31b8a | bellard | |
1537 | 992f48a0 | blueswir1 | elf_stack = ~((abi_ulong)0UL);
|
1538 | 31e31b8a | bellard | elf_interpreter = NULL;
|
1539 | 992f48a0 | blueswir1 | start_code = ~((abi_ulong)0UL);
|
1540 | 31e31b8a | bellard | end_code = 0;
|
1541 | 863cf0b7 | j_mayer | start_data = 0;
|
1542 | 31e31b8a | bellard | end_data = 0;
|
1543 | 98448f58 | blueswir1 | interp_ex.a_info = 0;
|
1544 | 31e31b8a | bellard | |
1545 | 31e31b8a | bellard | for(i=0;i < elf_ex.e_phnum; i++) { |
1546 | 31e31b8a | bellard | if (elf_ppnt->p_type == PT_INTERP) {
|
1547 | 31e31b8a | bellard | if ( elf_interpreter != NULL ) |
1548 | 31e31b8a | bellard | { |
1549 | 31e31b8a | bellard | free (elf_phdata); |
1550 | 31e31b8a | bellard | free(elf_interpreter); |
1551 | 31e31b8a | bellard | close(bprm->fd); |
1552 | 31e31b8a | bellard | return -EINVAL;
|
1553 | 31e31b8a | bellard | } |
1554 | 31e31b8a | bellard | |
1555 | 31e31b8a | bellard | /* This is the program interpreter used for
|
1556 | 31e31b8a | bellard | * shared libraries - for now assume that this
|
1557 | 31e31b8a | bellard | * is an a.out format binary
|
1558 | 31e31b8a | bellard | */
|
1559 | 31e31b8a | bellard | |
1560 | 32ce6337 | bellard | elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
|
1561 | 31e31b8a | bellard | |
1562 | 31e31b8a | bellard | if (elf_interpreter == NULL) { |
1563 | 31e31b8a | bellard | free (elf_phdata); |
1564 | 31e31b8a | bellard | close(bprm->fd); |
1565 | 31e31b8a | bellard | return -ENOMEM;
|
1566 | 31e31b8a | bellard | } |
1567 | 31e31b8a | bellard | |
1568 | 31e31b8a | bellard | retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); |
1569 | 31e31b8a | bellard | if(retval >= 0) { |
1570 | 32ce6337 | bellard | retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); |
1571 | 31e31b8a | bellard | } |
1572 | 31e31b8a | bellard | if(retval < 0) { |
1573 | 31e31b8a | bellard | perror("load_elf_binary2");
|
1574 | 31e31b8a | bellard | exit(-1);
|
1575 | 5fafdf24 | ths | } |
1576 | 31e31b8a | bellard | |
1577 | 31e31b8a | bellard | /* If the program interpreter is one of these two,
|
1578 | 31e31b8a | bellard | then assume an iBCS2 image. Otherwise assume
|
1579 | 31e31b8a | bellard | a native linux image. */
|
1580 | 31e31b8a | bellard | |
1581 | 31e31b8a | bellard | /* JRP - Need to add X86 lib dir stuff here... */
|
1582 | 31e31b8a | bellard | |
1583 | 31e31b8a | bellard | if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || |
1584 | 31e31b8a | bellard | strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { |
1585 | 31e31b8a | bellard | ibcs2_interpreter = 1;
|
1586 | 31e31b8a | bellard | } |
1587 | 31e31b8a | bellard | |
1588 | 31e31b8a | bellard | #if 0
|
1589 | 3bc0bdca | Paul Bolle | printf("Using ELF interpreter %s\n", path(elf_interpreter));
|
1590 | 31e31b8a | bellard | #endif
|
1591 | 31e31b8a | bellard | if (retval >= 0) { |
1592 | 32ce6337 | bellard | retval = open(path(elf_interpreter), O_RDONLY); |
1593 | 31e31b8a | bellard | if(retval >= 0) { |
1594 | 31e31b8a | bellard | interpreter_fd = retval; |
1595 | 31e31b8a | bellard | } |
1596 | 31e31b8a | bellard | else {
|
1597 | 31e31b8a | bellard | perror(elf_interpreter); |
1598 | 31e31b8a | bellard | exit(-1);
|
1599 | 31e31b8a | bellard | /* retval = -errno; */
|
1600 | 31e31b8a | bellard | } |
1601 | 31e31b8a | bellard | } |
1602 | 31e31b8a | bellard | |
1603 | 31e31b8a | bellard | if (retval >= 0) { |
1604 | 31e31b8a | bellard | retval = lseek(interpreter_fd, 0, SEEK_SET);
|
1605 | 31e31b8a | bellard | if(retval >= 0) { |
1606 | 31e31b8a | bellard | retval = read(interpreter_fd,bprm->buf,128);
|
1607 | 31e31b8a | bellard | } |
1608 | 31e31b8a | bellard | } |
1609 | 31e31b8a | bellard | if (retval >= 0) { |
1610 | 31e31b8a | bellard | interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ |
1611 | 6ece4df6 | Michael S. Tsirkin | interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */ |
1612 | 31e31b8a | bellard | } |
1613 | 31e31b8a | bellard | if (retval < 0) { |
1614 | 31e31b8a | bellard | perror("load_elf_binary3");
|
1615 | 31e31b8a | bellard | exit(-1);
|
1616 | 31e31b8a | bellard | free (elf_phdata); |
1617 | 31e31b8a | bellard | free(elf_interpreter); |
1618 | 31e31b8a | bellard | close(bprm->fd); |
1619 | 31e31b8a | bellard | return retval;
|
1620 | 31e31b8a | bellard | } |
1621 | 31e31b8a | bellard | } |
1622 | 31e31b8a | bellard | elf_ppnt++; |
1623 | 31e31b8a | bellard | } |
1624 | 31e31b8a | bellard | |
1625 | 31e31b8a | bellard | /* Some simple consistency checks for the interpreter */
|
1626 | 31e31b8a | bellard | if (elf_interpreter){
|
1627 | 31e31b8a | bellard | interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; |
1628 | 31e31b8a | bellard | |
1629 | 31e31b8a | bellard | /* Now figure out which format our binary is */
|
1630 | 31e31b8a | bellard | if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
|
1631 | 31e31b8a | bellard | (N_MAGIC(interp_ex) != QMAGIC)) { |
1632 | 31e31b8a | bellard | interpreter_type = INTERPRETER_ELF; |
1633 | 31e31b8a | bellard | } |
1634 | 31e31b8a | bellard | |
1635 | 31e31b8a | bellard | if (interp_elf_ex.e_ident[0] != 0x7f || |
1636 | b55266b5 | blueswir1 | strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) { |
1637 | 31e31b8a | bellard | interpreter_type &= ~INTERPRETER_ELF; |
1638 | 31e31b8a | bellard | } |
1639 | 31e31b8a | bellard | |
1640 | 31e31b8a | bellard | if (!interpreter_type) {
|
1641 | 31e31b8a | bellard | free(elf_interpreter); |
1642 | 31e31b8a | bellard | free(elf_phdata); |
1643 | 31e31b8a | bellard | close(bprm->fd); |
1644 | 31e31b8a | bellard | return -ELIBBAD;
|
1645 | 31e31b8a | bellard | } |
1646 | 31e31b8a | bellard | } |
1647 | 31e31b8a | bellard | |
1648 | 31e31b8a | bellard | /* OK, we are done with that, now set up the arg stuff,
|
1649 | 31e31b8a | bellard | and then start this sucker up */
|
1650 | 31e31b8a | bellard | |
1651 | e5fe0c52 | pbrook | { |
1652 | 31e31b8a | bellard | char * passed_p;
|
1653 | 31e31b8a | bellard | |
1654 | 31e31b8a | bellard | if (interpreter_type == INTERPRETER_AOUT) {
|
1655 | eba2af63 | bellard | snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); |
1656 | 31e31b8a | bellard | passed_p = passed_fileno; |
1657 | 31e31b8a | bellard | |
1658 | 31e31b8a | bellard | if (elf_interpreter) {
|
1659 | e5fe0c52 | pbrook | bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
|
1660 | 31e31b8a | bellard | bprm->argc++; |
1661 | 31e31b8a | bellard | } |
1662 | 31e31b8a | bellard | } |
1663 | 31e31b8a | bellard | if (!bprm->p) {
|
1664 | 31e31b8a | bellard | if (elf_interpreter) {
|
1665 | 31e31b8a | bellard | free(elf_interpreter); |
1666 | 31e31b8a | bellard | } |
1667 | 31e31b8a | bellard | free (elf_phdata); |
1668 | 31e31b8a | bellard | close(bprm->fd); |
1669 | 31e31b8a | bellard | return -E2BIG;
|
1670 | 31e31b8a | bellard | } |
1671 | 31e31b8a | bellard | } |
1672 | 31e31b8a | bellard | |
1673 | 31e31b8a | bellard | /* OK, This is the point of no return */
|
1674 | 31e31b8a | bellard | info->end_data = 0;
|
1675 | 31e31b8a | bellard | info->end_code = 0;
|
1676 | 992f48a0 | blueswir1 | info->start_mmap = (abi_ulong)ELF_START_MMAP; |
1677 | 31e31b8a | bellard | info->mmap = 0;
|
1678 | 992f48a0 | blueswir1 | elf_entry = (abi_ulong) elf_ex.e_entry; |
1679 | 31e31b8a | bellard | |
1680 | 379f6698 | Paul Brook | #if defined(CONFIG_USE_GUEST_BASE)
|
1681 | 379f6698 | Paul Brook | /*
|
1682 | 379f6698 | Paul Brook | * In case where user has not explicitly set the guest_base, we
|
1683 | 379f6698 | Paul Brook | * probe here that should we set it automatically.
|
1684 | 379f6698 | Paul Brook | */
|
1685 | 68a1c816 | Paul Brook | if (!(have_guest_base || reserved_va)) {
|
1686 | 379f6698 | Paul Brook | /*
|
1687 | c581deda | Paul Brook | * Go through ELF program header table and find the address
|
1688 | c581deda | Paul Brook | * range used by loadable segments. Check that this is available on
|
1689 | c581deda | Paul Brook | * the host, and if not find a suitable value for guest_base. */
|
1690 | c581deda | Paul Brook | abi_ulong app_start = ~0;
|
1691 | c581deda | Paul Brook | abi_ulong app_end = 0;
|
1692 | c581deda | Paul Brook | abi_ulong addr; |
1693 | c581deda | Paul Brook | unsigned long host_start; |
1694 | c581deda | Paul Brook | unsigned long real_start; |
1695 | c581deda | Paul Brook | unsigned long host_size; |
1696 | 379f6698 | Paul Brook | for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; |
1697 | 379f6698 | Paul Brook | i++, elf_ppnt++) { |
1698 | 379f6698 | Paul Brook | if (elf_ppnt->p_type != PT_LOAD)
|
1699 | 379f6698 | Paul Brook | continue;
|
1700 | c581deda | Paul Brook | addr = elf_ppnt->p_vaddr; |
1701 | c581deda | Paul Brook | if (addr < app_start) {
|
1702 | c581deda | Paul Brook | app_start = addr; |
1703 | c581deda | Paul Brook | } |
1704 | c581deda | Paul Brook | addr += elf_ppnt->p_memsz; |
1705 | c581deda | Paul Brook | if (addr > app_end) {
|
1706 | c581deda | Paul Brook | app_end = addr; |
1707 | c581deda | Paul Brook | } |
1708 | c581deda | Paul Brook | } |
1709 | c581deda | Paul Brook | |
1710 | c581deda | Paul Brook | /* If we don't have any loadable segments then something
|
1711 | c581deda | Paul Brook | is very wrong. */
|
1712 | c581deda | Paul Brook | assert(app_start < app_end); |
1713 | c581deda | Paul Brook | |
1714 | c581deda | Paul Brook | /* Round addresses to page boundaries. */
|
1715 | c581deda | Paul Brook | app_start = app_start & qemu_host_page_mask; |
1716 | c581deda | Paul Brook | app_end = HOST_PAGE_ALIGN(app_end); |
1717 | c581deda | Paul Brook | if (app_start < mmap_min_addr) {
|
1718 | c581deda | Paul Brook | host_start = HOST_PAGE_ALIGN(mmap_min_addr); |
1719 | c581deda | Paul Brook | } else {
|
1720 | c581deda | Paul Brook | host_start = app_start; |
1721 | c581deda | Paul Brook | if (host_start != app_start) {
|
1722 | c581deda | Paul Brook | fprintf(stderr, "qemu: Address overflow loading ELF binary\n");
|
1723 | c581deda | Paul Brook | abort(); |
1724 | c581deda | Paul Brook | } |
1725 | c581deda | Paul Brook | } |
1726 | c581deda | Paul Brook | host_size = app_end - app_start; |
1727 | c581deda | Paul Brook | while (1) { |
1728 | c581deda | Paul Brook | /* Do not use mmap_find_vma here because that is limited to the
|
1729 | c581deda | Paul Brook | guest address space. We are going to make the
|
1730 | c581deda | Paul Brook | guest address space fit whatever we're given. */
|
1731 | c581deda | Paul Brook | real_start = (unsigned long)mmap((void *)host_start, host_size, |
1732 | c581deda | Paul Brook | PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); |
1733 | c581deda | Paul Brook | if (real_start == (unsigned long)-1) { |
1734 | c581deda | Paul Brook | fprintf(stderr, "qemu: Virtual memory exausted\n");
|
1735 | c581deda | Paul Brook | abort(); |
1736 | c581deda | Paul Brook | } |
1737 | c581deda | Paul Brook | if (real_start == host_start) {
|
1738 | 379f6698 | Paul Brook | break;
|
1739 | 379f6698 | Paul Brook | } |
1740 | c581deda | Paul Brook | /* That address didn't work. Unmap and try a different one.
|
1741 | c581deda | Paul Brook | The address the host picked because is typically
|
1742 | c581deda | Paul Brook | right at the top of the host address space and leaves the
|
1743 | c581deda | Paul Brook | guest with no usable address space. Resort to a linear search.
|
1744 | c581deda | Paul Brook | We already compensated for mmap_min_addr, so this should not
|
1745 | c581deda | Paul Brook | happen often. Probably means we got unlucky and host address
|
1746 | c581deda | Paul Brook | space randomization put a shared library somewhere
|
1747 | c581deda | Paul Brook | inconvenient. */
|
1748 | c581deda | Paul Brook | munmap((void *)real_start, host_size);
|
1749 | c581deda | Paul Brook | host_start += qemu_host_page_size; |
1750 | c581deda | Paul Brook | if (host_start == app_start) {
|
1751 | c581deda | Paul Brook | /* Theoretically possible if host doesn't have any
|
1752 | c581deda | Paul Brook | suitably aligned areas. Normally the first mmap will
|
1753 | c581deda | Paul Brook | fail. */
|
1754 | c581deda | Paul Brook | fprintf(stderr, "qemu: Unable to find space for application\n");
|
1755 | c581deda | Paul Brook | abort(); |
1756 | c581deda | Paul Brook | } |
1757 | 379f6698 | Paul Brook | } |
1758 | c581deda | Paul Brook | qemu_log("Relocating guest address space from 0x" TARGET_ABI_FMT_lx
|
1759 | c581deda | Paul Brook | " to 0x%lx\n", app_start, real_start);
|
1760 | c581deda | Paul Brook | guest_base = real_start - app_start; |
1761 | 379f6698 | Paul Brook | } |
1762 | 379f6698 | Paul Brook | #endif /* CONFIG_USE_GUEST_BASE */ |
1763 | 379f6698 | Paul Brook | |
1764 | 31e31b8a | bellard | /* Do this so that we can load the interpreter, if need be. We will
|
1765 | 31e31b8a | bellard | change some of these later */
|
1766 | 31e31b8a | bellard | info->rss = 0;
|
1767 | 31e31b8a | bellard | bprm->p = setup_arg_pages(bprm->p, bprm, info); |
1768 | 31e31b8a | bellard | info->start_stack = bprm->p; |
1769 | 31e31b8a | bellard | |
1770 | 31e31b8a | bellard | /* Now we do a little grungy work by mmaping the ELF image into
|
1771 | 31e31b8a | bellard | * the correct location in memory. At this point, we assume that
|
1772 | 31e31b8a | bellard | * the image should be loaded at fixed address, not at a variable
|
1773 | 31e31b8a | bellard | * address.
|
1774 | 31e31b8a | bellard | */
|
1775 | 31e31b8a | bellard | |
1776 | 31e31b8a | bellard | for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { |
1777 | 09bfb054 | bellard | int elf_prot = 0; |
1778 | 09bfb054 | bellard | int elf_flags = 0; |
1779 | 992f48a0 | blueswir1 | abi_ulong error; |
1780 | 3b46e624 | ths | |
1781 | 09bfb054 | bellard | if (elf_ppnt->p_type != PT_LOAD)
|
1782 | 09bfb054 | bellard | continue;
|
1783 | 3b46e624 | ths | |
1784 | 09bfb054 | bellard | if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
|
1785 | 09bfb054 | bellard | if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
|
1786 | 09bfb054 | bellard | if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
|
1787 | 09bfb054 | bellard | elf_flags = MAP_PRIVATE | MAP_DENYWRITE; |
1788 | 09bfb054 | bellard | if (elf_ex.e_type == ET_EXEC || load_addr_set) {
|
1789 | 09bfb054 | bellard | elf_flags |= MAP_FIXED; |
1790 | 09bfb054 | bellard | } else if (elf_ex.e_type == ET_DYN) { |
1791 | 09bfb054 | bellard | /* Try and get dynamic programs out of the way of the default mmap
|
1792 | 09bfb054 | bellard | base, as well as whatever program they might try to exec. This
|
1793 | 09bfb054 | bellard | is because the brk will follow the loader, and is not movable. */
|
1794 | 09bfb054 | bellard | /* NOTE: for qemu, we do a big mmap to get enough space
|
1795 | e91c8a77 | ths | without hardcoding any address */
|
1796 | 54936004 | bellard | error = target_mmap(0, ET_DYN_MAP_SIZE,
|
1797 | 5fafdf24 | ths | PROT_NONE, MAP_PRIVATE | MAP_ANON, |
1798 | 54936004 | bellard | -1, 0); |
1799 | 09bfb054 | bellard | if (error == -1) { |
1800 | 09bfb054 | bellard | perror("mmap");
|
1801 | 09bfb054 | bellard | exit(-1);
|
1802 | 09bfb054 | bellard | } |
1803 | 54936004 | bellard | load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); |
1804 | 09bfb054 | bellard | } |
1805 | 3b46e624 | ths | |
1806 | 54936004 | bellard | error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), |
1807 | 54936004 | bellard | (elf_ppnt->p_filesz + |
1808 | 54936004 | bellard | TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), |
1809 | 54936004 | bellard | elf_prot, |
1810 | 54936004 | bellard | (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), |
1811 | 54936004 | bellard | bprm->fd, |
1812 | 5fafdf24 | ths | (elf_ppnt->p_offset - |
1813 | 54936004 | bellard | TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); |
1814 | 09bfb054 | bellard | if (error == -1) { |
1815 | 09bfb054 | bellard | perror("mmap");
|
1816 | 09bfb054 | bellard | exit(-1);
|
1817 | 09bfb054 | bellard | } |
1818 | 31e31b8a | bellard | |
1819 | 31e31b8a | bellard | #ifdef LOW_ELF_STACK
|
1820 | 54936004 | bellard | if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
|
1821 | 54936004 | bellard | elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); |
1822 | 31e31b8a | bellard | #endif
|
1823 | 3b46e624 | ths | |
1824 | 09bfb054 | bellard | if (!load_addr_set) {
|
1825 | 09bfb054 | bellard | load_addr_set = 1;
|
1826 | 09bfb054 | bellard | load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; |
1827 | 09bfb054 | bellard | if (elf_ex.e_type == ET_DYN) {
|
1828 | 09bfb054 | bellard | load_bias += error - |
1829 | 54936004 | bellard | TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); |
1830 | 09bfb054 | bellard | load_addr += load_bias; |
1831 | 84409ddb | j_mayer | reloc_func_desc = load_bias; |
1832 | 09bfb054 | bellard | } |
1833 | 09bfb054 | bellard | } |
1834 | 09bfb054 | bellard | k = elf_ppnt->p_vaddr; |
1835 | 5fafdf24 | ths | if (k < start_code)
|
1836 | 09bfb054 | bellard | start_code = k; |
1837 | 863cf0b7 | j_mayer | if (start_data < k)
|
1838 | 863cf0b7 | j_mayer | start_data = k; |
1839 | 09bfb054 | bellard | k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; |
1840 | 5fafdf24 | ths | if (k > elf_bss)
|
1841 | 09bfb054 | bellard | elf_bss = k; |
1842 | 09bfb054 | bellard | if ((elf_ppnt->p_flags & PF_X) && end_code < k)
|
1843 | 09bfb054 | bellard | end_code = k; |
1844 | 5fafdf24 | ths | if (end_data < k)
|
1845 | 09bfb054 | bellard | end_data = k; |
1846 | 09bfb054 | bellard | k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; |
1847 | 09bfb054 | bellard | if (k > elf_brk) elf_brk = k;
|
1848 | 31e31b8a | bellard | } |
1849 | 31e31b8a | bellard | |
1850 | 09bfb054 | bellard | elf_entry += load_bias; |
1851 | 09bfb054 | bellard | elf_bss += load_bias; |
1852 | 09bfb054 | bellard | elf_brk += load_bias; |
1853 | 09bfb054 | bellard | start_code += load_bias; |
1854 | 09bfb054 | bellard | end_code += load_bias; |
1855 | 863cf0b7 | j_mayer | start_data += load_bias; |
1856 | 09bfb054 | bellard | end_data += load_bias; |
1857 | 09bfb054 | bellard | |
1858 | 31e31b8a | bellard | if (elf_interpreter) {
|
1859 | 31e31b8a | bellard | if (interpreter_type & 1) { |
1860 | 31e31b8a | bellard | elf_entry = load_aout_interp(&interp_ex, interpreter_fd); |
1861 | 31e31b8a | bellard | } |
1862 | 31e31b8a | bellard | else if (interpreter_type & 2) { |
1863 | 31e31b8a | bellard | elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, |
1864 | 31e31b8a | bellard | &interp_load_addr); |
1865 | 31e31b8a | bellard | } |
1866 | 84409ddb | j_mayer | reloc_func_desc = interp_load_addr; |
1867 | 31e31b8a | bellard | |
1868 | 31e31b8a | bellard | close(interpreter_fd); |
1869 | 31e31b8a | bellard | free(elf_interpreter); |
1870 | 31e31b8a | bellard | |
1871 | 992f48a0 | blueswir1 | if (elf_entry == ~((abi_ulong)0UL)) { |
1872 | 31e31b8a | bellard | printf("Unable to load interpreter\n");
|
1873 | 31e31b8a | bellard | free(elf_phdata); |
1874 | 31e31b8a | bellard | exit(-1);
|
1875 | 31e31b8a | bellard | return 0; |
1876 | 31e31b8a | bellard | } |
1877 | 31e31b8a | bellard | } |
1878 | 31e31b8a | bellard | |
1879 | 31e31b8a | bellard | free(elf_phdata); |
1880 | 31e31b8a | bellard | |
1881 | 93fcfe39 | aliguori | if (qemu_log_enabled())
|
1882 | 689f936f | bellard | load_symbols(&elf_ex, bprm->fd); |
1883 | 689f936f | bellard | |
1884 | 31e31b8a | bellard | if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
|
1885 | 31e31b8a | bellard | info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); |
1886 | 31e31b8a | bellard | |
1887 | 31e31b8a | bellard | #ifdef LOW_ELF_STACK
|
1888 | 31e31b8a | bellard | info->start_stack = bprm->p = elf_stack - 4;
|
1889 | 31e31b8a | bellard | #endif
|
1890 | 53a5960a | pbrook | bprm->p = create_elf_tables(bprm->p, |
1891 | 31e31b8a | bellard | bprm->argc, |
1892 | 31e31b8a | bellard | bprm->envc, |
1893 | a1516e92 | bellard | &elf_ex, |
1894 | 09bfb054 | bellard | load_addr, load_bias, |
1895 | 31e31b8a | bellard | interp_load_addr, |
1896 | 31e31b8a | bellard | (interpreter_type == INTERPRETER_AOUT ? 0 : 1), |
1897 | 31e31b8a | bellard | info); |
1898 | 92a343da | j_mayer | info->load_addr = reloc_func_desc; |
1899 | 31e31b8a | bellard | info->start_brk = info->brk = elf_brk; |
1900 | 31e31b8a | bellard | info->end_code = end_code; |
1901 | 31e31b8a | bellard | info->start_code = start_code; |
1902 | 863cf0b7 | j_mayer | info->start_data = start_data; |
1903 | 31e31b8a | bellard | info->end_data = end_data; |
1904 | 31e31b8a | bellard | info->start_stack = bprm->p; |
1905 | 31e31b8a | bellard | |
1906 | 31e31b8a | bellard | /* Calling set_brk effectively mmaps the pages that we need for the bss and break
|
1907 | 31e31b8a | bellard | sections */
|
1908 | 31e31b8a | bellard | set_brk(elf_bss, elf_brk); |
1909 | 31e31b8a | bellard | |
1910 | 768a4a36 | ths | padzero(elf_bss, elf_brk); |
1911 | 31e31b8a | bellard | |
1912 | 31e31b8a | bellard | #if 0
|
1913 | 31e31b8a | bellard | printf("(start_brk) %x\n" , info->start_brk);
|
1914 | 31e31b8a | bellard | printf("(end_code) %x\n" , info->end_code);
|
1915 | 31e31b8a | bellard | printf("(start_code) %x\n" , info->start_code);
|
1916 | 31e31b8a | bellard | printf("(end_data) %x\n" , info->end_data);
|
1917 | 31e31b8a | bellard | printf("(start_stack) %x\n" , info->start_stack);
|
1918 | 31e31b8a | bellard | printf("(brk) %x\n" , info->brk);
|
1919 | 31e31b8a | bellard | #endif
|
1920 | 31e31b8a | bellard | |
1921 | 31e31b8a | bellard | if ( info->personality == PER_SVR4 )
|
1922 | 31e31b8a | bellard | { |
1923 | 31e31b8a | bellard | /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
|
1924 | 31e31b8a | bellard | and some applications "depend" upon this behavior.
|
1925 | 31e31b8a | bellard | Since we do not have the power to recompile these, we
|
1926 | 31e31b8a | bellard | emulate the SVr4 behavior. Sigh. */
|
1927 | 83fb7adf | bellard | mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
|
1928 | 54936004 | bellard | MAP_FIXED | MAP_PRIVATE, -1, 0); |
1929 | 31e31b8a | bellard | } |
1930 | 31e31b8a | bellard | |
1931 | 31e31b8a | bellard | info->entry = elf_entry; |
1932 | 31e31b8a | bellard | |
1933 | edf8e2af | Mika Westerberg | #ifdef USE_ELF_CORE_DUMP
|
1934 | edf8e2af | Mika Westerberg | bprm->core_dump = &elf_core_dump; |
1935 | edf8e2af | Mika Westerberg | #endif
|
1936 | edf8e2af | Mika Westerberg | |
1937 | 31e31b8a | bellard | return 0; |
1938 | 31e31b8a | bellard | } |
1939 | 31e31b8a | bellard | |
1940 | edf8e2af | Mika Westerberg | #ifdef USE_ELF_CORE_DUMP
|
1941 | edf8e2af | Mika Westerberg | |
1942 | edf8e2af | Mika Westerberg | /*
|
1943 | edf8e2af | Mika Westerberg | * Definitions to generate Intel SVR4-like core files.
|
1944 | a2547a13 | Laurent Desnogues | * These mostly have the same names as the SVR4 types with "target_elf_"
|
1945 | edf8e2af | Mika Westerberg | * tacked on the front to prevent clashes with linux definitions,
|
1946 | edf8e2af | Mika Westerberg | * and the typedef forms have been avoided. This is mostly like
|
1947 | edf8e2af | Mika Westerberg | * the SVR4 structure, but more Linuxy, with things that Linux does
|
1948 | edf8e2af | Mika Westerberg | * not support and which gdb doesn't really use excluded.
|
1949 | edf8e2af | Mika Westerberg | *
|
1950 | edf8e2af | Mika Westerberg | * Fields we don't dump (their contents is zero) in linux-user qemu
|
1951 | edf8e2af | Mika Westerberg | * are marked with XXX.
|
1952 | edf8e2af | Mika Westerberg | *
|
1953 | edf8e2af | Mika Westerberg | * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
|
1954 | edf8e2af | Mika Westerberg | *
|
1955 | edf8e2af | Mika Westerberg | * Porting ELF coredump for target is (quite) simple process. First you
|
1956 | dd0a3651 | Nathan Froyd | * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
|
1957 | edf8e2af | Mika Westerberg | * the target resides):
|
1958 | edf8e2af | Mika Westerberg | *
|
1959 | edf8e2af | Mika Westerberg | * #define USE_ELF_CORE_DUMP
|
1960 | edf8e2af | Mika Westerberg | *
|
1961 | edf8e2af | Mika Westerberg | * Next you define type of register set used for dumping. ELF specification
|
1962 | edf8e2af | Mika Westerberg | * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
|
1963 | edf8e2af | Mika Westerberg | *
|
1964 | c227f099 | Anthony Liguori | * typedef <target_regtype> target_elf_greg_t;
|
1965 | edf8e2af | Mika Westerberg | * #define ELF_NREG <number of registers>
|
1966 | c227f099 | Anthony Liguori | * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
1967 | edf8e2af | Mika Westerberg | *
|
1968 | edf8e2af | Mika Westerberg | * Last step is to implement target specific function that copies registers
|
1969 | edf8e2af | Mika Westerberg | * from given cpu into just specified register set. Prototype is:
|
1970 | edf8e2af | Mika Westerberg | *
|
1971 | c227f099 | Anthony Liguori | * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
|
1972 | a2547a13 | Laurent Desnogues | * const CPUState *env);
|
1973 | edf8e2af | Mika Westerberg | *
|
1974 | edf8e2af | Mika Westerberg | * Parameters:
|
1975 | edf8e2af | Mika Westerberg | * regs - copy register values into here (allocated and zeroed by caller)
|
1976 | edf8e2af | Mika Westerberg | * env - copy registers from here
|
1977 | edf8e2af | Mika Westerberg | *
|
1978 | edf8e2af | Mika Westerberg | * Example for ARM target is provided in this file.
|
1979 | edf8e2af | Mika Westerberg | */
|
1980 | edf8e2af | Mika Westerberg | |
1981 | edf8e2af | Mika Westerberg | /* An ELF note in memory */
|
1982 | edf8e2af | Mika Westerberg | struct memelfnote {
|
1983 | edf8e2af | Mika Westerberg | const char *name; |
1984 | edf8e2af | Mika Westerberg | size_t namesz; |
1985 | edf8e2af | Mika Westerberg | size_t namesz_rounded; |
1986 | edf8e2af | Mika Westerberg | int type;
|
1987 | edf8e2af | Mika Westerberg | size_t datasz; |
1988 | edf8e2af | Mika Westerberg | void *data;
|
1989 | edf8e2af | Mika Westerberg | size_t notesz; |
1990 | edf8e2af | Mika Westerberg | }; |
1991 | edf8e2af | Mika Westerberg | |
1992 | a2547a13 | Laurent Desnogues | struct target_elf_siginfo {
|
1993 | edf8e2af | Mika Westerberg | int si_signo; /* signal number */ |
1994 | edf8e2af | Mika Westerberg | int si_code; /* extra code */ |
1995 | edf8e2af | Mika Westerberg | int si_errno; /* errno */ |
1996 | edf8e2af | Mika Westerberg | }; |
1997 | edf8e2af | Mika Westerberg | |
1998 | a2547a13 | Laurent Desnogues | struct target_elf_prstatus {
|
1999 | a2547a13 | Laurent Desnogues | struct target_elf_siginfo pr_info; /* Info associated with signal */ |
2000 | edf8e2af | Mika Westerberg | short pr_cursig; /* Current signal */ |
2001 | edf8e2af | Mika Westerberg | target_ulong pr_sigpend; /* XXX */
|
2002 | edf8e2af | Mika Westerberg | target_ulong pr_sighold; /* XXX */
|
2003 | c227f099 | Anthony Liguori | target_pid_t pr_pid; |
2004 | c227f099 | Anthony Liguori | target_pid_t pr_ppid; |
2005 | c227f099 | Anthony Liguori | target_pid_t pr_pgrp; |
2006 | c227f099 | Anthony Liguori | target_pid_t pr_sid; |
2007 | edf8e2af | Mika Westerberg | struct target_timeval pr_utime; /* XXX User time */ |
2008 | edf8e2af | Mika Westerberg | struct target_timeval pr_stime; /* XXX System time */ |
2009 | edf8e2af | Mika Westerberg | struct target_timeval pr_cutime; /* XXX Cumulative user time */ |
2010 | edf8e2af | Mika Westerberg | struct target_timeval pr_cstime; /* XXX Cumulative system time */ |
2011 | c227f099 | Anthony Liguori | target_elf_gregset_t pr_reg; /* GP registers */
|
2012 | edf8e2af | Mika Westerberg | int pr_fpvalid; /* XXX */ |
2013 | edf8e2af | Mika Westerberg | }; |
2014 | edf8e2af | Mika Westerberg | |
2015 | edf8e2af | Mika Westerberg | #define ELF_PRARGSZ (80) /* Number of chars for args */ |
2016 | edf8e2af | Mika Westerberg | |
2017 | a2547a13 | Laurent Desnogues | struct target_elf_prpsinfo {
|
2018 | edf8e2af | Mika Westerberg | char pr_state; /* numeric process state */ |
2019 | edf8e2af | Mika Westerberg | char pr_sname; /* char for pr_state */ |
2020 | edf8e2af | Mika Westerberg | char pr_zomb; /* zombie */ |
2021 | edf8e2af | Mika Westerberg | char pr_nice; /* nice val */ |
2022 | edf8e2af | Mika Westerberg | target_ulong pr_flag; /* flags */
|
2023 | c227f099 | Anthony Liguori | target_uid_t pr_uid; |
2024 | c227f099 | Anthony Liguori | target_gid_t pr_gid; |
2025 | c227f099 | Anthony Liguori | target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; |
2026 | edf8e2af | Mika Westerberg | /* Lots missing */
|
2027 | edf8e2af | Mika Westerberg | char pr_fname[16]; /* filename of executable */ |
2028 | edf8e2af | Mika Westerberg | char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ |
2029 | edf8e2af | Mika Westerberg | }; |
2030 | edf8e2af | Mika Westerberg | |
2031 | edf8e2af | Mika Westerberg | /* Here is the structure in which status of each thread is captured. */
|
2032 | edf8e2af | Mika Westerberg | struct elf_thread_status {
|
2033 | 72cf2d4f | Blue Swirl | QTAILQ_ENTRY(elf_thread_status) ets_link; |
2034 | a2547a13 | Laurent Desnogues | struct target_elf_prstatus prstatus; /* NT_PRSTATUS */ |
2035 | edf8e2af | Mika Westerberg | #if 0
|
2036 | edf8e2af | Mika Westerberg | elf_fpregset_t fpu; /* NT_PRFPREG */
|
2037 | edf8e2af | Mika Westerberg | struct task_struct *thread;
|
2038 | edf8e2af | Mika Westerberg | elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */
|
2039 | edf8e2af | Mika Westerberg | #endif
|
2040 | edf8e2af | Mika Westerberg | struct memelfnote notes[1]; |
2041 | edf8e2af | Mika Westerberg | int num_notes;
|
2042 | edf8e2af | Mika Westerberg | }; |
2043 | edf8e2af | Mika Westerberg | |
2044 | edf8e2af | Mika Westerberg | struct elf_note_info {
|
2045 | edf8e2af | Mika Westerberg | struct memelfnote *notes;
|
2046 | a2547a13 | Laurent Desnogues | struct target_elf_prstatus *prstatus; /* NT_PRSTATUS */ |
2047 | a2547a13 | Laurent Desnogues | struct target_elf_prpsinfo *psinfo; /* NT_PRPSINFO */ |
2048 | edf8e2af | Mika Westerberg | |
2049 | 72cf2d4f | Blue Swirl | QTAILQ_HEAD(thread_list_head, elf_thread_status) thread_list; |
2050 | edf8e2af | Mika Westerberg | #if 0
|
2051 | edf8e2af | Mika Westerberg | /*
|
2052 | edf8e2af | Mika Westerberg | * Current version of ELF coredump doesn't support
|
2053 | edf8e2af | Mika Westerberg | * dumping fp regs etc.
|
2054 | edf8e2af | Mika Westerberg | */
|
2055 | edf8e2af | Mika Westerberg | elf_fpregset_t *fpu;
|
2056 | edf8e2af | Mika Westerberg | elf_fpxregset_t *xfpu;
|
2057 | edf8e2af | Mika Westerberg | int thread_status_size;
|
2058 | edf8e2af | Mika Westerberg | #endif
|
2059 | edf8e2af | Mika Westerberg | int notes_size;
|
2060 | edf8e2af | Mika Westerberg | int numnote;
|
2061 | edf8e2af | Mika Westerberg | }; |
2062 | edf8e2af | Mika Westerberg | |
2063 | edf8e2af | Mika Westerberg | struct vm_area_struct {
|
2064 | edf8e2af | Mika Westerberg | abi_ulong vma_start; /* start vaddr of memory region */
|
2065 | edf8e2af | Mika Westerberg | abi_ulong vma_end; /* end vaddr of memory region */
|
2066 | edf8e2af | Mika Westerberg | abi_ulong vma_flags; /* protection etc. flags for the region */
|
2067 | 72cf2d4f | Blue Swirl | QTAILQ_ENTRY(vm_area_struct) vma_link; |
2068 | edf8e2af | Mika Westerberg | }; |
2069 | edf8e2af | Mika Westerberg | |
2070 | edf8e2af | Mika Westerberg | struct mm_struct {
|
2071 | 72cf2d4f | Blue Swirl | QTAILQ_HEAD(, vm_area_struct) mm_mmap; |
2072 | edf8e2af | Mika Westerberg | int mm_count; /* number of mappings */ |
2073 | edf8e2af | Mika Westerberg | }; |
2074 | edf8e2af | Mika Westerberg | |
2075 | edf8e2af | Mika Westerberg | static struct mm_struct *vma_init(void); |
2076 | edf8e2af | Mika Westerberg | static void vma_delete(struct mm_struct *); |
2077 | edf8e2af | Mika Westerberg | static int vma_add_mapping(struct mm_struct *, abi_ulong, |
2078 | edf8e2af | Mika Westerberg | abi_ulong, abi_ulong); |
2079 | edf8e2af | Mika Westerberg | static int vma_get_mapping_count(const struct mm_struct *); |
2080 | edf8e2af | Mika Westerberg | static struct vm_area_struct *vma_first(const struct mm_struct *); |
2081 | edf8e2af | Mika Westerberg | static struct vm_area_struct *vma_next(struct vm_area_struct *); |
2082 | edf8e2af | Mika Westerberg | static abi_ulong vma_dump_size(const struct vm_area_struct *); |
2083 | b480d9b7 | Paul Brook | static int vma_walker(void *priv, abi_ulong start, abi_ulong end, |
2084 | edf8e2af | Mika Westerberg | unsigned long flags); |
2085 | edf8e2af | Mika Westerberg | |
2086 | edf8e2af | Mika Westerberg | static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t); |
2087 | edf8e2af | Mika Westerberg | static void fill_note(struct memelfnote *, const char *, int, |
2088 | edf8e2af | Mika Westerberg | unsigned int, void *); |
2089 | a2547a13 | Laurent Desnogues | static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int); |
2090 | a2547a13 | Laurent Desnogues | static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *); |
2091 | edf8e2af | Mika Westerberg | static void fill_auxv_note(struct memelfnote *, const TaskState *); |
2092 | edf8e2af | Mika Westerberg | static void fill_elf_note_phdr(struct elf_phdr *, int, off_t); |
2093 | edf8e2af | Mika Westerberg | static size_t note_size(const struct memelfnote *); |
2094 | edf8e2af | Mika Westerberg | static void free_note_info(struct elf_note_info *); |
2095 | edf8e2af | Mika Westerberg | static int fill_note_info(struct elf_note_info *, long, const CPUState *); |
2096 | edf8e2af | Mika Westerberg | static void fill_thread_info(struct elf_note_info *, const CPUState *); |
2097 | edf8e2af | Mika Westerberg | static int core_dump_filename(const TaskState *, char *, size_t); |
2098 | edf8e2af | Mika Westerberg | |
2099 | edf8e2af | Mika Westerberg | static int dump_write(int, const void *, size_t); |
2100 | edf8e2af | Mika Westerberg | static int write_note(struct memelfnote *, int); |
2101 | edf8e2af | Mika Westerberg | static int write_note_info(struct elf_note_info *, int); |
2102 | edf8e2af | Mika Westerberg | |
2103 | edf8e2af | Mika Westerberg | #ifdef BSWAP_NEEDED
|
2104 | a2547a13 | Laurent Desnogues | static void bswap_prstatus(struct target_elf_prstatus *); |
2105 | a2547a13 | Laurent Desnogues | static void bswap_psinfo(struct target_elf_prpsinfo *); |
2106 | edf8e2af | Mika Westerberg | |
2107 | a2547a13 | Laurent Desnogues | static void bswap_prstatus(struct target_elf_prstatus *prstatus) |
2108 | edf8e2af | Mika Westerberg | { |
2109 | edf8e2af | Mika Westerberg | prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo); |
2110 | edf8e2af | Mika Westerberg | prstatus->pr_info.si_code = tswapl(prstatus->pr_info.si_code); |
2111 | edf8e2af | Mika Westerberg | prstatus->pr_info.si_errno = tswapl(prstatus->pr_info.si_errno); |
2112 | edf8e2af | Mika Westerberg | prstatus->pr_cursig = tswap16(prstatus->pr_cursig); |
2113 | edf8e2af | Mika Westerberg | prstatus->pr_sigpend = tswapl(prstatus->pr_sigpend); |
2114 | edf8e2af | Mika Westerberg | prstatus->pr_sighold = tswapl(prstatus->pr_sighold); |
2115 | edf8e2af | Mika Westerberg | prstatus->pr_pid = tswap32(prstatus->pr_pid); |
2116 | edf8e2af | Mika Westerberg | prstatus->pr_ppid = tswap32(prstatus->pr_ppid); |
2117 | edf8e2af | Mika Westerberg | prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp); |
2118 | edf8e2af | Mika Westerberg | prstatus->pr_sid = tswap32(prstatus->pr_sid); |
2119 | edf8e2af | Mika Westerberg | /* cpu times are not filled, so we skip them */
|
2120 | edf8e2af | Mika Westerberg | /* regs should be in correct format already */
|
2121 | edf8e2af | Mika Westerberg | prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid); |
2122 | edf8e2af | Mika Westerberg | } |
2123 | edf8e2af | Mika Westerberg | |
2124 | a2547a13 | Laurent Desnogues | static void bswap_psinfo(struct target_elf_prpsinfo *psinfo) |
2125 | edf8e2af | Mika Westerberg | { |
2126 | edf8e2af | Mika Westerberg | psinfo->pr_flag = tswapl(psinfo->pr_flag); |
2127 | edf8e2af | Mika Westerberg | psinfo->pr_uid = tswap16(psinfo->pr_uid); |
2128 | edf8e2af | Mika Westerberg | psinfo->pr_gid = tswap16(psinfo->pr_gid); |
2129 | edf8e2af | Mika Westerberg | psinfo->pr_pid = tswap32(psinfo->pr_pid); |
2130 | edf8e2af | Mika Westerberg | psinfo->pr_ppid = tswap32(psinfo->pr_ppid); |
2131 | edf8e2af | Mika Westerberg | psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp); |
2132 | edf8e2af | Mika Westerberg | psinfo->pr_sid = tswap32(psinfo->pr_sid); |
2133 | edf8e2af | Mika Westerberg | } |
2134 | edf8e2af | Mika Westerberg | #endif /* BSWAP_NEEDED */ |
2135 | edf8e2af | Mika Westerberg | |
2136 | edf8e2af | Mika Westerberg | /*
|
2137 | edf8e2af | Mika Westerberg | * Minimal support for linux memory regions. These are needed
|
2138 | edf8e2af | Mika Westerberg | * when we are finding out what memory exactly belongs to
|
2139 | edf8e2af | Mika Westerberg | * emulated process. No locks needed here, as long as
|
2140 | edf8e2af | Mika Westerberg | * thread that received the signal is stopped.
|
2141 | edf8e2af | Mika Westerberg | */
|
2142 | edf8e2af | Mika Westerberg | |
2143 | edf8e2af | Mika Westerberg | static struct mm_struct *vma_init(void) |
2144 | edf8e2af | Mika Westerberg | { |
2145 | edf8e2af | Mika Westerberg | struct mm_struct *mm;
|
2146 | edf8e2af | Mika Westerberg | |
2147 | edf8e2af | Mika Westerberg | if ((mm = qemu_malloc(sizeof (*mm))) == NULL) |
2148 | edf8e2af | Mika Westerberg | return (NULL); |
2149 | edf8e2af | Mika Westerberg | |
2150 | edf8e2af | Mika Westerberg | mm->mm_count = 0;
|
2151 | 72cf2d4f | Blue Swirl | QTAILQ_INIT(&mm->mm_mmap); |
2152 | edf8e2af | Mika Westerberg | |
2153 | edf8e2af | Mika Westerberg | return (mm);
|
2154 | edf8e2af | Mika Westerberg | } |
2155 | edf8e2af | Mika Westerberg | |
2156 | edf8e2af | Mika Westerberg | static void vma_delete(struct mm_struct *mm) |
2157 | edf8e2af | Mika Westerberg | { |
2158 | edf8e2af | Mika Westerberg | struct vm_area_struct *vma;
|
2159 | edf8e2af | Mika Westerberg | |
2160 | edf8e2af | Mika Westerberg | while ((vma = vma_first(mm)) != NULL) { |
2161 | 72cf2d4f | Blue Swirl | QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link); |
2162 | edf8e2af | Mika Westerberg | qemu_free(vma); |
2163 | edf8e2af | Mika Westerberg | } |
2164 | edf8e2af | Mika Westerberg | qemu_free(mm); |
2165 | edf8e2af | Mika Westerberg | } |
2166 | edf8e2af | Mika Westerberg | |
2167 | edf8e2af | Mika Westerberg | static int vma_add_mapping(struct mm_struct *mm, abi_ulong start, |
2168 | edf8e2af | Mika Westerberg | abi_ulong end, abi_ulong flags) |
2169 | edf8e2af | Mika Westerberg | { |
2170 | edf8e2af | Mika Westerberg | struct vm_area_struct *vma;
|
2171 | edf8e2af | Mika Westerberg | |
2172 | edf8e2af | Mika Westerberg | if ((vma = qemu_mallocz(sizeof (*vma))) == NULL) |
2173 | edf8e2af | Mika Westerberg | return (-1); |
2174 | edf8e2af | Mika Westerberg | |
2175 | edf8e2af | Mika Westerberg | vma->vma_start = start; |
2176 | edf8e2af | Mika Westerberg | vma->vma_end = end; |
2177 | edf8e2af | Mika Westerberg | vma->vma_flags = flags; |
2178 | edf8e2af | Mika Westerberg | |
2179 | 72cf2d4f | Blue Swirl | QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link); |
2180 | edf8e2af | Mika Westerberg | mm->mm_count++; |
2181 | edf8e2af | Mika Westerberg | |
2182 | edf8e2af | Mika Westerberg | return (0); |
2183 | edf8e2af | Mika Westerberg | } |
2184 | edf8e2af | Mika Westerberg | |
2185 | edf8e2af | Mika Westerberg | static struct vm_area_struct *vma_first(const struct mm_struct *mm) |
2186 | edf8e2af | Mika Westerberg | { |
2187 | 72cf2d4f | Blue Swirl | return (QTAILQ_FIRST(&mm->mm_mmap));
|
2188 | edf8e2af | Mika Westerberg | } |
2189 | edf8e2af | Mika Westerberg | |
2190 | edf8e2af | Mika Westerberg | static struct vm_area_struct *vma_next(struct vm_area_struct *vma) |
2191 | edf8e2af | Mika Westerberg | { |
2192 | 72cf2d4f | Blue Swirl | return (QTAILQ_NEXT(vma, vma_link));
|
2193 | edf8e2af | Mika Westerberg | } |
2194 | edf8e2af | Mika Westerberg | |
2195 | edf8e2af | Mika Westerberg | static int vma_get_mapping_count(const struct mm_struct *mm) |
2196 | edf8e2af | Mika Westerberg | { |
2197 | edf8e2af | Mika Westerberg | return (mm->mm_count);
|
2198 | edf8e2af | Mika Westerberg | } |
2199 | edf8e2af | Mika Westerberg | |
2200 | edf8e2af | Mika Westerberg | /*
|
2201 | edf8e2af | Mika Westerberg | * Calculate file (dump) size of given memory region.
|
2202 | edf8e2af | Mika Westerberg | */
|
2203 | edf8e2af | Mika Westerberg | static abi_ulong vma_dump_size(const struct vm_area_struct *vma) |
2204 | edf8e2af | Mika Westerberg | { |
2205 | edf8e2af | Mika Westerberg | /* if we cannot even read the first page, skip it */
|
2206 | edf8e2af | Mika Westerberg | if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
|
2207 | edf8e2af | Mika Westerberg | return (0); |
2208 | edf8e2af | Mika Westerberg | |
2209 | edf8e2af | Mika Westerberg | /*
|
2210 | edf8e2af | Mika Westerberg | * Usually we don't dump executable pages as they contain
|
2211 | edf8e2af | Mika Westerberg | * non-writable code that debugger can read directly from
|
2212 | edf8e2af | Mika Westerberg | * target library etc. However, thread stacks are marked
|
2213 | edf8e2af | Mika Westerberg | * also executable so we read in first page of given region
|
2214 | edf8e2af | Mika Westerberg | * and check whether it contains elf header. If there is
|
2215 | edf8e2af | Mika Westerberg | * no elf header, we dump it.
|
2216 | edf8e2af | Mika Westerberg | */
|
2217 | edf8e2af | Mika Westerberg | if (vma->vma_flags & PROT_EXEC) {
|
2218 | edf8e2af | Mika Westerberg | char page[TARGET_PAGE_SIZE];
|
2219 | edf8e2af | Mika Westerberg | |
2220 | edf8e2af | Mika Westerberg | copy_from_user(page, vma->vma_start, sizeof (page));
|
2221 | edf8e2af | Mika Westerberg | if ((page[EI_MAG0] == ELFMAG0) &&
|
2222 | edf8e2af | Mika Westerberg | (page[EI_MAG1] == ELFMAG1) && |
2223 | edf8e2af | Mika Westerberg | (page[EI_MAG2] == ELFMAG2) && |
2224 | edf8e2af | Mika Westerberg | (page[EI_MAG3] == ELFMAG3)) { |
2225 | edf8e2af | Mika Westerberg | /*
|
2226 | edf8e2af | Mika Westerberg | * Mappings are possibly from ELF binary. Don't dump
|
2227 | edf8e2af | Mika Westerberg | * them.
|
2228 | edf8e2af | Mika Westerberg | */
|
2229 | edf8e2af | Mika Westerberg | return (0); |
2230 | edf8e2af | Mika Westerberg | } |
2231 | edf8e2af | Mika Westerberg | } |
2232 | edf8e2af | Mika Westerberg | |
2233 | edf8e2af | Mika Westerberg | return (vma->vma_end - vma->vma_start);
|
2234 | edf8e2af | Mika Westerberg | } |
2235 | edf8e2af | Mika Westerberg | |
2236 | b480d9b7 | Paul Brook | static int vma_walker(void *priv, abi_ulong start, abi_ulong end, |
2237 | edf8e2af | Mika Westerberg | unsigned long flags) |
2238 | edf8e2af | Mika Westerberg | { |
2239 | edf8e2af | Mika Westerberg | struct mm_struct *mm = (struct mm_struct *)priv; |
2240 | edf8e2af | Mika Westerberg | |
2241 | edf8e2af | Mika Westerberg | vma_add_mapping(mm, start, end, flags); |
2242 | edf8e2af | Mika Westerberg | return (0); |
2243 | edf8e2af | Mika Westerberg | } |
2244 | edf8e2af | Mika Westerberg | |
2245 | edf8e2af | Mika Westerberg | static void fill_note(struct memelfnote *note, const char *name, int type, |
2246 | edf8e2af | Mika Westerberg | unsigned int sz, void *data) |
2247 | edf8e2af | Mika Westerberg | { |
2248 | edf8e2af | Mika Westerberg | unsigned int namesz; |
2249 | edf8e2af | Mika Westerberg | |
2250 | edf8e2af | Mika Westerberg | namesz = strlen(name) + 1;
|
2251 | edf8e2af | Mika Westerberg | note->name = name; |
2252 | edf8e2af | Mika Westerberg | note->namesz = namesz; |
2253 | edf8e2af | Mika Westerberg | note->namesz_rounded = roundup(namesz, sizeof (int32_t));
|
2254 | edf8e2af | Mika Westerberg | note->type = type; |
2255 | edf8e2af | Mika Westerberg | note->datasz = roundup(sz, sizeof (int32_t));;
|
2256 | edf8e2af | Mika Westerberg | note->data = data; |
2257 | edf8e2af | Mika Westerberg | |
2258 | edf8e2af | Mika Westerberg | /*
|
2259 | edf8e2af | Mika Westerberg | * We calculate rounded up note size here as specified by
|
2260 | edf8e2af | Mika Westerberg | * ELF document.
|
2261 | edf8e2af | Mika Westerberg | */
|
2262 | edf8e2af | Mika Westerberg | note->notesz = sizeof (struct elf_note) + |
2263 | edf8e2af | Mika Westerberg | note->namesz_rounded + note->datasz; |
2264 | edf8e2af | Mika Westerberg | } |
2265 | edf8e2af | Mika Westerberg | |
2266 | edf8e2af | Mika Westerberg | static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine, |
2267 | edf8e2af | Mika Westerberg | uint32_t flags) |
2268 | edf8e2af | Mika Westerberg | { |
2269 | edf8e2af | Mika Westerberg | (void) memset(elf, 0, sizeof(*elf)); |
2270 | edf8e2af | Mika Westerberg | |
2271 | edf8e2af | Mika Westerberg | (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
|
2272 | edf8e2af | Mika Westerberg | elf->e_ident[EI_CLASS] = ELF_CLASS; |
2273 | edf8e2af | Mika Westerberg | elf->e_ident[EI_DATA] = ELF_DATA; |
2274 | edf8e2af | Mika Westerberg | elf->e_ident[EI_VERSION] = EV_CURRENT; |
2275 | edf8e2af | Mika Westerberg | elf->e_ident[EI_OSABI] = ELF_OSABI; |
2276 | edf8e2af | Mika Westerberg | |
2277 | edf8e2af | Mika Westerberg | elf->e_type = ET_CORE; |
2278 | edf8e2af | Mika Westerberg | elf->e_machine = machine; |
2279 | edf8e2af | Mika Westerberg | elf->e_version = EV_CURRENT; |
2280 | edf8e2af | Mika Westerberg | elf->e_phoff = sizeof(struct elfhdr); |
2281 | edf8e2af | Mika Westerberg | elf->e_flags = flags; |
2282 | edf8e2af | Mika Westerberg | elf->e_ehsize = sizeof(struct elfhdr); |
2283 | edf8e2af | Mika Westerberg | elf->e_phentsize = sizeof(struct elf_phdr); |
2284 | edf8e2af | Mika Westerberg | elf->e_phnum = segs; |
2285 | edf8e2af | Mika Westerberg | |
2286 | edf8e2af | Mika Westerberg | #ifdef BSWAP_NEEDED
|
2287 | edf8e2af | Mika Westerberg | bswap_ehdr(elf); |
2288 | edf8e2af | Mika Westerberg | #endif
|
2289 | edf8e2af | Mika Westerberg | } |
2290 | edf8e2af | Mika Westerberg | |
2291 | edf8e2af | Mika Westerberg | static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset) |
2292 | edf8e2af | Mika Westerberg | { |
2293 | edf8e2af | Mika Westerberg | phdr->p_type = PT_NOTE; |
2294 | edf8e2af | Mika Westerberg | phdr->p_offset = offset; |
2295 | edf8e2af | Mika Westerberg | phdr->p_vaddr = 0;
|
2296 | edf8e2af | Mika Westerberg | phdr->p_paddr = 0;
|
2297 | edf8e2af | Mika Westerberg | phdr->p_filesz = sz; |
2298 | edf8e2af | Mika Westerberg | phdr->p_memsz = 0;
|
2299 | edf8e2af | Mika Westerberg | phdr->p_flags = 0;
|
2300 | edf8e2af | Mika Westerberg | phdr->p_align = 0;
|
2301 | edf8e2af | Mika Westerberg | |
2302 | edf8e2af | Mika Westerberg | #ifdef BSWAP_NEEDED
|
2303 | edf8e2af | Mika Westerberg | bswap_phdr(phdr); |
2304 | edf8e2af | Mika Westerberg | #endif
|
2305 | edf8e2af | Mika Westerberg | } |
2306 | edf8e2af | Mika Westerberg | |
2307 | edf8e2af | Mika Westerberg | static size_t note_size(const struct memelfnote *note) |
2308 | edf8e2af | Mika Westerberg | { |
2309 | edf8e2af | Mika Westerberg | return (note->notesz);
|
2310 | edf8e2af | Mika Westerberg | } |
2311 | edf8e2af | Mika Westerberg | |
2312 | a2547a13 | Laurent Desnogues | static void fill_prstatus(struct target_elf_prstatus *prstatus, |
2313 | edf8e2af | Mika Westerberg | const TaskState *ts, int signr) |
2314 | edf8e2af | Mika Westerberg | { |
2315 | edf8e2af | Mika Westerberg | (void) memset(prstatus, 0, sizeof (*prstatus)); |
2316 | edf8e2af | Mika Westerberg | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; |
2317 | edf8e2af | Mika Westerberg | prstatus->pr_pid = ts->ts_tid; |
2318 | edf8e2af | Mika Westerberg | prstatus->pr_ppid = getppid(); |
2319 | edf8e2af | Mika Westerberg | prstatus->pr_pgrp = getpgrp(); |
2320 | edf8e2af | Mika Westerberg | prstatus->pr_sid = getsid(0);
|
2321 | edf8e2af | Mika Westerberg | |
2322 | edf8e2af | Mika Westerberg | #ifdef BSWAP_NEEDED
|
2323 | edf8e2af | Mika Westerberg | bswap_prstatus(prstatus); |
2324 | edf8e2af | Mika Westerberg | #endif
|
2325 | edf8e2af | Mika Westerberg | } |
2326 | edf8e2af | Mika Westerberg | |
2327 | a2547a13 | Laurent Desnogues | static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts) |
2328 | edf8e2af | Mika Westerberg | { |
2329 | edf8e2af | Mika Westerberg | char *filename, *base_filename;
|
2330 | edf8e2af | Mika Westerberg | unsigned int i, len; |
2331 | edf8e2af | Mika Westerberg | |
2332 | edf8e2af | Mika Westerberg | (void) memset(psinfo, 0, sizeof (*psinfo)); |
2333 | edf8e2af | Mika Westerberg | |
2334 | edf8e2af | Mika Westerberg | len = ts->info->arg_end - ts->info->arg_start; |
2335 | edf8e2af | Mika Westerberg | if (len >= ELF_PRARGSZ)
|
2336 | edf8e2af | Mika Westerberg | len = ELF_PRARGSZ - 1;
|
2337 | edf8e2af | Mika Westerberg | if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len))
|
2338 | edf8e2af | Mika Westerberg | return -EFAULT;
|
2339 | edf8e2af | Mika Westerberg | for (i = 0; i < len; i++) |
2340 | edf8e2af | Mika Westerberg | if (psinfo->pr_psargs[i] == 0) |
2341 | edf8e2af | Mika Westerberg | psinfo->pr_psargs[i] = ' ';
|
2342 | edf8e2af | Mika Westerberg | psinfo->pr_psargs[len] = 0;
|
2343 | edf8e2af | Mika Westerberg | |
2344 | edf8e2af | Mika Westerberg | psinfo->pr_pid = getpid(); |
2345 | edf8e2af | Mika Westerberg | psinfo->pr_ppid = getppid(); |
2346 | edf8e2af | Mika Westerberg | psinfo->pr_pgrp = getpgrp(); |
2347 | edf8e2af | Mika Westerberg | psinfo->pr_sid = getsid(0);
|
2348 | edf8e2af | Mika Westerberg | psinfo->pr_uid = getuid(); |
2349 | edf8e2af | Mika Westerberg | psinfo->pr_gid = getgid(); |
2350 | edf8e2af | Mika Westerberg | |
2351 | edf8e2af | Mika Westerberg | filename = strdup(ts->bprm->filename); |
2352 | edf8e2af | Mika Westerberg | base_filename = strdup(basename(filename)); |
2353 | edf8e2af | Mika Westerberg | (void) strncpy(psinfo->pr_fname, base_filename,
|
2354 | edf8e2af | Mika Westerberg | sizeof(psinfo->pr_fname));
|
2355 | edf8e2af | Mika Westerberg | free(base_filename); |
2356 | edf8e2af | Mika Westerberg | free(filename); |
2357 | edf8e2af | Mika Westerberg | |
2358 | edf8e2af | Mika Westerberg | #ifdef BSWAP_NEEDED
|
2359 | edf8e2af | Mika Westerberg | bswap_psinfo(psinfo); |
2360 | edf8e2af | Mika Westerberg | #endif
|
2361 | edf8e2af | Mika Westerberg | return (0); |
2362 | edf8e2af | Mika Westerberg | } |
2363 | edf8e2af | Mika Westerberg | |
2364 | edf8e2af | Mika Westerberg | static void fill_auxv_note(struct memelfnote *note, const TaskState *ts) |
2365 | edf8e2af | Mika Westerberg | { |
2366 | edf8e2af | Mika Westerberg | elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv; |
2367 | edf8e2af | Mika Westerberg | elf_addr_t orig_auxv = auxv; |
2368 | edf8e2af | Mika Westerberg | abi_ulong val; |
2369 | edf8e2af | Mika Westerberg | void *ptr;
|
2370 | edf8e2af | Mika Westerberg | int i, len;
|
2371 | edf8e2af | Mika Westerberg | |
2372 | edf8e2af | Mika Westerberg | /*
|
2373 | edf8e2af | Mika Westerberg | * Auxiliary vector is stored in target process stack. It contains
|
2374 | edf8e2af | Mika Westerberg | * {type, value} pairs that we need to dump into note. This is not
|
2375 | edf8e2af | Mika Westerberg | * strictly necessary but we do it here for sake of completeness.
|
2376 | edf8e2af | Mika Westerberg | */
|
2377 | edf8e2af | Mika Westerberg | |
2378 | edf8e2af | Mika Westerberg | /* find out lenght of the vector, AT_NULL is terminator */
|
2379 | edf8e2af | Mika Westerberg | i = len = 0;
|
2380 | edf8e2af | Mika Westerberg | do {
|
2381 | edf8e2af | Mika Westerberg | get_user_ual(val, auxv); |
2382 | edf8e2af | Mika Westerberg | i += 2;
|
2383 | edf8e2af | Mika Westerberg | auxv += 2 * sizeof (elf_addr_t); |
2384 | edf8e2af | Mika Westerberg | } while (val != AT_NULL);
|
2385 | edf8e2af | Mika Westerberg | len = i * sizeof (elf_addr_t);
|
2386 | edf8e2af | Mika Westerberg | |
2387 | edf8e2af | Mika Westerberg | /* read in whole auxv vector and copy it to memelfnote */
|
2388 | edf8e2af | Mika Westerberg | ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
|
2389 | edf8e2af | Mika Westerberg | if (ptr != NULL) { |
2390 | edf8e2af | Mika Westerberg | fill_note(note, "CORE", NT_AUXV, len, ptr);
|
2391 | edf8e2af | Mika Westerberg | unlock_user(ptr, auxv, len); |
2392 | edf8e2af | Mika Westerberg | } |
2393 | edf8e2af | Mika Westerberg | } |
2394 | edf8e2af | Mika Westerberg | |
2395 | edf8e2af | Mika Westerberg | /*
|
2396 | edf8e2af | Mika Westerberg | * Constructs name of coredump file. We have following convention
|
2397 | edf8e2af | Mika Westerberg | * for the name:
|
2398 | edf8e2af | Mika Westerberg | * qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
|
2399 | edf8e2af | Mika Westerberg | *
|
2400 | edf8e2af | Mika Westerberg | * Returns 0 in case of success, -1 otherwise (errno is set).
|
2401 | edf8e2af | Mika Westerberg | */
|
2402 | edf8e2af | Mika Westerberg | static int core_dump_filename(const TaskState *ts, char *buf, |
2403 | edf8e2af | Mika Westerberg | size_t bufsize) |
2404 | edf8e2af | Mika Westerberg | { |
2405 | edf8e2af | Mika Westerberg | char timestamp[64]; |
2406 | edf8e2af | Mika Westerberg | char *filename = NULL; |
2407 | edf8e2af | Mika Westerberg | char *base_filename = NULL; |
2408 | edf8e2af | Mika Westerberg | struct timeval tv;
|
2409 | edf8e2af | Mika Westerberg | struct tm tm;
|
2410 | edf8e2af | Mika Westerberg | |
2411 | edf8e2af | Mika Westerberg | assert(bufsize >= PATH_MAX); |
2412 | edf8e2af | Mika Westerberg | |
2413 | edf8e2af | Mika Westerberg | if (gettimeofday(&tv, NULL) < 0) { |
2414 | edf8e2af | Mika Westerberg | (void) fprintf(stderr, "unable to get current timestamp: %s", |
2415 | edf8e2af | Mika Westerberg | strerror(errno)); |
2416 | edf8e2af | Mika Westerberg | return (-1); |
2417 | edf8e2af | Mika Westerberg | } |
2418 | edf8e2af | Mika Westerberg | |
2419 | edf8e2af | Mika Westerberg | filename = strdup(ts->bprm->filename); |
2420 | edf8e2af | Mika Westerberg | base_filename = strdup(basename(filename)); |
2421 | edf8e2af | Mika Westerberg | (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S", |
2422 | edf8e2af | Mika Westerberg | localtime_r(&tv.tv_sec, &tm)); |
2423 | edf8e2af | Mika Westerberg | (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core", |
2424 | edf8e2af | Mika Westerberg | base_filename, timestamp, (int)getpid());
|
2425 | edf8e2af | Mika Westerberg | free(base_filename); |
2426 | edf8e2af | Mika Westerberg | free(filename); |
2427 | edf8e2af | Mika Westerberg | |
2428 | edf8e2af | Mika Westerberg | return (0); |
2429 | edf8e2af | Mika Westerberg | } |
2430 | edf8e2af | Mika Westerberg | |
2431 | edf8e2af | Mika Westerberg | static int dump_write(int fd, const void *ptr, size_t size) |
2432 | edf8e2af | Mika Westerberg | { |
2433 | edf8e2af | Mika Westerberg | const char *bufp = (const char *)ptr; |
2434 | edf8e2af | Mika Westerberg | ssize_t bytes_written, bytes_left; |
2435 | edf8e2af | Mika Westerberg | struct rlimit dumpsize;
|
2436 | edf8e2af | Mika Westerberg | off_t pos; |
2437 | edf8e2af | Mika Westerberg | |
2438 | edf8e2af | Mika Westerberg | bytes_written = 0;
|
2439 | edf8e2af | Mika Westerberg | getrlimit(RLIMIT_CORE, &dumpsize); |
2440 | edf8e2af | Mika Westerberg | if ((pos = lseek(fd, 0, SEEK_CUR))==-1) { |
2441 | edf8e2af | Mika Westerberg | if (errno == ESPIPE) { /* not a seekable stream */ |
2442 | edf8e2af | Mika Westerberg | bytes_left = size; |
2443 | edf8e2af | Mika Westerberg | } else {
|
2444 | edf8e2af | Mika Westerberg | return pos;
|
2445 | edf8e2af | Mika Westerberg | } |
2446 | edf8e2af | Mika Westerberg | } else {
|
2447 | edf8e2af | Mika Westerberg | if (dumpsize.rlim_cur <= pos) {
|
2448 | edf8e2af | Mika Westerberg | return -1; |
2449 | edf8e2af | Mika Westerberg | } else if (dumpsize.rlim_cur == RLIM_INFINITY) { |
2450 | edf8e2af | Mika Westerberg | bytes_left = size; |
2451 | edf8e2af | Mika Westerberg | } else {
|
2452 | edf8e2af | Mika Westerberg | size_t limit_left=dumpsize.rlim_cur - pos; |
2453 | edf8e2af | Mika Westerberg | bytes_left = limit_left >= size ? size : limit_left ; |
2454 | edf8e2af | Mika Westerberg | } |
2455 | edf8e2af | Mika Westerberg | } |
2456 | edf8e2af | Mika Westerberg | |
2457 | edf8e2af | Mika Westerberg | /*
|
2458 | edf8e2af | Mika Westerberg | * In normal conditions, single write(2) should do but
|
2459 | edf8e2af | Mika Westerberg | * in case of socket etc. this mechanism is more portable.
|
2460 | edf8e2af | Mika Westerberg | */
|
2461 | edf8e2af | Mika Westerberg | do {
|
2462 | edf8e2af | Mika Westerberg | bytes_written = write(fd, bufp, bytes_left); |
2463 | edf8e2af | Mika Westerberg | if (bytes_written < 0) { |
2464 | edf8e2af | Mika Westerberg | if (errno == EINTR)
|
2465 | edf8e2af | Mika Westerberg | continue;
|
2466 | edf8e2af | Mika Westerberg | return (-1); |
2467 | edf8e2af | Mika Westerberg | } else if (bytes_written == 0) { /* eof */ |
2468 | edf8e2af | Mika Westerberg | return (-1); |
2469 | edf8e2af | Mika Westerberg | } |
2470 | edf8e2af | Mika Westerberg | bufp += bytes_written; |
2471 | edf8e2af | Mika Westerberg | bytes_left -= bytes_written; |
2472 | edf8e2af | Mika Westerberg | } while (bytes_left > 0); |
2473 | edf8e2af | Mika Westerberg | |
2474 | edf8e2af | Mika Westerberg | return (0); |
2475 | edf8e2af | Mika Westerberg | } |
2476 | edf8e2af | Mika Westerberg | |
2477 | edf8e2af | Mika Westerberg | static int write_note(struct memelfnote *men, int fd) |
2478 | edf8e2af | Mika Westerberg | { |
2479 | edf8e2af | Mika Westerberg | struct elf_note en;
|
2480 | edf8e2af | Mika Westerberg | |
2481 | edf8e2af | Mika Westerberg | en.n_namesz = men->namesz; |
2482 | edf8e2af | Mika Westerberg | en.n_type = men->type; |
2483 | edf8e2af | Mika Westerberg | en.n_descsz = men->datasz; |
2484 | edf8e2af | Mika Westerberg | |
2485 | edf8e2af | Mika Westerberg | #ifdef BSWAP_NEEDED
|
2486 | edf8e2af | Mika Westerberg | bswap_note(&en); |
2487 | edf8e2af | Mika Westerberg | #endif
|
2488 | edf8e2af | Mika Westerberg | |
2489 | edf8e2af | Mika Westerberg | if (dump_write(fd, &en, sizeof(en)) != 0) |
2490 | edf8e2af | Mika Westerberg | return (-1); |
2491 | edf8e2af | Mika Westerberg | if (dump_write(fd, men->name, men->namesz_rounded) != 0) |
2492 | edf8e2af | Mika Westerberg | return (-1); |
2493 | edf8e2af | Mika Westerberg | if (dump_write(fd, men->data, men->datasz) != 0) |
2494 | edf8e2af | Mika Westerberg | return (-1); |
2495 | edf8e2af | Mika Westerberg | |
2496 | edf8e2af | Mika Westerberg | return (0); |
2497 | edf8e2af | Mika Westerberg | } |
2498 | edf8e2af | Mika Westerberg | |
2499 | edf8e2af | Mika Westerberg | static void fill_thread_info(struct elf_note_info *info, const CPUState *env) |
2500 | edf8e2af | Mika Westerberg | { |
2501 | edf8e2af | Mika Westerberg | TaskState *ts = (TaskState *)env->opaque; |
2502 | edf8e2af | Mika Westerberg | struct elf_thread_status *ets;
|
2503 | edf8e2af | Mika Westerberg | |
2504 | edf8e2af | Mika Westerberg | ets = qemu_mallocz(sizeof (*ets));
|
2505 | edf8e2af | Mika Westerberg | ets->num_notes = 1; /* only prstatus is dumped */ |
2506 | edf8e2af | Mika Westerberg | fill_prstatus(&ets->prstatus, ts, 0);
|
2507 | edf8e2af | Mika Westerberg | elf_core_copy_regs(&ets->prstatus.pr_reg, env); |
2508 | edf8e2af | Mika Westerberg | fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus), |
2509 | edf8e2af | Mika Westerberg | &ets->prstatus); |
2510 | edf8e2af | Mika Westerberg | |
2511 | 72cf2d4f | Blue Swirl | QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link); |
2512 | edf8e2af | Mika Westerberg | |
2513 | edf8e2af | Mika Westerberg | info->notes_size += note_size(&ets->notes[0]);
|
2514 | edf8e2af | Mika Westerberg | } |
2515 | edf8e2af | Mika Westerberg | |
2516 | edf8e2af | Mika Westerberg | static int fill_note_info(struct elf_note_info *info, |
2517 | edf8e2af | Mika Westerberg | long signr, const CPUState *env) |
2518 | edf8e2af | Mika Westerberg | { |
2519 | edf8e2af | Mika Westerberg | #define NUMNOTES 3 |
2520 | edf8e2af | Mika Westerberg | CPUState *cpu = NULL;
|
2521 | edf8e2af | Mika Westerberg | TaskState *ts = (TaskState *)env->opaque; |
2522 | edf8e2af | Mika Westerberg | int i;
|
2523 | edf8e2af | Mika Westerberg | |
2524 | edf8e2af | Mika Westerberg | (void) memset(info, 0, sizeof (*info)); |
2525 | edf8e2af | Mika Westerberg | |
2526 | 72cf2d4f | Blue Swirl | QTAILQ_INIT(&info->thread_list); |
2527 | edf8e2af | Mika Westerberg | |
2528 | edf8e2af | Mika Westerberg | info->notes = qemu_mallocz(NUMNOTES * sizeof (struct memelfnote)); |
2529 | edf8e2af | Mika Westerberg | if (info->notes == NULL) |
2530 | edf8e2af | Mika Westerberg | return (-ENOMEM);
|
2531 | edf8e2af | Mika Westerberg | info->prstatus = qemu_mallocz(sizeof (*info->prstatus));
|
2532 | edf8e2af | Mika Westerberg | if (info->prstatus == NULL) |
2533 | edf8e2af | Mika Westerberg | return (-ENOMEM);
|
2534 | edf8e2af | Mika Westerberg | info->psinfo = qemu_mallocz(sizeof (*info->psinfo));
|
2535 | edf8e2af | Mika Westerberg | if (info->prstatus == NULL) |
2536 | edf8e2af | Mika Westerberg | return (-ENOMEM);
|
2537 | edf8e2af | Mika Westerberg | |
2538 | edf8e2af | Mika Westerberg | /*
|
2539 | edf8e2af | Mika Westerberg | * First fill in status (and registers) of current thread
|
2540 | edf8e2af | Mika Westerberg | * including process info & aux vector.
|
2541 | edf8e2af | Mika Westerberg | */
|
2542 | edf8e2af | Mika Westerberg | fill_prstatus(info->prstatus, ts, signr); |
2543 | edf8e2af | Mika Westerberg | elf_core_copy_regs(&info->prstatus->pr_reg, env); |
2544 | edf8e2af | Mika Westerberg | fill_note(&info->notes[0], "CORE", NT_PRSTATUS, |
2545 | edf8e2af | Mika Westerberg | sizeof (*info->prstatus), info->prstatus);
|
2546 | edf8e2af | Mika Westerberg | fill_psinfo(info->psinfo, ts); |
2547 | edf8e2af | Mika Westerberg | fill_note(&info->notes[1], "CORE", NT_PRPSINFO, |
2548 | edf8e2af | Mika Westerberg | sizeof (*info->psinfo), info->psinfo);
|
2549 | edf8e2af | Mika Westerberg | fill_auxv_note(&info->notes[2], ts);
|
2550 | edf8e2af | Mika Westerberg | info->numnote = 3;
|
2551 | edf8e2af | Mika Westerberg | |
2552 | edf8e2af | Mika Westerberg | info->notes_size = 0;
|
2553 | edf8e2af | Mika Westerberg | for (i = 0; i < info->numnote; i++) |
2554 | edf8e2af | Mika Westerberg | info->notes_size += note_size(&info->notes[i]); |
2555 | edf8e2af | Mika Westerberg | |
2556 | edf8e2af | Mika Westerberg | /* read and fill status of all threads */
|
2557 | edf8e2af | Mika Westerberg | cpu_list_lock(); |
2558 | edf8e2af | Mika Westerberg | for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { |
2559 | edf8e2af | Mika Westerberg | if (cpu == thread_env)
|
2560 | edf8e2af | Mika Westerberg | continue;
|
2561 | edf8e2af | Mika Westerberg | fill_thread_info(info, cpu); |
2562 | edf8e2af | Mika Westerberg | } |
2563 | edf8e2af | Mika Westerberg | cpu_list_unlock(); |
2564 | edf8e2af | Mika Westerberg | |
2565 | edf8e2af | Mika Westerberg | return (0); |
2566 | edf8e2af | Mika Westerberg | } |
2567 | edf8e2af | Mika Westerberg | |
2568 | edf8e2af | Mika Westerberg | static void free_note_info(struct elf_note_info *info) |
2569 | edf8e2af | Mika Westerberg | { |
2570 | edf8e2af | Mika Westerberg | struct elf_thread_status *ets;
|
2571 | edf8e2af | Mika Westerberg | |
2572 | 72cf2d4f | Blue Swirl | while (!QTAILQ_EMPTY(&info->thread_list)) {
|
2573 | 72cf2d4f | Blue Swirl | ets = QTAILQ_FIRST(&info->thread_list); |
2574 | 72cf2d4f | Blue Swirl | QTAILQ_REMOVE(&info->thread_list, ets, ets_link); |
2575 | edf8e2af | Mika Westerberg | qemu_free(ets); |
2576 | edf8e2af | Mika Westerberg | } |
2577 | edf8e2af | Mika Westerberg | |
2578 | edf8e2af | Mika Westerberg | qemu_free(info->prstatus); |
2579 | edf8e2af | Mika Westerberg | qemu_free(info->psinfo); |
2580 | edf8e2af | Mika Westerberg | qemu_free(info->notes); |
2581 | edf8e2af | Mika Westerberg | } |
2582 | edf8e2af | Mika Westerberg | |
2583 | edf8e2af | Mika Westerberg | static int write_note_info(struct elf_note_info *info, int fd) |
2584 | edf8e2af | Mika Westerberg | { |
2585 | edf8e2af | Mika Westerberg | struct elf_thread_status *ets;
|
2586 | edf8e2af | Mika Westerberg | int i, error = 0; |
2587 | edf8e2af | Mika Westerberg | |
2588 | edf8e2af | Mika Westerberg | /* write prstatus, psinfo and auxv for current thread */
|
2589 | edf8e2af | Mika Westerberg | for (i = 0; i < info->numnote; i++) |
2590 | edf8e2af | Mika Westerberg | if ((error = write_note(&info->notes[i], fd)) != 0) |
2591 | edf8e2af | Mika Westerberg | return (error);
|
2592 | edf8e2af | Mika Westerberg | |
2593 | edf8e2af | Mika Westerberg | /* write prstatus for each thread */
|
2594 | edf8e2af | Mika Westerberg | for (ets = info->thread_list.tqh_first; ets != NULL; |
2595 | edf8e2af | Mika Westerberg | ets = ets->ets_link.tqe_next) { |
2596 | edf8e2af | Mika Westerberg | if ((error = write_note(&ets->notes[0], fd)) != 0) |
2597 | edf8e2af | Mika Westerberg | return (error);
|
2598 | edf8e2af | Mika Westerberg | } |
2599 | edf8e2af | Mika Westerberg | |
2600 | edf8e2af | Mika Westerberg | return (0); |
2601 | edf8e2af | Mika Westerberg | } |
2602 | edf8e2af | Mika Westerberg | |
2603 | edf8e2af | Mika Westerberg | /*
|
2604 | edf8e2af | Mika Westerberg | * Write out ELF coredump.
|
2605 | edf8e2af | Mika Westerberg | *
|
2606 | edf8e2af | Mika Westerberg | * See documentation of ELF object file format in:
|
2607 | edf8e2af | Mika Westerberg | * http://www.caldera.com/developers/devspecs/gabi41.pdf
|
2608 | edf8e2af | Mika Westerberg | *
|
2609 | edf8e2af | Mika Westerberg | * Coredump format in linux is following:
|
2610 | edf8e2af | Mika Westerberg | *
|
2611 | edf8e2af | Mika Westerberg | * 0 +----------------------+ \
|
2612 | edf8e2af | Mika Westerberg | * | ELF header | ET_CORE |
|
2613 | edf8e2af | Mika Westerberg | * +----------------------+ |
|
2614 | edf8e2af | Mika Westerberg | * | ELF program headers | |--- headers
|
2615 | edf8e2af | Mika Westerberg | * | - NOTE section | |
|
2616 | edf8e2af | Mika Westerberg | * | - PT_LOAD sections | |
|
2617 | edf8e2af | Mika Westerberg | * +----------------------+ /
|
2618 | edf8e2af | Mika Westerberg | * | NOTEs: |
|
2619 | edf8e2af | Mika Westerberg | * | - NT_PRSTATUS |
|
2620 | edf8e2af | Mika Westerberg | * | - NT_PRSINFO |
|
2621 | edf8e2af | Mika Westerberg | * | - NT_AUXV |
|
2622 | edf8e2af | Mika Westerberg | * +----------------------+ <-- aligned to target page
|
2623 | edf8e2af | Mika Westerberg | * | Process memory dump |
|
2624 | edf8e2af | Mika Westerberg | * : :
|
2625 | edf8e2af | Mika Westerberg | * . .
|
2626 | edf8e2af | Mika Westerberg | * : :
|
2627 | edf8e2af | Mika Westerberg | * | |
|
2628 | edf8e2af | Mika Westerberg | * +----------------------+
|
2629 | edf8e2af | Mika Westerberg | *
|
2630 | edf8e2af | Mika Westerberg | * NT_PRSTATUS -> struct elf_prstatus (per thread)
|
2631 | edf8e2af | Mika Westerberg | * NT_PRSINFO -> struct elf_prpsinfo
|
2632 | edf8e2af | Mika Westerberg | * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
|
2633 | edf8e2af | Mika Westerberg | *
|
2634 | edf8e2af | Mika Westerberg | * Format follows System V format as close as possible. Current
|
2635 | edf8e2af | Mika Westerberg | * version limitations are as follows:
|
2636 | edf8e2af | Mika Westerberg | * - no floating point registers are dumped
|
2637 | edf8e2af | Mika Westerberg | *
|
2638 | edf8e2af | Mika Westerberg | * Function returns 0 in case of success, negative errno otherwise.
|
2639 | edf8e2af | Mika Westerberg | *
|
2640 | edf8e2af | Mika Westerberg | * TODO: make this work also during runtime: it should be
|
2641 | edf8e2af | Mika Westerberg | * possible to force coredump from running process and then
|
2642 | edf8e2af | Mika Westerberg | * continue processing. For example qemu could set up SIGUSR2
|
2643 | edf8e2af | Mika Westerberg | * handler (provided that target process haven't registered
|
2644 | edf8e2af | Mika Westerberg | * handler for that) that does the dump when signal is received.
|
2645 | edf8e2af | Mika Westerberg | */
|
2646 | edf8e2af | Mika Westerberg | static int elf_core_dump(int signr, const CPUState *env) |
2647 | edf8e2af | Mika Westerberg | { |
2648 | edf8e2af | Mika Westerberg | const TaskState *ts = (const TaskState *)env->opaque; |
2649 | edf8e2af | Mika Westerberg | struct vm_area_struct *vma = NULL; |
2650 | edf8e2af | Mika Westerberg | char corefile[PATH_MAX];
|
2651 | edf8e2af | Mika Westerberg | struct elf_note_info info;
|
2652 | edf8e2af | Mika Westerberg | struct elfhdr elf;
|
2653 | edf8e2af | Mika Westerberg | struct elf_phdr phdr;
|
2654 | edf8e2af | Mika Westerberg | struct rlimit dumpsize;
|
2655 | edf8e2af | Mika Westerberg | struct mm_struct *mm = NULL; |
2656 | edf8e2af | Mika Westerberg | off_t offset = 0, data_offset = 0; |
2657 | edf8e2af | Mika Westerberg | int segs = 0; |
2658 | edf8e2af | Mika Westerberg | int fd = -1; |
2659 | edf8e2af | Mika Westerberg | |
2660 | edf8e2af | Mika Westerberg | errno = 0;
|
2661 | edf8e2af | Mika Westerberg | getrlimit(RLIMIT_CORE, &dumpsize); |
2662 | edf8e2af | Mika Westerberg | if (dumpsize.rlim_cur == 0) |
2663 | edf8e2af | Mika Westerberg | return 0; |
2664 | edf8e2af | Mika Westerberg | |
2665 | edf8e2af | Mika Westerberg | if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0) |
2666 | edf8e2af | Mika Westerberg | return (-errno);
|
2667 | edf8e2af | Mika Westerberg | |
2668 | edf8e2af | Mika Westerberg | if ((fd = open(corefile, O_WRONLY | O_CREAT,
|
2669 | edf8e2af | Mika Westerberg | S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
|
2670 | edf8e2af | Mika Westerberg | return (-errno);
|
2671 | edf8e2af | Mika Westerberg | |
2672 | edf8e2af | Mika Westerberg | /*
|
2673 | edf8e2af | Mika Westerberg | * Walk through target process memory mappings and
|
2674 | edf8e2af | Mika Westerberg | * set up structure containing this information. After
|
2675 | edf8e2af | Mika Westerberg | * this point vma_xxx functions can be used.
|
2676 | edf8e2af | Mika Westerberg | */
|
2677 | edf8e2af | Mika Westerberg | if ((mm = vma_init()) == NULL) |
2678 | edf8e2af | Mika Westerberg | goto out;
|
2679 | edf8e2af | Mika Westerberg | |
2680 | edf8e2af | Mika Westerberg | walk_memory_regions(mm, vma_walker); |
2681 | edf8e2af | Mika Westerberg | segs = vma_get_mapping_count(mm); |
2682 | edf8e2af | Mika Westerberg | |
2683 | edf8e2af | Mika Westerberg | /*
|
2684 | edf8e2af | Mika Westerberg | * Construct valid coredump ELF header. We also
|
2685 | edf8e2af | Mika Westerberg | * add one more segment for notes.
|
2686 | edf8e2af | Mika Westerberg | */
|
2687 | edf8e2af | Mika Westerberg | fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0); |
2688 | edf8e2af | Mika Westerberg | if (dump_write(fd, &elf, sizeof (elf)) != 0) |
2689 | edf8e2af | Mika Westerberg | goto out;
|
2690 | edf8e2af | Mika Westerberg | |
2691 | edf8e2af | Mika Westerberg | /* fill in in-memory version of notes */
|
2692 | edf8e2af | Mika Westerberg | if (fill_note_info(&info, signr, env) < 0) |
2693 | edf8e2af | Mika Westerberg | goto out;
|
2694 | edf8e2af | Mika Westerberg | |
2695 | edf8e2af | Mika Westerberg | offset += sizeof (elf); /* elf header */ |
2696 | edf8e2af | Mika Westerberg | offset += (segs + 1) * sizeof (struct elf_phdr); /* program headers */ |
2697 | edf8e2af | Mika Westerberg | |
2698 | edf8e2af | Mika Westerberg | /* write out notes program header */
|
2699 | edf8e2af | Mika Westerberg | fill_elf_note_phdr(&phdr, info.notes_size, offset); |
2700 | edf8e2af | Mika Westerberg | |
2701 | edf8e2af | Mika Westerberg | offset += info.notes_size; |
2702 | edf8e2af | Mika Westerberg | if (dump_write(fd, &phdr, sizeof (phdr)) != 0) |
2703 | edf8e2af | Mika Westerberg | goto out;
|
2704 | edf8e2af | Mika Westerberg | |
2705 | edf8e2af | Mika Westerberg | /*
|
2706 | edf8e2af | Mika Westerberg | * ELF specification wants data to start at page boundary so
|
2707 | edf8e2af | Mika Westerberg | * we align it here.
|
2708 | edf8e2af | Mika Westerberg | */
|
2709 | edf8e2af | Mika Westerberg | offset = roundup(offset, ELF_EXEC_PAGESIZE); |
2710 | edf8e2af | Mika Westerberg | |
2711 | edf8e2af | Mika Westerberg | /*
|
2712 | edf8e2af | Mika Westerberg | * Write program headers for memory regions mapped in
|
2713 | edf8e2af | Mika Westerberg | * the target process.
|
2714 | edf8e2af | Mika Westerberg | */
|
2715 | edf8e2af | Mika Westerberg | for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) { |
2716 | edf8e2af | Mika Westerberg | (void) memset(&phdr, 0, sizeof (phdr)); |
2717 | edf8e2af | Mika Westerberg | |
2718 | edf8e2af | Mika Westerberg | phdr.p_type = PT_LOAD; |
2719 | edf8e2af | Mika Westerberg | phdr.p_offset = offset; |
2720 | edf8e2af | Mika Westerberg | phdr.p_vaddr = vma->vma_start; |
2721 | edf8e2af | Mika Westerberg | phdr.p_paddr = 0;
|
2722 | edf8e2af | Mika Westerberg | phdr.p_filesz = vma_dump_size(vma); |
2723 | edf8e2af | Mika Westerberg | offset += phdr.p_filesz; |
2724 | edf8e2af | Mika Westerberg | phdr.p_memsz = vma->vma_end - vma->vma_start; |
2725 | edf8e2af | Mika Westerberg | phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
|
2726 | edf8e2af | Mika Westerberg | if (vma->vma_flags & PROT_WRITE)
|
2727 | edf8e2af | Mika Westerberg | phdr.p_flags |= PF_W; |
2728 | edf8e2af | Mika Westerberg | if (vma->vma_flags & PROT_EXEC)
|
2729 | edf8e2af | Mika Westerberg | phdr.p_flags |= PF_X; |
2730 | edf8e2af | Mika Westerberg | phdr.p_align = ELF_EXEC_PAGESIZE; |
2731 | edf8e2af | Mika Westerberg | |
2732 | edf8e2af | Mika Westerberg | dump_write(fd, &phdr, sizeof (phdr));
|
2733 | edf8e2af | Mika Westerberg | } |
2734 | edf8e2af | Mika Westerberg | |
2735 | edf8e2af | Mika Westerberg | /*
|
2736 | edf8e2af | Mika Westerberg | * Next we write notes just after program headers. No
|
2737 | edf8e2af | Mika Westerberg | * alignment needed here.
|
2738 | edf8e2af | Mika Westerberg | */
|
2739 | edf8e2af | Mika Westerberg | if (write_note_info(&info, fd) < 0) |
2740 | edf8e2af | Mika Westerberg | goto out;
|
2741 | edf8e2af | Mika Westerberg | |
2742 | edf8e2af | Mika Westerberg | /* align data to page boundary */
|
2743 | edf8e2af | Mika Westerberg | data_offset = lseek(fd, 0, SEEK_CUR);
|
2744 | edf8e2af | Mika Westerberg | data_offset = TARGET_PAGE_ALIGN(data_offset); |
2745 | edf8e2af | Mika Westerberg | if (lseek(fd, data_offset, SEEK_SET) != data_offset)
|
2746 | edf8e2af | Mika Westerberg | goto out;
|
2747 | edf8e2af | Mika Westerberg | |
2748 | edf8e2af | Mika Westerberg | /*
|
2749 | edf8e2af | Mika Westerberg | * Finally we can dump process memory into corefile as well.
|
2750 | edf8e2af | Mika Westerberg | */
|
2751 | edf8e2af | Mika Westerberg | for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) { |
2752 | edf8e2af | Mika Westerberg | abi_ulong addr; |
2753 | edf8e2af | Mika Westerberg | abi_ulong end; |
2754 | edf8e2af | Mika Westerberg | |
2755 | edf8e2af | Mika Westerberg | end = vma->vma_start + vma_dump_size(vma); |
2756 | edf8e2af | Mika Westerberg | |
2757 | edf8e2af | Mika Westerberg | for (addr = vma->vma_start; addr < end;
|
2758 | edf8e2af | Mika Westerberg | addr += TARGET_PAGE_SIZE) { |
2759 | edf8e2af | Mika Westerberg | char page[TARGET_PAGE_SIZE];
|
2760 | edf8e2af | Mika Westerberg | int error;
|
2761 | edf8e2af | Mika Westerberg | |
2762 | edf8e2af | Mika Westerberg | /*
|
2763 | edf8e2af | Mika Westerberg | * Read in page from target process memory and
|
2764 | edf8e2af | Mika Westerberg | * write it to coredump file.
|
2765 | edf8e2af | Mika Westerberg | */
|
2766 | edf8e2af | Mika Westerberg | error = copy_from_user(page, addr, sizeof (page));
|
2767 | edf8e2af | Mika Westerberg | if (error != 0) { |
2768 | 49995e17 | Aurelien Jarno | (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n", |
2769 | edf8e2af | Mika Westerberg | addr); |
2770 | edf8e2af | Mika Westerberg | errno = -error; |
2771 | edf8e2af | Mika Westerberg | goto out;
|
2772 | edf8e2af | Mika Westerberg | } |
2773 | edf8e2af | Mika Westerberg | if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0) |
2774 | edf8e2af | Mika Westerberg | goto out;
|
2775 | edf8e2af | Mika Westerberg | } |
2776 | edf8e2af | Mika Westerberg | } |
2777 | edf8e2af | Mika Westerberg | |
2778 | edf8e2af | Mika Westerberg | out:
|
2779 | edf8e2af | Mika Westerberg | free_note_info(&info); |
2780 | edf8e2af | Mika Westerberg | if (mm != NULL) |
2781 | edf8e2af | Mika Westerberg | vma_delete(mm); |
2782 | edf8e2af | Mika Westerberg | (void) close(fd);
|
2783 | edf8e2af | Mika Westerberg | |
2784 | edf8e2af | Mika Westerberg | if (errno != 0) |
2785 | edf8e2af | Mika Westerberg | return (-errno);
|
2786 | edf8e2af | Mika Westerberg | return (0); |
2787 | edf8e2af | Mika Westerberg | } |
2788 | edf8e2af | Mika Westerberg | |
2789 | edf8e2af | Mika Westerberg | #endif /* USE_ELF_CORE_DUMP */ |
2790 | edf8e2af | Mika Westerberg | |
2791 | 31e31b8a | bellard | static int load_aout_interp(void * exptr, int interp_fd) |
2792 | 31e31b8a | bellard | { |
2793 | 31e31b8a | bellard | printf("a.out interpreter not yet supported\n");
|
2794 | 31e31b8a | bellard | return(0); |
2795 | 31e31b8a | bellard | } |
2796 | 31e31b8a | bellard | |
2797 | e5fe0c52 | pbrook | void do_init_thread(struct target_pt_regs *regs, struct image_info *infop) |
2798 | e5fe0c52 | pbrook | { |
2799 | e5fe0c52 | pbrook | init_thread(regs, infop); |
2800 | e5fe0c52 | pbrook | } |