# 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("\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 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_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_castgdb_stdout)->set_stream(req->fp); + (dynamic_castgdb_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_castgdb_stdout)->set_stream(original_stdout_stream); + if (original_stderr_stream) + (dynamic_castgdb_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