提交 edf8e2af 编写于 作者: M Mika Westerberg 提交者: Riku Voipio

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: NMika Westerberg <mika.westerberg@iki.fi>
Signed-off-by: NRiku Voipio <riku.voipio@iki.fi>
上级 88a8c984
...@@ -735,6 +735,8 @@ extern unsigned long qemu_host_page_mask; ...@@ -735,6 +735,8 @@ extern unsigned long qemu_host_page_mask;
#define PAGE_RESERVED 0x0020 #define PAGE_RESERVED 0x0020
void page_dump(FILE *f); void page_dump(FILE *f);
int walk_memory_regions(void *,
int (*fn)(void *, unsigned long, unsigned long, unsigned long));
int page_get_flags(target_ulong address); int page_get_flags(target_ulong address);
void page_set_flags(target_ulong start, target_ulong end, int flags); void page_set_flags(target_ulong start, target_ulong end, int flags);
int page_check_range(target_ulong start, target_ulong len, int flags); int page_check_range(target_ulong start, target_ulong len, int flags);
......
...@@ -1081,7 +1081,23 @@ typedef struct elf64_shdr { ...@@ -1081,7 +1081,23 @@ typedef struct elf64_shdr {
#define EI_CLASS 4 #define EI_CLASS 4
#define EI_DATA 5 #define EI_DATA 5
#define EI_VERSION 6 #define EI_VERSION 6
#define EI_PAD 7 #define EI_OSABI 7
#define EI_PAD 8
#define ELFOSABI_NONE 0 /* UNIX System V ABI */
#define ELFOSABI_SYSV 0 /* Alias. */
#define ELFOSABI_HPUX 1 /* HP-UX */
#define ELFOSABI_NETBSD 2 /* NetBSD. */
#define ELFOSABI_LINUX 3 /* Linux. */
#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */
#define ELFOSABI_AIX 7 /* IBM AIX. */
#define ELFOSABI_IRIX 8 /* SGI Irix. */
#define ELFOSABI_FREEBSD 9 /* FreeBSD. */
#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
#define ELFMAG0 0x7f /* EI_MAG */ #define ELFMAG0 0x7f /* EI_MAG */
#define ELFMAG1 'E' #define ELFMAG1 'E'
...@@ -1108,6 +1124,7 @@ typedef struct elf64_shdr { ...@@ -1108,6 +1124,7 @@ typedef struct elf64_shdr {
#define NT_PRFPREG 2 #define NT_PRFPREG 2
#define NT_PRPSINFO 3 #define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4 #define NT_TASKSTRUCT 4
#define NT_AUXV 6
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
......
...@@ -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,
return 0; return 0;
} }
/* dump memory mappings */ /*
void page_dump(FILE *f) * Walks guest process memory "regions" one by one
* and calls callback function 'fn' for each region.
*/
int walk_memory_regions(void *priv,
int (*fn)(void *, unsigned long, unsigned long, unsigned long))
{ {
unsigned long start, end; unsigned long start, end;
PageDesc *p = NULL;
int i, j, prot, prot1; int i, j, prot, prot1;
PageDesc *p; int rc = 0;
fprintf(f, "%-8s %-8s %-8s %s\n", start = end = -1;
"start", "end", "size", "prot");
start = -1;
end = -1;
prot = 0; prot = 0;
for(i = 0; i <= L1_SIZE; i++) {
if (i < L1_SIZE) for (i = 0; i <= L1_SIZE; i++) {
p = l1_map[i]; p = (i < L1_SIZE) ? l1_map[i] : NULL;
else for (j = 0; j < L2_SIZE; j++) {
p = NULL; prot1 = (p == NULL) ? 0 : p[j].flags;
for(j = 0;j < L2_SIZE; j++) { /*
if (!p) * "region" is one continuous chunk of memory
prot1 = 0; * that has same protection flags set.
else */
prot1 = p[j].flags;
if (prot1 != prot) { if (prot1 != prot) {
end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
if (start != -1) { if (start != -1) {
fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", rc = (*fn)(priv, start, end, prot);
start, end, end - start, /* callback can stop iteration by returning != 0 */
prot & PAGE_READ ? 'r' : '-', if (rc != 0)
prot & PAGE_WRITE ? 'w' : '-', return (rc);
prot & PAGE_EXEC ? 'x' : '-');
} }
if (prot1 != 0) if (prot1 != 0)
start = end; start = end;
...@@ -2168,10 +2168,33 @@ void page_dump(FILE *f) ...@@ -2168,10 +2168,33 @@ void page_dump(FILE *f)
start = -1; start = -1;
prot = prot1; prot = prot1;
} }
if (!p) if (p == NULL)
break; break;
} }
} }
return (rc);
}
static int dump_region(void *priv, unsigned long start,
unsigned long end, unsigned long prot)
{
FILE *f = (FILE *)priv;
(void) fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
start, end, end - start,
((prot & PAGE_READ) ? 'r' : '-'),
((prot & PAGE_WRITE) ? 'w' : '-'),
((prot & PAGE_EXEC) ? 'x' : '-'));
return (0);
}
/* dump memory mappings */
void page_dump(FILE *f)
{
(void) fprintf(f, "%-8s %-8s %-8s %s\n",
"start", "end", "size", "prot");
walk_memory_regions(f, dump_region);
} }
int page_get_flags(target_ulong address) int page_get_flags(target_ulong address)
......
此差异已折叠。
...@@ -115,6 +115,7 @@ static int prepare_binprm(struct linux_binprm *bprm) ...@@ -115,6 +115,7 @@ static int prepare_binprm(struct linux_binprm *bprm)
abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
abi_ulong stringp, int push_ptr) abi_ulong stringp, int push_ptr)
{ {
TaskState *ts = (TaskState *)thread_env->opaque;
int n = sizeof(abi_ulong); int n = sizeof(abi_ulong);
abi_ulong envp; abi_ulong envp;
abi_ulong argv; 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,
sp -= n; sp -= n;
/* FIXME - handle put_user() failures */ /* FIXME - handle put_user() failures */
put_user_ual(argc, sp); put_user_ual(argc, sp);
ts->info->arg_start = stringp;
while (argc-- > 0) { while (argc-- > 0) {
/* FIXME - handle put_user() failures */ /* FIXME - handle put_user() failures */
put_user_ual(stringp, argv); put_user_ual(stringp, argv);
argv += n; argv += n;
stringp += target_strlen(stringp) + 1; stringp += target_strlen(stringp) + 1;
} }
ts->info->arg_end = stringp;
/* FIXME - handle put_user() failures */ /* FIXME - handle put_user() failures */
put_user_ual(0, argv); put_user_ual(0, argv);
while (envc-- > 0) { 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,
} }
int loader_exec(const char * filename, char ** argv, char ** envp, int loader_exec(const char * filename, char ** argv, char ** envp,
struct target_pt_regs * regs, struct image_info *infop) struct target_pt_regs * regs, struct image_info *infop,
struct linux_binprm *bprm)
{ {
struct linux_binprm bprm;
int retval; int retval;
int i; int i;
bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
bprm.page[i] = 0; bprm->page[i] = 0;
retval = open(filename, O_RDONLY); retval = open(filename, O_RDONLY);
if (retval < 0) if (retval < 0)
return retval; return retval;
bprm.fd = retval; bprm->fd = retval;
bprm.filename = (char *)filename; bprm->filename = (char *)filename;
bprm.argc = count(argv); bprm->argc = count(argv);
bprm.argv = argv; bprm->argv = argv;
bprm.envc = count(envp); bprm->envc = count(envp);
bprm.envp = envp; bprm->envp = envp;
retval = prepare_binprm(&bprm); retval = prepare_binprm(bprm);
infop->host_argv = argv; infop->host_argv = argv;
if(retval>=0) { if(retval>=0) {
if (bprm.buf[0] == 0x7f if (bprm->buf[0] == 0x7f
&& bprm.buf[1] == 'E' && bprm->buf[1] == 'E'
&& bprm.buf[2] == 'L' && bprm->buf[2] == 'L'
&& bprm.buf[3] == 'F') { && bprm->buf[3] == 'F') {
#ifndef TARGET_HAS_ELFLOAD32 #ifndef TARGET_HAS_ELFLOAD32
retval = load_elf_binary(&bprm,regs,infop); retval = load_elf_binary(bprm,regs,infop);
#else #else
retval = load_elf_binary_multi(&bprm, regs, infop); retval = load_elf_binary_multi(bprm, regs, infop);
#endif #endif
#if defined(TARGET_HAS_BFLT) #if defined(TARGET_HAS_BFLT)
} else if (bprm.buf[0] == 'b' } else if (bprm->buf[0] == 'b'
&& bprm.buf[1] == 'F' && bprm->buf[1] == 'F'
&& bprm.buf[2] == 'L' && bprm->buf[2] == 'L'
&& bprm.buf[3] == 'T') { && bprm->buf[3] == 'T') {
retval = load_flt_binary(&bprm,regs,infop); retval = load_flt_binary(bprm,regs,infop);
#endif #endif
} else { } else {
fprintf(stderr, "Unknown binary format\n"); 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,
/* Something went wrong, return the inode and free the argument pages*/ /* Something went wrong, return the inode and free the argument pages*/
for (i=0 ; i<MAX_ARG_PAGES ; i++) { for (i=0 ; i<MAX_ARG_PAGES ; i++) {
free(bprm.page[i]); free(bprm->page[i]);
} }
return(retval); return(retval);
} }
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/syscall.h>
#include "qemu.h" #include "qemu.h"
#include "qemu-common.h" #include "qemu-common.h"
...@@ -2319,6 +2320,27 @@ static void usage(void) ...@@ -2319,6 +2320,27 @@ static void usage(void)
THREAD CPUState *thread_env; THREAD CPUState *thread_env;
void task_settid(TaskState *ts)
{
if (ts->ts_tid == 0) {
#ifdef USE_NPTL
ts->ts_tid = (pid_t)syscall(SYS_gettid);
#else
/* when no threads are used, tid becomes pid */
ts->ts_tid = getpid();
#endif
}
}
void stop_all_tasks(void)
{
/*
* We trust that when using NPTL, start_exclusive()
* handles thread stopping correctly.
*/
start_exclusive();
}
/* Assumes contents are already zeroed. */ /* Assumes contents are already zeroed. */
void init_task_state(TaskState *ts) void init_task_state(TaskState *ts)
{ {
...@@ -2338,6 +2360,7 @@ int main(int argc, char **argv, char **envp) ...@@ -2338,6 +2360,7 @@ int main(int argc, char **argv, char **envp)
const char *cpu_model; const char *cpu_model;
struct target_pt_regs regs1, *regs = &regs1; struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1; struct image_info info1, *info = &info1;
struct linux_binprm bprm;
TaskState ts1, *ts = &ts1; TaskState ts1, *ts = &ts1;
CPUState *env; CPUState *env;
int optind; 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)
/* Zero out image_info */ /* Zero out image_info */
memset(info, 0, sizeof(struct image_info)); memset(info, 0, sizeof(struct image_info));
memset(&bprm, 0, sizeof (bprm));
/* Scan interp_prefix dir for replacement files. */ /* Scan interp_prefix dir for replacement files. */
init_paths(interp_prefix); init_paths(interp_prefix);
...@@ -2543,7 +2568,16 @@ int main(int argc, char **argv, char **envp) ...@@ -2543,7 +2568,16 @@ int main(int argc, char **argv, char **envp)
} }
target_argv[target_argc] = NULL; target_argv[target_argc] = NULL;
if (loader_exec(filename, target_argv, target_environ, regs, info) != 0) { memset(ts, 0, sizeof(TaskState));
init_task_state(ts);
/* build Task State */
ts->info = info;
ts->bprm = &bprm;
env->opaque = ts;
task_settid(ts);
if (loader_exec(filename, target_argv, target_environ, regs,
info, &bprm) != 0) {
printf("Error loading %s\n", filename); printf("Error loading %s\n", filename);
_exit(1); _exit(1);
} }
...@@ -2579,12 +2613,6 @@ int main(int argc, char **argv, char **envp) ...@@ -2579,12 +2613,6 @@ int main(int argc, char **argv, char **envp)
syscall_init(); syscall_init();
signal_init(); signal_init();
/* build Task State */
memset(ts, 0, sizeof(TaskState));
init_task_state(ts);
ts->info = info;
env->opaque = ts;
#if defined(TARGET_I386) #if defined(TARGET_I386)
cpu_x86_set_cpl(env, 3); cpu_x86_set_cpl(env, 3);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "syscall.h" #include "syscall.h"
#include "target_signal.h" #include "target_signal.h"
#include "gdbstub.h" #include "gdbstub.h"
#include "sys-queue.h"
#if defined(USE_NPTL) #if defined(USE_NPTL)
#define THREAD __thread #define THREAD __thread
...@@ -44,6 +45,9 @@ struct image_info { ...@@ -44,6 +45,9 @@ struct image_info {
abi_ulong entry; abi_ulong entry;
abi_ulong code_offset; abi_ulong code_offset;
abi_ulong data_offset; abi_ulong data_offset;
abi_ulong saved_auxv;
abi_ulong arg_start;
abi_ulong arg_end;
char **host_argv; char **host_argv;
int personality; int personality;
}; };
...@@ -87,7 +91,7 @@ struct emulated_sigtable { ...@@ -87,7 +91,7 @@ struct emulated_sigtable {
/* NOTE: we force a big alignment so that the stack stored after is /* NOTE: we force a big alignment so that the stack stored after is
aligned too */ aligned too */
typedef struct TaskState { typedef struct TaskState {
struct TaskState *next; pid_t ts_tid; /* tid (or pid) of this task */
#ifdef TARGET_ARM #ifdef TARGET_ARM
/* FPA state */ /* FPA state */
FPA11 fpa; FPA11 fpa;
...@@ -114,6 +118,7 @@ typedef struct TaskState { ...@@ -114,6 +118,7 @@ typedef struct TaskState {
#endif #endif
int used; /* non zero if used */ int used; /* non zero if used */
struct image_info *info; struct image_info *info;
struct linux_binprm *bprm;
struct emulated_sigtable sigtab[TARGET_NSIG]; struct emulated_sigtable sigtab[TARGET_NSIG];
struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
...@@ -125,6 +130,8 @@ typedef struct TaskState { ...@@ -125,6 +130,8 @@ typedef struct TaskState {
extern char *exec_path; extern char *exec_path;
void init_task_state(TaskState *ts); void init_task_state(TaskState *ts);
void task_settid(TaskState *);
void stop_all_tasks(void);
extern const char *qemu_uname_release; extern const char *qemu_uname_release;
/* ??? See if we can avoid exposing so much of the loader internals. */ /* ??? 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 {
char **argv; char **argv;
char **envp; char **envp;
char * filename; /* Name of binary */ char * filename; /* Name of binary */
int (*core_dump)(int, const CPUState *); /* coredump routine */
}; };
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
abi_ulong stringp, int push_ptr); abi_ulong stringp, int push_ptr);
int loader_exec(const char * filename, char ** argv, char ** envp, int loader_exec(const char * filename, char ** argv, char ** envp,
struct target_pt_regs * regs, struct image_info *infop); struct target_pt_regs * regs, struct image_info *infop,
struct linux_binprm *);
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info); struct image_info * info);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#include <sys/ucontext.h> #include <sys/ucontext.h>
#include <sys/resource.h>
#include "qemu.h" #include "qemu.h"
#include "qemu-common.h" #include "qemu-common.h"
...@@ -287,6 +288,23 @@ static int fatal_signal (int sig) ...@@ -287,6 +288,23 @@ static int fatal_signal (int sig)
} }
} }
/* returns 1 if given signal should dump core if not handled */
static int core_dump_signal(int sig)
{
switch (sig) {
case TARGET_SIGABRT:
case TARGET_SIGFPE:
case TARGET_SIGILL:
case TARGET_SIGQUIT:
case TARGET_SIGSEGV:
case TARGET_SIGTRAP:
case TARGET_SIGBUS:
return (1);
default:
return (0);
}
}
void signal_init(void) void signal_init(void)
{ {
struct sigaction act; 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)
/* abort execution with signal */ /* abort execution with signal */
static void QEMU_NORETURN force_sig(int sig) static void QEMU_NORETURN force_sig(int sig)
{ {
int host_sig; TaskState *ts = (TaskState *)thread_env->opaque;
int host_sig, core_dumped = 0;
struct sigaction act; struct sigaction act;
host_sig = target_to_host_signal(sig); host_sig = target_to_host_signal(sig);
fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
sig, strsignal(host_sig));
gdb_signalled(thread_env, sig); gdb_signalled(thread_env, sig);
/* dump core if supported by target binary format */
if (core_dump_signal(sig) && (ts->bprm->core_dump != NULL)) {
stop_all_tasks();
core_dumped =
((*ts->bprm->core_dump)(sig, thread_env) == 0);
}
if (core_dumped) {
/* we already dumped the core of target process, we don't want
* a coredump of qemu itself */
struct rlimit nodump;
getrlimit(RLIMIT_CORE, &nodump);
nodump.rlim_cur=0;
setrlimit(RLIMIT_CORE, &nodump);
(void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
sig, strsignal(host_sig), "core dumped" );
}
/* The proper exit code for dieing from an uncaught signal is /* The proper exit code for dieing from an uncaught signal is
* -<signal>. The kernel doesn't allow exit() or _exit() to pass * -<signal>. The kernel doesn't allow exit() or _exit() to pass
* a negative value. To get the proper exit code we need to * a negative value. To get the proper exit code we need to
......
...@@ -3379,11 +3379,14 @@ static void *clone_func(void *arg) ...@@ -3379,11 +3379,14 @@ static void *clone_func(void *arg)
{ {
new_thread_info *info = arg; new_thread_info *info = arg;
CPUState *env; CPUState *env;
TaskState *ts;
env = info->env; env = info->env;
thread_env = env; thread_env = env;
ts = (TaskState *)thread_env->opaque;
info->tid = gettid(); info->tid = gettid();
env->host_tid = info->tid; env->host_tid = info->tid;
task_settid(ts);
if (info->child_tidptr) if (info->child_tidptr)
put_user_u32(info->tid, info->child_tidptr); put_user_u32(info->tid, info->child_tidptr);
if (info->parent_tidptr) 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,
flags &= ~(CLONE_VFORK | CLONE_VM); flags &= ~(CLONE_VFORK | CLONE_VM);
if (flags & CLONE_VM) { if (flags & CLONE_VM) {
TaskState *parent_ts = (TaskState *)env->opaque;
#if defined(USE_NPTL) #if defined(USE_NPTL)
new_thread_info info; new_thread_info info;
pthread_attr_t attr; 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,
/* Init regs that differ from the parent. */ /* Init regs that differ from the parent. */
cpu_clone_regs(new_env, newsp); cpu_clone_regs(new_env, newsp);
new_env->opaque = ts; new_env->opaque = ts;
ts->bprm = parent_ts->bprm;
ts->info = parent_ts->info;
#if defined(USE_NPTL) #if defined(USE_NPTL)
nptl_flags = flags; nptl_flags = flags;
flags &= ~CLONE_NPTL_FLAGS2; flags &= ~CLONE_NPTL_FLAGS2;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册