mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
bug 595167 - Make Breakpad client libs work on Android. r=mwu a=blocking-fennec
This commit is contained in:
parent
a593182495
commit
cdd510c54b
@ -0,0 +1,4 @@
|
|||||||
|
#include <sys/exec_elf.h>
|
||||||
|
#define ElfW(type) _ElfW (Elf, ELFSIZE, type)
|
||||||
|
#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
|
||||||
|
#define _ElfW_1(e,w,t) e##w##t
|
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_UCONTEXT_H_
|
||||||
|
#define GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_UCONTEXT_H_
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
// Adapted from platform-linux.cc in V8
|
||||||
|
#if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
|
||||||
|
// Android runs a fairly new Linux kernel, so signal info is there,
|
||||||
|
// but the C library doesn't have the structs defined.
|
||||||
|
|
||||||
|
struct sigcontext {
|
||||||
|
uint32_t trap_no;
|
||||||
|
uint32_t error_code;
|
||||||
|
uint32_t oldmask;
|
||||||
|
uint32_t arm_r0;
|
||||||
|
uint32_t arm_r1;
|
||||||
|
uint32_t arm_r2;
|
||||||
|
uint32_t arm_r3;
|
||||||
|
uint32_t arm_r4;
|
||||||
|
uint32_t arm_r5;
|
||||||
|
uint32_t arm_r6;
|
||||||
|
uint32_t arm_r7;
|
||||||
|
uint32_t arm_r8;
|
||||||
|
uint32_t arm_r9;
|
||||||
|
uint32_t arm_r10;
|
||||||
|
uint32_t arm_fp;
|
||||||
|
uint32_t arm_ip;
|
||||||
|
uint32_t arm_sp;
|
||||||
|
uint32_t arm_lr;
|
||||||
|
uint32_t arm_pc;
|
||||||
|
uint32_t arm_cpsr;
|
||||||
|
uint32_t fault_address;
|
||||||
|
};
|
||||||
|
typedef uint32_t __sigset_t;
|
||||||
|
typedef struct sigcontext mcontext_t;
|
||||||
|
typedef struct ucontext {
|
||||||
|
uint32_t uc_flags;
|
||||||
|
struct ucontext* uc_link;
|
||||||
|
stack_t uc_stack;
|
||||||
|
mcontext_t uc_mcontext;
|
||||||
|
__sigset_t uc_sigmask;
|
||||||
|
} ucontext_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_UCONTEXT_H_
|
@ -73,12 +73,18 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
#include <sys/signal.h>
|
#include <sys/signal.h>
|
||||||
|
#endif
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
#include <sys/ucontext.h>
|
#include <sys/ucontext.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
|
#endif
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
#include <ucontext.h>
|
#include <ucontext.h>
|
||||||
|
#endif
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -186,7 +192,7 @@ bool ExceptionHandler::InstallHandlers() {
|
|||||||
stack.ss_sp = signal_stack;
|
stack.ss_sp = signal_stack;
|
||||||
stack.ss_size = kSigStackSize;
|
stack.ss_size = kSigStackSize;
|
||||||
|
|
||||||
if (sigaltstack(&stack, NULL) == -1)
|
if (sys_sigaltstack(&stack, NULL) == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
@ -310,7 +316,7 @@ bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Allow ourselves to be dumped.
|
// Allow ourselves to be dumped.
|
||||||
prctl(PR_SET_DUMPABLE, 1);
|
sys_prctl(PR_SET_DUMPABLE, 1);
|
||||||
CrashContext context;
|
CrashContext context;
|
||||||
memcpy(&context.siginfo, info, sizeof(siginfo_t));
|
memcpy(&context.siginfo, info, sizeof(siginfo_t));
|
||||||
memcpy(&context.context, uc, sizeof(struct ucontext));
|
memcpy(&context.context, uc, sizeof(struct ucontext));
|
||||||
|
@ -33,9 +33,11 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "client/linux/android_ucontext.h"
|
||||||
#include "client/linux/crash_generation/crash_generation_client.h"
|
#include "client/linux/crash_generation/crash_generation_client.h"
|
||||||
#include "processor/scoped_ptr.h"
|
#include "processor/scoped_ptr.h"
|
||||||
|
|
||||||
|
@ -45,7 +45,9 @@
|
|||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
@ -117,11 +119,16 @@ inline bool IsMappedFileOpenUnsafe(
|
|||||||
bool GetThreadRegisters(ThreadInfo* info) {
|
bool GetThreadRegisters(ThreadInfo* info) {
|
||||||
pid_t tid = info->tid;
|
pid_t tid = info->tid;
|
||||||
|
|
||||||
if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1 ||
|
if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) {
|
||||||
sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
|
if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__i386)
|
#if defined(__i386)
|
||||||
if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1)
|
if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1)
|
||||||
return false;
|
return false;
|
||||||
@ -425,7 +432,7 @@ bool LinuxDumper::ThreadInfoGet(ThreadInfo* info) {
|
|||||||
#elif defined(__x86_64)
|
#elif defined(__x86_64)
|
||||||
memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
|
memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
|
||||||
#elif defined(__ARM_EABI__)
|
#elif defined(__ARM_EABI__)
|
||||||
memcpy(&stack_pointer, &info->regs.uregs[R13], sizeof(info->regs.uregs[R13]));
|
memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
|
||||||
#else
|
#else
|
||||||
#error "This code hasn't been ported to your platform yet."
|
#error "This code hasn't been ported to your platform yet."
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,18 +34,38 @@
|
|||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common/memory.h"
|
#include "common/memory.h"
|
||||||
#include "google_breakpad/common/minidump_format.h"
|
#include "google_breakpad/common/minidump_format.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
#if defined(__i386) || defined(__x86_64)
|
||||||
typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t;
|
typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
|
// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
|
||||||
#if defined(__i386) || defined(__ARM_EABI__)
|
#if defined(__i386) || defined(__ARM_EABI__)
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
typedef Elf32_auxv_t elf_aux_entry;
|
typedef Elf32_auxv_t elf_aux_entry;
|
||||||
|
#else
|
||||||
|
// Android is missing this structure definition
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t a_type; /* Entry type */
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t a_val; /* Integer value */
|
||||||
|
} a_un;
|
||||||
|
} elf_aux_entry;
|
||||||
|
|
||||||
|
#if !defined(AT_SYSINFO_EHDR)
|
||||||
|
#define AT_SYSINFO_EHDR 33
|
||||||
|
#endif
|
||||||
|
#endif // __ANDROID__
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
typedef Elf64_auxv_t elf_aux_entry;
|
typedef Elf64_auxv_t elf_aux_entry;
|
||||||
#endif
|
#endif
|
||||||
@ -77,8 +97,12 @@ struct ThreadInfo {
|
|||||||
|
|
||||||
#elif defined(__ARM_EABI__)
|
#elif defined(__ARM_EABI__)
|
||||||
// Mimicking how strace does this(see syscall.c, search for GETREGS)
|
// Mimicking how strace does this(see syscall.c, search for GETREGS)
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
struct pt_regs regs;
|
||||||
|
#else
|
||||||
struct user_regs regs;
|
struct user_regs regs;
|
||||||
struct user_fpregs fpregs;
|
struct user_fpregs fpregs;
|
||||||
|
#endif // __ANDROID__
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,11 +50,17 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include "client/linux/android_link.h"
|
||||||
|
#else
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
#include <sys/ucontext.h>
|
#include <sys/ucontext.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
|
#endif
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
#include "client/minidump_file_writer.h"
|
#include "client/minidump_file_writer.h"
|
||||||
@ -62,6 +68,7 @@
|
|||||||
#include "google_breakpad/common/minidump_cpu_amd64.h"
|
#include "google_breakpad/common/minidump_cpu_amd64.h"
|
||||||
#include "google_breakpad/common/minidump_cpu_x86.h"
|
#include "google_breakpad/common/minidump_cpu_x86.h"
|
||||||
|
|
||||||
|
#include "client/linux/android_ucontext.h"
|
||||||
#include "client/linux/handler/exception_handler.h"
|
#include "client/linux/handler/exception_handler.h"
|
||||||
#include "client/linux/minidump_writer/line_reader.h"
|
#include "client/linux/minidump_writer/line_reader.h"
|
||||||
#include "client/linux/minidump_writer/linux_dumper.h"
|
#include "client/linux/minidump_writer/linux_dumper.h"
|
||||||
@ -337,11 +344,13 @@ static void CPUFillFromThreadInfo(MDRawContextARM *out,
|
|||||||
out->iregs[i] = info.regs.uregs[i];
|
out->iregs[i] = info.regs.uregs[i];
|
||||||
// No CPSR register in ThreadInfo(it's not accessible via ptrace)
|
// No CPSR register in ThreadInfo(it's not accessible via ptrace)
|
||||||
out->cpsr = 0;
|
out->cpsr = 0;
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
out->float_save.fpscr = info.fpregs.fpsr |
|
out->float_save.fpscr = info.fpregs.fpsr |
|
||||||
(static_cast<u_int64_t>(info.fpregs.fpcr) << 32);
|
(static_cast<u_int64_t>(info.fpregs.fpcr) << 32);
|
||||||
//TODO: sort this out, actually collect floating point registers
|
//TODO: sort this out, actually collect floating point registers
|
||||||
memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
|
memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
|
||||||
memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
|
memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CPUFillFromUContext(MDRawContextARM *out, const ucontext *uc,
|
static void CPUFillFromUContext(MDRawContextARM *out, const ucontext *uc,
|
||||||
@ -375,11 +384,11 @@ static void CPUFillFromUContext(MDRawContextARM *out, const ucontext *uc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static uintptr_t InstructionPointer(const ThreadInfo& info) {
|
static uintptr_t InstructionPointer(const ThreadInfo& info) {
|
||||||
return info.regs.uregs[R12];
|
return info.regs.ARM_ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uintptr_t StackPointer(const ThreadInfo& info) {
|
static uintptr_t StackPointer(const ThreadInfo& info) {
|
||||||
return info.regs.uregs[R13];
|
return info.regs.ARM_sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uintptr_t StackPointer(const ucontext* uc) {
|
static uintptr_t StackPointer(const ucontext* uc) {
|
||||||
@ -457,7 +466,7 @@ class MinidumpWriter {
|
|||||||
// it to a MD_LINUX_DSO_DEBUG stream.
|
// it to a MD_LINUX_DSO_DEBUG stream.
|
||||||
struct r_debug* r_debug = NULL;
|
struct r_debug* r_debug = NULL;
|
||||||
uint32_t dynamic_length = 0;
|
uint32_t dynamic_length = 0;
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
for (int i = 0;;) {
|
for (int i = 0;;) {
|
||||||
ElfW(Dyn) dyn;
|
ElfW(Dyn) dyn;
|
||||||
dynamic_length += sizeof(dyn);
|
dynamic_length += sizeof(dyn);
|
||||||
@ -468,6 +477,7 @@ class MinidumpWriter {
|
|||||||
} else if (dyn.d_tag == DT_NULL)
|
} else if (dyn.d_tag == DT_NULL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// A minidump file contains a number of tagged streams. This is the number
|
// A minidump file contains a number of tagged streams. This is the number
|
||||||
// of stream which we write.
|
// of stream which we write.
|
||||||
@ -949,6 +959,9 @@ class MinidumpWriter {
|
|||||||
|
|
||||||
bool WriteDSODebugStream(MDRawDirectory* dirent, struct r_debug* r_debug,
|
bool WriteDSODebugStream(MDRawDirectory* dirent, struct r_debug* r_debug,
|
||||||
uint32_t dynamic_length) {
|
uint32_t dynamic_length) {
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
// The caller provided us with a pointer to "struct r_debug". We can
|
// The caller provided us with a pointer to "struct r_debug". We can
|
||||||
// look up the "r_map" field to get a linked list of all loaded DSOs.
|
// look up the "r_map" field to get a linked list of all loaded DSOs.
|
||||||
// Our list of DSOs potentially is different from the ones in the crashing
|
// Our list of DSOs potentially is different from the ones in the crashing
|
||||||
@ -1022,6 +1035,7 @@ class MinidumpWriter {
|
|||||||
delete[] dso_debug_data;
|
delete[] dso_debug_data;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
#endif // __ANDROID__
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -50,9 +50,12 @@ LOCAL_INCLUDES = -I$(srcdir)/../..
|
|||||||
CPPSRCS = \
|
CPPSRCS = \
|
||||||
file_id.cc \
|
file_id.cc \
|
||||||
guid_creator.cc \
|
guid_creator.cc \
|
||||||
http_upload.cc \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
ifneq (Android,$(OS_TARGET))
|
||||||
|
CPPSRCS += http_upload.cc
|
||||||
|
endif
|
||||||
|
|
||||||
HOST_CPPSRCS = \
|
HOST_CPPSRCS = \
|
||||||
dump_symbols.cc \
|
dump_symbols.cc \
|
||||||
file_id.cc \
|
file_id.cc \
|
||||||
|
@ -38,7 +38,11 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include "client/linux/android_link.h"
|
||||||
|
#else
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
@ -71,7 +75,7 @@ FileID::FileID(const char* path) {
|
|||||||
reinterpret_cast<const ElfW(Ehdr)*>(elf_base);
|
reinterpret_cast<const ElfW(Ehdr)*>(elf_base);
|
||||||
if (my_strncmp(elf_base, ELFMAG, SELFMAG) != 0)
|
if (my_strncmp(elf_base, ELFMAG, SELFMAG) != 0)
|
||||||
return false;
|
return false;
|
||||||
#if __ELF_NATIVE_CLASS == 32
|
#if __ELF_NATIVE_CLASS == 32 || ELFSIZE == 32
|
||||||
#define ELFCLASS ELFCLASS32
|
#define ELFCLASS ELFCLASS32
|
||||||
#else
|
#else
|
||||||
#define ELFCLASS ELFCLASS64
|
#define ELFCLASS ELFCLASS64
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user