mirror of
https://github.com/crash-utility/crash
synced 2025-04-20 14:25:14 +00:00
In the previous commit, we fixed crash's logic which determines the module load addresses in the presence of sections with nonzero sh_addr. This allowed GDB to correctly locate public variables (i.e. GLOBAL symbols) via the ELF symbol table (msymbols). However, LOCAL symbols still had incorrect addresses. The root cause for those issues is not in crash. Instead, GDB does not expect sections with nonzero sh_addr, and so it slipped up in multiple places: 1. In default_symfile_offsets(), GDB detects the nonzero sh_addr field and fails to apply the user-supplied section offsets. The result is that later, in symfile_relocate_debug_section(), relocations are applied to the DWARF info using the wrong section addresses, which results in invalid addresses for variables. Clearly, this has happened before, because crash has special-cased the "__ksymtab*" section names to avoid this condition. To resolve this, we simply drop the check for nonzero sh_addr altogether: the only ET_REL files we encounter should be kernel modules, so there's no real reason to be picky. 2. Even with that fixed, the user-supplied section addresses are clobbered by the addr_info_make_relative(), which subtracts out section offsets during its operation. To resolve this, undo the operation for ET_REL files where a section address was provided by the user (i.e. crash). With these two fixes, both local and global variables from a module section with nonzero sh_addr are correctly reported. Behavior is unchanged for modules with a zero sh_addr. Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
1955 lines
66 KiB
Diff
1955 lines
66 KiB
Diff
|
|
# When this file is updated in an existing source tree, it gets re-applied
|
|
# during the next build using "patch -N --fuzz=0", which ignores patches
|
|
# that have already been applied. However, if a gdb file has been modified
|
|
# multiple times, the subsequent patching may fail to recognize that a
|
|
# given patch has been previously applied, and will attempt to re-apply it.
|
|
# To prevent any unintended consequences, this file also acts as a
|
|
# shell script that can restore any gdb file to its original state prior
|
|
# to all subsequent patch applications.
|
|
|
|
tar xvzmf gdb-16.2.tar.gz \
|
|
gdb-16.2/gdb/symfile.c
|
|
|
|
exit 0
|
|
|
|
--- gdb-16.2/Makefile.in.orig
|
|
+++ gdb-16.2/Makefile.in
|
|
@@ -369,6 +369,9 @@ CC_FOR_BUILD = @CC_FOR_BUILD@
|
|
CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
|
|
CPP_FOR_BUILD = @CPP_FOR_BUILD@
|
|
CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
|
|
+ifeq (${CRASH_TARGET}, PPC64)
|
|
+CFLAGS_FOR_BUILD += -m64 -fPIC
|
|
+endif
|
|
CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@
|
|
CXX_FOR_BUILD = @CXX_FOR_BUILD@
|
|
DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@
|
|
@@ -441,6 +444,9 @@ GNATBIND = @GNATBIND@
|
|
GNATMAKE = @GNATMAKE@
|
|
|
|
CFLAGS = @CFLAGS@
|
|
+ifeq (${CRASH_TARGET}, PPC64)
|
|
+CFLAGS += -m64 -fPIC
|
|
+endif
|
|
LDFLAGS = @LDFLAGS@
|
|
LIBCFLAGS = $(CFLAGS)
|
|
CXXFLAGS = @CXXFLAGS@
|
|
--- gdb-16.2/gdb/Makefile.in.orig
|
|
+++ gdb-16.2/gdb/Makefile.in
|
|
@@ -603,7 +603,7 @@ CONFIG_DEP_SUBDIR = $(addsuffix /$(DEPDIR),$(CONFIG_SRC_SUBDIR))
|
|
# It is also possible that you will need to add -I/usr/include/sys if
|
|
# your system doesn't have fcntl.h in /usr/include (which is where it
|
|
# should be according to Posix).
|
|
-DEFS = @DEFS@
|
|
+DEFS = -DCRASH_MERGE -D${CRASH_TARGET} @DEFS@
|
|
GDB_INCLUDED_HEADER = -include $(srcdir)/defs.h
|
|
GDB_CFLAGS = \
|
|
-I. \
|
|
@@ -1220,6 +1220,7 @@ COMMON_SFILES = \
|
|
symmisc.c \
|
|
symtab.c \
|
|
target.c \
|
|
+ ../../crash_target.c \
|
|
target-connection.c \
|
|
target-dcache.c \
|
|
target-descriptions.c \
|
|
@@ -1906,7 +1907,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
|
|
$(SUBDIR_TARGET_OBS) \
|
|
$(SUBDIR_GCC_COMPILE_OBS)
|
|
|
|
-SUBDIRS = doc @subdirs@ data-directory
|
|
+SUBDIRS = build_no_subdirs
|
|
CLEANDIRS = $(SUBDIRS)
|
|
|
|
# List of subdirectories in the build tree that must exist.
|
|
@@ -1947,8 +1948,8 @@ generated_files = \
|
|
# Flags needed to compile Python code
|
|
PYTHON_CFLAGS = @PYTHON_CFLAGS@
|
|
|
|
-all: gdb$(EXEEXT) $(CONFIG_ALL) gdb-gdb.py gdb-gdb.gdb gcore gstack
|
|
- @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=$(SUBDIRS)" subdir_do
|
|
+all: gdb$(EXEEXT) gdb-gdb.py gdb-gdb.gdb gcore gstack
|
|
+ @$(MAKE) -s $(FLAGS_TO_PASS) DO=all "DODIRS=$(SUBDIRS)" subdir_do
|
|
|
|
# Rule for compiling .c files in the top-level gdb directory.
|
|
# The order-only dependencies ensure that we create the build subdirectories.
|
|
@@ -2230,9 +2231,10 @@ libgdb.a: $(LIBGDB_OBS)
|
|
# Removing the old gdb first works better if it is running, at least on SunOS.
|
|
gdb$(EXEEXT): gdb.o $(LIBGDB_OBS) $(CDEPS) $(TDEPLIBS)
|
|
$(SILENCE) rm -f gdb$(EXEEXT)
|
|
+ @$(MAKE) -C ../.. GDB_FLAGS=-DGDB_16_2 library
|
|
$(ECHO_CXXLD) $(CC_LD) $(INTERNAL_LDFLAGS) $(WIN32LDAPP) \
|
|
- -o gdb$(EXEEXT) gdb.o $(LIBGDB_OBS) \
|
|
- $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES)
|
|
+ -o $(shell /bin/cat mergeobj) $(LIBGDB_OBS) \
|
|
+ $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) $(shell /bin/cat mergelibs)
|
|
ifneq ($(CODESIGN_CERT),)
|
|
$(ECHO_SIGN) $(CODESIGN) -s $(CODESIGN_CERT) gdb$(EXEEXT)
|
|
endif
|
|
@@ -2699,9 +2701,9 @@ ifeq ($(DEPMODE),depmode=gcc3)
|
|
# into place if the compile succeeds. We need this because gcc does
|
|
# not atomically write the dependency output file.
|
|
override COMPILE.post = -c -o $@ -MT $@ -MMD -MP \
|
|
- -MF $(@D)/$(DEPDIR)/$(basename $(@F)).Tpo
|
|
-override POSTCOMPILE = @mv $(@D)/$(DEPDIR)/$(basename $(@F)).Tpo \
|
|
- $(@D)/$(DEPDIR)/$(basename $(@F)).Po
|
|
+ -MF $(subst ../..,.,$(@D))/$(DEPDIR)/$(basename $(@F)).Tpo
|
|
+override POSTCOMPILE = @mv $(subst ../..,.,$(@D))/$(DEPDIR)/$(basename $(@F)).Tpo \
|
|
+ $(subst ../..,.,$(@D))/$(DEPDIR)/$(basename $(@F)).Po
|
|
else
|
|
override COMPILE.pre = source='$<' object='$@' libtool=no \
|
|
DEPDIR=$(DEPDIR) $(DEPMODE) $(depcomp) \
|
|
--- gdb-16.2/gdb/c-typeprint.c.orig
|
|
+++ gdb-16.2/gdb/c-typeprint.c
|
|
@@ -1066,6 +1066,9 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
|
|
= podata->end_bitpos
|
|
- type->field (i).type ()->length () * TARGET_CHAR_BIT;
|
|
}
|
|
+ else if (strlen(type->field(i).name()) == 0)
|
|
+ /* crash: Print details for unnamed struct and union. */
|
|
+ newshow = show;
|
|
|
|
c_print_type_1 (type->field (i).type (),
|
|
type->field (i).name (),
|
|
--- gdb-16.2/gdb/cli/cli-cmds.c.orig
|
|
+++ gdb-16.2/gdb/cli/cli-cmds.c
|
|
@@ -427,6 +427,11 @@ complete_command (const char *arg, int from_tty)
|
|
}
|
|
}
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+static int crash_from_tty = 0;
|
|
+extern "C" void untrusted_file(FILE *, char *);
|
|
+#endif
|
|
+
|
|
int
|
|
is_complete_command (struct cmd_list_element *c)
|
|
{
|
|
@@ -659,8 +664,32 @@ find_and_open_script (const char *script_file, int search_path)
|
|
close (fd);
|
|
errno = save_errno;
|
|
}
|
|
- else
|
|
- opened.emplace (gdb_file_up (result), std::move (full_path));
|
|
+#ifdef CRASH_MERGE
|
|
+ /*
|
|
+ * Only allow trusted versions of .gdbinit files to be
|
|
+ * sourced during session initialization.
|
|
+ */
|
|
+ if (crash_from_tty == -1)
|
|
+ {
|
|
+ struct stat statbuf;
|
|
+ FILE *stream = result;
|
|
+ int _fd = fileno (stream);
|
|
+ if (fstat (_fd, &statbuf) < 0)
|
|
+ {
|
|
+ perror_with_name (full_path.get());
|
|
+ fclose (stream);
|
|
+ return opened;
|
|
+ }
|
|
+ if (statbuf.st_uid != getuid () || (statbuf.st_mode & S_IWOTH))
|
|
+ {
|
|
+ untrusted_file(NULL, full_path.get());
|
|
+ fclose (stream);
|
|
+ return opened;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ opened.emplace (gdb_file_up (result), std::move (full_path));
|
|
+
|
|
|
|
return opened;
|
|
}
|
|
@@ -724,7 +753,11 @@ source_script_with_search (const char *file, int from_tty, int search_path)
|
|
If the source command was invoked interactively, throw an
|
|
error. Otherwise (e.g. if it was invoked by a script),
|
|
just emit a warning, rather than cause an error. */
|
|
+#ifdef CRASH_MERGE
|
|
+ if (from_tty > 0)
|
|
+#else
|
|
if (from_tty)
|
|
+#endif
|
|
perror_with_name (file);
|
|
else
|
|
{
|
|
@@ -756,7 +789,14 @@ source_script_with_search (const char *file, int from_tty, int search_path)
|
|
void
|
|
source_script (const char *file, int from_tty)
|
|
{
|
|
+#ifdef CRASH_MERGE
|
|
+ crash_from_tty = from_tty;
|
|
+#endif
|
|
source_script_with_search (file, from_tty, 0);
|
|
+#ifdef CRASH_MERGE
|
|
+ crash_from_tty = 0;
|
|
+#endif
|
|
+
|
|
}
|
|
|
|
static void
|
|
--- gdb-16.2/gdb/completer.c.orig
|
|
+++ gdb-16.2/gdb/completer.c
|
|
@@ -3315,6 +3315,8 @@ gdb_display_match_list_1 (char **matches, int len, int max,
|
|
|
|
/* How many items of MAX length can we fit in the screen window? */
|
|
cols = gdb_complete_get_screenwidth (displayer);
|
|
+ rl_reset_screen_size();
|
|
+ rl_get_screen_size(NULL, &cols);
|
|
max += 2;
|
|
limit = cols / max;
|
|
if (limit != 1 && (limit * max == cols))
|
|
--- gdb-16.2/gdb/defs.h.orig
|
|
+++ gdb-16.2/gdb/defs.h
|
|
@@ -407,4 +407,7 @@ DEF_ENUM_FLAGS_TYPE (enum user_selected_what_flag, user_selected_what);
|
|
|
|
#include "utils.h"
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+extern "C" int gdb_main_entry(int, char **);
|
|
+#endif
|
|
#endif /* GDB_DEFS_H */
|
|
--- gdb-16.2/gdb/dwarf2/read-gdb-index.c.orig
|
|
+++ gdb-16.2/gdb/dwarf2/read-gdb-index.c
|
|
@@ -369,7 +369,11 @@ read_gdb_index_from_buffer (const char *filename,
|
|
indices. */
|
|
if (version < 4)
|
|
{
|
|
+#ifdef CRASH_MERGE
|
|
+ static int warning_printed = 1;
|
|
+#else
|
|
static int warning_printed = 0;
|
|
+#endif
|
|
if (!warning_printed)
|
|
{
|
|
warning (_("Skipping obsolete .gdb_index section in %s."),
|
|
@@ -388,7 +392,11 @@ read_gdb_index_from_buffer (const char *filename,
|
|
"set use-deprecated-index-sections on". */
|
|
if (version < 6 && !deprecated_ok)
|
|
{
|
|
+#ifdef CRASH_MERGE
|
|
+ static int warning_printed = 1;
|
|
+#else
|
|
static int warning_printed = 0;
|
|
+#endif
|
|
if (!warning_printed)
|
|
{
|
|
warning (_("\
|
|
--- gdb-16.2/gdb/event-top.c.orig
|
|
+++ gdb-16.2/gdb/event-top.c
|
|
@@ -1558,6 +1558,10 @@ gdb_setup_readline (int editing)
|
|
{
|
|
struct ui *ui = current_ui;
|
|
|
|
+ if (!batch_silent)
|
|
+ gdb_stdout = new stdio_file (ui->outstream);
|
|
+ gdb_stderr = new stderr_file (ui->errstream);
|
|
+
|
|
/* If the input stream is connected to a terminal, turn on editing.
|
|
However, that is only allowed on the main UI, as we can only have
|
|
one instance of readline. Also, INSTREAM might be nullptr when
|
|
--- gdb-16.2/gdb/frame.c.orig
|
|
+++ gdb-16.2/gdb/frame.c
|
|
@@ -966,6 +966,10 @@ frame_find_by_id (struct frame_id id)
|
|
return NULL;
|
|
}
|
|
|
|
+#if defined(CRASH_MERGE) && defined(ARM64)
|
|
+extern "C" void crash_decode_ptrauth_pc(ulong* pc);
|
|
+#endif
|
|
+
|
|
static CORE_ADDR
|
|
frame_unwind_pc (const frame_info_ptr &this_frame)
|
|
{
|
|
@@ -996,6 +1000,9 @@ frame_unwind_pc (const frame_info_ptr &this_frame)
|
|
try
|
|
{
|
|
pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);
|
|
+#if defined(CRASH_MERGE) && defined(ARM64)
|
|
+ crash_decode_ptrauth_pc(&pc);
|
|
+#endif
|
|
pc_p = true;
|
|
}
|
|
catch (const gdb_exception_error &ex)
|
|
--- gdb-16.2/gdb/main.c.orig
|
|
+++ gdb-16.2/gdb/main.c
|
|
@@ -442,6 +442,14 @@ start_event_loop ()
|
|
return;
|
|
}
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+extern "C" void update_gdb_hooks(void);
|
|
+extern "C" void main_loop(void);
|
|
+extern "C" unsigned long crash_get_kaslr_offset(void);
|
|
+extern "C" int console(const char *, ...);
|
|
+void crash_target_init (void);
|
|
+#endif
|
|
+
|
|
/* Call command_loop. */
|
|
|
|
/* Prevent inlining this function for the benefit of GDB's selftests
|
|
@@ -1031,7 +1039,11 @@ captured_main_1 (struct captured_main_args *context)
|
|
}
|
|
}
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+ save_original_signals_state (1);
|
|
+#else
|
|
save_original_signals_state (quiet);
|
|
+#endif
|
|
|
|
/* Try to set up an alternate signal stack for SIGSEGV handlers. */
|
|
gdb::alternate_signal_stack signal_stack;
|
|
@@ -1129,7 +1141,7 @@ captured_main_1 (struct captured_main_args *context)
|
|
if (print_version)
|
|
{
|
|
print_gdb_version (gdb_stdout, false);
|
|
- gdb_printf ("\n");
|
|
+ gdb_printf ("\n\n");
|
|
exit (0);
|
|
}
|
|
|
|
@@ -1150,6 +1162,10 @@ captured_main_1 (struct captured_main_args *context)
|
|
look at things by now. Initialize the default interpreter. */
|
|
set_top_level_interpreter (interpreter_p.c_str (), false);
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+ update_gdb_hooks();
|
|
+#endif
|
|
+
|
|
/* The interpreter should have installed the real uiout by now. */
|
|
gdb_assert (current_uiout != temp_uiout.get ());
|
|
temp_uiout = nullptr;
|
|
@@ -1177,7 +1193,11 @@ captured_main_1 (struct captured_main_args *context)
|
|
if (!system_gdbinit.empty () && !inhibit_gdbinit)
|
|
{
|
|
for (const std::string &file : system_gdbinit)
|
|
+#ifdef CRASH_MERGE
|
|
+ ret = catch_command_errors (source_script, file.c_str (), -1);
|
|
+#else
|
|
ret = catch_command_errors (source_script, file.c_str (), 0);
|
|
+#endif
|
|
}
|
|
|
|
/* Read and execute $HOME/.gdbinit file, if it exists. This is done
|
|
@@ -1186,7 +1206,11 @@ captured_main_1 (struct captured_main_args *context)
|
|
debugging or what directory you are in. */
|
|
|
|
if (!home_gdbinit.empty () && !inhibit_gdbinit && !inhibit_home_gdbinit)
|
|
+#ifdef CRASH_MERGE
|
|
+ ret = catch_command_errors (source_script, home_gdbinit.c_str (), -1);
|
|
+#else
|
|
ret = catch_command_errors (source_script, home_gdbinit.c_str (), 0);
|
|
+#endif
|
|
|
|
/* Process '-ix' and '-iex' options early. */
|
|
execute_cmdargs (&cmdarg_vec, CMDARG_INIT_FILE, CMDARG_INIT_COMMAND, &ret);
|
|
@@ -1217,7 +1241,11 @@ captured_main_1 (struct captured_main_args *context)
|
|
!batch_flag);
|
|
if (ret != 0)
|
|
ret = catch_command_errors (symbol_file_add_main_adapter,
|
|
+#ifdef CRASH_MERGE
|
|
+ symarg, 0);
|
|
+#else
|
|
symarg, !batch_flag);
|
|
+#endif
|
|
}
|
|
else
|
|
{
|
|
@@ -1291,7 +1319,11 @@ captured_main_1 (struct captured_main_args *context)
|
|
{
|
|
auto_load_local_gdbinit_loaded = 1;
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+ ret = catch_command_errors (source_script, local_gdbinit.c_str (), -1);
|
|
+#else
|
|
ret = catch_command_errors (source_script, local_gdbinit.c_str (), 0);
|
|
+#endif
|
|
}
|
|
}
|
|
}
|
|
@@ -1332,6 +1364,16 @@ captured_main (void *data)
|
|
|
|
captured_main_1 (context);
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+ /* Relocate the vmlinux. */
|
|
+ objfile_rebase (current_program_space->symfile_object_file, crash_get_kaslr_offset());
|
|
+
|
|
+ crash_target_init();
|
|
+
|
|
+ /* Back to crash. */
|
|
+ main_loop();
|
|
+#endif
|
|
+
|
|
/* NOTE: cagney/1999-11-07: There is probably no reason for not
|
|
moving this loop and the code found in captured_command_loop()
|
|
into the command_loop() proper. The main thing holding back that
|
|
@@ -1350,6 +1392,9 @@ captured_main (void *data)
|
|
{
|
|
exception_print (gdb_stderr, ex);
|
|
}
|
|
+#ifdef CRASH_MERGE
|
|
+ console("<CAPTURED_MAIN WHILE LOOP>\n");
|
|
+#endif
|
|
}
|
|
/* No exit -- exit is through quit_command. */
|
|
}
|
|
@@ -1371,6 +1416,24 @@ gdb_main (struct captured_main_args *args)
|
|
return 1;
|
|
}
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+/*
|
|
+ * NOTE: adapted from gdb.c, which is no longer built in; changed name of
|
|
+ * original main() to gdb_main_entry() for use as crash entry point
|
|
+ */
|
|
+extern bool is_main_thread ();
|
|
+int
|
|
+gdb_main_entry (int argc, char **argv)
|
|
+{
|
|
+ struct captured_main_args args;
|
|
+ gdb_assert (is_main_thread ());
|
|
+ memset (&args, 0, sizeof args);
|
|
+ args.argc = argc;
|
|
+ args.argv = argv;
|
|
+ args.interpreter_p = INTERP_CONSOLE;
|
|
+ return gdb_main (&args);
|
|
+}
|
|
+#endif
|
|
|
|
/* Don't use *_filtered for printing help. We don't want to prompt
|
|
for continue no matter how small the screen or how much we're going
|
|
--- gdb-16.2/gdb/objfiles.h.orig
|
|
+++ gdb-16.2/gdb/objfiles.h
|
|
@@ -891,6 +891,8 @@ struct objfile : intrusive_list_node<objfile>
|
|
mechanism as ELF should set this flag too. This flag is used in
|
|
conjunction with the minimal_symbol::maybe_copied method. */
|
|
bool object_format_has_copy_relocs = false;
|
|
+
|
|
+ bool all_symtabs_expanded = false;
|
|
};
|
|
|
|
/* A deleter for objfile. */
|
|
@@ -951,11 +953,11 @@ extern bool objfile_has_symbols (objfile *objfile);
|
|
|
|
/* Return true if any objfile of PSPACE has partial symbols. */
|
|
|
|
-extern bool have_partial_symbols (program_space *pspace);
|
|
+extern "C" bool have_partial_symbols (program_space *pspace);
|
|
|
|
/* Return true if any objfile of PSPACE has full symbols. */
|
|
|
|
-extern bool have_full_symbols (program_space *pspace);
|
|
+extern "C" bool have_full_symbols (program_space *pspace);
|
|
|
|
extern void objfile_set_sym_fns (struct objfile *objfile,
|
|
const struct sym_fns *sf);
|
|
--- gdb-16.2/gdb/printcmd.c.orig
|
|
+++ gdb-16.2/gdb/printcmd.c
|
|
@@ -552,6 +552,9 @@ set_next_address (struct gdbarch *gdbarch, CORE_ADDR addr)
|
|
form. However note that DO_DEMANGLE can be overridden by the specific
|
|
settings of the demangle and asm_demangle variables. Returns
|
|
non-zero if anything was printed; zero otherwise. */
|
|
+#ifdef CRASH_MERGE
|
|
+extern "C" int gdb_print_callback(unsigned long);
|
|
+#endif
|
|
|
|
int
|
|
print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr,
|
|
@@ -563,6 +566,12 @@ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr,
|
|
int offset = 0;
|
|
int line = 0;
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+ if (!gdb_print_callback(addr)) {
|
|
+ return 0;
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (build_address_symbolic (gdbarch, addr, do_demangle, false, &name,
|
|
&offset, &filename, &line, &unmapped))
|
|
return 0;
|
|
@@ -595,6 +604,10 @@ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr,
|
|
|
|
/* See valprint.h. */
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+extern "C" char *gdb_lookup_module_symbol(unsigned long, unsigned long *);
|
|
+#endif
|
|
+
|
|
int
|
|
build_address_symbolic (struct gdbarch *gdbarch,
|
|
CORE_ADDR addr, /* IN */
|
|
@@ -701,7 +714,19 @@ build_address_symbolic (struct gdbarch *gdbarch,
|
|
}
|
|
}
|
|
if (symbol == NULL && msymbol.minsym == NULL)
|
|
+#ifdef CRASH_MERGE
|
|
+ {
|
|
+ char *name_ptr = gdb_lookup_module_symbol(addr, (unsigned long *)offset);
|
|
+ if (name_ptr) {
|
|
+ *name = name_ptr;
|
|
+ return 0;
|
|
+ } else {
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+#else
|
|
return 1;
|
|
+#endif
|
|
|
|
/* If the nearest symbol is too far away, don't print anything symbolic. */
|
|
|
|
@@ -1242,6 +1267,42 @@ print_command_parse_format (const char **expp, const char *cmdname,
|
|
*expp = exp;
|
|
}
|
|
|
|
+static void
|
|
+print_command_2 (const char *args, int voidprint)
|
|
+{
|
|
+ struct value *val;
|
|
+ value_print_options print_opts;
|
|
+
|
|
+ get_user_print_options (&print_opts);
|
|
+ /* Override global settings with explicit options, if any. */
|
|
+ auto group = make_value_print_options_def_group (&print_opts);
|
|
+ gdb::option::process_options
|
|
+ (&args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER, group);
|
|
+
|
|
+ print_command_parse_format (&args, "print", &print_opts);
|
|
+
|
|
+ const char *exp = args;
|
|
+
|
|
+ if (exp != nullptr && *exp)
|
|
+ {
|
|
+ expression_up expr = parse_expression (exp);
|
|
+ val = expr->evaluate ();
|
|
+ } else
|
|
+ val = access_value_history (0);
|
|
+
|
|
+ gdb_printf("%d %d %ld %ld %ld %ld\n",
|
|
+ check_typedef(val->type ())->code(),
|
|
+ check_typedef(val->type ())->is_unsigned(),
|
|
+ check_typedef(val->type ())->length(),
|
|
+ val->offset(), val->bitpos(), val->bitsize());
|
|
+}
|
|
+
|
|
+static void
|
|
+printm_command (const char *exp, int from_tty)
|
|
+{
|
|
+ print_command_2 (exp, 1);
|
|
+}
|
|
+
|
|
/* See valprint.h. */
|
|
|
|
void
|
|
@@ -3357,6 +3418,12 @@ but no count or size letter (see \"x\" command)."),
|
|
= add_com ("print", class_vars, print_command, print_help.c_str ());
|
|
set_cmd_completer_handle_brkchars (print_cmd, print_command_completer);
|
|
add_com_alias ("p", print_cmd, class_vars, 1);
|
|
+
|
|
+ c = add_com ("printm", class_vars, printm_command, _("\
|
|
+Similar to \"print\" command, but it used to print the type, size, offset,\n\
|
|
+bitpos and bitsize of the expression EXP."));
|
|
+ set_cmd_completer (c, expression_completer);
|
|
+
|
|
add_com_alias ("inspect", print_cmd, class_vars, 1);
|
|
|
|
add_setshow_uinteger_cmd ("max-symbolic-offset", no_class,
|
|
--- gdb-16.2/gdb/psymtab.c.orig
|
|
+++ gdb-16.2/gdb/psymtab.c
|
|
@@ -80,6 +80,9 @@ psymbol_functions::partial_symbols (struct objfile *objfile)
|
|
return m_partial_symtabs->range ();
|
|
}
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+ extern "C" int gdb_line_number_callback(unsigned long, unsigned long, unsigned long);
|
|
+#endif
|
|
/* Find which partial symtab contains PC and SECTION starting at psymtab PST.
|
|
We may find a different psymtab than PST. See FIND_PC_SECT_PSYMTAB. */
|
|
|
|
@@ -170,7 +173,12 @@ psymbol_functions::find_pc_sect_psymtab (struct objfile *objfile,
|
|
|
|
best_pst = find_pc_sect_psymtab_closer (objfile, pc, section, pst,
|
|
msymbol);
|
|
+#ifdef CRASH_MERGE
|
|
+ if ((best_pst != NULL) &&
|
|
+ gdb_line_number_callback(pc, pst->text_low (objfile), pst->text_high (objfile)))
|
|
+#else
|
|
if (best_pst != NULL)
|
|
+#endif
|
|
return best_pst;
|
|
}
|
|
|
|
--- gdb-16.2/gdb/stack.c.orig
|
|
+++ gdb-16.2/gdb/stack.c
|
|
@@ -1968,6 +1968,11 @@ static frame_command_helper <select_frame_command_core> select_frame_cmd;
|
|
/* Print briefly all stack frames or just the innermost COUNT_EXP
|
|
frames. */
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+extern "C" int is_kvaddr(ulong);
|
|
+extern "C" int gdb_CRASHDEBUG(ulong);
|
|
+#endif
|
|
+
|
|
static void
|
|
backtrace_command_1 (const frame_print_options &fp_opts,
|
|
const backtrace_cmd_options &bt_opts,
|
|
@@ -2062,6 +2067,17 @@ backtrace_command_1 (const frame_print_options &fp_opts,
|
|
hand, perhaps the code does or could be fixed to make sure
|
|
the frame->prev field gets set to NULL in that case). */
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+ CORE_ADDR pc = 0;
|
|
+ get_frame_pc_if_available (fi, &pc);
|
|
+ if (!is_kvaddr(pc)) {
|
|
+ if (gdb_CRASHDEBUG(1)) {
|
|
+ gdb_printf(_("Backtrace stopped: due to non-kernel addr: 0x%lx\n"),pc);
|
|
+ }
|
|
+ fi = NULL;
|
|
+ break;
|
|
+ }
|
|
+#endif
|
|
print_frame_info (fp_opts, fi, 1, LOCATION, 1, 0);
|
|
if ((flags & PRINT_LOCALS) != 0)
|
|
print_frame_local_vars (fi, false, NULL, NULL, 1, gdb_stdout);
|
|
@@ -2081,7 +2097,7 @@ backtrace_command_1 (const frame_print_options &fp_opts,
|
|
enum unwind_stop_reason reason;
|
|
|
|
reason = get_frame_unwind_stop_reason (trailing);
|
|
- if (reason >= UNWIND_FIRST_ERROR)
|
|
+ if (reason >= UNWIND_FIRST_ERROR && gdb_CRASHDEBUG(1))
|
|
gdb_printf (_("Backtrace stopped: %s\n"),
|
|
frame_stop_reason_string (trailing));
|
|
}
|
|
--- gdb-16.2/gdb/symfile.c.orig
|
|
+++ gdb-16.2/gdb/symfile.c
|
|
@@ -633,7 +633,26 @@ default_symfile_offsets (struct objfile *objfile,
|
|
for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next)
|
|
/* We do not expect this to happen; just skip this step if the
|
|
relocatable file has a section with an assigned VMA. */
|
|
- if (bfd_section_vma (cur_sec) != 0)
|
|
+ if (bfd_section_vma (cur_sec) != 0
|
|
+ /*
|
|
+ * Kernel modules may have some non-zero VMAs, i.e., like the
|
|
+ * __ksymtab and __ksymtab_gpl sections in this example:
|
|
+ *
|
|
+ * Section Headers:
|
|
+ * [Nr] Name Type Address Offset
|
|
+ * Size EntSize Flags Link Info Align
|
|
+ * ...
|
|
+ * [ 8] __ksymtab PROGBITS 0000000000000060 0000ad90
|
|
+ * 0000000000000010 0000000000000000 A 0 0 16
|
|
+ * [ 9] .rela__ksymtab RELA 0000000000000000 0000ada0
|
|
+ * 0000000000000030 0000000000000018 43 8 8
|
|
+ * [10] __ksymtab_gpl PROGBITS 0000000000000070 0000add0
|
|
+ * 00000000000001a0 0000000000000000 A 0 0 16
|
|
+ * ...
|
|
+ *
|
|
+ * but they should be treated as if they are NULL.
|
|
+ */
|
|
+ && strncmp (bfd_section_name (cur_sec), "__k", 3) != 0)
|
|
break;
|
|
|
|
if (cur_sec == NULL)
|
|
@@ -1069,6 +1088,12 @@ symbol_file_add_with_addrs (const gdb_bfd_ref_ptr &abfd, const char *name,
|
|
|
|
objfile *objfile
|
|
= objfile::make (abfd, current_program_space, name, flags, parent);
|
|
+#ifdef CRASH_MERGE
|
|
+ if (add_flags & SYMFILE_MAINLINE) {
|
|
+ extern struct objfile *gdb_kernel_objfile;
|
|
+ gdb_kernel_objfile = objfile;
|
|
+ }
|
|
+#endif
|
|
|
|
/* We either created a new mapped symbol table, mapped an existing
|
|
symbol table file which has not had initial symbol reading
|
|
@@ -1095,6 +1120,7 @@ symbol_file_add_with_addrs (const gdb_bfd_ref_ptr &abfd, const char *name,
|
|
styled_string (file_name_style.style (), name));
|
|
|
|
objfile->expand_all_symtabs ();
|
|
+ objfile->all_symtabs_expanded = true;
|
|
}
|
|
|
|
/* Note that we only print a message if we have no symbols and have
|
|
@@ -1352,6 +1378,10 @@ show_debug_file_directory (struct ui_file *file, int from_tty,
|
|
#if ! defined (DEBUG_SUBDIRECTORY)
|
|
#define DEBUG_SUBDIRECTORY ".debug"
|
|
#endif
|
|
+#ifdef CRASH_MERGE
|
|
+extern "C" int check_specified_module_tree(const char *, const char *);
|
|
+extern "C" char *check_specified_kernel_debug_file();
|
|
+#endif
|
|
|
|
/* Find a separate debuginfo file for OBJFILE, using DIR as the directory
|
|
where the original file resides (may not be the same as
|
|
@@ -1390,6 +1420,15 @@ find_separate_debug_file (const char *dir,
|
|
if (separate_debug_file_exists (debugfile, crc32, objfile, warnings))
|
|
return debugfile;
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+{
|
|
+ if (check_specified_module_tree(objfile_name (objfile), debugfile.c_str()) &&
|
|
+ separate_debug_file_exists(debugfile, crc32, objfile, warnings)) {
|
|
+ return debugfile;
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
/* Then try in the global debugfile directories.
|
|
|
|
Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will
|
|
@@ -1545,6 +1584,14 @@ find_separate_debug_file_by_debuglink
|
|
}
|
|
}
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+ if (debugfile.empty ()) {
|
|
+ char *name_copy;
|
|
+ name_copy = check_specified_kernel_debug_file();
|
|
+ return name_copy ? std::string (name_copy) : std::string ();
|
|
+ }
|
|
+#endif
|
|
+
|
|
return debugfile;
|
|
}
|
|
|
|
@@ -2318,8 +2365,10 @@ add_symbol_file_command (const char *args, int from_tty)
|
|
else if (section_addrs.empty ())
|
|
gdb_printf ("\n");
|
|
|
|
+#ifndef CRASH_MERGE
|
|
if (from_tty && (!query ("%s", "")))
|
|
error (_("Not confirmed."));
|
|
+#endif
|
|
|
|
objf = symbol_file_add (filename.get (), add_flags, §ion_addrs,
|
|
flags);
|
|
@@ -2660,6 +2709,7 @@ reread_symbols (int from_tty)
|
|
objfile_name (objfile)));
|
|
|
|
objfile->expand_all_symtabs ();
|
|
+ objfile->all_symtabs_expanded = true;
|
|
}
|
|
|
|
if (!objfile_has_symbols (objfile))
|
|
@@ -3638,6 +3688,15 @@ bfd_byte *
|
|
symfile_relocate_debug_section (struct objfile *objfile,
|
|
asection *sectp, bfd_byte *buf)
|
|
{
|
|
+#ifdef CRASH_MERGE
|
|
+ /* Executable files have all the relocations already resolved.
|
|
+ * Handle files linked with --emit-relocs.
|
|
+ * http://sources.redhat.com/ml/gdb/2006-08/msg00137.html
|
|
+ */
|
|
+ bfd *abfd = objfile->obfd.get();
|
|
+ if ((abfd->flags & EXEC_P) != 0)
|
|
+ return NULL;
|
|
+#endif
|
|
gdb_assert (objfile->sf->sym_relocate);
|
|
|
|
return (*objfile->sf->sym_relocate) (objfile, sectp, buf);
|
|
--- gdb-16.2/gdb/symtab.c.orig
|
|
+++ gdb-16.2/gdb/symtab.c
|
|
@@ -2012,6 +2012,10 @@ search_name_hash (enum language language, const char *search_name)
|
|
variable and thus can probably assume it will never hit the C++
|
|
code). */
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+static void gdb_bait_and_switch(char *, struct symbol *);
|
|
+#endif
|
|
+
|
|
struct block_symbol
|
|
lookup_symbol_in_language (const char *name, const struct block *block,
|
|
const domain_search_flags domain,
|
|
@@ -2020,22 +2024,37 @@ lookup_symbol_in_language (const char *name, const struct block *block,
|
|
{
|
|
SYMBOL_LOOKUP_SCOPED_DEBUG_ENTER_EXIT;
|
|
|
|
+ struct block_symbol result;
|
|
demangle_result_storage storage;
|
|
const char *modified_name = demangle_for_lookup (name, lang, storage);
|
|
|
|
- return lookup_symbol_aux (modified_name,
|
|
+ result = lookup_symbol_aux (modified_name,
|
|
symbol_name_match_type::FULL,
|
|
block, domain, lang,
|
|
is_a_field_of_this);
|
|
+#ifdef CRASH_MERGE
|
|
+ if (result.symbol && (domain & SEARCH_TYPE_DOMAIN))
|
|
+ gdb_bait_and_switch((char *)modified_name, result.symbol);
|
|
+#endif
|
|
+ return result;
|
|
}
|
|
|
|
/* See symtab.h. */
|
|
|
|
+#ifdef CRASH_MERGE
|
|
+static const struct block *gdb_get_crash_block(void);
|
|
+#endif
|
|
+
|
|
struct block_symbol
|
|
lookup_symbol (const char *name, const struct block *block,
|
|
domain_search_flags domain,
|
|
struct field_of_this_result *is_a_field_of_this)
|
|
{
|
|
+#ifdef CRASH_MERGE
|
|
+ if (!block)
|
|
+ block = gdb_get_crash_block();
|
|
+#endif
|
|
+
|
|
return lookup_symbol_in_language (name, block, domain,
|
|
current_language->la_language,
|
|
is_a_field_of_this);
|
|
@@ -3004,7 +3023,7 @@ find_pc_sect_compunit_symtab (CORE_ADDR pc, struct obj_section *section)
|
|
for (objfile *objf : current_program_space->objfiles ())
|
|
{
|
|
struct compunit_symtab *result
|
|
- = objf->find_pc_sect_compunit_symtab (msymbol, pc, section, 1);
|
|
+ = objf->find_pc_sect_compunit_symtab (msymbol, pc, section, 0);
|
|
if (result != NULL)
|
|
return result;
|
|
}
|
|
@@ -7320,3 +7339,914 @@ the use of prologue scanners."),
|
|
"symtab");
|
|
gdb::observers::free_objfile.attach (symtab_free_objfile_observer, "symtab");
|
|
}
|
|
+
|
|
+#ifdef CRASH_MERGE
|
|
+#include "gdb-stabs.h"
|
|
+#include "gdbsupport/version.h"
|
|
+#define GDB_COMMON
|
|
+#include "../../defs.h"
|
|
+
|
|
+static void get_member_data(struct gnu_request *, struct type *, long, int);
|
|
+static void walk_enum(struct type *, struct gnu_request *);
|
|
+static void eval_enum(struct type *, struct gnu_request *);
|
|
+static void gdb_get_line_number(struct gnu_request *);
|
|
+static void gdb_get_datatype(struct gnu_request *);
|
|
+static void gdb_get_symbol_type(struct gnu_request *);
|
|
+static void gdb_command_exists(struct gnu_request *);
|
|
+static void gdb_debug_command(struct gnu_request *);
|
|
+static void gdb_function_numargs(struct gnu_request *);
|
|
+static void gdb_add_symbol_file(struct gnu_request *);
|
|
+static void gdb_delete_symbol_file(struct gnu_request *);
|
|
+static void gdb_patch_symbol_values(struct gnu_request *);
|
|
+static void get_user_print_option_address(struct gnu_request *);
|
|
+extern int get_frame_offset(CORE_ADDR);
|
|
+static void gdb_set_crash_block(struct gnu_request *);
|
|
+extern "C" void gdb_command_funnel(struct gnu_request *);
|
|
+void gdb_command_funnel_1(struct gnu_request *);
|
|
+static long lookup_struct_contents(struct gnu_request *);
|
|
+static void iterate_datatypes(struct gnu_request *);
|
|
+extern void execute_command (const char *, int);
|
|
+
|
|
+struct objfile *gdb_kernel_objfile = { 0 };
|
|
+
|
|
+static ulong gdb_merge_flags = 0;
|
|
+#define KERNEL_SYMBOLS_PATCHED (0x1)
|
|
+
|
|
+#undef STREQ
|
|
+#define STREQ(A, B) (A && B && (strcmp(A, B) == 0))
|
|
+#define TYPE_CODE(t) (t->code ())
|
|
+#define TYPE_TAG_NAME(t) (TYPE_MAIN_TYPE(t)->name)
|
|
+#define TYPE_NFIELDS(t) (t->num_fields ())
|
|
+#define TYPE_NAME(t) (t->name ())
|
|
+
|
|
+/*
|
|
+ * All commands from above come through here.
|
|
+ */
|
|
+void
|
|
+gdb_command_funnel(struct gnu_request *req)
|
|
+{
|
|
+ try {
|
|
+ gdb_command_funnel_1(req);
|
|
+ } catch (const gdb_exception &ex) {
|
|
+ if (req->flags & GNU_RETURN_ON_ERROR)
|
|
+ req->flags |= GNU_COMMAND_FAILED;
|
|
+ else
|
|
+ throw ex;
|
|
+ }
|
|
+}
|
|
+
|
|
+void
|
|
+gdb_command_funnel_1(struct gnu_request *req)
|
|
+{
|
|
+ struct symbol *sym;
|
|
+ FILE *original_stdout_stream = nullptr;
|
|
+ FILE *original_stderr_stream = nullptr;
|
|
+
|
|
+ if (req->command != GNU_VERSION && req->command != GNU_USER_PRINT_OPTION) {
|
|
+ original_stdout_stream = (dynamic_cast< stdio_file * >gdb_stdout)->get_stream();
|
|
+ original_stderr_stream = (dynamic_cast< stdio_file * >gdb_stderr)->get_stream();
|
|
+ (dynamic_cast<stdio_file *>gdb_stdout)->set_stream(req->fp);
|
|
+ (dynamic_cast<stdio_file *>gdb_stderr)->set_stream(req->fp);
|
|
+ }
|
|
+
|
|
+ switch (req->command)
|
|
+ {
|
|
+ case GNU_VERSION:
|
|
+ req->buf = (char *)version;
|
|
+ break;
|
|
+
|
|
+ case GNU_PASS_THROUGH:
|
|
+ execute_command(req->buf,
|
|
+ req->flags & GNU_FROM_TTY_OFF ? FALSE : TRUE);
|
|
+ break;
|
|
+
|
|
+ case GNU_USER_PRINT_OPTION:
|
|
+ get_user_print_option_address(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_RESOLVE_TEXT_ADDR:
|
|
+ sym = find_pc_function(req->addr);
|
|
+ if (!sym || TYPE_CODE(sym->type()) != TYPE_CODE_FUNC)
|
|
+ req->flags |= GNU_COMMAND_FAILED;
|
|
+ break;
|
|
+
|
|
+ case GNU_DISASSEMBLE:
|
|
+ if (req->addr2)
|
|
+ sprintf(req->buf, "disassemble 0x%lx 0x%lx",
|
|
+ req->addr, req->addr2);
|
|
+ else
|
|
+ sprintf(req->buf, "disassemble 0x%lx", req->addr);
|
|
+ execute_command(req->buf, TRUE);
|
|
+ break;
|
|
+
|
|
+ case GNU_ADD_SYMBOL_FILE:
|
|
+ gdb_add_symbol_file(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_DELETE_SYMBOL_FILE:
|
|
+ gdb_delete_symbol_file(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_GET_LINE_NUMBER:
|
|
+ gdb_get_line_number(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_GET_DATATYPE:
|
|
+ gdb_get_datatype(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_GET_SYMBOL_TYPE:
|
|
+ gdb_get_symbol_type(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_COMMAND_EXISTS:
|
|
+ gdb_command_exists(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_ALPHA_FRAME_OFFSET:
|
|
+ req->value = 0;
|
|
+ break;
|
|
+
|
|
+ case GNU_FUNCTION_NUMARGS:
|
|
+ gdb_function_numargs(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_DEBUG_COMMAND:
|
|
+ gdb_debug_command(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_PATCH_SYMBOL_VALUES:
|
|
+ gdb_patch_symbol_values(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_SET_CRASH_BLOCK:
|
|
+ gdb_set_crash_block(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_GET_FUNCTION_RANGE:
|
|
+ {
|
|
+ CORE_ADDR start, end;
|
|
+ if (!find_pc_partial_function(req->pc, NULL, &start, &end))
|
|
+ req->flags |= GNU_COMMAND_FAILED;
|
|
+ else {
|
|
+ req->addr = (ulong)start;
|
|
+ req->addr2 = (ulong)end;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case GNU_LOOKUP_STRUCT_CONTENTS:
|
|
+ req->value = lookup_struct_contents(req);
|
|
+ break;
|
|
+
|
|
+ case GNU_ITERATE_DATATYPES:
|
|
+ iterate_datatypes(req);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ req->flags |= GNU_COMMAND_FAILED;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Restore the streams gdb output was using */
|
|
+ if (original_stdout_stream)
|
|
+ (dynamic_cast<stdio_file *>gdb_stdout)->set_stream(original_stdout_stream);
|
|
+ if (original_stderr_stream)
|
|
+ (dynamic_cast<stdio_file *>gdb_stderr)->set_stream(original_stderr_stream);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Given a PC value, return the file and line number.
|
|
+ */
|
|
+static void
|
|
+gdb_get_line_number(struct gnu_request *req)
|
|
+{
|
|
+ struct symtab_and_line sal;
|
|
+ struct objfile *objfile;
|
|
+ CORE_ADDR pc;
|
|
+
|
|
+#define LASTCHAR(s) (s[strlen(s)-1])
|
|
+
|
|
+ /*
|
|
+ * Prime the addrmap pump.
|
|
+ */
|
|
+ pc = req->addr;
|
|
+
|
|
+ sal = find_pc_line(pc, 0);
|
|
+
|
|
+ if (!sal.symtab) {
|
|
+ /*
|
|
+ * If a module address line number can't be found, it's typically
|
|
+ * due to its addrmap still containing offset values because its
|
|
+ * objfile doesn't have full symbols loaded.
|
|
+ */
|
|
+ if (req->lm) {
|
|
+ objfile = req->lm->loaded_objfile;
|
|
+ if (!objfile->all_symtabs_expanded && objfile->sf) {
|
|
+ objfile->expand_all_symtabs();
|
|
+ objfile->all_symtabs_expanded = true;
|
|
+ sal = find_pc_line(pc, 0);
|
|
+ }
|
|
+ }
|
|
+ if (!sal.symtab) {
|
|
+ req->buf[0] = '\0';
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (sal.symtab->filename && (sal.symtab)->compunit ()->dirname ()) {
|
|
+ if (sal.symtab->filename[0] == '/')
|
|
+ sprintf(req->buf, "%s: %d",
|
|
+ sal.symtab->filename, sal.line);
|
|
+ else
|
|
+ sprintf(req->buf, "%s%s%s: %d",
|
|
+ (sal.symtab)->compunit ()->dirname (),
|
|
+ LASTCHAR((sal.symtab)->compunit ()->dirname ()) == '/' ? "" : "/",
|
|
+ sal.symtab->filename, sal.line);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+ * Follow the type linkage for full member and value type resolution, with callback
|
|
+ */
|
|
+static void drillDownType(struct gnu_request *req, struct type *type)
|
|
+{
|
|
+ while (type)
|
|
+ {
|
|
+ /* check out for stub types and pull in the definition instead */
|
|
+ if (type->is_stub() && TYPE_TAG_NAME(type)) {
|
|
+ struct symbol *sym;
|
|
+ sym = lookup_symbol(TYPE_TAG_NAME(type), 0, SEARCH_STRUCT_DOMAIN, 0).symbol;
|
|
+ if (sym)
|
|
+ type = sym->type();
|
|
+ }
|
|
+ switch (TYPE_CODE(type)) {
|
|
+ drill_ops_t op;
|
|
+ long l1, l2;
|
|
+ int typecode;
|
|
+
|
|
+ case TYPE_CODE_PTR:
|
|
+ req->tcb(EOP_POINTER, req, 0, 0, 0, 0);
|
|
+ break;
|
|
+
|
|
+ case TYPE_CODE_TYPEDEF:
|
|
+ req->is_typedef = 1;
|
|
+ req->typecode = TYPE_CODE(type);
|
|
+ if (!req->tcb(EOP_TYPEDEF, req, TYPE_NAME(type), 0, 0, 0))
|
|
+ return;
|
|
+ break;
|
|
+
|
|
+ case TYPE_CODE_FUNC:
|
|
+ req->tcb(EOP_FUNCTION, req, 0, 0, 0, 0);
|
|
+ break;
|
|
+
|
|
+ case TYPE_CODE_ARRAY:
|
|
+ l1 = type->length();
|
|
+ l2 = check_typedef(type->target_type())->length();
|
|
+ req->tcb(EOP_ARRAY, req, &l1, &l2, 0, 0);
|
|
+ break;
|
|
+
|
|
+ case TYPE_CODE_VOID:
|
|
+ case TYPE_CODE_INT:
|
|
+ case TYPE_CODE_BOOL:
|
|
+ l1 = type->length();
|
|
+ req->tcb(EOP_INT, req, &l1, 0, 0, 0);
|
|
+ break;
|
|
+
|
|
+ case TYPE_CODE_UNION:
|
|
+ op = EOP_UNION;
|
|
+ goto label;
|
|
+
|
|
+ case TYPE_CODE_ENUM:
|
|
+ op = EOP_ENUM;
|
|
+ goto label;
|
|
+
|
|
+ case TYPE_CODE_STRUCT:
|
|
+ op = EOP_STRUCT;
|
|
+ goto label;
|
|
+
|
|
+ default:
|
|
+ typecode = TYPE_CODE(type);
|
|
+ req->tcb(EOP_OOPS, req, &typecode, "Unknown typecode", 0, 0);
|
|
+ return; /* not reached */
|
|
+
|
|
+ label:
|
|
+ l1 = type->length();
|
|
+ req->tcb(op, req, &l1, type, TYPE_TAG_NAME(type), 0);
|
|
+ }
|
|
+ type = type->target_type();
|
|
+ }
|
|
+ req->tcb(EOP_DONE, req, 0, 0, 0, 0);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * General purpose routine for determining datatypes.
|
|
+ */
|
|
+
|
|
+static void
|
|
+gdb_get_datatype(struct gnu_request *req)
|
|
+{
|
|
+ struct type *type;
|
|
+ struct type *typedef_type;
|
|
+ expression_up expr;
|
|
+ struct symbol *sym;
|
|
+ struct value *val;
|
|
+
|
|
+ if (gdb_CRASHDEBUG(2))
|
|
+ console("gdb_get_datatype [%s] (a)\n", req->name);
|
|
+
|
|
+ req->typecode = TYPE_CODE_UNDEF;
|
|
+
|
|
+ /*
|
|
+ * lookup_symbol() will pick up struct and union names.
|
|
+ */
|
|
+ sym = lookup_symbol(req->name, 0, SEARCH_STRUCT_DOMAIN, 0).symbol;
|
|
+ if (sym) {
|
|
+ req->typecode = TYPE_CODE(sym->type());
|
|
+ req->length = sym->type()->length();
|
|
+ if (req->member)
|
|
+ get_member_data(req, sym->type(), 0, 1);
|
|
+
|
|
+ if (TYPE_CODE(sym->type()) == TYPE_CODE_ENUM)
|
|
+ walk_enum(sym->type(), req);
|
|
+
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Otherwise parse the expression.
|
|
+ */
|
|
+ if (gdb_CRASHDEBUG(2))
|
|
+ console("gdb_get_datatype [%s] (b)\n", req->name);
|
|
+
|
|
+ expr = parse_expression(req->name);
|
|
+
|
|
+
|
|
+ switch (expr->first_opcode())
|
|
+ {
|
|
+ case OP_VAR_VALUE:
|
|
+ if (gdb_CRASHDEBUG(2))
|
|
+ console("expr->first_opcode(): OP_VAR_VALUE\n");
|
|
+ type = expr->evaluate_type()->type();
|
|
+ if (req->tcb) {
|
|
+ long value = value_as_long(expr->evaluate());
|
|
+ /* callback with symbol value */
|
|
+ req->typecode = TYPE_CODE(type);
|
|
+ req->tcb(EOP_VALUE, req, &value, 0, 0, 0);
|
|
+ drillDownType(req, type);
|
|
+ } else {
|
|
+ if (req->flags & GNU_VAR_LENGTH_TYPECODE) {
|
|
+ req->typecode = TYPE_CODE(type);
|
|
+ req->length = type->length();
|
|
+ }
|
|
+ if (TYPE_CODE(type) == TYPE_CODE_ENUM) {
|
|
+ req->typecode = TYPE_CODE(type);
|
|
+ req->value = value_as_long(expr->evaluate());
|
|
+ req->tagname = (char *)TYPE_TAG_NAME(type);
|
|
+ if (!req->tagname) {
|
|
+ val = expr->evaluate_type();
|
|
+ eval_enum(val->type(), req);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case OP_TYPE:
|
|
+ if (gdb_CRASHDEBUG(2))
|
|
+ console("expr->first_opcode(): OP_TYPE\n");
|
|
+ type = expr->evaluate_type()->type();
|
|
+
|
|
+ if (req->tcb) {
|
|
+ drillDownType(req, type);
|
|
+ } else {
|
|
+ req->typecode = TYPE_CODE(type);
|
|
+ req->length = type->length();
|
|
+ if (TYPE_CODE(type) == TYPE_CODE_TYPEDEF) {
|
|
+ req->is_typedef = TYPE_CODE_TYPEDEF;
|
|
+ if ((typedef_type = check_typedef(type))) {
|
|
+ req->typecode = TYPE_CODE(typedef_type);
|
|
+ req->length = typedef_type->length();
|
|
+ type = typedef_type;
|
|
+ }
|
|
+ }
|
|
+ if (TYPE_CODE(type) == TYPE_CODE_ENUM)
|
|
+ walk_enum(type, req);
|
|
+ }
|
|
+
|
|
+ if (req->member)
|
|
+ get_member_data(req, type, 0, 1);
|
|
+
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ if (gdb_CRASHDEBUG(2))
|
|
+ console("expr->first_opcode(): %d (?)\n",
|
|
+ expr->first_opcode());
|
|
+ break;
|
|
+
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * More robust enum list dump that gdb's, showing the value of each
|
|
+ * identifier, each on its own line.
|
|
+ */
|
|
+static void
|
|
+walk_enum(struct type *type, struct gnu_request *req)
|
|
+{
|
|
+ int i;
|
|
+ int len, print = (req->flags & GNU_PRINT_ENUMERATORS);
|
|
+ long long lastval;
|
|
+
|
|
+ if (print) {
|
|
+ if (req->is_typedef)
|
|
+ gdb_printf(gdb_stdout, "typedef ");
|
|
+ if (TYPE_TAG_NAME(type))
|
|
+ gdb_printf(gdb_stdout, "enum %s {\n", TYPE_TAG_NAME (type));
|
|
+ else
|
|
+ gdb_printf(gdb_stdout, "enum {\n");
|
|
+ }
|
|
+
|
|
+ len = TYPE_NFIELDS (type);
|
|
+ for (i = 0; i < len; i++) {
|
|
+ if (print)
|
|
+ gdb_printf(gdb_stdout, " %s", type->field(i).name());
|
|
+ lastval = type->field(i).loc_enumval();
|
|
+ if (print) {
|
|
+ gdb_printf(gdb_stdout, " = %s", plongest(lastval));
|
|
+ gdb_printf(gdb_stdout, "\n");
|
|
+ } else if (req->tcb)
|
|
+ req->tcb(EOP_ENUMVAL, req, type->field(i).name(), &lastval, 0, 0);
|
|
+ }
|
|
+ if (print) {
|
|
+ if (TYPE_TAG_NAME(type))
|
|
+ gdb_printf(gdb_stdout, "};\n");
|
|
+ else
|
|
+ gdb_printf(gdb_stdout, "} %s;\n", req->name);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Given an enum type with no tagname, determine its value.
|
|
+ */
|
|
+static void
|
|
+eval_enum(struct type *type, struct gnu_request *req)
|
|
+{
|
|
+ int i;
|
|
+ int len;
|
|
+ long long lastval;
|
|
+
|
|
+ len = TYPE_NFIELDS (type);
|
|
+ lastval = 0;
|
|
+
|
|
+ for (i = 0; i < len; i++) {
|
|
+ if (lastval != type->field(i).loc_enumval())
|
|
+ lastval = type->field(i).loc_enumval();
|
|
+
|
|
+ if (STREQ(type->field(i).name(), req->name)) {
|
|
+ req->tagname = "(unknown)";
|
|
+ req->value = lastval;
|
|
+ return;
|
|
+ }
|
|
+ lastval++;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Walk through a struct type's list of fields looking for the desired
|
|
+ * member field, and when found, return its relevant data.
|
|
+ */
|
|
+static void
|
|
+get_member_data(struct gnu_request *req, struct type *type, long offset, int is_first)
|
|
+{
|
|
+ short i;
|
|
+ struct field *nextfield;
|
|
+ short nfields;
|
|
+ struct type *typedef_type, *target_type;
|
|
+
|
|
+ req->member_offset = -1;
|
|
+
|
|
+ nfields = TYPE_MAIN_TYPE(type)->m_nfields;
|
|
+ nextfield = TYPE_MAIN_TYPE(type)->flds_bnds.fields;
|
|
+
|
|
+ if (nfields == 0 && is_first /* The first call */) {
|
|
+ struct type *newtype;
|
|
+ newtype = lookup_transparent_type(req->name);
|
|
+ if (newtype) {
|
|
+ console("get_member_data(%s.%s): switching type from %lx to %lx\n",
|
|
+ req->name, req->member, type, newtype);
|
|
+ nfields = TYPE_MAIN_TYPE(newtype)->m_nfields;
|
|
+ nextfield = TYPE_MAIN_TYPE(newtype)->flds_bnds.fields;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < nfields; i++) {
|
|
+ if (*nextfield->m_name == 0) { /* Anonymous struct/union */
|
|
+ get_member_data(req, nextfield->type(),
|
|
+ offset + nextfield->m_loc.bitpos, 0);
|
|
+ if (req->member_offset != -1)
|
|
+ return;
|
|
+ } else {
|
|
+ /* callback may be just looking for a specific member name */
|
|
+ if (req->tcb) {
|
|
+ if (req->tcb(EOP_MEMBER_NAME, req, nextfield->m_name, 0, 0, 0)) {
|
|
+ long bitpos = nextfield->loc_bitpos();
|
|
+ long bitsize = nextfield->bitsize();
|
|
+ long len = nextfield->type()->length();
|
|
+ long byteOffset;
|
|
+ offset += nextfield->m_loc.bitpos;
|
|
+ byteOffset = offset/8;
|
|
+ console("EOP_MEMBER_SIZES\n");
|
|
+ req->tcb(EOP_MEMBER_SIZES, req, &byteOffset, &len, &bitpos, &bitsize);
|
|
+ /* callback with full type info */
|
|
+ drillDownType(req, nextfield->type());
|
|
+ }
|
|
+ } else if (STREQ(req->member, nextfield->m_name)) {
|
|
+ req->member_offset = offset + nextfield->m_loc.bitpos;
|
|
+ req->member_length = nextfield->type()->length();
|
|
+ req->member_typecode = TYPE_CODE(nextfield->type());
|
|
+ req->member_main_type_name = (char *)TYPE_NAME(nextfield->type());
|
|
+ req->member_main_type_tag_name = (char *)TYPE_TAG_NAME(nextfield->type());
|
|
+ target_type = nextfield->type()->target_type();
|
|
+ if (target_type) {
|
|
+ req->member_target_type_name = (char *)TYPE_NAME(target_type);
|
|
+ req->member_target_type_tag_name = (char *)TYPE_TAG_NAME(target_type);
|
|
+ }
|
|
+ if ((req->member_typecode == TYPE_CODE_TYPEDEF) &&
|
|
+ (typedef_type = check_typedef(nextfield->type()))) {
|
|
+ req->member_length = typedef_type->length();
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ nextfield++;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Check whether a command exists. If it doesn't, the command will be
|
|
+ * returned indirectly via the error_hook.
|
|
+ */
|
|
+static void
|
|
+gdb_command_exists(struct gnu_request *req)
|
|
+{
|
|
+ extern struct cmd_list_element *cmdlist;
|
|
+
|
|
+ req->value = FALSE;
|
|
+ lookup_cmd((const char **)&req->name, cmdlist, "", NULL, 0, 1);
|
|
+ req->value = TRUE;
|
|
+}
|
|
+
|
|
+static void
|
|
+gdb_function_numargs(struct gnu_request *req)
|
|
+{
|
|
+ struct symbol *sym;
|
|
+
|
|
+ sym = find_pc_function(req->pc);
|
|
+
|
|
+ if (!sym || TYPE_CODE(sym->type()) != TYPE_CODE_FUNC) {
|
|
+ req->flags |= GNU_COMMAND_FAILED;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ req->value = (ulong)TYPE_NFIELDS(sym->type());
|
|
+}
|
|
+
|
|
+struct load_module *gdb_current_load_module = NULL;
|
|
+
|
|
+static void
|
|
+gdb_add_symbol_file(struct gnu_request *req)
|
|
+{
|
|
+ struct load_module *lm;
|
|
+ int i;
|
|
+ int allsect = 0;
|
|
+ char *secname;
|
|
+ char buf[96];
|
|
+
|
|
+ gdb_current_load_module = lm = (struct load_module *)req->addr;
|
|
+
|
|
+ req->name = lm->mod_namelist;
|
|
+ gdb_delete_symbol_file(req);
|
|
+ lm->loaded_objfile = NULL;
|
|
+
|
|
+ if ((lm->mod_flags & MOD_NOPATCH) == 0) {
|
|
+ for (i = 0 ; i < lm->mod_sections; i++) {
|
|
+ if (STREQ(lm->mod_section_data[i].name, ".text") &&
|
|
+ (lm->mod_section_data[i].flags & SEC_FOUND))
|
|
+ allsect = 1;
|
|
+ }
|
|
+
|
|
+ if (!allsect) {
|
|
+ sprintf(req->buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist,
|
|
+ lm->mod_text_start ? lm->mod_text_start : lm->mod_base,
|
|
+ lm->mod_flags & MOD_DO_READNOW ? "-readnow" : "");
|
|
+ if (lm->mod_data_start) {
|
|
+ sprintf(buf, " -s .data 0x%lx", lm->mod_data_start);
|
|
+ strcat(req->buf, buf);
|
|
+ }
|
|
+ if (lm->mod_bss_start) {
|
|
+ sprintf(buf, " -s .bss 0x%lx", lm->mod_bss_start);
|
|
+ strcat(req->buf, buf);
|
|
+ }
|
|
+ if (lm->mod_rodata_start) {
|
|
+ sprintf(buf, " -s .rodata 0x%lx", lm->mod_rodata_start);
|
|
+ strcat(req->buf, buf);
|
|
+ }
|
|
+ } else {
|
|
+ sprintf(req->buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist,
|
|
+ lm->mod_text_start, lm->mod_flags & MOD_DO_READNOW ?
|
|
+ "-readnow" : "");
|
|
+ for (i = 0; i < lm->mod_sections; i++) {
|
|
+ secname = lm->mod_section_data[i].name;
|
|
+ if ((lm->mod_section_data[i].flags & SEC_FOUND) &&
|
|
+ !STREQ(secname, ".text")) {
|
|
+ if (lm->mod_section_data[i].addr)
|
|
+ sprintf(buf, " -s %s 0x%lx", secname, lm->mod_section_data[i].addr);
|
|
+ else
|
|
+ sprintf(buf, " -s %s 0x%lx", secname,
|
|
+ lm->mod_section_data[i].offset + lm->mod_base);
|
|
+ strcat(req->buf, buf);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (gdb_CRASHDEBUG(1))
|
|
+ gdb_printf(gdb_stdout, "%s\n", req->buf);
|
|
+
|
|
+ execute_command(req->buf, FALSE);
|
|
+
|
|
+ for (objfile *objfile : current_program_space->objfiles ()) {
|
|
+ if (same_file((char *)objfile_name(objfile), lm->mod_namelist)) {
|
|
+ if (objfile->separate_debug_objfile)
|
|
+ lm->loaded_objfile = objfile->separate_debug_objfile;
|
|
+ else
|
|
+ lm->loaded_objfile = objfile;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!lm->loaded_objfile)
|
|
+ req->flags |= GNU_COMMAND_FAILED;
|
|
+}
|
|
+
|
|
+static void
|
|
+gdb_delete_symbol_file(struct gnu_request *req)
|
|
+{
|
|
+ for (objfile *objfile : current_program_space->objfiles ()) {
|
|
+ if (STREQ(objfile_name(objfile), req->name) ||
|
|
+ same_file((char *)objfile_name(objfile), req->name)) {
|
|
+ objfile->unlink ();
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (gdb_CRASHDEBUG(2)) {
|
|
+ gdb_printf(gdb_stdout, "current object files:\n");
|
|
+ for (objfile *objfile : current_program_space->objfiles ())
|
|
+ gdb_printf(gdb_stdout, " %s\n", objfile_name(objfile));
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Walk through all minimal_symbols, patching their values with the
|
|
+ * correct addresses.
|
|
+ */
|
|
+static void
|
|
+gdb_patch_symbol_values(struct gnu_request *req)
|
|
+{
|
|
+ req->name = PATCH_KERNEL_SYMBOLS_START;
|
|
+ patch_kernel_symbol(req);
|
|
+
|
|
+ for (objfile *objfile : current_program_space->objfiles ())
|
|
+ for (minimal_symbol *msymbol : objfile->msymbols ())
|
|
+ {
|
|
+ req->name = (char *)msymbol->m_name;
|
|
+ req->addr = (ulong)(&msymbol->m_value.ivalue);
|
|
+ if (!patch_kernel_symbol(req)) {
|
|
+ req->flags |= GNU_COMMAND_FAILED;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ req->name = PATCH_KERNEL_SYMBOLS_STOP;
|
|
+ patch_kernel_symbol(req);
|
|
+
|
|
+ clear_symtab_users(0);
|
|
+ gdb_merge_flags |= KERNEL_SYMBOLS_PATCHED;
|
|
+}
|
|
+
|
|
+static void
|
|
+gdb_get_symbol_type(struct gnu_request *req)
|
|
+{
|
|
+ expression_up expr;
|
|
+ struct value *val;
|
|
+ struct type *type;
|
|
+ struct type *target_type;
|
|
+
|
|
+ req->typecode = TYPE_CODE_UNDEF;
|
|
+
|
|
+ expr = parse_expression (req->name);
|
|
+ val = expr->evaluate_type();
|
|
+
|
|
+ type = val->type();
|
|
+
|
|
+ req->type_name = (char *)TYPE_MAIN_TYPE(type)->name;
|
|
+ req->typecode = TYPE_MAIN_TYPE(type)->code;
|
|
+ req->length = type->m_length;
|
|
+ req->type_tag_name = (char *)TYPE_TAG_NAME(type);
|
|
+ target_type = TYPE_MAIN_TYPE(type)->m_target_type;
|
|
+
|
|
+ if (target_type) {
|
|
+ req->target_typename = (char *)TYPE_MAIN_TYPE(target_type)->name;
|
|
+ req->target_typecode = TYPE_MAIN_TYPE(target_type)->code;
|
|
+ req->target_length = target_type->m_length;
|
|
+ }
|
|
+
|
|
+ if (req->member)
|
|
+ get_member_data(req, type, 0, 1);
|
|
+}
|
|
+
|
|
+static void
|
|
+gdb_debug_command(struct gnu_request *req)
|
|
+{
|
|
+
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Only necessary on "patched" kernel symbol sessions, and called only by
|
|
+ * lookup_symbol(), pull a symbol value bait-and-switch operation by altering
|
|
+ * either a data symbol's address value or a text symbol's block start address.
|
|
+ */
|
|
+static void
|
|
+gdb_bait_and_switch(char *name, struct symbol *sym)
|
|
+{
|
|
+ struct bound_minimal_symbol msym;
|
|
+ struct block *block;
|
|
+
|
|
+ if ((gdb_merge_flags & KERNEL_SYMBOLS_PATCHED) &&
|
|
+ (msym = lookup_minimal_symbol(current_program_space, name, gdb_kernel_objfile, NULL)).minsym) {
|
|
+ if (sym->aclass() == LOC_BLOCK) {
|
|
+ block = (struct block *)(sym->value_block());
|
|
+ block->set_start(msym.value_address());
|
|
+ } else
|
|
+ sym->set_value_address(msym.value_address());
|
|
+ }
|
|
+}
|
|
+
|
|
+#include "valprint.h"
|
|
+
|
|
+void
|
|
+get_user_print_option_address(struct gnu_request *req)
|
|
+{
|
|
+ extern struct value_print_options user_print_options;
|
|
+
|
|
+ req->addr = 0;
|
|
+
|
|
+ if (strcmp(req->name, "output_format") == 0)
|
|
+ req->addr = (ulong)&user_print_options.output_format;
|
|
+ if (strcmp(req->name, "print_max") == 0)
|
|
+ req->addr = (ulong)&user_print_options.print_max;
|
|
+ if (strcmp(req->name, "prettyprint_structs") == 0)
|
|
+ req->addr = (ulong)&user_print_options.prettyformat_structs;
|
|
+ if (strcmp(req->name, "prettyprint_arrays") == 0)
|
|
+ req->addr = (ulong)&user_print_options.prettyformat_arrays;
|
|
+ if (strcmp(req->name, "repeat_count_threshold") == 0)
|
|
+ req->addr = (ulong)&user_print_options.repeat_count_threshold;
|
|
+ if (strcmp(req->name, "stop_print_at_null") == 0)
|
|
+ req->addr = (ulong)&user_print_options.stop_print_at_null;
|
|
+ if (strcmp(req->name, "output_radix") == 0)
|
|
+ req->addr = (ulong)&output_radix;
|
|
+}
|
|
+
|
|
+CORE_ADDR crash_text_scope;
|
|
+
|
|
+static void
|
|
+gdb_set_crash_block(struct gnu_request *req)
|
|
+{
|
|
+ if (!req->addr) { /* debug */
|
|
+ crash_text_scope = 0;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((req->addr2 = (ulong)block_for_pc(req->addr)))
|
|
+ crash_text_scope = req->addr;
|
|
+ else {
|
|
+ crash_text_scope = 0;
|
|
+ req->flags |= GNU_COMMAND_FAILED;
|
|
+ }
|
|
+}
|
|
+
|
|
+static const struct block *
|
|
+gdb_get_crash_block(void)
|
|
+{
|
|
+ if (crash_text_scope)
|
|
+ return block_for_pc(crash_text_scope);
|
|
+ else
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static long
|
|
+lookup_struct_contents(struct gnu_request *req)
|
|
+{
|
|
+ int i;
|
|
+ long r;
|
|
+ struct field *f;
|
|
+ struct main_type *m;
|
|
+ const char *n;
|
|
+ struct main_type *top_m = (struct main_type *)req->addr;
|
|
+ char *type_name = req->type_name;
|
|
+
|
|
+ if (!top_m || !type_name)
|
|
+ return 0;
|
|
+
|
|
+ for (i = 0; i < top_m->m_nfields; i++)
|
|
+ {
|
|
+ f = top_m->flds_bnds.fields + i;
|
|
+ if (!f->type())
|
|
+ continue;
|
|
+ m = f->type()->main_type;
|
|
+
|
|
+ // If the field is an array, check the target type -
|
|
+ // it might be structure, or might not be.
|
|
+ // - struct request_sock *syn_table[0];
|
|
+ // here m->target_type->main_type->code is expected
|
|
+ // to be TYPE_CODE_PTR
|
|
+ // - struct list_head vec[TVN_SIZE];
|
|
+ // here m->target_type->main_type->code should be
|
|
+ // TYPE_CODE_STRUCT
|
|
+ if (m->code == TYPE_CODE_ARRAY && m->m_target_type)
|
|
+ m = m->m_target_type->main_type;
|
|
+
|
|
+ /* Here is a recursion.
|
|
+ * If we have struct variable (not pointer),
|
|
+ * scan this inner structure
|
|
+ */
|
|
+ if (m->code == TYPE_CODE_STRUCT) {
|
|
+ req->addr = (ulong)m;
|
|
+ r = lookup_struct_contents(req);
|
|
+ req->addr = (ulong)top_m;
|
|
+ if (r)
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (m->code == TYPE_CODE_PTR && m->m_target_type)
|
|
+ m = m->m_target_type->main_type;
|
|
+ if (m->name)
|
|
+ n = m->name;
|
|
+ else
|
|
+ continue;
|
|
+
|
|
+ if (strstr(n, type_name))
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void
|
|
+iterate_datatypes (struct gnu_request *req)
|
|
+{
|
|
+ for (objfile *objfile : current_program_space->objfiles ())
|
|
+ {
|
|
+ if (objfile->sf) {
|
|
+ objfile->expand_all_symtabs();
|
|
+ objfile->all_symtabs_expanded = true;
|
|
+ }
|
|
+
|
|
+ for (compunit_symtab *cust : objfile->compunits ())
|
|
+ {
|
|
+ const struct blockvector *bv = cust->blockvector();
|
|
+
|
|
+ for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; ++i)
|
|
+ {
|
|
+ const struct block *b = bv->block(i);
|
|
+
|
|
+ for (struct symbol *sym : block_iterator_range (b))
|
|
+ {
|
|
+ QUIT;
|
|
+
|
|
+ if (sym->aclass() != LOC_TYPEDEF)
|
|
+ continue;
|
|
+
|
|
+ if (req->highest &&
|
|
+ !(req->lowest <= sym->type()->m_length && sym->type()->m_length <= req->highest))
|
|
+ continue;
|
|
+
|
|
+ req->addr = (ulong)(sym->type()->main_type);
|
|
+ req->name = (char *)(sym->m_name);
|
|
+ req->length = sym->type()->m_length;
|
|
+
|
|
+ if (req->member) {
|
|
+ req->value = lookup_struct_contents(req);
|
|
+ if (!req->value)
|
|
+ continue;
|
|
+ }
|
|
+ req->callback(req, req->callback_data);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+#endif
|
|
--- gdb-16.2/gdb/ui-file.c.orig
|
|
+++ gdb-16.2/gdb/ui-file.c
|
|
@@ -251,6 +251,12 @@ stdio_file::~stdio_file ()
|
|
fclose (m_file);
|
|
}
|
|
|
|
+FILE*
|
|
+stdio_file::get_stream(void)
|
|
+{
|
|
+ return m_file;
|
|
+}
|
|
+
|
|
void
|
|
stdio_file::set_stream (FILE *file)
|
|
{
|
|
--- gdb-16.2/gdb/ui-file.h.orig
|
|
+++ gdb-16.2/gdb/ui-file.h
|
|
@@ -273,10 +273,11 @@ class stdio_file : public ui_file
|
|
int fd () const override
|
|
{ return m_fd; }
|
|
|
|
-private:
|
|
+ FILE *get_stream(void);
|
|
/* Sets the internal stream to FILE, and saves the FILE's file
|
|
descriptor in M_FD. */
|
|
void set_stream (FILE *file);
|
|
+private:
|
|
|
|
/* The file. */
|
|
FILE *m_file;
|
|
--- gdb-16.2/gdb/xml-syscall.c.orig
|
|
+++ gdb-16.2/gdb/xml-syscall.c
|
|
@@ -36,7 +36,11 @@
|
|
static void
|
|
syscall_warn_user (void)
|
|
{
|
|
+#ifdef CRASH_MERGE
|
|
+ static int have_warned = 1;
|
|
+#else
|
|
static int have_warned = 0;
|
|
+#endif
|
|
if (!have_warned)
|
|
{
|
|
have_warned = 1;
|
|
--- gdb-16.2/libiberty/Makefile.in.orig
|
|
+++ gdb-16.2/libiberty/Makefile.in
|
|
@@ -181,6 +181,7 @@ REQUIRED_OFILES = \
|
|
./getruntime.$(objext) ./hashtab.$(objext) ./hex.$(objext) \
|
|
./lbasename.$(objext) ./lrealpath.$(objext) \
|
|
./make-relative-prefix.$(objext) ./make-temp-file.$(objext) \
|
|
+ ./mkstemps.$(objext) \
|
|
./objalloc.$(objext) \
|
|
./obstack.$(objext) \
|
|
./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext) \
|
|
@@ -214,7 +215,7 @@ CONFIGURED_OFILES = ./asprintf.$(objext) ./atexit.$(objext) \
|
|
./index.$(objext) ./insque.$(objext) \
|
|
./memchr.$(objext) ./memcmp.$(objext) ./memcpy.$(objext) \
|
|
./memmem.$(objext) ./memmove.$(objext) \
|
|
- ./mempcpy.$(objext) ./memset.$(objext) ./mkstemps.$(objext) \
|
|
+ ./mempcpy.$(objext) ./memset.$(objext) \
|
|
./pex-djgpp.$(objext) ./pex-msdos.$(objext) \
|
|
./pex-unix.$(objext) ./pex-win32.$(objext) \
|
|
./putenv.$(objext) \
|
|
--- gdb-16.2/opcodes/i386-dis.c.orig
|
|
+++ gdb-16.2/opcodes/i386-dis.c
|
|
@@ -9589,6 +9589,10 @@ print_insn (bfd_vma pc, disassemble_info *info, int intel_syntax)
|
|
|
|
dp = &dis386_twobyte[*ins.codep];
|
|
ins.need_modrm = twobyte_has_modrm[*ins.codep];
|
|
+ if (dp->name && ((strcmp(dp->name, "ud2a") == 0) || (strcmp(dp->name, "ud2") == 0))) {
|
|
+ extern int kernel_BUG_encoding_bytes(void);
|
|
+ ins.codep += kernel_BUG_encoding_bytes();
|
|
+ }
|
|
}
|
|
else
|
|
{
|
|
--- gdb-16.2/readline/readline/misc.c.orig
|
|
+++ gdb-16.2/readline/readline/misc.c
|
|
@@ -411,7 +411,7 @@ _rl_history_set_point (void)
|
|
|
|
#if defined (VI_MODE)
|
|
if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap)
|
|
- rl_point = 0;
|
|
+ rl_point = rl_end;
|
|
#endif /* VI_MODE */
|
|
|
|
if (rl_editing_mode == emacs_mode)
|
|
--- gdb-16.2/readline/readline/readline.h.orig
|
|
+++ gdb-16.2/readline/readline/readline.h
|
|
@@ -407,7 +407,7 @@ extern int rl_mark_active_p (void);
|
|
#if defined (USE_VARARGS) && defined (PREFER_STDARG)
|
|
extern int rl_message (const char *, ...) __attribute__((__format__ (printf, 1, 2)));
|
|
#else
|
|
-extern int rl_message ();
|
|
+extern int rl_message (void);
|
|
#endif
|
|
|
|
extern int rl_show_char (int);
|
|
--- gdb-16.2/readline/readline/rltypedefs.h.orig
|
|
+++ gdb-16.2/readline/readline/rltypedefs.h
|
|
@@ -32,10 +32,10 @@ extern "C" {
|
|
# define _FUNCTION_DEF
|
|
|
|
#if defined(__GNUC__) || defined(__clang__)
|
|
-typedef int Function () __attribute__((deprecated));
|
|
-typedef void VFunction () __attribute__((deprecated));
|
|
-typedef char *CPFunction () __attribute__((deprecated));
|
|
-typedef char **CPPFunction () __attribute__((deprecated));
|
|
+typedef int Function (void) __attribute__ ((deprecated));
|
|
+typedef void VFunction (void) __attribute__ ((deprecated));
|
|
+typedef char *CPFunction (void) __attribute__ ((deprecated));
|
|
+typedef char **CPPFunction (void) __attribute__ ((deprecated));
|
|
#else
|
|
typedef int Function ();
|
|
typedef void VFunction ();
|
|
--- gdb-16.2/readline/readline/util.c.orig
|
|
+++ gdb-16.2/readline/readline/util.c
|
|
@@ -489,10 +489,13 @@ _rl_trace (va_alist)
|
|
|
|
if (_rl_tracefp == 0)
|
|
_rl_tropen ();
|
|
+ if (!_rl_tracefp)
|
|
+ goto out;
|
|
vfprintf (_rl_tracefp, format, args);
|
|
fprintf (_rl_tracefp, "\n");
|
|
fflush (_rl_tracefp);
|
|
|
|
+out:
|
|
va_end (args);
|
|
}
|
|
|
|
@@ -512,16 +515,17 @@ _rl_tropen (void)
|
|
#endif
|
|
snprintf (fnbuf, sizeof (fnbuf), "%s/rltrace.%ld", x, (long)getpid());
|
|
unlink(fnbuf);
|
|
- _rl_tracefp = fopen (fnbuf, "w+");
|
|
+ _rl_tracefp = fopen (fnbuf, "w+xe");
|
|
return _rl_tracefp != 0;
|
|
}
|
|
|
|
int
|
|
_rl_trclose (void)
|
|
{
|
|
- int r;
|
|
+ int r = 0;
|
|
|
|
- r = fclose (_rl_tracefp);
|
|
+ if (_rl_tracefp)
|
|
+ r = fclose (_rl_tracefp);
|
|
_rl_tracefp = 0;
|
|
return r;
|
|
}
|
|
--- gdb-16.2/configure.orig
|
|
+++ gdb-16.2/configure
|
|
@@ -3620,6 +3620,9 @@ case "${target}" in
|
|
;;
|
|
esac
|
|
|
|
+#disable gdbserver build in crash-utility
|
|
+enable_gdbserver=no
|
|
+
|
|
# Only allow gdbserver on some systems.
|
|
if test -d ${srcdir}/gdbserver; then
|
|
if test x$enable_gdbserver = x; then
|
|
--- gdb-16.2/gdb/symfile.c.orig
|
|
+++ gdb-16.2/gdb/symfile.c
|
|
@@ -341,8 +341,15 @@ place_section (bfd *abfd, asection *sect, section_offsets &offsets,
|
|
return;
|
|
|
|
/* If the user specified an offset, honor it. */
|
|
- if (offsets[gdb_bfd_section_index (abfd, sect)] != 0)
|
|
+ if (offsets[gdb_bfd_section_index (abfd, sect)] != 0) {
|
|
+ /*
|
|
+ * addr_info_make_relative() subtracts out the section VMA. But if the user
|
|
+ * specified an offset, they have already taken this into account. Add it
|
|
+ * back in
|
|
+ */
|
|
+ offsets[gdb_bfd_section_index (abfd, sect)] += bfd_section_vma(sect);
|
|
return;
|
|
+ }
|
|
|
|
/* Otherwise, let's try to find a place for the section. */
|
|
start_addr = (lowest + align - 1) & -align;
|
|
@@ -630,33 +637,6 @@ default_symfile_offsets (struct objfile *objfile,
|
|
bfd *abfd = objfile->obfd.get ();
|
|
asection *cur_sec;
|
|
|
|
- for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next)
|
|
- /* We do not expect this to happen; just skip this step if the
|
|
- relocatable file has a section with an assigned VMA. */
|
|
- if (bfd_section_vma (cur_sec) != 0
|
|
- /*
|
|
- * Kernel modules may have some non-zero VMAs, i.e., like the
|
|
- * __ksymtab and __ksymtab_gpl sections in this example:
|
|
- *
|
|
- * Section Headers:
|
|
- * [Nr] Name Type Address Offset
|
|
- * Size EntSize Flags Link Info Align
|
|
- * ...
|
|
- * [ 8] __ksymtab PROGBITS 0000000000000060 0000ad90
|
|
- * 0000000000000010 0000000000000000 A 0 0 16
|
|
- * [ 9] .rela__ksymtab RELA 0000000000000000 0000ada0
|
|
- * 0000000000000030 0000000000000018 43 8 8
|
|
- * [10] __ksymtab_gpl PROGBITS 0000000000000070 0000add0
|
|
- * 00000000000001a0 0000000000000000 A 0 0 16
|
|
- * ...
|
|
- *
|
|
- * but they should be treated as if they are NULL.
|
|
- */
|
|
- && strncmp (bfd_section_name (cur_sec), "__k", 3) != 0)
|
|
- break;
|
|
-
|
|
- if (cur_sec == NULL)
|
|
- {
|
|
section_offsets &offsets = objfile->section_offsets;
|
|
|
|
/* Pick non-overlapping offsets for sections the user did not
|
|
@@ -704,7 +684,6 @@ default_symfile_offsets (struct objfile *objfile,
|
|
offsets[cur_sec->index]);
|
|
offsets[cur_sec->index] = 0;
|
|
}
|
|
- }
|
|
}
|
|
|
|
/* Remember the bfd indexes for the .text, .data, .bss and
|