diff options
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc')
-rw-r--r-- | toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc | 322 |
1 files changed, 0 insertions, 322 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc deleted file mode 100644 index c9491f6f2..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// crash_generator.cc: Implement google_breakpad::CrashGenerator. -// See crash_generator.h for details. - -#include "common/linux/tests/crash_generator.h" - -#include <pthread.h> -#include <signal.h> -#include <stdio.h> -#include <sys/mman.h> -#include <sys/resource.h> -#include <sys/syscall.h> -#include <sys/wait.h> -#include <unistd.h> - -#include <string> - -#if defined(__ANDROID__) -#include "common/android/testing/pthread_fixes.h" -#endif -#include "common/linux/eintr_wrapper.h" -#include "common/tests/auto_tempdir.h" -#include "common/tests/file_utils.h" -#include "common/using_std_string.h" - -namespace { - -struct ThreadData { - pthread_t thread; - pthread_barrier_t* barrier; - pid_t* thread_id_ptr; -}; - -const char* const kProcFilesToCopy[] = { - "auxv", "cmdline", "environ", "maps", "status" -}; -const size_t kNumProcFilesToCopy = - sizeof(kProcFilesToCopy) / sizeof(kProcFilesToCopy[0]); - -int gettid() { - // Glibc does not provide a wrapper for this. - return syscall(__NR_gettid); -} - -int tkill(pid_t tid, int sig) { - // Glibc does not provide a wrapper for this. - return syscall(__NR_tkill, tid, sig); -} - -// Core file size limit set to 1 MB, which is big enough for test purposes. -const rlim_t kCoreSizeLimit = 1024 * 1024; - -void *thread_function(void *data) { - ThreadData* thread_data = reinterpret_cast<ThreadData*>(data); - volatile pid_t thread_id = gettid(); - *(thread_data->thread_id_ptr) = thread_id; - int result = pthread_barrier_wait(thread_data->barrier); - if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) { - perror("Failed to wait for sync barrier"); - exit(1); - } - while (true) { - pthread_yield(); - } -} - -} // namespace - -namespace google_breakpad { - -CrashGenerator::CrashGenerator() - : shared_memory_(NULL), - shared_memory_size_(0) { -} - -CrashGenerator::~CrashGenerator() { - UnmapSharedMemory(); -} - -bool CrashGenerator::HasDefaultCorePattern() const { - char buffer[8]; - ssize_t buffer_size = sizeof(buffer); - return ReadFile("/proc/sys/kernel/core_pattern", buffer, &buffer_size) && - buffer_size == 5 && memcmp(buffer, "core", 4) == 0; -} - -string CrashGenerator::GetCoreFilePath() const { - return temp_dir_.path() + "/core"; -} - -string CrashGenerator::GetDirectoryOfProcFilesCopy() const { - return temp_dir_.path() + "/proc"; -} - -pid_t CrashGenerator::GetThreadId(unsigned index) const { - return reinterpret_cast<pid_t*>(shared_memory_)[index]; -} - -pid_t* CrashGenerator::GetThreadIdPointer(unsigned index) { - return reinterpret_cast<pid_t*>(shared_memory_) + index; -} - -bool CrashGenerator::MapSharedMemory(size_t memory_size) { - if (!UnmapSharedMemory()) - return false; - - void* mapped_memory = mmap(0, memory_size, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, -1, 0); - if (mapped_memory == MAP_FAILED) { - perror("CrashGenerator: Failed to map shared memory"); - return false; - } - - memset(mapped_memory, 0, memory_size); - shared_memory_ = mapped_memory; - shared_memory_size_ = memory_size; - return true; -} - -bool CrashGenerator::UnmapSharedMemory() { - if (!shared_memory_) - return true; - - if (munmap(shared_memory_, shared_memory_size_) == 0) { - shared_memory_ = NULL; - shared_memory_size_ = 0; - return true; - } - - perror("CrashGenerator: Failed to unmap shared memory"); - return false; -} - -bool CrashGenerator::SetCoreFileSizeLimit(rlim_t limit) const { - struct rlimit limits = { limit, limit }; - if (setrlimit(RLIMIT_CORE, &limits) == -1) { - perror("CrashGenerator: Failed to set core file size limit"); - return false; - } - return true; -} - -bool CrashGenerator::CreateChildCrash( - unsigned num_threads, unsigned crash_thread, int crash_signal, - pid_t* child_pid) { - if (num_threads == 0 || crash_thread >= num_threads) { - fprintf(stderr, "CrashGenerator: Invalid thread counts; num_threads=%u" - " crash_thread=%u\n", num_threads, crash_thread); - return false; - } - - if (!MapSharedMemory(num_threads * sizeof(pid_t))) { - perror("CrashGenerator: Unable to map shared memory"); - return false; - } - - pid_t pid = fork(); - if (pid == 0) { - if (chdir(temp_dir_.path().c_str()) == -1) { - perror("CrashGenerator: Failed to change directory"); - exit(1); - } - if (SetCoreFileSizeLimit(kCoreSizeLimit)) { - CreateThreadsInChildProcess(num_threads); - string proc_dir = GetDirectoryOfProcFilesCopy(); - if (mkdir(proc_dir.c_str(), 0755) == -1) { - perror("CrashGenerator: Failed to create proc directory"); - exit(1); - } - if (!CopyProcFiles(getpid(), proc_dir.c_str())) { - fprintf(stderr, "CrashGenerator: Failed to copy proc files\n"); - exit(1); - } - // On Android the signal sometimes doesn't seem to get sent even though - // tkill returns '0'. Retry a couple of times if the signal doesn't get - // through on the first go: - // https://code.google.com/p/google-breakpad/issues/detail?id=579 -#if defined(__ANDROID__) - const int kRetries = 60; - const unsigned int kSleepTimeInSeconds = 1; -#else - const int kRetries = 1; - const unsigned int kSleepTimeInSeconds = 600; -#endif - for (int i = 0; i < kRetries; i++) { - if (tkill(*GetThreadIdPointer(crash_thread), crash_signal) == -1) { - perror("CrashGenerator: Failed to kill thread by signal"); - } else { - // At this point, we've queued the signal for delivery, but there's no - // guarantee when it'll be delivered. We don't want the main thread to - // race and exit before the thread we signaled is processed. So sleep - // long enough that we won't flake even under fairly high load. - // TODO: See if we can't be a bit more deterministic. There doesn't - // seem to be an API to check on signal delivery status, so we can't - // really poll and wait for the kernel to declare the signal has been - // delivered. If it has, and things worked, we'd be killed, so the - // sleep length doesn't really matter. - sleep(kSleepTimeInSeconds); - } - } - } else { - perror("CrashGenerator: Failed to set core limit"); - } - exit(1); - } else if (pid == -1) { - perror("CrashGenerator: Failed to create child process"); - return false; - } - - int status; - if (HANDLE_EINTR(waitpid(pid, &status, 0)) == -1) { - perror("CrashGenerator: Failed to wait for child process"); - return false; - } - if (!WIFSIGNALED(status) || WTERMSIG(status) != crash_signal) { - fprintf(stderr, "CrashGenerator: Child process not killed by the expected signal\n" - " exit status=0x%x pid=%u signaled=%s sig=%d expected=%d\n", - status, pid, WIFSIGNALED(status) ? "true" : "false", - WTERMSIG(status), crash_signal); - return false; - } - - if (child_pid) - *child_pid = pid; - return true; -} - -bool CrashGenerator::CopyProcFiles(pid_t pid, const char* path) const { - char from_path[PATH_MAX], to_path[PATH_MAX]; - for (size_t i = 0; i < kNumProcFilesToCopy; ++i) { - int num_chars = snprintf(from_path, PATH_MAX, "/proc/%d/%s", - pid, kProcFilesToCopy[i]); - if (num_chars < 0 || num_chars >= PATH_MAX) - return false; - - num_chars = snprintf(to_path, PATH_MAX, "%s/%s", - path, kProcFilesToCopy[i]); - if (num_chars < 0 || num_chars >= PATH_MAX) - return false; - - if (!CopyFile(from_path, to_path)) - return false; - } - return true; -} - -void CrashGenerator::CreateThreadsInChildProcess(unsigned num_threads) { - *GetThreadIdPointer(0) = getpid(); - - if (num_threads <= 1) - return; - - // This method does not clean up any pthread resource, as the process - // is expected to be killed anyway. - ThreadData* thread_data = new ThreadData[num_threads]; - - // Create detached threads so that we do not worry about pthread_join() - // later being called or not. - pthread_attr_t thread_attributes; - if (pthread_attr_init(&thread_attributes) != 0 || - pthread_attr_setdetachstate(&thread_attributes, - PTHREAD_CREATE_DETACHED) != 0) { - fprintf(stderr, "CrashGenerator: Failed to initialize thread attribute\n"); - exit(1); - } - - pthread_barrier_t thread_barrier; - if (pthread_barrier_init(&thread_barrier, NULL, num_threads) != 0) { - fprintf(stderr, "CrashGenerator: Failed to initialize thread barrier\n"); - exit(1); - } - - for (unsigned i = 1; i < num_threads; ++i) { - thread_data[i].barrier = &thread_barrier; - thread_data[i].thread_id_ptr = GetThreadIdPointer(i); - if (pthread_create(&thread_data[i].thread, &thread_attributes, - thread_function, &thread_data[i]) != 0) { - fprintf(stderr, "CrashGenerator: Failed to create thread %d\n", i); - exit(1); - } - } - - int result = pthread_barrier_wait(&thread_barrier); - if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) { - fprintf(stderr, "CrashGenerator: Failed to wait for thread barrier\n"); - exit(1); - } - - pthread_barrier_destroy(&thread_barrier); - pthread_attr_destroy(&thread_attributes); - delete[] thread_data; -} - -} // namespace google_breakpad |