From cfc8628092e17069d8d6c7068d4f21d9baabe077 Mon Sep 17 00:00:00 2001 From: "ted.mielczarek" Date: Wed, 20 Oct 2010 15:51:38 +0000 Subject: Add support for building the Linux client code using the Android NDK r=mwu at http://breakpad.appspot.com/212001/show git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@716 4c0a9323-5329-0410-9bdc-e9ce6186880e --- .../linux/minidump_writer/line_reader_unittest.cc | 8 +++++++- src/client/linux/minidump_writer/linux_dumper.cc | 13 +++++++++--- src/client/linux/minidump_writer/linux_dumper.h | 24 ++++++++++++++++++++++ .../linux/minidump_writer/linux_dumper_unittest.cc | 24 +++++++++++++++++++--- .../linux_dumper_unittest_helper.cc | 4 +++- .../linux/minidump_writer/minidump_writer.cc | 19 ++++++++++++++++- .../minidump_writer/minidump_writer_unittest.cc | 8 +++++++- 7 files changed, 90 insertions(+), 10 deletions(-) (limited to 'src/client/linux/minidump_writer') diff --git a/src/client/linux/minidump_writer/line_reader_unittest.cc b/src/client/linux/minidump_writer/line_reader_unittest.cc index 7c4c3ced..a2ea17f7 100644 --- a/src/client/linux/minidump_writer/line_reader_unittest.cc +++ b/src/client/linux/minidump_writer/line_reader_unittest.cc @@ -36,8 +36,14 @@ using namespace google_breakpad; +#if !defined(__ANDROID__) +#define TEMPDIR "/tmp" +#else +#define TEMPDIR "/data/local/tmp" +#endif + static int TemporaryFile() { - static const char templ[] = "/tmp/line-reader-unittest-XXXXXX"; + static const char templ[] = TEMPDIR "/line-reader-unittest-XXXXXX"; char templ_copy[sizeof(templ)]; memcpy(templ_copy, templ, sizeof(templ)); const int fd = mkstemp(templ_copy); diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc index b7ee1c4d..11b6a18b 100644 --- a/src/client/linux/minidump_writer/linux_dumper.cc +++ b/src/client/linux/minidump_writer/linux_dumper.cc @@ -45,7 +45,9 @@ #include #include #include +#if !defined(__ANDROID__) #include +#endif #include #include @@ -388,11 +390,16 @@ bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo* info) { if (info->ppid == -1 || info->tgid == -1) return false; - if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1 || - sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) { + if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) { return false; } +#if !defined(__ANDROID__) + if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) { + return false; + } +#endif + #if defined(__i386) if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) return false; @@ -417,7 +424,7 @@ bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo* info) { #elif defined(__x86_64) memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); #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 #error "This code hasn't been ported to your platform yet." #endif diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h index b0c479a9..71d1188f 100644 --- a/src/client/linux/minidump_writer/linux_dumper.h +++ b/src/client/linux/minidump_writer/linux_dumper.h @@ -34,18 +34,38 @@ #include #include #include +#if !defined(__ANDROID__) #include +#endif #include "common/memory.h" #include "google_breakpad/common/minidump_format.h" namespace google_breakpad { +#if defined(__i386) || defined(__x86_64) typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t; +#endif // Typedef for our parsing of the auxv variables in /proc/pid/auxv. #if defined(__i386) || defined(__ARM_EABI__) +#if !defined(__ANDROID__) 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__) typedef Elf64_auxv_t elf_aux_entry; #endif @@ -76,8 +96,12 @@ struct ThreadInfo { #elif defined(__ARM_EABI__) // 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_fpregs fpregs; +#endif // __ANDROID__ #endif }; diff --git a/src/client/linux/minidump_writer/linux_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_dumper_unittest.cc index 8cfb6004..b81291b6 100644 --- a/src/client/linux/minidump_writer/linux_dumper_unittest.cc +++ b/src/client/linux/minidump_writer/linux_dumper_unittest.cc @@ -27,6 +27,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include + #include #include #include @@ -37,6 +39,7 @@ #include "common/linux/file_id.h" #include "common/memory.h" +using std::string; using namespace google_breakpad; // This provides a wrapper around system calls which may be @@ -87,21 +90,36 @@ TEST(LinuxDumperTest, VerifyStackReadWithMultipleThreads) { pid_t child_pid = fork(); if (child_pid == 0) { + // Locate helper binary next to the current binary. + char self_path[PATH_MAX]; + if (readlink("/proc/self/exe", self_path, sizeof(self_path) - 1) == -1) { + FAIL() << "readlink failed: " << strerror(errno); + exit(1); + } + string helper_path(self_path); + size_t pos = helper_path.rfind('/'); + if (pos == string::npos) { + FAIL() << "no trailing slash in path: " << helper_path; + exit(1); + } + helper_path.erase(pos + 1); + helper_path += "linux_dumper_unittest_helper"; + // Set the number of threads - execl("src/client/linux/linux_dumper_unittest_helper", + execl(helper_path.c_str(), "linux_dumper_unittest_helper", kNumberOfThreadsArgument, NULL); // Kill if we get here. printf("Errno from exec: %d", errno); - FAIL() << "Exec failed: " << strerror(errno); + FAIL() << "Exec of " << helper_path << " failed: " << strerror(errno); exit(0); } // The sleep is flaky, but prevents us from reading // the child process before all threads have been created. sleep(1); LinuxDumper dumper(child_pid); - EXPECT_TRUE(dumper.Init()); + ASSERT_TRUE(dumper.Init()); EXPECT_EQ((size_t)kNumberOfThreadsInHelperProgram, dumper.threads().size()); EXPECT_TRUE(dumper.ThreadsSuspend()); diff --git a/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc b/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc index e91e9767..6b7ad5a2 100644 --- a/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc +++ b/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc @@ -37,6 +37,8 @@ #include #include +#include "third_party/lss/linux_syscall_support.h" + #if defined(__ARM_EABI__) #define TID_PTR_REGISTER "r3" #elif defined(__i386) @@ -48,7 +50,7 @@ #endif void *thread_function(void *data) { - volatile pid_t thread_id = syscall(SYS_gettid); + volatile pid_t thread_id = syscall(__NR_gettid); register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = &thread_id; while (true) asm volatile ("" : : "r" (thread_id_ptr)); diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index d629ee81..9deed20b 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -50,11 +50,15 @@ #include #include +#if !defined(__ANDROID__) #include +#endif #include #include +#if !defined(__ANDROID__) #include #include +#endif #include #include "client/minidump_file_writer.h" @@ -62,6 +66,10 @@ #include "google_breakpad/common/minidump_cpu_amd64.h" #include "google_breakpad/common/minidump_cpu_x86.h" +#if defined(__ANDROID__) +#include "client/linux/android_link.h" +#include "client/linux/android_ucontext.h" +#endif #include "client/linux/handler/exception_handler.h" #include "client/linux/minidump_writer/line_reader.h" #include "client/linux/minidump_writer/linux_dumper.h" @@ -311,11 +319,13 @@ static void CPUFillFromThreadInfo(MDRawContextARM *out, out->iregs[i] = info.regs.uregs[i]; // No CPSR register in ThreadInfo(it's not accessible via ptrace) out->cpsr = 0; +#if !defined(__ANDROID__) out->float_save.fpscr = info.fpregs.fpsr | (static_cast(info.fpregs.fpcr) << 32); //TODO: sort this out, actually collect floating point registers memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); +#endif } static void CPUFillFromUContext(MDRawContextARM *out, const ucontext *uc, @@ -389,7 +399,9 @@ class MinidumpWriter { // it to a MD_LINUX_DSO_DEBUG stream. struct r_debug* r_debug = NULL; uint32_t dynamic_length = 0; - +#if !defined(__ANDROID__) + // The Android NDK is missing structure definitions for most of this. + // For now, it's simpler just to skip it. for (int i = 0;;) { ElfW(Dyn) dyn; dynamic_length += sizeof(dyn); @@ -400,6 +412,7 @@ class MinidumpWriter { } else if (dyn.d_tag == DT_NULL) break; } +#endif // A minidump file contains a number of tagged streams. This is the number // of stream which we write. @@ -866,6 +879,9 @@ class MinidumpWriter { bool WriteDSODebugStream(MDRawDirectory* dirent, struct r_debug* r_debug, uint32_t dynamic_length) { +#if defined(__ANDROID__) + return false; +#else // 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. // Our list of DSOs potentially is different from the ones in the crashing @@ -939,6 +955,7 @@ class MinidumpWriter { delete[] dso_debug_data; return true; +#endif } private: diff --git a/src/client/linux/minidump_writer/minidump_writer_unittest.cc b/src/client/linux/minidump_writer/minidump_writer_unittest.cc index 0c02f587..e7a62145 100644 --- a/src/client/linux/minidump_writer/minidump_writer_unittest.cc +++ b/src/client/linux/minidump_writer/minidump_writer_unittest.cc @@ -37,6 +37,12 @@ using namespace google_breakpad; +#if !defined(__ANDROID__) +#define TEMPDIR "/tmp" +#else +#define TEMPDIR "/data/local/tmp" +#endif + namespace { typedef testing::Test MinidumpWriterTest; } @@ -58,7 +64,7 @@ TEST(MinidumpWriterTest, Setup) { ExceptionHandler::CrashContext context; memset(&context, 0, sizeof(context)); - char templ[] = "/tmp/minidump-writer-unittest-XXXXXX"; + char templ[] = TEMPDIR "/minidump-writer-unittest-XXXXXX"; mktemp(templ); ASSERT_TRUE(WriteMinidump(templ, child, &context, sizeof(context))); struct stat st; -- cgit v1.2.1