1// Copyright (c) 2011, Google Inc. 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are 6// met: 7// 8// * Redistributions of source code must retain the above copyright 9// notice, this list of conditions and the following disclaimer. 10// * Redistributions in binary form must reproduce the above 11// copyright notice, this list of conditions and the following disclaimer 12// in the documentation and/or other materials provided with the 13// distribution. 14// * Neither the name of Google Inc. nor the names of its 15// contributors may be used to endorse or promote products derived from 16// this software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30// crash_generator.cc: Implement google_breakpad::CrashGenerator. 31// See crash_generator.h for details. 32 33#include "common/linux/tests/crash_generator.h" 34 35#include <pthread.h> 36#include <signal.h> 37#include <stdio.h> 38#include <sys/mman.h> 39#include <sys/resource.h> 40#include <sys/syscall.h> 41#include <sys/wait.h> 42#include <unistd.h> 43 44#include <string> 45 46#if defined(__ANDROID__) 47#include "common/android/testing/pthread_fixes.h" 48#endif 49#include "common/linux/eintr_wrapper.h" 50#include "common/tests/auto_tempdir.h" 51#include "common/tests/file_utils.h" 52#include "common/using_std_string.h" 53 54namespace { 55 56struct ThreadData { 57 pthread_t thread; 58 pthread_barrier_t* barrier; 59 pid_t* thread_id_ptr; 60}; 61 62const char* const kProcFilesToCopy[] = { 63 "auxv", "cmdline", "environ", "maps", "status" 64}; 65const size_t kNumProcFilesToCopy = 66 sizeof(kProcFilesToCopy) / sizeof(kProcFilesToCopy[0]); 67 68int gettid() { 69 // Glibc does not provide a wrapper for this. 70 return syscall(__NR_gettid); 71} 72 73int tkill(pid_t tid, int sig) { 74 // Glibc does not provide a wrapper for this. 75 return syscall(__NR_tkill, tid, sig); 76} 77 78// Core file size limit set to 1 MB, which is big enough for test purposes. 79const rlim_t kCoreSizeLimit = 1024 * 1024; 80 81void *thread_function(void *data) { 82 ThreadData* thread_data = reinterpret_cast<ThreadData*>(data); 83 volatile pid_t thread_id = gettid(); 84 *(thread_data->thread_id_ptr) = thread_id; 85 int result = pthread_barrier_wait(thread_data->barrier); 86 if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) { 87 perror("Failed to wait for sync barrier"); 88 exit(1); 89 } 90 while (true) { 91 pthread_yield(); 92 } 93} 94 95} // namespace 96 97namespace google_breakpad { 98 99CrashGenerator::CrashGenerator() 100 : shared_memory_(NULL), 101 shared_memory_size_(0) { 102} 103 104CrashGenerator::~CrashGenerator() { 105 UnmapSharedMemory(); 106} 107 108bool CrashGenerator::HasDefaultCorePattern() const { 109 char buffer[8]; 110 ssize_t buffer_size = sizeof(buffer); 111 return ReadFile("/proc/sys/kernel/core_pattern", buffer, &buffer_size) && 112 buffer_size == 5 && memcmp(buffer, "core", 4) == 0; 113} 114 115string CrashGenerator::GetCoreFilePath() const { 116 return temp_dir_.path() + "/core"; 117} 118 119string CrashGenerator::GetDirectoryOfProcFilesCopy() const { 120 return temp_dir_.path() + "/proc"; 121} 122 123pid_t CrashGenerator::GetThreadId(unsigned index) const { 124 return reinterpret_cast<pid_t*>(shared_memory_)[index]; 125} 126 127pid_t* CrashGenerator::GetThreadIdPointer(unsigned index) { 128 return reinterpret_cast<pid_t*>(shared_memory_) + index; 129} 130 131bool CrashGenerator::MapSharedMemory(size_t memory_size) { 132 if (!UnmapSharedMemory()) 133 return false; 134 135 void* mapped_memory = mmap(0, memory_size, PROT_READ | PROT_WRITE, 136 MAP_SHARED | MAP_ANONYMOUS, -1, 0); 137 if (mapped_memory == MAP_FAILED) { 138 perror("CrashGenerator: Failed to map shared memory"); 139 return false; 140 } 141 142 memset(mapped_memory, 0, memory_size); 143 shared_memory_ = mapped_memory; 144 shared_memory_size_ = memory_size; 145 return true; 146} 147 148bool CrashGenerator::UnmapSharedMemory() { 149 if (!shared_memory_) 150 return true; 151 152 if (munmap(shared_memory_, shared_memory_size_) == 0) { 153 shared_memory_ = NULL; 154 shared_memory_size_ = 0; 155 return true; 156 } 157 158 perror("CrashGenerator: Failed to unmap shared memory"); 159 return false; 160} 161 162bool CrashGenerator::SetCoreFileSizeLimit(rlim_t limit) const { 163 struct rlimit limits = { limit, limit }; 164 if (setrlimit(RLIMIT_CORE, &limits) == -1) { 165 perror("CrashGenerator: Failed to set core file size limit"); 166 return false; 167 } 168 return true; 169} 170 171bool CrashGenerator::CreateChildCrash( 172 unsigned num_threads, unsigned crash_thread, int crash_signal, 173 pid_t* child_pid) { 174 if (num_threads == 0 || crash_thread >= num_threads) { 175 fprintf(stderr, "CrashGenerator: Invalid thread counts; num_threads=%u" 176 " crash_thread=%u\n", num_threads, crash_thread); 177 return false; 178 } 179 180 if (!MapSharedMemory(num_threads * sizeof(pid_t))) { 181 perror("CrashGenerator: Unable to map shared memory"); 182 return false; 183 } 184 185 pid_t pid = fork(); 186 if (pid == 0) { 187 if (chdir(temp_dir_.path().c_str()) == -1) { 188 perror("CrashGenerator: Failed to change directory"); 189 exit(1); 190 } 191 if (SetCoreFileSizeLimit(kCoreSizeLimit)) { 192 CreateThreadsInChildProcess(num_threads); 193 string proc_dir = GetDirectoryOfProcFilesCopy(); 194 if (mkdir(proc_dir.c_str(), 0755) == -1) { 195 perror("CrashGenerator: Failed to create proc directory"); 196 exit(1); 197 } 198 if (!CopyProcFiles(getpid(), proc_dir.c_str())) { 199 fprintf(stderr, "CrashGenerator: Failed to copy proc files\n"); 200 exit(1); 201 } 202 // On Android the signal sometimes doesn't seem to get sent even though 203 // tkill returns '0'. Retry a couple of times if the signal doesn't get 204 // through on the first go: 205 // https://code.google.com/p/google-breakpad/issues/detail?id=579 206#if defined(__ANDROID__) 207 const int kRetries = 60; 208 const unsigned int kSleepTimeInSeconds = 1; 209#else 210 const int kRetries = 1; 211 const unsigned int kSleepTimeInSeconds = 600; 212#endif 213 for (int i = 0; i < kRetries; i++) { 214 if (tkill(*GetThreadIdPointer(crash_thread), crash_signal) == -1) { 215 perror("CrashGenerator: Failed to kill thread by signal"); 216 } else { 217 // At this point, we've queued the signal for delivery, but there's no 218 // guarantee when it'll be delivered. We don't want the main thread to 219 // race and exit before the thread we signaled is processed. So sleep 220 // long enough that we won't flake even under fairly high load. 221 // TODO: See if we can't be a bit more deterministic. There doesn't 222 // seem to be an API to check on signal delivery status, so we can't 223 // really poll and wait for the kernel to declare the signal has been 224 // delivered. If it has, and things worked, we'd be killed, so the 225 // sleep length doesn't really matter. 226 sleep(kSleepTimeInSeconds); 227 } 228 } 229 } else { 230 perror("CrashGenerator: Failed to set core limit"); 231 } 232 exit(1); 233 } else if (pid == -1) { 234 perror("CrashGenerator: Failed to create child process"); 235 return false; 236 } 237 238 int status; 239 if (HANDLE_EINTR(waitpid(pid, &status, 0)) == -1) { 240 perror("CrashGenerator: Failed to wait for child process"); 241 return false; 242 } 243 if (!WIFSIGNALED(status) || WTERMSIG(status) != crash_signal) { 244 fprintf(stderr, "CrashGenerator: Child process not killed by the expected signal\n" 245 " exit status=0x%x pid=%u signaled=%s sig=%d expected=%d\n", 246 status, pid, WIFSIGNALED(status) ? "true" : "false", 247 WTERMSIG(status), crash_signal); 248 return false; 249 } 250 251 if (child_pid) 252 *child_pid = pid; 253 return true; 254} 255 256bool CrashGenerator::CopyProcFiles(pid_t pid, const char* path) const { 257 char from_path[PATH_MAX], to_path[PATH_MAX]; 258 for (size_t i = 0; i < kNumProcFilesToCopy; ++i) { 259 int num_chars = snprintf(from_path, PATH_MAX, "/proc/%d/%s", 260 pid, kProcFilesToCopy[i]); 261 if (num_chars < 0 || num_chars >= PATH_MAX) 262 return false; 263 264 num_chars = snprintf(to_path, PATH_MAX, "%s/%s", 265 path, kProcFilesToCopy[i]); 266 if (num_chars < 0 || num_chars >= PATH_MAX) 267 return false; 268 269 if (!CopyFile(from_path, to_path)) 270 return false; 271 } 272 return true; 273} 274 275void CrashGenerator::CreateThreadsInChildProcess(unsigned num_threads) { 276 *GetThreadIdPointer(0) = getpid(); 277 278 if (num_threads <= 1) 279 return; 280 281 // This method does not clean up any pthread resource, as the process 282 // is expected to be killed anyway. 283 ThreadData* thread_data = new ThreadData[num_threads]; 284 285 // Create detached threads so that we do not worry about pthread_join() 286 // later being called or not. 287 pthread_attr_t thread_attributes; 288 if (pthread_attr_init(&thread_attributes) != 0 || 289 pthread_attr_setdetachstate(&thread_attributes, 290 PTHREAD_CREATE_DETACHED) != 0) { 291 fprintf(stderr, "CrashGenerator: Failed to initialize thread attribute\n"); 292 exit(1); 293 } 294 295 pthread_barrier_t thread_barrier; 296 if (pthread_barrier_init(&thread_barrier, NULL, num_threads) != 0) { 297 fprintf(stderr, "CrashGenerator: Failed to initialize thread barrier\n"); 298 exit(1); 299 } 300 301 for (unsigned i = 1; i < num_threads; ++i) { 302 thread_data[i].barrier = &thread_barrier; 303 thread_data[i].thread_id_ptr = GetThreadIdPointer(i); 304 if (pthread_create(&thread_data[i].thread, &thread_attributes, 305 thread_function, &thread_data[i]) != 0) { 306 fprintf(stderr, "CrashGenerator: Failed to create thread %d\n", i); 307 exit(1); 308 } 309 } 310 311 int result = pthread_barrier_wait(&thread_barrier); 312 if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) { 313 fprintf(stderr, "CrashGenerator: Failed to wait for thread barrier\n"); 314 exit(1); 315 } 316 317 pthread_barrier_destroy(&thread_barrier); 318 pthread_attr_destroy(&thread_attributes); 319 delete[] thread_data; 320} 321 322} // namespace google_breakpad 323