From e4014689b9a1b9aa0dde8f8a358401774566fe8b Mon Sep 17 00:00:00 2001 From: Andrew Burgess Date: Tue, 10 May 2022 15:16:46 +0100 Subject: [PATCH] gdb: add infcall specific debugging Add two new commands: set debug infcall on|off show debug infcall These enable some new debugging related to when GDB makes inferior function calls. I've added some basic debugging for what I think are the major steps in the inferior function call process, but I'm sure we might want to add more later. --- gdb/NEWS | 4 +++ gdb/doc/gdb.texinfo | 7 +++++ gdb/infcall.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/gdb/NEWS b/gdb/NEWS index 796a4ef8072..8b519a648f7 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -111,6 +111,10 @@ maintenance print frame-id [ LEVEL ] Print GDB's internal frame-id for the frame at LEVEL. If LEVEL is not given, then print the frame-id for the currently selected frame. +set debug infcall on|off +show debug infcall + Print additional debug messages about inferior function calls. + * Changed commands document user-defined diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 44d87e95748..3de511a4844 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -27587,6 +27587,13 @@ for implementing operations such as single-stepping the inferior. @item show debug infrun Displays the current state of @value{GDBN} inferior debugging. +@item set debug infcall +@cindex inferior function call debugging info +Turns on or off display of debugging info related to inferior function +calls made by @value{GDBN}. +@item show debug infcall +Displays the current state of @value{GDBN} inferior function call debugging. + @item set debug jit @cindex just-in-time compilation, debugging messages Turn on or off debugging messages from JIT debug support. diff --git a/gdb/infcall.c b/gdb/infcall.c index 16e6b9e9355..e2de045d7b7 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -44,6 +44,34 @@ #include "gdbsupport/scope-exit.h" #include +/* True if we are debugging inferior calls. */ + +static bool debug_infcall = false; + +/* Print an "infcall" debug statement. */ + +#define infcall_debug_printf(fmt, ...) \ + debug_prefixed_printf_cond (debug_infcall, "infcall", fmt, ##__VA_ARGS__) + +/* Print "infcall" enter/exit debug statements. */ + +#define INFCALL_SCOPED_DEBUG_ENTER_EXIT \ + scoped_debug_enter_exit (debug_infcall, "infcall") + +/* Print "infcall" start/end debug statements. */ + +#define INFCALL_SCOPED_DEBUG_START_END(fmt, ...) \ + scoped_debug_start_end (debug_infrun, "infcall", fmt, ##__VA_ARGS__) + +/* Implement 'show debug infcall'. */ + +static void +show_debug_infcall (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + gdb_printf (file, _("Inferior call debugging is %s.\n"), value); +} + /* If we can't find a function's name from its address, we print this instead. */ #define RAW_FUNCTION_ADDRESS_FORMAT "at 0x%s" @@ -529,6 +557,8 @@ call_thread_fsm::call_thread_fsm (struct ui *waiting_ui, bool call_thread_fsm::should_stop (struct thread_info *thread) { + INFCALL_SCOPED_DEBUG_ENTER_EXIT; + if (stop_stack_dummy == STOP_STACK_DUMMY) { /* Done. */ @@ -577,10 +607,17 @@ static struct gdb_exception run_inferior_call (std::unique_ptr sm, struct thread_info *call_thread, CORE_ADDR real_pc) { + INFCALL_SCOPED_DEBUG_ENTER_EXIT; + struct gdb_exception caught_error; ptid_t call_thread_ptid = call_thread->ptid; int was_running = call_thread->state == THREAD_RUNNING; + infcall_debug_printf ("call function at %s in thread %s, was_running = %d", + core_addr_to_string (real_pc), + call_thread_ptid.to_string ().c_str (), + was_running); + current_ui->unregister_file_handler (); scoped_restore restore_in_infcall @@ -610,15 +647,25 @@ run_inferior_call (std::unique_ptr sm, proceed (real_pc, GDB_SIGNAL_0); + infrun_debug_show_threads ("non-exited threads after proceed for inferior-call", + all_non_exited_threads ()); + /* Inferior function calls are always synchronous, even if the target supports asynchronous execution. */ wait_sync_command_done (); + + infcall_debug_printf ("inferior call completed successfully"); } catch (gdb_exception &e) { + infcall_debug_printf ("exception while making inferior call (%d): %s", + e.reason, e.what ()); caught_error = std::move (e); } + infcall_debug_printf ("thread is now: %s", + inferior_ptid.to_string ().c_str ()); + /* If GDB has the prompt blocked before, then ensure that it remains so. normal_stop calls async_enable_stdin, so reset the prompt state again here. In other cases, stdin will be re-enabled by @@ -764,6 +811,8 @@ call_function_by_hand_dummy (struct value *function, dummy_frame_dtor_ftype *dummy_dtor, void *dummy_dtor_data) { + INFCALL_SCOPED_DEBUG_ENTER_EXIT; + CORE_ADDR sp; struct type *target_values_type; function_call_return_method return_method = return_method_normal; @@ -830,6 +879,9 @@ call_function_by_hand_dummy (struct value *function, if (args.size () < ftype->num_fields ()) error (_("Too few arguments in function call.")); + infcall_debug_printf ("calling %s", get_function_name (funaddr, name_buf, + sizeof (name_buf))); + /* A holder for the inferior status. This is only needed while we're preparing the inferior function call. */ infcall_control_state_up inf_status (save_infcall_control_state ()); @@ -1276,6 +1328,12 @@ call_function_by_hand_dummy (struct value *function, e = run_inferior_call (std::move (sm_up), call_thread.get (), real_pc); } + if (e.reason < 0) + infcall_debug_printf ("after inferior call, exception (%d): %s", + e.reason, e.what ()); + infcall_debug_printf ("after inferior call, thread state is: %s", + thread_state_string (call_thread->state)); + gdb::observers::inferior_call_post.notify (call_thread_ptid, funaddr); if (call_thread->state != THREAD_EXITED) @@ -1287,6 +1345,8 @@ call_function_by_hand_dummy (struct value *function, { struct value *retval; + infcall_debug_printf ("call completed"); + /* The inferior call is successful. Pop the dummy frame, which runs its destructors and restores the inferior's suspend state, and restore the inferior control @@ -1317,6 +1377,8 @@ call_function_by_hand_dummy (struct value *function, return retval; } + else + infcall_debug_printf ("call did not complete"); /* Didn't complete. Clean up / destroy the call FSM, and restore the previous state machine, and handle the error. */ @@ -1572,4 +1634,10 @@ The default is to unwind the frame."), show_unwind_on_terminating_exception_p, &setlist, &showlist); + add_setshow_boolean_cmd + ("infcall", class_maintenance, &debug_infcall, + _("Set inferior call debugging."), + _("Show inferior call debugging."), + _("When on, inferior function call specific debugging is enabled."), + NULL, show_debug_infcall, &setdebuglist, &showdebuglist); } -- 2.30.2