| /* Copyright (C) 2021-2024 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "bt-utils.h" | 
 | #include "command.h" | 
 | #include "cli/cli-cmds.h" | 
 | #include "ui.h" | 
 | #include "cli/cli-decode.h" | 
 |  | 
 | /* See bt-utils.h.  */ | 
 |  | 
 | void | 
 | gdb_internal_backtrace_set_cmd (const char *args, int from_tty, | 
 | 				cmd_list_element *c) | 
 | { | 
 |   gdb_assert (c->type == set_cmd); | 
 |   gdb_assert (c->var.has_value ()); | 
 |   gdb_assert (c->var->type () == var_boolean); | 
 |  | 
 | #ifndef GDB_PRINT_INTERNAL_BACKTRACE | 
 |   if (c->var->get<bool> ()) | 
 |     { | 
 |       c->var->set<bool> (false); | 
 |       error (_("support for this feature is not compiled into GDB")); | 
 |     } | 
 | #endif | 
 | } | 
 |  | 
 | #ifdef GDB_PRINT_INTERNAL_BACKTRACE | 
 | #ifdef GDB_PRINT_INTERNAL_BACKTRACE_USING_LIBBACKTRACE | 
 |  | 
 | /* Callback used by libbacktrace if it encounters an error.  */ | 
 |  | 
 | static void | 
 | libbacktrace_error (void *data, const char *errmsg, int errnum) | 
 | { | 
 |   /* A negative errnum indicates no debug info was available, just | 
 |      skip printing a backtrace in this case.  */ | 
 |   if (errnum < 0) | 
 |     return; | 
 |  | 
 |   const auto sig_write = [] (const char *msg) -> void | 
 |   { | 
 |     gdb_stderr->write_async_safe (msg, strlen (msg)); | 
 |   }; | 
 |  | 
 |   sig_write ("error creating backtrace: "); | 
 |   sig_write (errmsg); | 
 |   if (errnum > 0) | 
 |     { | 
 |       char buf[20]; | 
 |       snprintf (buf, sizeof (buf), ": %d", errnum); | 
 |       buf[sizeof (buf) - 1] = '\0'; | 
 |  | 
 |       sig_write (buf); | 
 |     } | 
 |   sig_write ("\n"); | 
 | } | 
 |  | 
 | /* Callback used by libbacktrace to print a single stack frame.  */ | 
 |  | 
 | static int | 
 | libbacktrace_print (void *data, uintptr_t pc, const char *filename, | 
 | 		    int lineno, const char *function) | 
 | { | 
 |   const auto sig_write = [] (const char *msg) -> void | 
 |   { | 
 |     gdb_stderr->write_async_safe (msg, strlen (msg)); | 
 |   }; | 
 |  | 
 |   /* Buffer to print addresses and line numbers into.  An 8-byte address | 
 |      with '0x' prefix and a null terminator requires 20 characters.  This | 
 |      also feels like it should be enough to represent line numbers in most | 
 |      files.  We are also careful to ensure we don't overflow this buffer.  */ | 
 |   char buf[20]; | 
 |  | 
 |   snprintf (buf, sizeof (buf), "0x%" PRIxPTR " ", pc); | 
 |   buf[sizeof (buf) - 1] = '\0'; | 
 |   sig_write (buf); | 
 |   sig_write (function == nullptr ? "???" : function); | 
 |   if (filename != nullptr) | 
 |     { | 
 |       sig_write ("\n\t"); | 
 |       sig_write (filename); | 
 |       sig_write (":"); | 
 |       snprintf (buf, sizeof (buf), "%d", lineno); | 
 |       buf[sizeof (buf) - 1] = '\0'; | 
 |       sig_write (buf); | 
 |     } | 
 |   sig_write ("\n"); | 
 |  | 
 |   return function != nullptr && strcmp (function, "main") == 0; | 
 | } | 
 |  | 
 | /* Write a backtrace to GDB's stderr in an async safe manner.  This is a | 
 |    backtrace of GDB, not any running inferior, and is to be used when GDB | 
 |    crashes or hits some other error condition.  */ | 
 |  | 
 | static void | 
 | gdb_internal_backtrace_1 () | 
 | { | 
 |   static struct backtrace_state *state = nullptr; | 
 |  | 
 |   if (state == nullptr) | 
 |     state = backtrace_create_state (nullptr, 0, libbacktrace_error, nullptr); | 
 |  | 
 |   backtrace_full (state, 0, libbacktrace_print, libbacktrace_error, nullptr); | 
 | } | 
 |  | 
 | #elif defined GDB_PRINT_INTERNAL_BACKTRACE_USING_EXECINFO | 
 |  | 
 | /* See the comment on previous version of this function.  */ | 
 |  | 
 | static void | 
 | gdb_internal_backtrace_1 () | 
 | { | 
 |   const auto sig_write = [] (const char *msg) -> void | 
 |   { | 
 |     gdb_stderr->write_async_safe (msg, strlen (msg)); | 
 |   }; | 
 |  | 
 |   /* Allow up to 25 frames of backtrace.  */ | 
 |   void *buffer[25]; | 
 |   int frames = backtrace (buffer, ARRAY_SIZE (buffer)); | 
 |  | 
 |   backtrace_symbols_fd (buffer, frames, gdb_stderr->fd ()); | 
 |   if (frames == ARRAY_SIZE (buffer)) | 
 |     sig_write (_("Backtrace might be incomplete.\n")); | 
 | } | 
 |  | 
 | #else | 
 | #error "unexpected internal backtrace policy" | 
 | #endif | 
 | #endif /* GDB_PRINT_INTERNAL_BACKTRACE */ | 
 |  | 
 | /* See bt-utils.h.  */ | 
 |  | 
 | void | 
 | gdb_internal_backtrace () | 
 | { | 
 |   if (current_ui == nullptr) | 
 |     return; | 
 |  | 
 | #ifdef GDB_PRINT_INTERNAL_BACKTRACE | 
 |   const auto sig_write = [] (const char *msg) -> void | 
 |   { | 
 |     gdb_stderr->write_async_safe (msg, strlen (msg)); | 
 |   }; | 
 |  | 
 |   sig_write (_("----- Backtrace -----\n")); | 
 |  | 
 |   if (gdb_stderr->fd () > -1) | 
 |     gdb_internal_backtrace_1 (); | 
 |   else | 
 |     sig_write (_("Backtrace unavailable\n")); | 
 |  | 
 |   sig_write ("---------------------\n"); | 
 | #endif | 
 | } |