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 54 namespace { 55 56 struct ThreadData { 57 pthread_t thread; 58 pthread_barrier_t* barrier; 59 pid_t* thread_id_ptr; 60 }; 61 62 const char* const kProcFilesToCopy[] = { 63 "auxv", "cmdline", "environ", "maps", "status" 64 }; 65 const size_t kNumProcFilesToCopy = 66 sizeof(kProcFilesToCopy) / sizeof(kProcFilesToCopy[0]); 67 68 int gettid() { 69 // Glibc does not provide a wrapper for this. 70 return syscall(__NR_gettid); 71 } 72 73 int 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. 79 const rlim_t kCoreSizeLimit = 1024 * 1024; 80 81 void *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 97 namespace google_breakpad { 98 99 CrashGenerator::CrashGenerator() 100 : shared_memory_(NULL), 101 shared_memory_size_(0) { 102 } 103 104 CrashGenerator::~CrashGenerator() { 105 UnmapSharedMemory(); 106 } 107 108 bool 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 115 string CrashGenerator::GetCoreFilePath() const { 116 return temp_dir_.path() + "/core"; 117 } 118 119 string CrashGenerator::GetDirectoryOfProcFilesCopy() const { 120 return temp_dir_.path() + "/proc"; 121 } 122 123 pid_t CrashGenerator::GetThreadId(unsigned index) const { 124 return reinterpret_cast<pid_t*>(shared_memory_)[index]; 125 } 126 127 pid_t* CrashGenerator::GetThreadIdPointer(unsigned index) { 128 return reinterpret_cast<pid_t*>(shared_memory_) + index; 129 } 130 131 bool 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 148 bool 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 162 bool 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 171 bool 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 256 bool 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 275 void 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