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