1 | // Copyright (c) 2020, 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 | // core_handler.cc: A tool to handle coredumps on Linux |
31 | |
32 | #include <pwd.h> |
33 | #include <stdio.h> |
34 | #include <stdlib.h> |
35 | #include <sys/mman.h> |
36 | #include <sys/types.h> |
37 | #include <syslog.h> |
38 | #include <unistd.h> |
39 | #include <sstream> |
40 | |
41 | #include "client/linux/minidump_writer/linux_core_dumper.h" |
42 | #include "client/linux/minidump_writer/minidump_writer.h" |
43 | #include "common/path_helper.h" |
44 | #include "common/scoped_ptr.h" |
45 | |
46 | namespace { |
47 | |
48 | using google_breakpad::AppMemoryList; |
49 | using google_breakpad::LinuxCoreDumper; |
50 | using google_breakpad::MappingList; |
51 | using google_breakpad::scoped_array; |
52 | |
53 | // Size of the core dump to read in order to access all the threads |
54 | // descriptions. |
55 | // |
56 | // The first section is the note0 section which contains the thread states. On |
57 | // x86-64 a typical thread description take about 1432B. Reading 1 MB allows |
58 | // several hundreds of threads. |
59 | const int core_read_size = 1024 * 1024; |
60 | |
61 | void ShowUsage(const char* argv0) { |
62 | fprintf(stderr, "Usage: %s <process id> <minidump file>\n\n" , |
63 | google_breakpad::BaseName(argv0).c_str()); |
64 | fprintf(stderr, |
65 | "A tool which serves as a core dump handler and produces " |
66 | "minidump files.\n" ); |
67 | fprintf(stderr, "Please refer to the online documentation:\n" ); |
68 | fprintf(stderr, |
69 | "https://chromium.googlesource.com/breakpad/breakpad/+/HEAD" |
70 | "/docs/linux_core_handler.md\n" ); |
71 | } |
72 | |
73 | bool WriteMinidumpFromCore(const char* filename, |
74 | const char* core_path, |
75 | const char* procfs_override) { |
76 | MappingList mappings; |
77 | AppMemoryList memory_list; |
78 | LinuxCoreDumper dumper(0, core_path, procfs_override); |
79 | return google_breakpad::WriteMinidump(filename, mappings, memory_list, |
80 | &dumper); |
81 | } |
82 | |
83 | bool HandleCrash(pid_t pid, const char* procfs_dir, const char* md_filename) { |
84 | int r = 0; |
85 | scoped_array<char> buf(new char[core_read_size]); |
86 | while (r != core_read_size) { |
87 | int ret = read(STDIN_FILENO, &buf[r], core_read_size - r); |
88 | if (ret == 0) { |
89 | break; |
90 | } else if (ret == -1) { |
91 | return false; |
92 | } |
93 | r += ret; |
94 | } |
95 | |
96 | int fd = memfd_create("core_file" , MFD_CLOEXEC); |
97 | if (fd == -1) { |
98 | return false; |
99 | } |
100 | |
101 | int w = write(fd, &buf[0], r); |
102 | if (w != r) { |
103 | close(fd); |
104 | return false; |
105 | } |
106 | |
107 | std::stringstream core_file_ss; |
108 | core_file_ss << "/proc/self/fd/" << fd; |
109 | std::string core_file(core_file_ss.str()); |
110 | |
111 | if (!WriteMinidumpFromCore(md_filename, core_file.c_str(), procfs_dir)) { |
112 | close(fd); |
113 | return false; |
114 | } |
115 | close(fd); |
116 | |
117 | return true; |
118 | } |
119 | |
120 | } // namespace |
121 | |
122 | int main(int argc, char* argv[]) { |
123 | int ret = EXIT_FAILURE; |
124 | |
125 | if (argc != 3) { |
126 | ShowUsage(argv[0]); |
127 | return ret; |
128 | } |
129 | |
130 | const char* pid_str = argv[1]; |
131 | const char* md_filename = argv[2]; |
132 | pid_t pid = atoi(pid_str); |
133 | |
134 | std::stringstream proc_dir_ss; |
135 | proc_dir_ss << "/proc/" << pid_str; |
136 | std::string proc_dir(proc_dir_ss.str()); |
137 | |
138 | openlog("core_handler" , 0, 0); |
139 | if (HandleCrash(pid, proc_dir.c_str(), md_filename)) { |
140 | syslog(LOG_NOTICE, "Minidump generated at %s\n" , md_filename); |
141 | ret = EXIT_SUCCESS; |
142 | } else { |
143 | syslog(LOG_ERR, "Cannot generate minidump %s\n" , md_filename); |
144 | } |
145 | closelog(); |
146 | |
147 | return ret; |
148 | } |
149 | |