1 // Copyright 2012 The Kyua Authors. 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 copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of Google Inc. nor the names of its contributors 14 // may be used to endorse or promote products derived from this software 15 // 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 #include "utils/stacktrace.hpp" 30 31 extern "C" { 32 #include <sys/param.h> 33 #include <sys/resource.h> 34 35 #include <unistd.h> 36 } 37 38 #include <cerrno> 39 #include <cstdlib> 40 #include <cstring> 41 #include <fstream> 42 #include <iostream> 43 #include <stdexcept> 44 #include <string> 45 #include <vector> 46 47 #include "utils/datetime.hpp" 48 #include "utils/env.hpp" 49 #include "utils/format/macros.hpp" 50 #include "utils/fs/operations.hpp" 51 #include "utils/fs/path.hpp" 52 #include "utils/logging/macros.hpp" 53 #include "utils/optional.ipp" 54 #include "utils/process/executor.ipp" 55 #include "utils/process/operations.hpp" 56 #include "utils/process/status.hpp" 57 #include "utils/sanity.hpp" 58 59 namespace datetime = utils::datetime; 60 namespace executor = utils::process::executor; 61 namespace fs = utils::fs; 62 namespace process = utils::process; 63 64 using utils::none; 65 using utils::optional; 66 67 68 /// Built-in path to GDB. 69 /// 70 /// This is the value that should be passed to the find_gdb() function. If this 71 /// is an absolute path, then we use the binary specified by the variable; if it 72 /// is a relative path, we look for the binary in the path. 73 /// 74 /// Test cases can override the value of this built-in constant to unit-test the 75 /// behavior of the functions below. 76 const char* utils::builtin_gdb = GDB; 77 78 79 /// Maximum time the external GDB process is allowed to run for. 80 datetime::delta utils::gdb_timeout(60, 0); 81 82 83 namespace { 84 85 86 /// Maximum length of the core file name, if known. 87 /// 88 /// Some operating systems impose a maximum length on the basename of the core 89 /// file. If MAXCOMLEN is defined, then we need to truncate the program name to 90 /// this length before searching for the core file. If no such limit is known, 91 /// this is infinite. 92 static const std::string::size_type max_core_name_length = 93 #if defined(MAXCOMLEN) 94 MAXCOMLEN 95 #else 96 std::string::npos 97 #endif 98 ; 99 100 101 /// Functor to execute GDB in a subprocess. 102 class run_gdb { 103 /// Path to the GDB binary to use. 104 const fs::path& _gdb; 105 106 /// Path to the program being debugged. 107 const fs::path& _program; 108 109 /// Path to the dumped core. 110 const fs::path& _core_name; 111 112 public: 113 /// Constructs the functor. 114 /// 115 /// \param gdb_ Path to the GDB binary to use. 116 /// \param program_ Path to the program being debugged. Can be relative to 117 /// the given work directory. 118 /// \param core_name_ Path to the dumped core. Use find_core() to deduce 119 /// a valid candidate. Can be relative to the given work directory. 120 run_gdb(const fs::path& gdb_, const fs::path& program_, 121 const fs::path& core_name_) : 122 _gdb(gdb_), _program(program_), _core_name(core_name_) 123 { 124 } 125 126 /// Executes GDB. 127 /// 128 /// \param control_directory Directory where we can store control files to 129 /// not clobber any files created by the program being debugged. 130 void 131 operator()(const fs::path& control_directory) 132 { 133 const fs::path gdb_script_path = control_directory / "gdb.script"; 134 135 // Old versions of GDB, such as the one shipped by FreeBSD as of 136 // 11.0-CURRENT on 2014-11-26, do not support scripts on the command 137 // line via the '-ex' flag. Instead, we have to create a script file 138 // and use that instead. 139 std::ofstream gdb_script(gdb_script_path.c_str()); 140 if (!gdb_script) { 141 std::cerr << "Cannot create GDB script\n"; 142 ::_exit(EXIT_FAILURE); 143 } 144 gdb_script << "backtrace\n"; 145 gdb_script.close(); 146 147 utils::unsetenv("TERM"); 148 149 std::vector< std::string > args; 150 args.push_back("-batch"); 151 args.push_back("-q"); 152 args.push_back("-x"); 153 args.push_back(gdb_script_path.str()); 154 args.push_back(_program.str()); 155 args.push_back(_core_name.str()); 156 157 // Force all GDB output to go to stderr. We print messages to stderr 158 // when grabbing the stacktrace and we do not want GDB's output to end 159 // up split in two different files. 160 if (::dup2(STDERR_FILENO, STDOUT_FILENO) == -1) { 161 std::cerr << "Cannot redirect stdout to stderr\n"; 162 ::_exit(EXIT_FAILURE); 163 } 164 165 process::exec(_gdb, args); 166 } 167 }; 168 169 170 } // anonymous namespace 171 172 173 /// Looks for the path to the GDB binary. 174 /// 175 /// \return The absolute path to the GDB binary if any, otherwise none. Note 176 /// that the returned path may or may not be valid: there is no guarantee that 177 /// the path exists and is executable. 178 optional< fs::path > 179 utils::find_gdb(void) 180 { 181 if (std::strlen(builtin_gdb) == 0) { 182 LW("The builtin path to GDB is bogus, which probably indicates a bug " 183 "in the build system; cannot gather stack traces"); 184 return none; 185 } 186 187 const fs::path gdb(builtin_gdb); 188 if (gdb.is_absolute()) 189 return utils::make_optional(gdb); 190 else 191 return fs::find_in_path(gdb.c_str()); 192 } 193 194 195 /// Looks for a core file for the given program. 196 /// 197 /// \param program The name of the binary that generated the core file. Can be 198 /// either absolute or relative. 199 /// \param status The exit status of the program. This is necessary to gather 200 /// the PID. 201 /// \param work_directory The directory from which the program was run. 202 /// 203 /// \return The path to the core file, if found; otherwise none. 204 optional< fs::path > 205 utils::find_core(const fs::path& program, const process::status& status, 206 const fs::path& work_directory) 207 { 208 std::vector< fs::path > candidates; 209 210 candidates.push_back(work_directory / 211 (program.leaf_name().substr(0, max_core_name_length) + ".core")); 212 if (program.is_absolute()) { 213 candidates.push_back(program.branch_path() / 214 (program.leaf_name().substr(0, max_core_name_length) + ".core")); 215 } 216 candidates.push_back(work_directory / (F("core.%s") % status.dead_pid())); 217 candidates.push_back(fs::path("/cores") / 218 (F("core.%s") % status.dead_pid())); 219 220 for (std::vector< fs::path >::const_iterator iter = candidates.begin(); 221 iter != candidates.end(); ++iter) { 222 if (fs::exists(*iter)) { 223 LD(F("Attempting core file candidate %s: found") % *iter); 224 return utils::make_optional(*iter); 225 } else { 226 LD(F("Attempting core file candidate %s: not found") % *iter); 227 } 228 } 229 return none; 230 } 231 232 233 /// Raises core size limit to its possible maximum. 234 /// 235 /// This is a best-effort operation. There is no guarantee that the operation 236 /// will yield a large-enough limit to generate any possible core file. 237 /// 238 /// \return True if the core size could be unlimited; false otherwise. 239 bool 240 utils::unlimit_core_size(void) 241 { 242 bool ok; 243 244 struct ::rlimit rl; 245 if (::getrlimit(RLIMIT_CORE, &rl) == -1) { 246 const int original_errno = errno; 247 LW(F("getrlimit should not have failed but got: %s") % 248 std::strerror(original_errno)); 249 ok = false; 250 } else { 251 if (rl.rlim_max == 0) { 252 LW("getrlimit returned 0 for RLIMIT_CORE rlim_max; cannot raise " 253 "soft core limit"); 254 ok = false; 255 } else { 256 rl.rlim_cur = rl.rlim_max; 257 LD(F("Raising soft core size limit to %s (hard value)") % 258 rl.rlim_cur); 259 if (::setrlimit(RLIMIT_CORE, &rl) == -1) { 260 const int original_errno = errno; 261 LW(F("setrlimit should not have failed but got: %s") % 262 std::strerror(original_errno)); 263 ok = false; 264 } else { 265 ok = true; 266 } 267 } 268 } 269 270 return ok; 271 } 272 273 274 /// Gathers a stacktrace of a crashed program. 275 /// 276 /// \param program The name of the binary that crashed and dumped a core file. 277 /// Can be either absolute or relative. 278 /// \param executor_handle The executor handler to get the status from and 279 /// gdb handler from. 280 /// \param exit_handle The exit handler to stream additional diagnostic 281 /// information from (stderr) and for redirecting to additional 282 /// information to gdb from. 283 /// 284 /// \post If anything goes wrong, the diagnostic messages are written to the 285 /// output. This function should not throw. 286 void 287 utils::dump_stacktrace(const fs::path& program, 288 executor::executor_handle& executor_handle, 289 const executor::exit_handle& exit_handle) 290 { 291 PRE(exit_handle.status()); 292 const process::status& status = exit_handle.status().get(); 293 PRE(status.signaled() && status.coredump()); 294 295 std::ofstream gdb_err(exit_handle.stderr_file().c_str(), std::ios::app); 296 if (!gdb_err) { 297 LW(F("Failed to open %s to append GDB's output") % 298 exit_handle.stderr_file()); 299 return; 300 } 301 302 gdb_err << F("Process with PID %s exited with signal %s and dumped core; " 303 "attempting to gather stack trace\n") % 304 status.dead_pid() % status.termsig(); 305 306 const optional< fs::path > gdb = utils::find_gdb(); 307 if (!gdb) { 308 gdb_err << F("Cannot find GDB binary; builtin was '%s'\n") % 309 builtin_gdb; 310 return; 311 } 312 313 const optional< fs::path > core_file = find_core( 314 program, status, exit_handle.work_directory()); 315 if (!core_file) { 316 gdb_err << F("Cannot find any core file\n"); 317 return; 318 } 319 320 gdb_err.flush(); 321 const executor::exec_handle exec_handle = 322 executor_handle.spawn_followup( 323 run_gdb(gdb.get(), program, core_file.get()), 324 exit_handle, gdb_timeout); 325 const executor::exit_handle gdb_exit_handle = 326 executor_handle.wait(exec_handle); 327 328 const optional< process::status >& gdb_status = gdb_exit_handle.status(); 329 if (!gdb_status) { 330 gdb_err << "GDB timed out\n"; 331 } else { 332 if (gdb_status.get().exited() && 333 gdb_status.get().exitstatus() == EXIT_SUCCESS) { 334 gdb_err << "GDB exited successfully\n"; 335 } else { 336 gdb_err << "GDB failed; see output above for details\n"; 337 } 338 } 339 } 340 341 342 /// Gathers a stacktrace of a program if it crashed. 343 /// 344 /// This is just a convenience function to allow appending the stacktrace to an 345 /// existing file and to permit reusing the status as returned by auxiliary 346 /// process-spawning functions. 347 /// 348 /// \param program The name of the binary that crashed and dumped a core file. 349 /// Can be either absolute or relative. 350 /// \param executor_handle The executor handler to get the status from and 351 /// gdb handler from. 352 /// \param exit_handle The exit handler to stream additional diagnostic 353 /// information from (stderr) and for redirecting to additional 354 /// information to gdb from. 355 /// 356 /// \throw std::runtime_error If the output file cannot be opened. 357 /// 358 /// \post If anything goes wrong with the stack gatheringq, the diagnostic 359 /// messages are written to the output. 360 void 361 utils::dump_stacktrace_if_available(const fs::path& program, 362 executor::executor_handle& executor_handle, 363 const executor::exit_handle& exit_handle) 364 { 365 const optional< process::status >& status = exit_handle.status(); 366 if (!status || !status.get().signaled() || !status.get().coredump()) 367 return; 368 369 dump_stacktrace(program, executor_handle, exit_handle); 370 } 371