bug 595167 - Make Breakpad client libs work on Android. r=mwu a=blocking-fennec

This commit is contained in:
Ted Mielczarek 2010-10-13 11:37:58 -04:00
parent a593182495
commit cdd510c54b
10 changed files with 708 additions and 56 deletions

View File

@ -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

View File

@ -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_

View File

@ -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));

View File

@ -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"

View File

@ -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

View File

@ -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
}; };

View File

@ -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:

View File

@ -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 \

View File

@ -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