Commit edf8e2af1453ce56c72b2f25a745e3734177a05d
Committed by
Riku Voipio
1 parent
88a8c984
linux-user: implemented ELF coredump support for ARM target
When target process is killed with signal (such signal that should dump core) a coredump file is created. This file is similar than coredump generated by Linux (there are few exceptions though). Riku Voipio: added support for rlimit Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
Showing
9 changed files
with
1101 additions
and
68 deletions
cpu-all.h
@@ -735,6 +735,8 @@ extern unsigned long qemu_host_page_mask; | @@ -735,6 +735,8 @@ extern unsigned long qemu_host_page_mask; | ||
735 | #define PAGE_RESERVED 0x0020 | 735 | #define PAGE_RESERVED 0x0020 |
736 | 736 | ||
737 | void page_dump(FILE *f); | 737 | void page_dump(FILE *f); |
738 | +int walk_memory_regions(void *, | ||
739 | + int (*fn)(void *, unsigned long, unsigned long, unsigned long)); | ||
738 | int page_get_flags(target_ulong address); | 740 | int page_get_flags(target_ulong address); |
739 | void page_set_flags(target_ulong start, target_ulong end, int flags); | 741 | void page_set_flags(target_ulong start, target_ulong end, int flags); |
740 | int page_check_range(target_ulong start, target_ulong len, int flags); | 742 | int page_check_range(target_ulong start, target_ulong len, int flags); |
elf.h
@@ -1081,7 +1081,23 @@ typedef struct elf64_shdr { | @@ -1081,7 +1081,23 @@ typedef struct elf64_shdr { | ||
1081 | #define EI_CLASS 4 | 1081 | #define EI_CLASS 4 |
1082 | #define EI_DATA 5 | 1082 | #define EI_DATA 5 |
1083 | #define EI_VERSION 6 | 1083 | #define EI_VERSION 6 |
1084 | -#define EI_PAD 7 | 1084 | +#define EI_OSABI 7 |
1085 | +#define EI_PAD 8 | ||
1086 | + | ||
1087 | +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ | ||
1088 | +#define ELFOSABI_SYSV 0 /* Alias. */ | ||
1089 | +#define ELFOSABI_HPUX 1 /* HP-UX */ | ||
1090 | +#define ELFOSABI_NETBSD 2 /* NetBSD. */ | ||
1091 | +#define ELFOSABI_LINUX 3 /* Linux. */ | ||
1092 | +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ | ||
1093 | +#define ELFOSABI_AIX 7 /* IBM AIX. */ | ||
1094 | +#define ELFOSABI_IRIX 8 /* SGI Irix. */ | ||
1095 | +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ | ||
1096 | +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ | ||
1097 | +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ | ||
1098 | +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ | ||
1099 | +#define ELFOSABI_ARM 97 /* ARM */ | ||
1100 | +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ | ||
1085 | 1101 | ||
1086 | #define ELFMAG0 0x7f /* EI_MAG */ | 1102 | #define ELFMAG0 0x7f /* EI_MAG */ |
1087 | #define ELFMAG1 'E' | 1103 | #define ELFMAG1 'E' |
@@ -1108,6 +1124,7 @@ typedef struct elf64_shdr { | @@ -1108,6 +1124,7 @@ typedef struct elf64_shdr { | ||
1108 | #define NT_PRFPREG 2 | 1124 | #define NT_PRFPREG 2 |
1109 | #define NT_PRPSINFO 3 | 1125 | #define NT_PRPSINFO 3 |
1110 | #define NT_TASKSTRUCT 4 | 1126 | #define NT_TASKSTRUCT 4 |
1127 | +#define NT_AUXV 6 | ||
1111 | #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ | 1128 | #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ |
1112 | 1129 | ||
1113 | 1130 |
exec.c
@@ -2131,36 +2131,36 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, | @@ -2131,36 +2131,36 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, | ||
2131 | return 0; | 2131 | return 0; |
2132 | } | 2132 | } |
2133 | 2133 | ||
2134 | -/* dump memory mappings */ | ||
2135 | -void page_dump(FILE *f) | 2134 | +/* |
2135 | + * Walks guest process memory "regions" one by one | ||
2136 | + * and calls callback function 'fn' for each region. | ||
2137 | + */ | ||
2138 | +int walk_memory_regions(void *priv, | ||
2139 | + int (*fn)(void *, unsigned long, unsigned long, unsigned long)) | ||
2136 | { | 2140 | { |
2137 | unsigned long start, end; | 2141 | unsigned long start, end; |
2142 | + PageDesc *p = NULL; | ||
2138 | int i, j, prot, prot1; | 2143 | int i, j, prot, prot1; |
2139 | - PageDesc *p; | 2144 | + int rc = 0; |
2140 | 2145 | ||
2141 | - fprintf(f, "%-8s %-8s %-8s %s\n", | ||
2142 | - "start", "end", "size", "prot"); | ||
2143 | - start = -1; | ||
2144 | - end = -1; | 2146 | + start = end = -1; |
2145 | prot = 0; | 2147 | prot = 0; |
2146 | - for(i = 0; i <= L1_SIZE; i++) { | ||
2147 | - if (i < L1_SIZE) | ||
2148 | - p = l1_map[i]; | ||
2149 | - else | ||
2150 | - p = NULL; | ||
2151 | - for(j = 0;j < L2_SIZE; j++) { | ||
2152 | - if (!p) | ||
2153 | - prot1 = 0; | ||
2154 | - else | ||
2155 | - prot1 = p[j].flags; | 2148 | + |
2149 | + for (i = 0; i <= L1_SIZE; i++) { | ||
2150 | + p = (i < L1_SIZE) ? l1_map[i] : NULL; | ||
2151 | + for (j = 0; j < L2_SIZE; j++) { | ||
2152 | + prot1 = (p == NULL) ? 0 : p[j].flags; | ||
2153 | + /* | ||
2154 | + * "region" is one continuous chunk of memory | ||
2155 | + * that has same protection flags set. | ||
2156 | + */ | ||
2156 | if (prot1 != prot) { | 2157 | if (prot1 != prot) { |
2157 | end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); | 2158 | end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); |
2158 | if (start != -1) { | 2159 | if (start != -1) { |
2159 | - fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", | ||
2160 | - start, end, end - start, | ||
2161 | - prot & PAGE_READ ? 'r' : '-', | ||
2162 | - prot & PAGE_WRITE ? 'w' : '-', | ||
2163 | - prot & PAGE_EXEC ? 'x' : '-'); | 2160 | + rc = (*fn)(priv, start, end, prot); |
2161 | + /* callback can stop iteration by returning != 0 */ | ||
2162 | + if (rc != 0) | ||
2163 | + return (rc); | ||
2164 | } | 2164 | } |
2165 | if (prot1 != 0) | 2165 | if (prot1 != 0) |
2166 | start = end; | 2166 | start = end; |
@@ -2168,10 +2168,33 @@ void page_dump(FILE *f) | @@ -2168,10 +2168,33 @@ void page_dump(FILE *f) | ||
2168 | start = -1; | 2168 | start = -1; |
2169 | prot = prot1; | 2169 | prot = prot1; |
2170 | } | 2170 | } |
2171 | - if (!p) | 2171 | + if (p == NULL) |
2172 | break; | 2172 | break; |
2173 | } | 2173 | } |
2174 | } | 2174 | } |
2175 | + return (rc); | ||
2176 | +} | ||
2177 | + | ||
2178 | +static int dump_region(void *priv, unsigned long start, | ||
2179 | + unsigned long end, unsigned long prot) | ||
2180 | +{ | ||
2181 | + FILE *f = (FILE *)priv; | ||
2182 | + | ||
2183 | + (void) fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", | ||
2184 | + start, end, end - start, | ||
2185 | + ((prot & PAGE_READ) ? 'r' : '-'), | ||
2186 | + ((prot & PAGE_WRITE) ? 'w' : '-'), | ||
2187 | + ((prot & PAGE_EXEC) ? 'x' : '-')); | ||
2188 | + | ||
2189 | + return (0); | ||
2190 | +} | ||
2191 | + | ||
2192 | +/* dump memory mappings */ | ||
2193 | +void page_dump(FILE *f) | ||
2194 | +{ | ||
2195 | + (void) fprintf(f, "%-8s %-8s %-8s %s\n", | ||
2196 | + "start", "end", "size", "prot"); | ||
2197 | + walk_memory_regions(f, dump_region); | ||
2175 | } | 2198 | } |
2176 | 2199 | ||
2177 | int page_get_flags(target_ulong address) | 2200 | int page_get_flags(target_ulong address) |
linux-user/elfload.c
1 | /* This is the Linux kernel elf-loading code, ported into user space */ | 1 | /* This is the Linux kernel elf-loading code, ported into user space */ |
2 | +#include <sys/time.h> | ||
3 | +#include <sys/param.h> | ||
2 | 4 | ||
3 | #include <stdio.h> | 5 | #include <stdio.h> |
4 | #include <sys/types.h> | 6 | #include <sys/types.h> |
@@ -6,8 +8,10 @@ | @@ -6,8 +8,10 @@ | ||
6 | #include <errno.h> | 8 | #include <errno.h> |
7 | #include <unistd.h> | 9 | #include <unistd.h> |
8 | #include <sys/mman.h> | 10 | #include <sys/mman.h> |
11 | +#include <sys/resource.h> | ||
9 | #include <stdlib.h> | 12 | #include <stdlib.h> |
10 | #include <string.h> | 13 | #include <string.h> |
14 | +#include <time.h> | ||
11 | 15 | ||
12 | #include "qemu.h" | 16 | #include "qemu.h" |
13 | #include "disas.h" | 17 | #include "disas.h" |
@@ -21,6 +25,8 @@ | @@ -21,6 +25,8 @@ | ||
21 | #undef ELF_ARCH | 25 | #undef ELF_ARCH |
22 | #endif | 26 | #endif |
23 | 27 | ||
28 | +#define ELF_OSABI ELFOSABI_SYSV | ||
29 | + | ||
24 | /* from personality.h */ | 30 | /* from personality.h */ |
25 | 31 | ||
26 | /* | 32 | /* |
@@ -160,7 +166,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | @@ -160,7 +166,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
160 | } | 166 | } |
161 | #endif | 167 | #endif |
162 | 168 | ||
163 | -#define USE_ELF_CORE_DUMP | ||
164 | #define ELF_EXEC_PAGESIZE 4096 | 169 | #define ELF_EXEC_PAGESIZE 4096 |
165 | 170 | ||
166 | #endif | 171 | #endif |
@@ -198,6 +203,37 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | @@ -198,6 +203,37 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
198 | regs->ARM_r10 = infop->start_data; | 203 | regs->ARM_r10 = infop->start_data; |
199 | } | 204 | } |
200 | 205 | ||
206 | +typedef uint32_t elf_greg_t; | ||
207 | +typedef uint16_t target_uid_t; | ||
208 | +typedef uint16_t target_gid_t; | ||
209 | +typedef int32_t target_pid_t; | ||
210 | + | ||
211 | +#define ELF_NREG 18 | ||
212 | +typedef elf_greg_t elf_gregset_t[ELF_NREG]; | ||
213 | + | ||
214 | +static void elf_core_copy_regs(elf_gregset_t *regs, const CPUState *env) | ||
215 | +{ | ||
216 | + (*regs)[0] = env->regs[0]; | ||
217 | + (*regs)[1] = env->regs[1]; | ||
218 | + (*regs)[2] = env->regs[2]; | ||
219 | + (*regs)[3] = env->regs[3]; | ||
220 | + (*regs)[4] = env->regs[4]; | ||
221 | + (*regs)[5] = env->regs[5]; | ||
222 | + (*regs)[6] = env->regs[6]; | ||
223 | + (*regs)[7] = env->regs[7]; | ||
224 | + (*regs)[8] = env->regs[8]; | ||
225 | + (*regs)[9] = env->regs[9]; | ||
226 | + (*regs)[10] = env->regs[10]; | ||
227 | + (*regs)[11] = env->regs[11]; | ||
228 | + (*regs)[12] = env->regs[12]; | ||
229 | + (*regs)[13] = env->regs[13]; | ||
230 | + (*regs)[14] = env->regs[14]; | ||
231 | + (*regs)[15] = env->regs[15]; | ||
232 | + | ||
233 | + (*regs)[16] = cpsr_read((CPUState *)env); | ||
234 | + (*regs)[17] = env->regs[0]; /* XXX */ | ||
235 | +} | ||
236 | + | ||
201 | #define USE_ELF_CORE_DUMP | 237 | #define USE_ELF_CORE_DUMP |
202 | #define ELF_EXEC_PAGESIZE 4096 | 238 | #define ELF_EXEC_PAGESIZE 4096 |
203 | 239 | ||
@@ -418,7 +454,6 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * | @@ -418,7 +454,6 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * | ||
418 | _regs->gpr[5] = pos; | 454 | _regs->gpr[5] = pos; |
419 | } | 455 | } |
420 | 456 | ||
421 | -#define USE_ELF_CORE_DUMP | ||
422 | #define ELF_EXEC_PAGESIZE 4096 | 457 | #define ELF_EXEC_PAGESIZE 4096 |
423 | 458 | ||
424 | #endif | 459 | #endif |
@@ -448,7 +483,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | @@ -448,7 +483,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
448 | regs->regs[29] = infop->start_stack; | 483 | regs->regs[29] = infop->start_stack; |
449 | } | 484 | } |
450 | 485 | ||
451 | -#define USE_ELF_CORE_DUMP | ||
452 | #define ELF_EXEC_PAGESIZE 4096 | 486 | #define ELF_EXEC_PAGESIZE 4096 |
453 | 487 | ||
454 | #endif /* TARGET_MIPS */ | 488 | #endif /* TARGET_MIPS */ |
@@ -470,7 +504,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | @@ -470,7 +504,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
470 | 504 | ||
471 | } | 505 | } |
472 | 506 | ||
473 | -#define USE_ELF_CORE_DUMP | ||
474 | #define ELF_EXEC_PAGESIZE 4096 | 507 | #define ELF_EXEC_PAGESIZE 4096 |
475 | 508 | ||
476 | #endif /* TARGET_MICROBLAZE */ | 509 | #endif /* TARGET_MICROBLAZE */ |
@@ -492,7 +525,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | @@ -492,7 +525,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
492 | regs->regs[15] = infop->start_stack; | 525 | regs->regs[15] = infop->start_stack; |
493 | } | 526 | } |
494 | 527 | ||
495 | -#define USE_ELF_CORE_DUMP | ||
496 | #define ELF_EXEC_PAGESIZE 4096 | 528 | #define ELF_EXEC_PAGESIZE 4096 |
497 | 529 | ||
498 | #endif | 530 | #endif |
@@ -512,7 +544,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | @@ -512,7 +544,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
512 | regs->erp = infop->entry; | 544 | regs->erp = infop->entry; |
513 | } | 545 | } |
514 | 546 | ||
515 | -#define USE_ELF_CORE_DUMP | ||
516 | #define ELF_EXEC_PAGESIZE 8192 | 547 | #define ELF_EXEC_PAGESIZE 8192 |
517 | 548 | ||
518 | #endif | 549 | #endif |
@@ -537,7 +568,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | @@ -537,7 +568,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
537 | regs->pc = infop->entry; | 568 | regs->pc = infop->entry; |
538 | } | 569 | } |
539 | 570 | ||
540 | -#define USE_ELF_CORE_DUMP | ||
541 | #define ELF_EXEC_PAGESIZE 8192 | 571 | #define ELF_EXEC_PAGESIZE 8192 |
542 | 572 | ||
543 | #endif | 573 | #endif |
@@ -562,7 +592,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | @@ -562,7 +592,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
562 | regs->unique, infop->start_data); | 592 | regs->unique, infop->start_data); |
563 | } | 593 | } |
564 | 594 | ||
565 | -#define USE_ELF_CORE_DUMP | ||
566 | #define ELF_EXEC_PAGESIZE 8192 | 595 | #define ELF_EXEC_PAGESIZE 8192 |
567 | 596 | ||
568 | #endif /* TARGET_ALPHA */ | 597 | #endif /* TARGET_ALPHA */ |
@@ -680,6 +709,20 @@ static void bswap_sym(struct elf_sym *sym) | @@ -680,6 +709,20 @@ static void bswap_sym(struct elf_sym *sym) | ||
680 | } | 709 | } |
681 | #endif | 710 | #endif |
682 | 711 | ||
712 | +#ifdef USE_ELF_CORE_DUMP | ||
713 | +static int elf_core_dump(int, const CPUState *); | ||
714 | + | ||
715 | +#ifdef BSWAP_NEEDED | ||
716 | +static void bswap_note(struct elf_note *en) | ||
717 | +{ | ||
718 | + bswaptls(&en->n_namesz); | ||
719 | + bswaptls(&en->n_descsz); | ||
720 | + bswaptls(&en->n_type); | ||
721 | +} | ||
722 | +#endif /* BSWAP_NEEDED */ | ||
723 | + | ||
724 | +#endif /* USE_ELF_CORE_DUMP */ | ||
725 | + | ||
683 | /* | 726 | /* |
684 | * 'copy_elf_strings()' copies argument/envelope strings from user | 727 | * 'copy_elf_strings()' copies argument/envelope strings from user |
685 | * memory to free pages in kernel mem. These are in a format ready | 728 | * memory to free pages in kernel mem. These are in a format ready |
@@ -904,6 +947,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, | @@ -904,6 +947,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, | ||
904 | #endif | 947 | #endif |
905 | #undef NEW_AUX_ENT | 948 | #undef NEW_AUX_ENT |
906 | 949 | ||
950 | + info->saved_auxv = sp; | ||
951 | + | ||
907 | sp = loader_build_argptr(envc, argc, sp, p, !ibcs); | 952 | sp = loader_build_argptr(envc, argc, sp, p, !ibcs); |
908 | return sp; | 953 | return sp; |
909 | } | 954 | } |
@@ -1586,9 +1631,876 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, | @@ -1586,9 +1631,876 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, | ||
1586 | 1631 | ||
1587 | info->entry = elf_entry; | 1632 | info->entry = elf_entry; |
1588 | 1633 | ||
1634 | +#ifdef USE_ELF_CORE_DUMP | ||
1635 | + bprm->core_dump = &elf_core_dump; | ||
1636 | +#endif | ||
1637 | + | ||
1589 | return 0; | 1638 | return 0; |
1590 | } | 1639 | } |
1591 | 1640 | ||
1641 | +#ifdef USE_ELF_CORE_DUMP | ||
1642 | + | ||
1643 | +/* | ||
1644 | + * Definitions to generate Intel SVR4-like core files. | ||
1645 | + * These mostly have the same names as the SVR4 types with "elf_" | ||
1646 | + * tacked on the front to prevent clashes with linux definitions, | ||
1647 | + * and the typedef forms have been avoided. This is mostly like | ||
1648 | + * the SVR4 structure, but more Linuxy, with things that Linux does | ||
1649 | + * not support and which gdb doesn't really use excluded. | ||
1650 | + * | ||
1651 | + * Fields we don't dump (their contents is zero) in linux-user qemu | ||
1652 | + * are marked with XXX. | ||
1653 | + * | ||
1654 | + * Core dump code is copied from linux kernel (fs/binfmt_elf.c). | ||
1655 | + * | ||
1656 | + * Porting ELF coredump for target is (quite) simple process. First you | ||
1657 | + * define ELF_USE_CORE_DUMP in target ELF code (where init_thread() for | ||
1658 | + * the target resides): | ||
1659 | + * | ||
1660 | + * #define USE_ELF_CORE_DUMP | ||
1661 | + * | ||
1662 | + * Next you define type of register set used for dumping. ELF specification | ||
1663 | + * says that it needs to be array of elf_greg_t that has size of ELF_NREG. | ||
1664 | + * | ||
1665 | + * typedef <target_regtype> elf_greg_t; | ||
1666 | + * #define ELF_NREG <number of registers> | ||
1667 | + * typedef elf_greg_t elf_gregset_t[ELF_NREG]; | ||
1668 | + * | ||
1669 | + * Then define following types to match target types. Actual types can | ||
1670 | + * be found from linux kernel (arch/<ARCH>/include/asm/posix_types.h): | ||
1671 | + * | ||
1672 | + * typedef <target_uid_type> target_uid_t; | ||
1673 | + * typedef <target_gid_type> target_gid_t; | ||
1674 | + * typedef <target_pid_type> target_pid_t; | ||
1675 | + * | ||
1676 | + * Last step is to implement target specific function that copies registers | ||
1677 | + * from given cpu into just specified register set. Prototype is: | ||
1678 | + * | ||
1679 | + * static void elf_core_copy_regs(elf_gregset_t *regs, const CPUState *env); | ||
1680 | + * | ||
1681 | + * Parameters: | ||
1682 | + * regs - copy register values into here (allocated and zeroed by caller) | ||
1683 | + * env - copy registers from here | ||
1684 | + * | ||
1685 | + * Example for ARM target is provided in this file. | ||
1686 | + */ | ||
1687 | + | ||
1688 | +/* An ELF note in memory */ | ||
1689 | +struct memelfnote { | ||
1690 | + const char *name; | ||
1691 | + size_t namesz; | ||
1692 | + size_t namesz_rounded; | ||
1693 | + int type; | ||
1694 | + size_t datasz; | ||
1695 | + void *data; | ||
1696 | + size_t notesz; | ||
1697 | +}; | ||
1698 | + | ||
1699 | +struct elf_siginfo { | ||
1700 | + int si_signo; /* signal number */ | ||
1701 | + int si_code; /* extra code */ | ||
1702 | + int si_errno; /* errno */ | ||
1703 | +}; | ||
1704 | + | ||
1705 | +struct elf_prstatus { | ||
1706 | + struct elf_siginfo pr_info; /* Info associated with signal */ | ||
1707 | + short pr_cursig; /* Current signal */ | ||
1708 | + target_ulong pr_sigpend; /* XXX */ | ||
1709 | + target_ulong pr_sighold; /* XXX */ | ||
1710 | + target_pid_t pr_pid; | ||
1711 | + target_pid_t pr_ppid; | ||
1712 | + target_pid_t pr_pgrp; | ||
1713 | + target_pid_t pr_sid; | ||
1714 | + struct target_timeval pr_utime; /* XXX User time */ | ||
1715 | + struct target_timeval pr_stime; /* XXX System time */ | ||
1716 | + struct target_timeval pr_cutime; /* XXX Cumulative user time */ | ||
1717 | + struct target_timeval pr_cstime; /* XXX Cumulative system time */ | ||
1718 | + elf_gregset_t pr_reg; /* GP registers */ | ||
1719 | + int pr_fpvalid; /* XXX */ | ||
1720 | +}; | ||
1721 | + | ||
1722 | +#define ELF_PRARGSZ (80) /* Number of chars for args */ | ||
1723 | + | ||
1724 | +struct elf_prpsinfo { | ||
1725 | + char pr_state; /* numeric process state */ | ||
1726 | + char pr_sname; /* char for pr_state */ | ||
1727 | + char pr_zomb; /* zombie */ | ||
1728 | + char pr_nice; /* nice val */ | ||
1729 | + target_ulong pr_flag; /* flags */ | ||
1730 | + target_uid_t pr_uid; | ||
1731 | + target_gid_t pr_gid; | ||
1732 | + target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; | ||
1733 | + /* Lots missing */ | ||
1734 | + char pr_fname[16]; /* filename of executable */ | ||
1735 | + char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ | ||
1736 | +}; | ||
1737 | + | ||
1738 | +/* Here is the structure in which status of each thread is captured. */ | ||
1739 | +struct elf_thread_status { | ||
1740 | + TAILQ_ENTRY(elf_thread_status) ets_link; | ||
1741 | + struct elf_prstatus prstatus; /* NT_PRSTATUS */ | ||
1742 | +#if 0 | ||
1743 | + elf_fpregset_t fpu; /* NT_PRFPREG */ | ||
1744 | + struct task_struct *thread; | ||
1745 | + elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ | ||
1746 | +#endif | ||
1747 | + struct memelfnote notes[1]; | ||
1748 | + int num_notes; | ||
1749 | +}; | ||
1750 | + | ||
1751 | +struct elf_note_info { | ||
1752 | + struct memelfnote *notes; | ||
1753 | + struct elf_prstatus *prstatus; /* NT_PRSTATUS */ | ||
1754 | + struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */ | ||
1755 | + | ||
1756 | + TAILQ_HEAD(thread_list_head, elf_thread_status) thread_list; | ||
1757 | +#if 0 | ||
1758 | + /* | ||
1759 | + * Current version of ELF coredump doesn't support | ||
1760 | + * dumping fp regs etc. | ||
1761 | + */ | ||
1762 | + elf_fpregset_t *fpu; | ||
1763 | + elf_fpxregset_t *xfpu; | ||
1764 | + int thread_status_size; | ||
1765 | +#endif | ||
1766 | + int notes_size; | ||
1767 | + int numnote; | ||
1768 | +}; | ||
1769 | + | ||
1770 | +struct vm_area_struct { | ||
1771 | + abi_ulong vma_start; /* start vaddr of memory region */ | ||
1772 | + abi_ulong vma_end; /* end vaddr of memory region */ | ||
1773 | + abi_ulong vma_flags; /* protection etc. flags for the region */ | ||
1774 | + TAILQ_ENTRY(vm_area_struct) vma_link; | ||
1775 | +}; | ||
1776 | + | ||
1777 | +struct mm_struct { | ||
1778 | + TAILQ_HEAD(, vm_area_struct) mm_mmap; | ||
1779 | + int mm_count; /* number of mappings */ | ||
1780 | +}; | ||
1781 | + | ||
1782 | +static struct mm_struct *vma_init(void); | ||
1783 | +static void vma_delete(struct mm_struct *); | ||
1784 | +static int vma_add_mapping(struct mm_struct *, abi_ulong, | ||
1785 | + abi_ulong, abi_ulong); | ||
1786 | +static int vma_get_mapping_count(const struct mm_struct *); | ||
1787 | +static struct vm_area_struct *vma_first(const struct mm_struct *); | ||
1788 | +static struct vm_area_struct *vma_next(struct vm_area_struct *); | ||
1789 | +static abi_ulong vma_dump_size(const struct vm_area_struct *); | ||
1790 | +static int vma_walker(void *priv, unsigned long start, unsigned long end, | ||
1791 | + unsigned long flags); | ||
1792 | + | ||
1793 | +static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t); | ||
1794 | +static void fill_note(struct memelfnote *, const char *, int, | ||
1795 | + unsigned int, void *); | ||
1796 | +static void fill_prstatus(struct elf_prstatus *, const TaskState *, int); | ||
1797 | +static int fill_psinfo(struct elf_prpsinfo *, const TaskState *); | ||
1798 | +static void fill_auxv_note(struct memelfnote *, const TaskState *); | ||
1799 | +static void fill_elf_note_phdr(struct elf_phdr *, int, off_t); | ||
1800 | +static size_t note_size(const struct memelfnote *); | ||
1801 | +static void free_note_info(struct elf_note_info *); | ||
1802 | +static int fill_note_info(struct elf_note_info *, long, const CPUState *); | ||
1803 | +static void fill_thread_info(struct elf_note_info *, const CPUState *); | ||
1804 | +static int core_dump_filename(const TaskState *, char *, size_t); | ||
1805 | + | ||
1806 | +static int dump_write(int, const void *, size_t); | ||
1807 | +static int write_note(struct memelfnote *, int); | ||
1808 | +static int write_note_info(struct elf_note_info *, int); | ||
1809 | + | ||
1810 | +#ifdef BSWAP_NEEDED | ||
1811 | +static void bswap_prstatus(struct elf_prstatus *); | ||
1812 | +static void bswap_psinfo(struct elf_prpsinfo *); | ||
1813 | + | ||
1814 | +static void bswap_prstatus(struct elf_prstatus *prstatus) | ||
1815 | +{ | ||
1816 | + prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo); | ||
1817 | + prstatus->pr_info.si_code = tswapl(prstatus->pr_info.si_code); | ||
1818 | + prstatus->pr_info.si_errno = tswapl(prstatus->pr_info.si_errno); | ||
1819 | + prstatus->pr_cursig = tswap16(prstatus->pr_cursig); | ||
1820 | + prstatus->pr_sigpend = tswapl(prstatus->pr_sigpend); | ||
1821 | + prstatus->pr_sighold = tswapl(prstatus->pr_sighold); | ||
1822 | + prstatus->pr_pid = tswap32(prstatus->pr_pid); | ||
1823 | + prstatus->pr_ppid = tswap32(prstatus->pr_ppid); | ||
1824 | + prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp); | ||
1825 | + prstatus->pr_sid = tswap32(prstatus->pr_sid); | ||
1826 | + /* cpu times are not filled, so we skip them */ | ||
1827 | + /* regs should be in correct format already */ | ||
1828 | + prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid); | ||
1829 | +} | ||
1830 | + | ||
1831 | +static void bswap_psinfo(struct elf_prpsinfo *psinfo) | ||
1832 | +{ | ||
1833 | + psinfo->pr_flag = tswapl(psinfo->pr_flag); | ||
1834 | + psinfo->pr_uid = tswap16(psinfo->pr_uid); | ||
1835 | + psinfo->pr_gid = tswap16(psinfo->pr_gid); | ||
1836 | + psinfo->pr_pid = tswap32(psinfo->pr_pid); | ||
1837 | + psinfo->pr_ppid = tswap32(psinfo->pr_ppid); | ||
1838 | + psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp); | ||
1839 | + psinfo->pr_sid = tswap32(psinfo->pr_sid); | ||
1840 | +} | ||
1841 | +#endif /* BSWAP_NEEDED */ | ||
1842 | + | ||
1843 | +/* | ||
1844 | + * Minimal support for linux memory regions. These are needed | ||
1845 | + * when we are finding out what memory exactly belongs to | ||
1846 | + * emulated process. No locks needed here, as long as | ||
1847 | + * thread that received the signal is stopped. | ||
1848 | + */ | ||
1849 | + | ||
1850 | +static struct mm_struct *vma_init(void) | ||
1851 | +{ | ||
1852 | + struct mm_struct *mm; | ||
1853 | + | ||
1854 | + if ((mm = qemu_malloc(sizeof (*mm))) == NULL) | ||
1855 | + return (NULL); | ||
1856 | + | ||
1857 | + mm->mm_count = 0; | ||
1858 | + TAILQ_INIT(&mm->mm_mmap); | ||
1859 | + | ||
1860 | + return (mm); | ||
1861 | +} | ||
1862 | + | ||
1863 | +static void vma_delete(struct mm_struct *mm) | ||
1864 | +{ | ||
1865 | + struct vm_area_struct *vma; | ||
1866 | + | ||
1867 | + while ((vma = vma_first(mm)) != NULL) { | ||
1868 | + TAILQ_REMOVE(&mm->mm_mmap, vma, vma_link); | ||
1869 | + qemu_free(vma); | ||
1870 | + } | ||
1871 | + qemu_free(mm); | ||
1872 | +} | ||
1873 | + | ||
1874 | +static int vma_add_mapping(struct mm_struct *mm, abi_ulong start, | ||
1875 | + abi_ulong end, abi_ulong flags) | ||
1876 | +{ | ||
1877 | + struct vm_area_struct *vma; | ||
1878 | + | ||
1879 | + if ((vma = qemu_mallocz(sizeof (*vma))) == NULL) | ||
1880 | + return (-1); | ||
1881 | + | ||
1882 | + vma->vma_start = start; | ||
1883 | + vma->vma_end = end; | ||
1884 | + vma->vma_flags = flags; | ||
1885 | + | ||
1886 | + TAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link); | ||
1887 | + mm->mm_count++; | ||
1888 | + | ||
1889 | + return (0); | ||
1890 | +} | ||
1891 | + | ||
1892 | +static struct vm_area_struct *vma_first(const struct mm_struct *mm) | ||
1893 | +{ | ||
1894 | + return (TAILQ_FIRST(&mm->mm_mmap)); | ||
1895 | +} | ||
1896 | + | ||
1897 | +static struct vm_area_struct *vma_next(struct vm_area_struct *vma) | ||
1898 | +{ | ||
1899 | + return (TAILQ_NEXT(vma, vma_link)); | ||
1900 | +} | ||
1901 | + | ||
1902 | +static int vma_get_mapping_count(const struct mm_struct *mm) | ||
1903 | +{ | ||
1904 | + return (mm->mm_count); | ||
1905 | +} | ||
1906 | + | ||
1907 | +/* | ||
1908 | + * Calculate file (dump) size of given memory region. | ||
1909 | + */ | ||
1910 | +static abi_ulong vma_dump_size(const struct vm_area_struct *vma) | ||
1911 | +{ | ||
1912 | + /* if we cannot even read the first page, skip it */ | ||
1913 | + if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE)) | ||
1914 | + return (0); | ||
1915 | + | ||
1916 | + /* | ||
1917 | + * Usually we don't dump executable pages as they contain | ||
1918 | + * non-writable code that debugger can read directly from | ||
1919 | + * target library etc. However, thread stacks are marked | ||
1920 | + * also executable so we read in first page of given region | ||
1921 | + * and check whether it contains elf header. If there is | ||
1922 | + * no elf header, we dump it. | ||
1923 | + */ | ||
1924 | + if (vma->vma_flags & PROT_EXEC) { | ||
1925 | + char page[TARGET_PAGE_SIZE]; | ||
1926 | + | ||
1927 | + copy_from_user(page, vma->vma_start, sizeof (page)); | ||
1928 | + if ((page[EI_MAG0] == ELFMAG0) && | ||
1929 | + (page[EI_MAG1] == ELFMAG1) && | ||
1930 | + (page[EI_MAG2] == ELFMAG2) && | ||
1931 | + (page[EI_MAG3] == ELFMAG3)) { | ||
1932 | + /* | ||
1933 | + * Mappings are possibly from ELF binary. Don't dump | ||
1934 | + * them. | ||
1935 | + */ | ||
1936 | + return (0); | ||
1937 | + } | ||
1938 | + } | ||
1939 | + | ||
1940 | + return (vma->vma_end - vma->vma_start); | ||
1941 | +} | ||
1942 | + | ||
1943 | +static int vma_walker(void *priv, unsigned long start, unsigned long end, | ||
1944 | + unsigned long flags) | ||
1945 | +{ | ||
1946 | + struct mm_struct *mm = (struct mm_struct *)priv; | ||
1947 | + | ||
1948 | + /* | ||
1949 | + * Don't dump anything that qemu has reserved for internal use. | ||
1950 | + */ | ||
1951 | + if (flags & PAGE_RESERVED) | ||
1952 | + return (0); | ||
1953 | + | ||
1954 | + vma_add_mapping(mm, start, end, flags); | ||
1955 | + return (0); | ||
1956 | +} | ||
1957 | + | ||
1958 | +static void fill_note(struct memelfnote *note, const char *name, int type, | ||
1959 | + unsigned int sz, void *data) | ||
1960 | +{ | ||
1961 | + unsigned int namesz; | ||
1962 | + | ||
1963 | + namesz = strlen(name) + 1; | ||
1964 | + note->name = name; | ||
1965 | + note->namesz = namesz; | ||
1966 | + note->namesz_rounded = roundup(namesz, sizeof (int32_t)); | ||
1967 | + note->type = type; | ||
1968 | + note->datasz = roundup(sz, sizeof (int32_t));; | ||
1969 | + note->data = data; | ||
1970 | + | ||
1971 | + /* | ||
1972 | + * We calculate rounded up note size here as specified by | ||
1973 | + * ELF document. | ||
1974 | + */ | ||
1975 | + note->notesz = sizeof (struct elf_note) + | ||
1976 | + note->namesz_rounded + note->datasz; | ||
1977 | +} | ||
1978 | + | ||
1979 | +static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine, | ||
1980 | + uint32_t flags) | ||
1981 | +{ | ||
1982 | + (void) memset(elf, 0, sizeof(*elf)); | ||
1983 | + | ||
1984 | + (void) memcpy(elf->e_ident, ELFMAG, SELFMAG); | ||
1985 | + elf->e_ident[EI_CLASS] = ELF_CLASS; | ||
1986 | + elf->e_ident[EI_DATA] = ELF_DATA; | ||
1987 | + elf->e_ident[EI_VERSION] = EV_CURRENT; | ||
1988 | + elf->e_ident[EI_OSABI] = ELF_OSABI; | ||
1989 | + | ||
1990 | + elf->e_type = ET_CORE; | ||
1991 | + elf->e_machine = machine; | ||
1992 | + elf->e_version = EV_CURRENT; | ||
1993 | + elf->e_phoff = sizeof(struct elfhdr); | ||
1994 | + elf->e_flags = flags; | ||
1995 | + elf->e_ehsize = sizeof(struct elfhdr); | ||
1996 | + elf->e_phentsize = sizeof(struct elf_phdr); | ||
1997 | + elf->e_phnum = segs; | ||
1998 | + | ||
1999 | +#ifdef BSWAP_NEEDED | ||
2000 | + bswap_ehdr(elf); | ||
2001 | +#endif | ||
2002 | +} | ||
2003 | + | ||
2004 | +static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset) | ||
2005 | +{ | ||
2006 | + phdr->p_type = PT_NOTE; | ||
2007 | + phdr->p_offset = offset; | ||
2008 | + phdr->p_vaddr = 0; | ||
2009 | + phdr->p_paddr = 0; | ||
2010 | + phdr->p_filesz = sz; | ||
2011 | + phdr->p_memsz = 0; | ||
2012 | + phdr->p_flags = 0; | ||
2013 | + phdr->p_align = 0; | ||
2014 | + | ||
2015 | +#ifdef BSWAP_NEEDED | ||
2016 | + bswap_phdr(phdr); | ||
2017 | +#endif | ||
2018 | +} | ||
2019 | + | ||
2020 | +static size_t note_size(const struct memelfnote *note) | ||
2021 | +{ | ||
2022 | + return (note->notesz); | ||
2023 | +} | ||
2024 | + | ||
2025 | +static void fill_prstatus(struct elf_prstatus *prstatus, | ||
2026 | + const TaskState *ts, int signr) | ||
2027 | +{ | ||
2028 | + (void) memset(prstatus, 0, sizeof (*prstatus)); | ||
2029 | + prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; | ||
2030 | + prstatus->pr_pid = ts->ts_tid; | ||
2031 | + prstatus->pr_ppid = getppid(); | ||
2032 | + prstatus->pr_pgrp = getpgrp(); | ||
2033 | + prstatus->pr_sid = getsid(0); | ||
2034 | + | ||
2035 | +#ifdef BSWAP_NEEDED | ||
2036 | + bswap_prstatus(prstatus); | ||
2037 | +#endif | ||
2038 | +} | ||
2039 | + | ||
2040 | +static int fill_psinfo(struct elf_prpsinfo *psinfo, const TaskState *ts) | ||
2041 | +{ | ||
2042 | + char *filename, *base_filename; | ||
2043 | + unsigned int i, len; | ||
2044 | + | ||
2045 | + (void) memset(psinfo, 0, sizeof (*psinfo)); | ||
2046 | + | ||
2047 | + len = ts->info->arg_end - ts->info->arg_start; | ||
2048 | + if (len >= ELF_PRARGSZ) | ||
2049 | + len = ELF_PRARGSZ - 1; | ||
2050 | + if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len)) | ||
2051 | + return -EFAULT; | ||
2052 | + for (i = 0; i < len; i++) | ||
2053 | + if (psinfo->pr_psargs[i] == 0) | ||
2054 | + psinfo->pr_psargs[i] = ' '; | ||
2055 | + psinfo->pr_psargs[len] = 0; | ||
2056 | + | ||
2057 | + psinfo->pr_pid = getpid(); | ||
2058 | + psinfo->pr_ppid = getppid(); | ||
2059 | + psinfo->pr_pgrp = getpgrp(); | ||
2060 | + psinfo->pr_sid = getsid(0); | ||
2061 | + psinfo->pr_uid = getuid(); | ||
2062 | + psinfo->pr_gid = getgid(); | ||
2063 | + | ||
2064 | + filename = strdup(ts->bprm->filename); | ||
2065 | + base_filename = strdup(basename(filename)); | ||
2066 | + (void) strncpy(psinfo->pr_fname, base_filename, | ||
2067 | + sizeof(psinfo->pr_fname)); | ||
2068 | + free(base_filename); | ||
2069 | + free(filename); | ||
2070 | + | ||
2071 | +#ifdef BSWAP_NEEDED | ||
2072 | + bswap_psinfo(psinfo); | ||
2073 | +#endif | ||
2074 | + return (0); | ||
2075 | +} | ||
2076 | + | ||
2077 | +static void fill_auxv_note(struct memelfnote *note, const TaskState *ts) | ||
2078 | +{ | ||
2079 | + elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv; | ||
2080 | + elf_addr_t orig_auxv = auxv; | ||
2081 | + abi_ulong val; | ||
2082 | + void *ptr; | ||
2083 | + int i, len; | ||
2084 | + | ||
2085 | + /* | ||
2086 | + * Auxiliary vector is stored in target process stack. It contains | ||
2087 | + * {type, value} pairs that we need to dump into note. This is not | ||
2088 | + * strictly necessary but we do it here for sake of completeness. | ||
2089 | + */ | ||
2090 | + | ||
2091 | + /* find out lenght of the vector, AT_NULL is terminator */ | ||
2092 | + i = len = 0; | ||
2093 | + do { | ||
2094 | + get_user_ual(val, auxv); | ||
2095 | + i += 2; | ||
2096 | + auxv += 2 * sizeof (elf_addr_t); | ||
2097 | + } while (val != AT_NULL); | ||
2098 | + len = i * sizeof (elf_addr_t); | ||
2099 | + | ||
2100 | + /* read in whole auxv vector and copy it to memelfnote */ | ||
2101 | + ptr = lock_user(VERIFY_READ, orig_auxv, len, 0); | ||
2102 | + if (ptr != NULL) { | ||
2103 | + fill_note(note, "CORE", NT_AUXV, len, ptr); | ||
2104 | + unlock_user(ptr, auxv, len); | ||
2105 | + } | ||
2106 | +} | ||
2107 | + | ||
2108 | +/* | ||
2109 | + * Constructs name of coredump file. We have following convention | ||
2110 | + * for the name: | ||
2111 | + * qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core | ||
2112 | + * | ||
2113 | + * Returns 0 in case of success, -1 otherwise (errno is set). | ||
2114 | + */ | ||
2115 | +static int core_dump_filename(const TaskState *ts, char *buf, | ||
2116 | + size_t bufsize) | ||
2117 | +{ | ||
2118 | + char timestamp[64]; | ||
2119 | + char *filename = NULL; | ||
2120 | + char *base_filename = NULL; | ||
2121 | + struct timeval tv; | ||
2122 | + struct tm tm; | ||
2123 | + | ||
2124 | + assert(bufsize >= PATH_MAX); | ||
2125 | + | ||
2126 | + if (gettimeofday(&tv, NULL) < 0) { | ||
2127 | + (void) fprintf(stderr, "unable to get current timestamp: %s", | ||
2128 | + strerror(errno)); | ||
2129 | + return (-1); | ||
2130 | + } | ||
2131 | + | ||
2132 | + filename = strdup(ts->bprm->filename); | ||
2133 | + base_filename = strdup(basename(filename)); | ||
2134 | + (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S", | ||
2135 | + localtime_r(&tv.tv_sec, &tm)); | ||
2136 | + (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core", | ||
2137 | + base_filename, timestamp, (int)getpid()); | ||
2138 | + free(base_filename); | ||
2139 | + free(filename); | ||
2140 | + | ||
2141 | + return (0); | ||
2142 | +} | ||
2143 | + | ||
2144 | +static int dump_write(int fd, const void *ptr, size_t size) | ||
2145 | +{ | ||
2146 | + const char *bufp = (const char *)ptr; | ||
2147 | + ssize_t bytes_written, bytes_left; | ||
2148 | + struct rlimit dumpsize; | ||
2149 | + off_t pos; | ||
2150 | + | ||
2151 | + bytes_written = 0; | ||
2152 | + getrlimit(RLIMIT_CORE, &dumpsize); | ||
2153 | + if ((pos = lseek(fd, 0, SEEK_CUR))==-1) { | ||
2154 | + if (errno == ESPIPE) { /* not a seekable stream */ | ||
2155 | + bytes_left = size; | ||
2156 | + } else { | ||
2157 | + return pos; | ||
2158 | + } | ||
2159 | + } else { | ||
2160 | + if (dumpsize.rlim_cur <= pos) { | ||
2161 | + return -1; | ||
2162 | + } else if (dumpsize.rlim_cur == RLIM_INFINITY) { | ||
2163 | + bytes_left = size; | ||
2164 | + } else { | ||
2165 | + size_t limit_left=dumpsize.rlim_cur - pos; | ||
2166 | + bytes_left = limit_left >= size ? size : limit_left ; | ||
2167 | + } | ||
2168 | + } | ||
2169 | + | ||
2170 | + /* | ||
2171 | + * In normal conditions, single write(2) should do but | ||
2172 | + * in case of socket etc. this mechanism is more portable. | ||
2173 | + */ | ||
2174 | + do { | ||
2175 | + bytes_written = write(fd, bufp, bytes_left); | ||
2176 | + if (bytes_written < 0) { | ||
2177 | + if (errno == EINTR) | ||
2178 | + continue; | ||
2179 | + return (-1); | ||
2180 | + } else if (bytes_written == 0) { /* eof */ | ||
2181 | + return (-1); | ||
2182 | + } | ||
2183 | + bufp += bytes_written; | ||
2184 | + bytes_left -= bytes_written; | ||
2185 | + } while (bytes_left > 0); | ||
2186 | + | ||
2187 | + return (0); | ||
2188 | +} | ||
2189 | + | ||
2190 | +static int write_note(struct memelfnote *men, int fd) | ||
2191 | +{ | ||
2192 | + struct elf_note en; | ||
2193 | + | ||
2194 | + en.n_namesz = men->namesz; | ||
2195 | + en.n_type = men->type; | ||
2196 | + en.n_descsz = men->datasz; | ||
2197 | + | ||
2198 | +#ifdef BSWAP_NEEDED | ||
2199 | + bswap_note(&en); | ||
2200 | +#endif | ||
2201 | + | ||
2202 | + if (dump_write(fd, &en, sizeof(en)) != 0) | ||
2203 | + return (-1); | ||
2204 | + if (dump_write(fd, men->name, men->namesz_rounded) != 0) | ||
2205 | + return (-1); | ||
2206 | + if (dump_write(fd, men->data, men->datasz) != 0) | ||
2207 | + return (-1); | ||
2208 | + | ||
2209 | + return (0); | ||
2210 | +} | ||
2211 | + | ||
2212 | +static void fill_thread_info(struct elf_note_info *info, const CPUState *env) | ||
2213 | +{ | ||
2214 | + TaskState *ts = (TaskState *)env->opaque; | ||
2215 | + struct elf_thread_status *ets; | ||
2216 | + | ||
2217 | + ets = qemu_mallocz(sizeof (*ets)); | ||
2218 | + ets->num_notes = 1; /* only prstatus is dumped */ | ||
2219 | + fill_prstatus(&ets->prstatus, ts, 0); | ||
2220 | + elf_core_copy_regs(&ets->prstatus.pr_reg, env); | ||
2221 | + fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus), | ||
2222 | + &ets->prstatus); | ||
2223 | + | ||
2224 | + TAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link); | ||
2225 | + | ||
2226 | + info->notes_size += note_size(&ets->notes[0]); | ||
2227 | +} | ||
2228 | + | ||
2229 | +static int fill_note_info(struct elf_note_info *info, | ||
2230 | + long signr, const CPUState *env) | ||
2231 | +{ | ||
2232 | +#define NUMNOTES 3 | ||
2233 | + CPUState *cpu = NULL; | ||
2234 | + TaskState *ts = (TaskState *)env->opaque; | ||
2235 | + int i; | ||
2236 | + | ||
2237 | + (void) memset(info, 0, sizeof (*info)); | ||
2238 | + | ||
2239 | + TAILQ_INIT(&info->thread_list); | ||
2240 | + | ||
2241 | + info->notes = qemu_mallocz(NUMNOTES * sizeof (struct memelfnote)); | ||
2242 | + if (info->notes == NULL) | ||
2243 | + return (-ENOMEM); | ||
2244 | + info->prstatus = qemu_mallocz(sizeof (*info->prstatus)); | ||
2245 | + if (info->prstatus == NULL) | ||
2246 | + return (-ENOMEM); | ||
2247 | + info->psinfo = qemu_mallocz(sizeof (*info->psinfo)); | ||
2248 | + if (info->prstatus == NULL) | ||
2249 | + return (-ENOMEM); | ||
2250 | + | ||
2251 | + /* | ||
2252 | + * First fill in status (and registers) of current thread | ||
2253 | + * including process info & aux vector. | ||
2254 | + */ | ||
2255 | + fill_prstatus(info->prstatus, ts, signr); | ||
2256 | + elf_core_copy_regs(&info->prstatus->pr_reg, env); | ||
2257 | + fill_note(&info->notes[0], "CORE", NT_PRSTATUS, | ||
2258 | + sizeof (*info->prstatus), info->prstatus); | ||
2259 | + fill_psinfo(info->psinfo, ts); | ||
2260 | + fill_note(&info->notes[1], "CORE", NT_PRPSINFO, | ||
2261 | + sizeof (*info->psinfo), info->psinfo); | ||
2262 | + fill_auxv_note(&info->notes[2], ts); | ||
2263 | + info->numnote = 3; | ||
2264 | + | ||
2265 | + info->notes_size = 0; | ||
2266 | + for (i = 0; i < info->numnote; i++) | ||
2267 | + info->notes_size += note_size(&info->notes[i]); | ||
2268 | + | ||
2269 | + /* read and fill status of all threads */ | ||
2270 | + cpu_list_lock(); | ||
2271 | + for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { | ||
2272 | + if (cpu == thread_env) | ||
2273 | + continue; | ||
2274 | + fill_thread_info(info, cpu); | ||
2275 | + } | ||
2276 | + cpu_list_unlock(); | ||
2277 | + | ||
2278 | + return (0); | ||
2279 | +} | ||
2280 | + | ||
2281 | +static void free_note_info(struct elf_note_info *info) | ||
2282 | +{ | ||
2283 | + struct elf_thread_status *ets; | ||
2284 | + | ||
2285 | + while (!TAILQ_EMPTY(&info->thread_list)) { | ||
2286 | + ets = TAILQ_FIRST(&info->thread_list); | ||
2287 | + TAILQ_REMOVE(&info->thread_list, ets, ets_link); | ||
2288 | + qemu_free(ets); | ||
2289 | + } | ||
2290 | + | ||
2291 | + qemu_free(info->prstatus); | ||
2292 | + qemu_free(info->psinfo); | ||
2293 | + qemu_free(info->notes); | ||
2294 | +} | ||
2295 | + | ||
2296 | +static int write_note_info(struct elf_note_info *info, int fd) | ||
2297 | +{ | ||
2298 | + struct elf_thread_status *ets; | ||
2299 | + int i, error = 0; | ||
2300 | + | ||
2301 | + /* write prstatus, psinfo and auxv for current thread */ | ||
2302 | + for (i = 0; i < info->numnote; i++) | ||
2303 | + if ((error = write_note(&info->notes[i], fd)) != 0) | ||
2304 | + return (error); | ||
2305 | + | ||
2306 | + /* write prstatus for each thread */ | ||
2307 | + for (ets = info->thread_list.tqh_first; ets != NULL; | ||
2308 | + ets = ets->ets_link.tqe_next) { | ||
2309 | + if ((error = write_note(&ets->notes[0], fd)) != 0) | ||
2310 | + return (error); | ||
2311 | + } | ||
2312 | + | ||
2313 | + return (0); | ||
2314 | +} | ||
2315 | + | ||
2316 | +/* | ||
2317 | + * Write out ELF coredump. | ||
2318 | + * | ||
2319 | + * See documentation of ELF object file format in: | ||
2320 | + * http://www.caldera.com/developers/devspecs/gabi41.pdf | ||
2321 | + * | ||
2322 | + * Coredump format in linux is following: | ||
2323 | + * | ||
2324 | + * 0 +----------------------+ \ | ||
2325 | + * | ELF header | ET_CORE | | ||
2326 | + * +----------------------+ | | ||
2327 | + * | ELF program headers | |--- headers | ||
2328 | + * | - NOTE section | | | ||
2329 | + * | - PT_LOAD sections | | | ||
2330 | + * +----------------------+ / | ||
2331 | + * | NOTEs: | | ||
2332 | + * | - NT_PRSTATUS | | ||
2333 | + * | - NT_PRSINFO | | ||
2334 | + * | - NT_AUXV | | ||
2335 | + * +----------------------+ <-- aligned to target page | ||
2336 | + * | Process memory dump | | ||
2337 | + * : : | ||
2338 | + * . . | ||
2339 | + * : : | ||
2340 | + * | | | ||
2341 | + * +----------------------+ | ||
2342 | + * | ||
2343 | + * NT_PRSTATUS -> struct elf_prstatus (per thread) | ||
2344 | + * NT_PRSINFO -> struct elf_prpsinfo | ||
2345 | + * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()). | ||
2346 | + * | ||
2347 | + * Format follows System V format as close as possible. Current | ||
2348 | + * version limitations are as follows: | ||
2349 | + * - no floating point registers are dumped | ||
2350 | + * | ||
2351 | + * Function returns 0 in case of success, negative errno otherwise. | ||
2352 | + * | ||
2353 | + * TODO: make this work also during runtime: it should be | ||
2354 | + * possible to force coredump from running process and then | ||
2355 | + * continue processing. For example qemu could set up SIGUSR2 | ||
2356 | + * handler (provided that target process haven't registered | ||
2357 | + * handler for that) that does the dump when signal is received. | ||
2358 | + */ | ||
2359 | +static int elf_core_dump(int signr, const CPUState *env) | ||
2360 | +{ | ||
2361 | + const TaskState *ts = (const TaskState *)env->opaque; | ||
2362 | + struct vm_area_struct *vma = NULL; | ||
2363 | + char corefile[PATH_MAX]; | ||
2364 | + struct elf_note_info info; | ||
2365 | + struct elfhdr elf; | ||
2366 | + struct elf_phdr phdr; | ||
2367 | + struct rlimit dumpsize; | ||
2368 | + struct mm_struct *mm = NULL; | ||
2369 | + off_t offset = 0, data_offset = 0; | ||
2370 | + int segs = 0; | ||
2371 | + int fd = -1; | ||
2372 | + | ||
2373 | + errno = 0; | ||
2374 | + getrlimit(RLIMIT_CORE, &dumpsize); | ||
2375 | + if (dumpsize.rlim_cur == 0) | ||
2376 | + return 0; | ||
2377 | + | ||
2378 | + if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0) | ||
2379 | + return (-errno); | ||
2380 | + | ||
2381 | + if ((fd = open(corefile, O_WRONLY | O_CREAT, | ||
2382 | + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) | ||
2383 | + return (-errno); | ||
2384 | + | ||
2385 | + /* | ||
2386 | + * Walk through target process memory mappings and | ||
2387 | + * set up structure containing this information. After | ||
2388 | + * this point vma_xxx functions can be used. | ||
2389 | + */ | ||
2390 | + if ((mm = vma_init()) == NULL) | ||
2391 | + goto out; | ||
2392 | + | ||
2393 | + walk_memory_regions(mm, vma_walker); | ||
2394 | + segs = vma_get_mapping_count(mm); | ||
2395 | + | ||
2396 | + /* | ||
2397 | + * Construct valid coredump ELF header. We also | ||
2398 | + * add one more segment for notes. | ||
2399 | + */ | ||
2400 | + fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0); | ||
2401 | + if (dump_write(fd, &elf, sizeof (elf)) != 0) | ||
2402 | + goto out; | ||
2403 | + | ||
2404 | + /* fill in in-memory version of notes */ | ||
2405 | + if (fill_note_info(&info, signr, env) < 0) | ||
2406 | + goto out; | ||
2407 | + | ||
2408 | + offset += sizeof (elf); /* elf header */ | ||
2409 | + offset += (segs + 1) * sizeof (struct elf_phdr); /* program headers */ | ||
2410 | + | ||
2411 | + /* write out notes program header */ | ||
2412 | + fill_elf_note_phdr(&phdr, info.notes_size, offset); | ||
2413 | + | ||
2414 | + offset += info.notes_size; | ||
2415 | + if (dump_write(fd, &phdr, sizeof (phdr)) != 0) | ||
2416 | + goto out; | ||
2417 | + | ||
2418 | + /* | ||
2419 | + * ELF specification wants data to start at page boundary so | ||
2420 | + * we align it here. | ||
2421 | + */ | ||
2422 | + offset = roundup(offset, ELF_EXEC_PAGESIZE); | ||
2423 | + | ||
2424 | + /* | ||
2425 | + * Write program headers for memory regions mapped in | ||
2426 | + * the target process. | ||
2427 | + */ | ||
2428 | + for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) { | ||
2429 | + (void) memset(&phdr, 0, sizeof (phdr)); | ||
2430 | + | ||
2431 | + phdr.p_type = PT_LOAD; | ||
2432 | + phdr.p_offset = offset; | ||
2433 | + phdr.p_vaddr = vma->vma_start; | ||
2434 | + phdr.p_paddr = 0; | ||
2435 | + phdr.p_filesz = vma_dump_size(vma); | ||
2436 | + offset += phdr.p_filesz; | ||
2437 | + phdr.p_memsz = vma->vma_end - vma->vma_start; | ||
2438 | + phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0; | ||
2439 | + if (vma->vma_flags & PROT_WRITE) | ||
2440 | + phdr.p_flags |= PF_W; | ||
2441 | + if (vma->vma_flags & PROT_EXEC) | ||
2442 | + phdr.p_flags |= PF_X; | ||
2443 | + phdr.p_align = ELF_EXEC_PAGESIZE; | ||
2444 | + | ||
2445 | + dump_write(fd, &phdr, sizeof (phdr)); | ||
2446 | + } | ||
2447 | + | ||
2448 | + /* | ||
2449 | + * Next we write notes just after program headers. No | ||
2450 | + * alignment needed here. | ||
2451 | + */ | ||
2452 | + if (write_note_info(&info, fd) < 0) | ||
2453 | + goto out; | ||
2454 | + | ||
2455 | + /* align data to page boundary */ | ||
2456 | + data_offset = lseek(fd, 0, SEEK_CUR); | ||
2457 | + data_offset = TARGET_PAGE_ALIGN(data_offset); | ||
2458 | + if (lseek(fd, data_offset, SEEK_SET) != data_offset) | ||
2459 | + goto out; | ||
2460 | + | ||
2461 | + /* | ||
2462 | + * Finally we can dump process memory into corefile as well. | ||
2463 | + */ | ||
2464 | + for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) { | ||
2465 | + abi_ulong addr; | ||
2466 | + abi_ulong end; | ||
2467 | + | ||
2468 | + end = vma->vma_start + vma_dump_size(vma); | ||
2469 | + | ||
2470 | + for (addr = vma->vma_start; addr < end; | ||
2471 | + addr += TARGET_PAGE_SIZE) { | ||
2472 | + char page[TARGET_PAGE_SIZE]; | ||
2473 | + int error; | ||
2474 | + | ||
2475 | + /* | ||
2476 | + * Read in page from target process memory and | ||
2477 | + * write it to coredump file. | ||
2478 | + */ | ||
2479 | + error = copy_from_user(page, addr, sizeof (page)); | ||
2480 | + if (error != 0) { | ||
2481 | + (void) fprintf(stderr, "unable to dump " TARGET_FMT_lx "\n", | ||
2482 | + addr); | ||
2483 | + errno = -error; | ||
2484 | + goto out; | ||
2485 | + } | ||
2486 | + if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0) | ||
2487 | + goto out; | ||
2488 | + } | ||
2489 | + } | ||
2490 | + | ||
2491 | +out: | ||
2492 | + free_note_info(&info); | ||
2493 | + if (mm != NULL) | ||
2494 | + vma_delete(mm); | ||
2495 | + (void) close(fd); | ||
2496 | + | ||
2497 | + if (errno != 0) | ||
2498 | + return (-errno); | ||
2499 | + return (0); | ||
2500 | +} | ||
2501 | + | ||
2502 | +#endif /* USE_ELF_CORE_DUMP */ | ||
2503 | + | ||
1592 | static int load_aout_interp(void * exptr, int interp_fd) | 2504 | static int load_aout_interp(void * exptr, int interp_fd) |
1593 | { | 2505 | { |
1594 | printf("a.out interpreter not yet supported\n"); | 2506 | printf("a.out interpreter not yet supported\n"); |
linux-user/linuxload.c
@@ -115,6 +115,7 @@ static int prepare_binprm(struct linux_binprm *bprm) | @@ -115,6 +115,7 @@ static int prepare_binprm(struct linux_binprm *bprm) | ||
115 | abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, | 115 | abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, |
116 | abi_ulong stringp, int push_ptr) | 116 | abi_ulong stringp, int push_ptr) |
117 | { | 117 | { |
118 | + TaskState *ts = (TaskState *)thread_env->opaque; | ||
118 | int n = sizeof(abi_ulong); | 119 | int n = sizeof(abi_ulong); |
119 | abi_ulong envp; | 120 | abi_ulong envp; |
120 | abi_ulong argv; | 121 | abi_ulong argv; |
@@ -133,13 +134,14 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, | @@ -133,13 +134,14 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, | ||
133 | sp -= n; | 134 | sp -= n; |
134 | /* FIXME - handle put_user() failures */ | 135 | /* FIXME - handle put_user() failures */ |
135 | put_user_ual(argc, sp); | 136 | put_user_ual(argc, sp); |
136 | - | 137 | + ts->info->arg_start = stringp; |
137 | while (argc-- > 0) { | 138 | while (argc-- > 0) { |
138 | /* FIXME - handle put_user() failures */ | 139 | /* FIXME - handle put_user() failures */ |
139 | put_user_ual(stringp, argv); | 140 | put_user_ual(stringp, argv); |
140 | argv += n; | 141 | argv += n; |
141 | stringp += target_strlen(stringp) + 1; | 142 | stringp += target_strlen(stringp) + 1; |
142 | } | 143 | } |
144 | + ts->info->arg_end = stringp; | ||
143 | /* FIXME - handle put_user() failures */ | 145 | /* FIXME - handle put_user() failures */ |
144 | put_user_ual(0, argv); | 146 | put_user_ual(0, argv); |
145 | while (envc-- > 0) { | 147 | while (envc-- > 0) { |
@@ -155,45 +157,45 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, | @@ -155,45 +157,45 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, | ||
155 | } | 157 | } |
156 | 158 | ||
157 | int loader_exec(const char * filename, char ** argv, char ** envp, | 159 | int loader_exec(const char * filename, char ** argv, char ** envp, |
158 | - struct target_pt_regs * regs, struct image_info *infop) | 160 | + struct target_pt_regs * regs, struct image_info *infop, |
161 | + struct linux_binprm *bprm) | ||
159 | { | 162 | { |
160 | - struct linux_binprm bprm; | ||
161 | int retval; | 163 | int retval; |
162 | int i; | 164 | int i; |
163 | 165 | ||
164 | - bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); | 166 | + bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); |
165 | for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ | 167 | for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ |
166 | - bprm.page[i] = 0; | 168 | + bprm->page[i] = 0; |
167 | retval = open(filename, O_RDONLY); | 169 | retval = open(filename, O_RDONLY); |
168 | if (retval < 0) | 170 | if (retval < 0) |
169 | return retval; | 171 | return retval; |
170 | - bprm.fd = retval; | ||
171 | - bprm.filename = (char *)filename; | ||
172 | - bprm.argc = count(argv); | ||
173 | - bprm.argv = argv; | ||
174 | - bprm.envc = count(envp); | ||
175 | - bprm.envp = envp; | 172 | + bprm->fd = retval; |
173 | + bprm->filename = (char *)filename; | ||
174 | + bprm->argc = count(argv); | ||
175 | + bprm->argv = argv; | ||
176 | + bprm->envc = count(envp); | ||
177 | + bprm->envp = envp; | ||
176 | 178 | ||
177 | - retval = prepare_binprm(&bprm); | 179 | + retval = prepare_binprm(bprm); |
178 | 180 | ||
179 | infop->host_argv = argv; | 181 | infop->host_argv = argv; |
180 | 182 | ||
181 | if(retval>=0) { | 183 | if(retval>=0) { |
182 | - if (bprm.buf[0] == 0x7f | ||
183 | - && bprm.buf[1] == 'E' | ||
184 | - && bprm.buf[2] == 'L' | ||
185 | - && bprm.buf[3] == 'F') { | 184 | + if (bprm->buf[0] == 0x7f |
185 | + && bprm->buf[1] == 'E' | ||
186 | + && bprm->buf[2] == 'L' | ||
187 | + && bprm->buf[3] == 'F') { | ||
186 | #ifndef TARGET_HAS_ELFLOAD32 | 188 | #ifndef TARGET_HAS_ELFLOAD32 |
187 | - retval = load_elf_binary(&bprm,regs,infop); | 189 | + retval = load_elf_binary(bprm,regs,infop); |
188 | #else | 190 | #else |
189 | - retval = load_elf_binary_multi(&bprm, regs, infop); | 191 | + retval = load_elf_binary_multi(bprm, regs, infop); |
190 | #endif | 192 | #endif |
191 | #if defined(TARGET_HAS_BFLT) | 193 | #if defined(TARGET_HAS_BFLT) |
192 | - } else if (bprm.buf[0] == 'b' | ||
193 | - && bprm.buf[1] == 'F' | ||
194 | - && bprm.buf[2] == 'L' | ||
195 | - && bprm.buf[3] == 'T') { | ||
196 | - retval = load_flt_binary(&bprm,regs,infop); | 194 | + } else if (bprm->buf[0] == 'b' |
195 | + && bprm->buf[1] == 'F' | ||
196 | + && bprm->buf[2] == 'L' | ||
197 | + && bprm->buf[3] == 'T') { | ||
198 | + retval = load_flt_binary(bprm,regs,infop); | ||
197 | #endif | 199 | #endif |
198 | } else { | 200 | } else { |
199 | fprintf(stderr, "Unknown binary format\n"); | 201 | fprintf(stderr, "Unknown binary format\n"); |
@@ -209,7 +211,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp, | @@ -209,7 +211,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp, | ||
209 | 211 | ||
210 | /* Something went wrong, return the inode and free the argument pages*/ | 212 | /* Something went wrong, return the inode and free the argument pages*/ |
211 | for (i=0 ; i<MAX_ARG_PAGES ; i++) { | 213 | for (i=0 ; i<MAX_ARG_PAGES ; i++) { |
212 | - free(bprm.page[i]); | 214 | + free(bprm->page[i]); |
213 | } | 215 | } |
214 | return(retval); | 216 | return(retval); |
215 | } | 217 | } |
linux-user/main.c
@@ -25,6 +25,7 @@ | @@ -25,6 +25,7 @@ | ||
25 | #include <errno.h> | 25 | #include <errno.h> |
26 | #include <unistd.h> | 26 | #include <unistd.h> |
27 | #include <sys/mman.h> | 27 | #include <sys/mman.h> |
28 | +#include <sys/syscall.h> | ||
28 | 29 | ||
29 | #include "qemu.h" | 30 | #include "qemu.h" |
30 | #include "qemu-common.h" | 31 | #include "qemu-common.h" |
@@ -2319,6 +2320,27 @@ static void usage(void) | @@ -2319,6 +2320,27 @@ static void usage(void) | ||
2319 | 2320 | ||
2320 | THREAD CPUState *thread_env; | 2321 | THREAD CPUState *thread_env; |
2321 | 2322 | ||
2323 | +void task_settid(TaskState *ts) | ||
2324 | +{ | ||
2325 | + if (ts->ts_tid == 0) { | ||
2326 | +#ifdef USE_NPTL | ||
2327 | + ts->ts_tid = (pid_t)syscall(SYS_gettid); | ||
2328 | +#else | ||
2329 | + /* when no threads are used, tid becomes pid */ | ||
2330 | + ts->ts_tid = getpid(); | ||
2331 | +#endif | ||
2332 | + } | ||
2333 | +} | ||
2334 | + | ||
2335 | +void stop_all_tasks(void) | ||
2336 | +{ | ||
2337 | + /* | ||
2338 | + * We trust that when using NPTL, start_exclusive() | ||
2339 | + * handles thread stopping correctly. | ||
2340 | + */ | ||
2341 | + start_exclusive(); | ||
2342 | +} | ||
2343 | + | ||
2322 | /* Assumes contents are already zeroed. */ | 2344 | /* Assumes contents are already zeroed. */ |
2323 | void init_task_state(TaskState *ts) | 2345 | void init_task_state(TaskState *ts) |
2324 | { | 2346 | { |
@@ -2338,6 +2360,7 @@ int main(int argc, char **argv, char **envp) | @@ -2338,6 +2360,7 @@ int main(int argc, char **argv, char **envp) | ||
2338 | const char *cpu_model; | 2360 | const char *cpu_model; |
2339 | struct target_pt_regs regs1, *regs = ®s1; | 2361 | struct target_pt_regs regs1, *regs = ®s1; |
2340 | struct image_info info1, *info = &info1; | 2362 | struct image_info info1, *info = &info1; |
2363 | + struct linux_binprm bprm; | ||
2341 | TaskState ts1, *ts = &ts1; | 2364 | TaskState ts1, *ts = &ts1; |
2342 | CPUState *env; | 2365 | CPUState *env; |
2343 | int optind; | 2366 | int optind; |
@@ -2467,6 +2490,8 @@ int main(int argc, char **argv, char **envp) | @@ -2467,6 +2490,8 @@ int main(int argc, char **argv, char **envp) | ||
2467 | /* Zero out image_info */ | 2490 | /* Zero out image_info */ |
2468 | memset(info, 0, sizeof(struct image_info)); | 2491 | memset(info, 0, sizeof(struct image_info)); |
2469 | 2492 | ||
2493 | + memset(&bprm, 0, sizeof (bprm)); | ||
2494 | + | ||
2470 | /* Scan interp_prefix dir for replacement files. */ | 2495 | /* Scan interp_prefix dir for replacement files. */ |
2471 | init_paths(interp_prefix); | 2496 | init_paths(interp_prefix); |
2472 | 2497 | ||
@@ -2543,7 +2568,16 @@ int main(int argc, char **argv, char **envp) | @@ -2543,7 +2568,16 @@ int main(int argc, char **argv, char **envp) | ||
2543 | } | 2568 | } |
2544 | target_argv[target_argc] = NULL; | 2569 | target_argv[target_argc] = NULL; |
2545 | 2570 | ||
2546 | - if (loader_exec(filename, target_argv, target_environ, regs, info) != 0) { | 2571 | + memset(ts, 0, sizeof(TaskState)); |
2572 | + init_task_state(ts); | ||
2573 | + /* build Task State */ | ||
2574 | + ts->info = info; | ||
2575 | + ts->bprm = &bprm; | ||
2576 | + env->opaque = ts; | ||
2577 | + task_settid(ts); | ||
2578 | + | ||
2579 | + if (loader_exec(filename, target_argv, target_environ, regs, | ||
2580 | + info, &bprm) != 0) { | ||
2547 | printf("Error loading %s\n", filename); | 2581 | printf("Error loading %s\n", filename); |
2548 | _exit(1); | 2582 | _exit(1); |
2549 | } | 2583 | } |
@@ -2579,12 +2613,6 @@ int main(int argc, char **argv, char **envp) | @@ -2579,12 +2613,6 @@ int main(int argc, char **argv, char **envp) | ||
2579 | syscall_init(); | 2613 | syscall_init(); |
2580 | signal_init(); | 2614 | signal_init(); |
2581 | 2615 | ||
2582 | - /* build Task State */ | ||
2583 | - memset(ts, 0, sizeof(TaskState)); | ||
2584 | - init_task_state(ts); | ||
2585 | - ts->info = info; | ||
2586 | - env->opaque = ts; | ||
2587 | - | ||
2588 | #if defined(TARGET_I386) | 2616 | #if defined(TARGET_I386) |
2589 | cpu_x86_set_cpl(env, 3); | 2617 | cpu_x86_set_cpl(env, 3); |
2590 | 2618 |
linux-user/qemu.h
@@ -18,6 +18,7 @@ | @@ -18,6 +18,7 @@ | ||
18 | #include "syscall.h" | 18 | #include "syscall.h" |
19 | #include "target_signal.h" | 19 | #include "target_signal.h" |
20 | #include "gdbstub.h" | 20 | #include "gdbstub.h" |
21 | +#include "sys-queue.h" | ||
21 | 22 | ||
22 | #if defined(USE_NPTL) | 23 | #if defined(USE_NPTL) |
23 | #define THREAD __thread | 24 | #define THREAD __thread |
@@ -44,6 +45,9 @@ struct image_info { | @@ -44,6 +45,9 @@ struct image_info { | ||
44 | abi_ulong entry; | 45 | abi_ulong entry; |
45 | abi_ulong code_offset; | 46 | abi_ulong code_offset; |
46 | abi_ulong data_offset; | 47 | abi_ulong data_offset; |
48 | + abi_ulong saved_auxv; | ||
49 | + abi_ulong arg_start; | ||
50 | + abi_ulong arg_end; | ||
47 | char **host_argv; | 51 | char **host_argv; |
48 | int personality; | 52 | int personality; |
49 | }; | 53 | }; |
@@ -87,7 +91,7 @@ struct emulated_sigtable { | @@ -87,7 +91,7 @@ struct emulated_sigtable { | ||
87 | /* NOTE: we force a big alignment so that the stack stored after is | 91 | /* NOTE: we force a big alignment so that the stack stored after is |
88 | aligned too */ | 92 | aligned too */ |
89 | typedef struct TaskState { | 93 | typedef struct TaskState { |
90 | - struct TaskState *next; | 94 | + pid_t ts_tid; /* tid (or pid) of this task */ |
91 | #ifdef TARGET_ARM | 95 | #ifdef TARGET_ARM |
92 | /* FPA state */ | 96 | /* FPA state */ |
93 | FPA11 fpa; | 97 | FPA11 fpa; |
@@ -114,6 +118,7 @@ typedef struct TaskState { | @@ -114,6 +118,7 @@ typedef struct TaskState { | ||
114 | #endif | 118 | #endif |
115 | int used; /* non zero if used */ | 119 | int used; /* non zero if used */ |
116 | struct image_info *info; | 120 | struct image_info *info; |
121 | + struct linux_binprm *bprm; | ||
117 | 122 | ||
118 | struct emulated_sigtable sigtab[TARGET_NSIG]; | 123 | struct emulated_sigtable sigtab[TARGET_NSIG]; |
119 | struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ | 124 | struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ |
@@ -125,6 +130,8 @@ typedef struct TaskState { | @@ -125,6 +130,8 @@ typedef struct TaskState { | ||
125 | 130 | ||
126 | extern char *exec_path; | 131 | extern char *exec_path; |
127 | void init_task_state(TaskState *ts); | 132 | void init_task_state(TaskState *ts); |
133 | +void task_settid(TaskState *); | ||
134 | +void stop_all_tasks(void); | ||
128 | extern const char *qemu_uname_release; | 135 | extern const char *qemu_uname_release; |
129 | 136 | ||
130 | /* ??? See if we can avoid exposing so much of the loader internals. */ | 137 | /* ??? See if we can avoid exposing so much of the loader internals. */ |
@@ -149,13 +156,15 @@ struct linux_binprm { | @@ -149,13 +156,15 @@ struct linux_binprm { | ||
149 | char **argv; | 156 | char **argv; |
150 | char **envp; | 157 | char **envp; |
151 | char * filename; /* Name of binary */ | 158 | char * filename; /* Name of binary */ |
159 | + int (*core_dump)(int, const CPUState *); /* coredump routine */ | ||
152 | }; | 160 | }; |
153 | 161 | ||
154 | void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); | 162 | void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); |
155 | abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, | 163 | abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, |
156 | abi_ulong stringp, int push_ptr); | 164 | abi_ulong stringp, int push_ptr); |
157 | int loader_exec(const char * filename, char ** argv, char ** envp, | 165 | int loader_exec(const char * filename, char ** argv, char ** envp, |
158 | - struct target_pt_regs * regs, struct image_info *infop); | 166 | + struct target_pt_regs * regs, struct image_info *infop, |
167 | + struct linux_binprm *); | ||
159 | 168 | ||
160 | int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, | 169 | int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, |
161 | struct image_info * info); | 170 | struct image_info * info); |
linux-user/signal.c
@@ -27,6 +27,7 @@ | @@ -27,6 +27,7 @@ | ||
27 | #include <errno.h> | 27 | #include <errno.h> |
28 | #include <assert.h> | 28 | #include <assert.h> |
29 | #include <sys/ucontext.h> | 29 | #include <sys/ucontext.h> |
30 | +#include <sys/resource.h> | ||
30 | 31 | ||
31 | #include "qemu.h" | 32 | #include "qemu.h" |
32 | #include "qemu-common.h" | 33 | #include "qemu-common.h" |
@@ -287,6 +288,23 @@ static int fatal_signal (int sig) | @@ -287,6 +288,23 @@ static int fatal_signal (int sig) | ||
287 | } | 288 | } |
288 | } | 289 | } |
289 | 290 | ||
291 | +/* returns 1 if given signal should dump core if not handled */ | ||
292 | +static int core_dump_signal(int sig) | ||
293 | +{ | ||
294 | + switch (sig) { | ||
295 | + case TARGET_SIGABRT: | ||
296 | + case TARGET_SIGFPE: | ||
297 | + case TARGET_SIGILL: | ||
298 | + case TARGET_SIGQUIT: | ||
299 | + case TARGET_SIGSEGV: | ||
300 | + case TARGET_SIGTRAP: | ||
301 | + case TARGET_SIGBUS: | ||
302 | + return (1); | ||
303 | + default: | ||
304 | + return (0); | ||
305 | + } | ||
306 | +} | ||
307 | + | ||
290 | void signal_init(void) | 308 | void signal_init(void) |
291 | { | 309 | { |
292 | struct sigaction act; | 310 | struct sigaction act; |
@@ -352,13 +370,29 @@ static inline void free_sigqueue(CPUState *env, struct sigqueue *q) | @@ -352,13 +370,29 @@ static inline void free_sigqueue(CPUState *env, struct sigqueue *q) | ||
352 | /* abort execution with signal */ | 370 | /* abort execution with signal */ |
353 | static void QEMU_NORETURN force_sig(int sig) | 371 | static void QEMU_NORETURN force_sig(int sig) |
354 | { | 372 | { |
355 | - int host_sig; | 373 | + TaskState *ts = (TaskState *)thread_env->opaque; |
374 | + int host_sig, core_dumped = 0; | ||
356 | struct sigaction act; | 375 | struct sigaction act; |
357 | host_sig = target_to_host_signal(sig); | 376 | host_sig = target_to_host_signal(sig); |
358 | - fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", | ||
359 | - sig, strsignal(host_sig)); | ||
360 | gdb_signalled(thread_env, sig); | 377 | gdb_signalled(thread_env, sig); |
361 | 378 | ||
379 | + /* dump core if supported by target binary format */ | ||
380 | + if (core_dump_signal(sig) && (ts->bprm->core_dump != NULL)) { | ||
381 | + stop_all_tasks(); | ||
382 | + core_dumped = | ||
383 | + ((*ts->bprm->core_dump)(sig, thread_env) == 0); | ||
384 | + } | ||
385 | + if (core_dumped) { | ||
386 | + /* we already dumped the core of target process, we don't want | ||
387 | + * a coredump of qemu itself */ | ||
388 | + struct rlimit nodump; | ||
389 | + getrlimit(RLIMIT_CORE, &nodump); | ||
390 | + nodump.rlim_cur=0; | ||
391 | + setrlimit(RLIMIT_CORE, &nodump); | ||
392 | + (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n", | ||
393 | + sig, strsignal(host_sig), "core dumped" ); | ||
394 | + } | ||
395 | + | ||
362 | /* The proper exit code for dieing from an uncaught signal is | 396 | /* The proper exit code for dieing from an uncaught signal is |
363 | * -<signal>. The kernel doesn't allow exit() or _exit() to pass | 397 | * -<signal>. The kernel doesn't allow exit() or _exit() to pass |
364 | * a negative value. To get the proper exit code we need to | 398 | * a negative value. To get the proper exit code we need to |
linux-user/syscall.c
@@ -3379,11 +3379,14 @@ static void *clone_func(void *arg) | @@ -3379,11 +3379,14 @@ static void *clone_func(void *arg) | ||
3379 | { | 3379 | { |
3380 | new_thread_info *info = arg; | 3380 | new_thread_info *info = arg; |
3381 | CPUState *env; | 3381 | CPUState *env; |
3382 | + TaskState *ts; | ||
3382 | 3383 | ||
3383 | env = info->env; | 3384 | env = info->env; |
3384 | thread_env = env; | 3385 | thread_env = env; |
3386 | + ts = (TaskState *)thread_env->opaque; | ||
3385 | info->tid = gettid(); | 3387 | info->tid = gettid(); |
3386 | env->host_tid = info->tid; | 3388 | env->host_tid = info->tid; |
3389 | + task_settid(ts); | ||
3387 | if (info->child_tidptr) | 3390 | if (info->child_tidptr) |
3388 | put_user_u32(info->tid, info->child_tidptr); | 3391 | put_user_u32(info->tid, info->child_tidptr); |
3389 | if (info->parent_tidptr) | 3392 | if (info->parent_tidptr) |
@@ -3435,6 +3438,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, | @@ -3435,6 +3438,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, | ||
3435 | flags &= ~(CLONE_VFORK | CLONE_VM); | 3438 | flags &= ~(CLONE_VFORK | CLONE_VM); |
3436 | 3439 | ||
3437 | if (flags & CLONE_VM) { | 3440 | if (flags & CLONE_VM) { |
3441 | + TaskState *parent_ts = (TaskState *)env->opaque; | ||
3438 | #if defined(USE_NPTL) | 3442 | #if defined(USE_NPTL) |
3439 | new_thread_info info; | 3443 | new_thread_info info; |
3440 | pthread_attr_t attr; | 3444 | pthread_attr_t attr; |
@@ -3447,6 +3451,8 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, | @@ -3447,6 +3451,8 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, | ||
3447 | /* Init regs that differ from the parent. */ | 3451 | /* Init regs that differ from the parent. */ |
3448 | cpu_clone_regs(new_env, newsp); | 3452 | cpu_clone_regs(new_env, newsp); |
3449 | new_env->opaque = ts; | 3453 | new_env->opaque = ts; |
3454 | + ts->bprm = parent_ts->bprm; | ||
3455 | + ts->info = parent_ts->info; | ||
3450 | #if defined(USE_NPTL) | 3456 | #if defined(USE_NPTL) |
3451 | nptl_flags = flags; | 3457 | nptl_flags = flags; |
3452 | flags &= ~CLONE_NPTL_FLAGS2; | 3458 | flags &= ~CLONE_NPTL_FLAGS2; |