mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-12-17 16:18:37 +08:00
Consider this backtrace within GDB: #0 notify_breakpoint_modified (b=0x57d31d0) at ../../src/gdb/breakpoint.c:1083 #1 0x00000000005b6406 in breakpoint_set_commands (b=0x57d31d0, commands=...) at ../../src/gdb/breakpoint.c:1523 #2 0x00000000005c8c63 in update_dprintf_command_list (b=0x57d31d0) at ../../src/gdb/breakpoint.c:8641 #3 0x00000000005d3c4e in dprintf_breakpoint::re_set (this=0x57d31d0) at ../../src/gdb/breakpoint.c:12476 #4 0x00000000005d6347 in breakpoint_re_set () at ../../src/gdb/breakpoint.c:13298 Whenever breakpoint_re_set is called we re-build the commands that the dprintf b/p will execute and store these into the breakpoint. The commands are re-built in update_dprintf_command_list and stored into the breakpoint object in breakpoint_set_commands. Now sometimes these commands can change, dprintf_breakpoint::re_set explains one case where this can occur, and I'm sure there must be others. But in most cases the commands we recalculate will not change. This means that the breakpoint modified event which is emitted from breakpoint_set_commands is redundant. This commit aims to eliminate the redundant breakpoint modified events for dprintf breakpoints. This is done by adding a commands_equal call to the start of breakpoint_set_commands. The commands_equal function is a new function which compares two command_line objects and returns true if they are identical. Using this function we can check if the new commands passed to breakpoint_set_commands are identical to the breakpoint's existing commands. If the new commands are equal then we don't need to change anything on the new breakpoint, and the breakpoint modified event can be skipped. The test for this commit stops at a dlopen() call in the inferior, sets up a dprintf breakpoint, then uses 'next' to step over the dlopen() call. When the library loads GDB call breakpoint_re_set, which calls dprintf_breakpoint::re_set. But in this case we don't expect the calculated command string to change, so we don't expect to see the breakpoint modified event.
198 lines
5.6 KiB
C++
198 lines
5.6 KiB
C++
/* Header file for GDB CLI command implementation library.
|
|
Copyright (C) 2000-2024 Free Software Foundation, Inc.
|
|
|
|
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/>. */
|
|
|
|
#ifndef GDB_CLI_CLI_SCRIPT_H
|
|
#define GDB_CLI_CLI_SCRIPT_H
|
|
|
|
#include "compile/compile.h"
|
|
#include "gdbsupport/function-view.h"
|
|
|
|
struct ui_file;
|
|
struct cmd_list_element;
|
|
|
|
/* * Control types for commands. */
|
|
|
|
enum misc_command_type
|
|
{
|
|
ok_command,
|
|
end_command,
|
|
else_command,
|
|
nop_command
|
|
};
|
|
|
|
enum command_control_type
|
|
{
|
|
simple_control,
|
|
break_control,
|
|
continue_control,
|
|
while_control,
|
|
if_control,
|
|
commands_control,
|
|
python_control,
|
|
compile_control,
|
|
guile_control,
|
|
while_stepping_control,
|
|
define_control,
|
|
document_control,
|
|
invalid_control
|
|
};
|
|
|
|
struct command_line;
|
|
|
|
extern void free_command_lines (struct command_line **);
|
|
|
|
/* A deleter for command_line that calls free_command_lines. */
|
|
|
|
struct command_lines_deleter
|
|
{
|
|
void operator() (command_line *cmd_lines) const
|
|
{
|
|
free_command_lines (&cmd_lines);
|
|
}
|
|
};
|
|
|
|
/* A reference-counted struct command_line. */
|
|
typedef std::shared_ptr<command_line> counted_command_line;
|
|
|
|
/* A unique_ptr specialization for command_line. */
|
|
typedef std::unique_ptr<command_line, command_lines_deleter> command_line_up;
|
|
|
|
/* * Structure for saved commands lines (for breakpoints, defined
|
|
commands, etc). */
|
|
|
|
struct command_line
|
|
{
|
|
explicit command_line (command_control_type type_, char *line_ = nullptr)
|
|
: line (line_),
|
|
control_type (type_)
|
|
{
|
|
memset (&control_u, 0, sizeof (control_u));
|
|
}
|
|
|
|
DISABLE_COPY_AND_ASSIGN (command_line);
|
|
|
|
struct command_line *next = nullptr;
|
|
char *line;
|
|
enum command_control_type control_type;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
enum compile_i_scope_types scope;
|
|
void *scope_data;
|
|
}
|
|
compile;
|
|
}
|
|
control_u;
|
|
/* * For composite commands, the nested lists of commands. For
|
|
example, for "if" command this will contain the then branch and
|
|
the else branch, if that is available. */
|
|
counted_command_line body_list_0;
|
|
counted_command_line body_list_1;
|
|
|
|
private:
|
|
|
|
friend void free_command_lines (struct command_line **);
|
|
|
|
~command_line ()
|
|
{
|
|
xfree (line);
|
|
}
|
|
};
|
|
|
|
/* Prototype for a function to call to get one more input line.
|
|
|
|
If the function needs to return a dynamically allocated string, it can place
|
|
in the passed-in buffer, and return a pointer to it. Otherwise, it can
|
|
simply ignore it. */
|
|
|
|
using read_next_line_ftype = gdb::function_view<const char * (std::string &)>;
|
|
|
|
extern counted_command_line read_command_lines
|
|
(const char *, int, int, gdb::function_view<void (const char *)>);
|
|
extern counted_command_line read_command_lines_1
|
|
(read_next_line_ftype, int, gdb::function_view<void (const char *)>);
|
|
|
|
|
|
/* Exported to cli/cli-cmds.c */
|
|
|
|
extern void script_from_file (FILE *stream, const char *file);
|
|
|
|
extern void show_user_1 (struct cmd_list_element *c,
|
|
const char *prefix,
|
|
const char *name,
|
|
struct ui_file *stream);
|
|
|
|
/* Execute the commands in CMDLINES. */
|
|
|
|
extern void execute_control_commands (struct command_line *cmdlines,
|
|
int from_tty);
|
|
|
|
/* Run execute_control_commands for COMMANDS. Capture its output into
|
|
the returned string, do not display it to the screen. BATCH_FLAG
|
|
will be temporarily set to true. When TERM_OUT is true the output is
|
|
collected with terminal behavior (e.g. with styling). When TERM_OUT is
|
|
false raw output will be collected (e.g. no styling). */
|
|
|
|
extern std::string execute_control_commands_to_string
|
|
(struct command_line *commands, int from_tty, bool term_out);
|
|
|
|
/* Exported to gdb/breakpoint.c */
|
|
|
|
extern enum command_control_type
|
|
execute_control_command (struct command_line *cmd,
|
|
int from_tty = 0);
|
|
|
|
extern enum command_control_type
|
|
execute_control_command_untraced (struct command_line *cmd);
|
|
|
|
extern counted_command_line get_command_line (enum command_control_type,
|
|
const char *);
|
|
|
|
extern void print_command_lines (struct ui_out *,
|
|
struct command_line *, unsigned int);
|
|
|
|
/* Exported to gdb/infrun.c */
|
|
|
|
extern void execute_user_command (struct cmd_list_element *c, const char *args);
|
|
|
|
/* If we're in a user-defined command, replace any $argc/$argN
|
|
reference found in LINE with the arguments that were passed to the
|
|
command. Otherwise, treat $argc/$argN as normal convenience
|
|
variables. */
|
|
extern std::string insert_user_defined_cmd_args (const char *line);
|
|
|
|
/* Exported to top.c */
|
|
|
|
extern void print_command_trace (const char *cmd, ...)
|
|
ATTRIBUTE_PRINTF (1, 2);
|
|
|
|
/* Exported to event-top.c */
|
|
|
|
extern void reset_command_nest_depth (void);
|
|
|
|
/* Return true if A and B are identical. Some commands carry around a
|
|
'void *' compilation context, in this case this function doesn't try to
|
|
validate if the context is actually the same or not, and will just
|
|
return false indicating the commands have changed. That is, a return
|
|
value of true is a guarantee that the commands are equal, a return
|
|
value of false means the commands are possibly different (and in most
|
|
cases are different). */
|
|
|
|
extern bool commands_equal (const command_line *a, const command_line *b);
|
|
|
|
#endif /* GDB_CLI_CLI_SCRIPT_H */
|