core_handler.cc
1 // Copyright 2020 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 // core_handler.cc: A tool to handle coredumps on Linux 30 31 #ifdef HAVE_CONFIG_H 32 #include <config.h> // Must come first 33 #endif 34 35 #include <pwd.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <sys/mman.h> 39 #include <sys/types.h> 40 #include <syslog.h> 41 #include <unistd.h> 42 #include <sstream> 43 44 #include "client/linux/minidump_writer/linux_core_dumper.h" 45 #include "client/linux/minidump_writer/minidump_writer.h" 46 #include "common/path_helper.h" 47 #include "common/scoped_ptr.h" 48 49 namespace { 50 51 using google_breakpad::AppMemoryList; 52 using google_breakpad::LinuxCoreDumper; 53 using google_breakpad::MappingList; 54 using google_breakpad::scoped_array; 55 56 // Size of the core dump to read in order to access all the threads 57 // descriptions. 58 // 59 // The first section is the note0 section which contains the thread states. On 60 // x86-64 a typical thread description take about 1432B. Reading 1 MB allows 61 // several hundreds of threads. 62 const int core_read_size = 1024 * 1024; 63 64 void ShowUsage(const char* argv0) { 65 fprintf(stderr, "Usage: %s <process id> <minidump file>\n\n", 66 google_breakpad::BaseName(argv0).c_str()); 67 fprintf(stderr, 68 "A tool which serves as a core dump handler and produces " 69 "minidump files.\n"); 70 fprintf(stderr, "Please refer to the online documentation:\n"); 71 fprintf(stderr, 72 "https://chromium.googlesource.com/breakpad/breakpad/+/HEAD" 73 "/docs/linux_core_handler.md\n"); 74 } 75 76 bool WriteMinidumpFromCore(const char* filename, 77 const char* core_path, 78 const char* procfs_override) { 79 MappingList mappings; 80 AppMemoryList memory_list; 81 LinuxCoreDumper dumper(0, core_path, procfs_override); 82 return google_breakpad::WriteMinidump(filename, mappings, memory_list, 83 &dumper); 84 } 85 86 bool HandleCrash(pid_t pid, const char* procfs_dir, const char* md_filename) { 87 int r = 0; 88 scoped_array<char> buf(new char[core_read_size]); 89 while (r != core_read_size) { 90 int ret = read(STDIN_FILENO, &buf[r], core_read_size - r); 91 if (ret == 0) { 92 break; 93 } else if (ret == -1) { 94 return false; 95 } 96 r += ret; 97 } 98 99 int fd = memfd_create("core_file", MFD_CLOEXEC); 100 if (fd == -1) { 101 return false; 102 } 103 104 int w = write(fd, &buf[0], r); 105 if (w != r) { 106 close(fd); 107 return false; 108 } 109 110 std::stringstream core_file_ss; 111 core_file_ss << "/proc/self/fd/" << fd; 112 std::string core_file(core_file_ss.str()); 113 114 if (!WriteMinidumpFromCore(md_filename, core_file.c_str(), procfs_dir)) { 115 close(fd); 116 return false; 117 } 118 close(fd); 119 120 return true; 121 } 122 123 } // namespace 124 125 int main(int argc, char* argv[]) { 126 int ret = EXIT_FAILURE; 127 128 if (argc != 3) { 129 ShowUsage(argv[0]); 130 return ret; 131 } 132 133 const char* pid_str = argv[1]; 134 const char* md_filename = argv[2]; 135 pid_t pid = atoi(pid_str); 136 137 std::stringstream proc_dir_ss; 138 proc_dir_ss << "/proc/" << pid_str; 139 std::string proc_dir(proc_dir_ss.str()); 140 141 openlog("core_handler", 0, 0); 142 if (HandleCrash(pid, proc_dir.c_str(), md_filename)) { 143 syslog(LOG_NOTICE, "Minidump generated at %s\n", md_filename); 144 ret = EXIT_SUCCESS; 145 } else { 146 syslog(LOG_ERR, "Cannot generate minidump %s\n", md_filename); 147 } 148 closelog(); 149 150 return ret; 151 }