X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fexec.c;h=d27949c609f45663449be03741268cfa667411fa;hb=c20cb6860c27d6ef15a1e561f4be78e7b85952ac;hp=92c87e4e02f096c2ec04bf305465649c876153f8;hpb=14278e1fdbe045df184d6dd546ff6a1e9e3c3797;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/exec.c b/gdb/exec.c index 92c87e4e02..d27949c609 100644 --- a/gdb/exec.c +++ b/gdb/exec.c @@ -1,6 +1,6 @@ /* Work with executable files, for GDB. - Copyright (C) 1988-2017 Free Software Foundation, Inc. + Copyright (C) 1988-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -29,43 +29,109 @@ #include "completer.h" #include "value.h" #include "exec.h" -#include "observer.h" +#include "observable.h" #include "arch-utils.h" #include "gdbthread.h" #include "progspace.h" +#include "progspace-and-thread.h" #include "gdb_bfd.h" #include "gcore.h" +#include "source.h" +#include "build-id.h" #include -#include "readline/readline.h" +#include "readline/tilde.h" #include "gdbcore.h" #include #include #include "solist.h" #include +#include "gdbsupport/pathstuff.h" +#include "cli/cli-style.h" -void (*deprecated_file_changed_hook) (char *); +void (*deprecated_file_changed_hook) (const char *); -/* Prototypes for local functions */ - -static void file_command (char *, int); - -static void set_section_command (char *, int); - -static void exec_files_info (struct target_ops *); - -static void init_exec_ops (void); - -void _initialize_exec (void); +static const target_info exec_target_info = { + "exec", + N_("Local exec file"), + N_("Use an executable file as a target.\n\ +Specify the filename of the executable file.") +}; /* The target vector for executable files. */ -static struct target_ops exec_ops; +struct exec_target final : public target_ops +{ + const target_info &info () const override + { return exec_target_info; } + + strata stratum () const override { return file_stratum; } + + void close () override; + enum target_xfer_status xfer_partial (enum target_object object, + const char *annex, + gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) override; + target_section_table *get_section_table () override; + void files_info () override; + + bool has_memory () override; + gdb::unique_xmalloc_ptr make_corefile_notes (bfd *, int *) override; + int find_memory_regions (find_memory_region_ftype func, void *data) override; +}; + +static exec_target exec_ops; + +/* How to handle a mismatch between the current exec file and the exec + file determined from target. */ + +static const char *const exec_file_mismatch_names[] + = {"ask", "warn", "off", NULL }; +enum exec_file_mismatch_mode + { + exec_file_mismatch_ask, exec_file_mismatch_warn, exec_file_mismatch_off + }; +static const char *exec_file_mismatch = exec_file_mismatch_names[0]; +static enum exec_file_mismatch_mode exec_file_mismatch_mode + = exec_file_mismatch_ask; + +/* Show command. */ +static void +show_exec_file_mismatch_command (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (gdb_stdout, + _("exec-file-mismatch handling is currently \"%s\".\n"), + exec_file_mismatch_names[exec_file_mismatch_mode]); +} + +/* Set command. Change the setting for range checking. */ +static void +set_exec_file_mismatch_command (const char *ignore, + int from_tty, struct cmd_list_element *c) +{ + for (enum exec_file_mismatch_mode mode = exec_file_mismatch_ask; + ; + mode = static_cast(1 + (int) mode)) + { + if (strcmp (exec_file_mismatch, exec_file_mismatch_names[mode]) == 0) + { + exec_file_mismatch_mode = mode; + return; + } + if (mode == exec_file_mismatch_off) + internal_error (__FILE__, __LINE__, + _("Unrecognized exec-file-mismatch setting: \"%s\""), + exec_file_mismatch); + } +} /* Whether to open exec and core files read-only or read-write. */ -int write_files = 0; +bool write_files = false; static void show_write_files (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -76,7 +142,7 @@ show_write_files (struct ui_file *file, int from_tty, static void -exec_open (const char *args, int from_tty) +exec_target_open (const char *args, int from_tty) { target_preopen (from_tty); exec_file_attach (args, from_tty); @@ -101,48 +167,33 @@ exec_close (void) remove_target_sections (&exec_bfd); - xfree (exec_filename); - exec_filename = NULL; + current_program_space->exec_filename.reset (nullptr); } } /* This is the target_close implementation. Clears all target sections and closes all executable bfds from all program spaces. */ -static void -exec_close_1 (struct target_ops *self) +void +exec_target::close () { - struct program_space *ss; scoped_restore_current_program_space restore_pspace; - ALL_PSPACES (ss) + for (struct program_space *ss : program_spaces) { set_current_program_space (ss); - clear_section_table (current_target_sections); + current_target_sections->clear (); exec_close (); } } -void -exec_file_clear (int from_tty) -{ - /* Remove exec file. */ - exec_close (); - - if (from_tty) - printf_unfiltered (_("No executable file now.\n")); -} - -/* See exec.h. */ +/* See gdbcore.h. */ void try_open_exec_file (const char *exec_file_host, struct inferior *inf, symfile_add_flags add_flags) { - struct cleanup *old_chain; - struct gdb_exception prev_err = exception_none; - - old_chain = make_cleanup (free_current_contents, &prev_err.message); + struct gdb_exception prev_err; /* exec_file_attach and symbol_file_add_main may throw an error if the file cannot be opened either locally or remotely. @@ -155,40 +206,132 @@ try_open_exec_file (const char *exec_file_host, struct inferior *inf, Even without a symbol file, the remote-based debugging session should continue normally instead of ending abruptly. Hence we catch thrown errors/exceptions in the following code. */ - TRY + try { /* We must do this step even if exec_file_host is NULL, so that exec_file_attach will clear state. */ exec_file_attach (exec_file_host, add_flags & SYMFILE_VERBOSE); } - CATCH (err, RETURN_MASK_ERROR) + catch (gdb_exception_error &err) { if (err.message != NULL) - warning ("%s", err.message); - - prev_err = err; + warning ("%s", err.what ()); - /* Save message so it doesn't get trashed by the catch below. */ - if (err.message != NULL) - prev_err.message = xstrdup (err.message); + prev_err = std::move (err); } - END_CATCH if (exec_file_host != NULL) { - TRY + try { symbol_file_add_main (exec_file_host, add_flags); } - CATCH (err, RETURN_MASK_ERROR) + catch (const gdb_exception_error &err) { if (!exception_print_same (prev_err, err)) - warning ("%s", err.message); + warning ("%s", err.what ()); } - END_CATCH } +} - do_cleanups (old_chain); +/* See gdbcore.h. */ + +void +validate_exec_file (int from_tty) +{ + /* If user asked to ignore the mismatch, do nothing. */ + if (exec_file_mismatch_mode == exec_file_mismatch_off) + return; + + const char *current_exec_file = get_exec_file (0); + struct inferior *inf = current_inferior (); + /* Try to determine a filename from the process itself. */ + const char *pid_exec_file = target_pid_to_exec_file (inf->pid); + bool build_id_mismatch = false; + + /* If we cannot validate the exec file, return. */ + if (current_exec_file == NULL || pid_exec_file == NULL) + return; + + /* Try validating via build-id, if available. This is the most + reliable check. */ + + /* In case current_exec_file was changed, reopen_exec_file ensures + an up to date build_id (will do nothing if the file timestamp + did not change). If exec file changed, reopen_exec_file has + allocated another file name, so get_exec_file again. */ + reopen_exec_file (); + current_exec_file = get_exec_file (0); + + const bfd_build_id *exec_file_build_id = build_id_bfd_get (exec_bfd); + if (exec_file_build_id != nullptr) + { + /* Prepend the target prefix, to force gdb_bfd_open to open the + file on the remote file system (if indeed remote). */ + std::string target_pid_exec_file + = std::string (TARGET_SYSROOT_PREFIX) + pid_exec_file; + + gdb_bfd_ref_ptr abfd (gdb_bfd_open (target_pid_exec_file.c_str (), + gnutarget, -1, false)); + if (abfd != nullptr) + { + const bfd_build_id *target_exec_file_build_id + = build_id_bfd_get (abfd.get ()); + + if (target_exec_file_build_id != nullptr) + { + if (exec_file_build_id->size == target_exec_file_build_id->size + && memcmp (exec_file_build_id->data, + target_exec_file_build_id->data, + exec_file_build_id->size) == 0) + { + /* Match. */ + return; + } + else + build_id_mismatch = true; + } + } + } + + if (build_id_mismatch) + { + std::string exec_file_target (pid_exec_file); + + /* In case the exec file is not local, exec_file_target has to point at + the target file system. */ + if (is_target_filename (current_exec_file) && !target_filesystem_is_local ()) + exec_file_target = TARGET_SYSROOT_PREFIX + exec_file_target; + + warning + (_("Build ID mismatch between current exec-file %ps\n" + "and automatically determined exec-file %ps\n" + "exec-file-mismatch handling is currently \"%s\""), + styled_string (file_name_style.style (), current_exec_file), + styled_string (file_name_style.style (), exec_file_target.c_str ()), + exec_file_mismatch_names[exec_file_mismatch_mode]); + if (exec_file_mismatch_mode == exec_file_mismatch_ask) + { + symfile_add_flags add_flags = SYMFILE_MAINLINE; + if (from_tty) + { + add_flags |= SYMFILE_VERBOSE; + add_flags |= SYMFILE_ALWAYS_CONFIRM; + } + try + { + symbol_file_add_main (exec_file_target.c_str (), add_flags); + exec_file_attach (exec_file_target.c_str (), from_tty); + } + catch (gdb_exception_error &err) + { + warning (_("loading %ps %s"), + styled_string (file_name_style.style (), + exec_file_target.c_str ()), + err.message != NULL ? err.what () : "error"); + } + } + } } /* See gdbcore.h. */ @@ -196,8 +339,7 @@ try_open_exec_file (const char *exec_file_host, struct inferior *inf, void exec_file_locate_attach (int pid, int defer_bp_reset, int from_tty) { - char *exec_file_target, *exec_file_host; - struct cleanup *old_chain; + char *exec_file_target; symfile_add_flags add_flags = 0; /* Do nothing if we already have an executable filename. */ @@ -215,8 +357,8 @@ exec_file_locate_attach (int pid, int defer_bp_reset, int from_tty) return; } - exec_file_host = exec_file_find (exec_file_target, NULL); - old_chain = make_cleanup (xfree, exec_file_host); + gdb::unique_xmalloc_ptr exec_file_host + = exec_file_find (exec_file_target, NULL); if (defer_bp_reset) add_flags |= SYMFILE_DEFER_BP_RESET; @@ -225,8 +367,7 @@ exec_file_locate_attach (int pid, int defer_bp_reset, int from_tty) add_flags |= SYMFILE_VERBOSE; /* Attempt to open the exec file. */ - try_open_exec_file (exec_file_host, current_inferior (), add_flags); - do_cleanups (old_chain); + try_open_exec_file (exec_file_host.get (), current_inferior (), add_flags); } /* Set FILENAME as the new exec file. @@ -252,8 +393,7 @@ exec_file_attach (const char *filename, int from_tty) /* First, acquire a reference to the current exec_bfd. We release this at the end of the function; but acquiring it now lets the BFD cache return it if this call refers to the same file. */ - gdb_bfd_ref (exec_bfd); - gdb_bfd_ref_ptr exec_bfd_holder (exec_bfd); + gdb_bfd_ref_ptr exec_bfd_holder = gdb_bfd_ref_ptr::new_reference (exec_bfd); /* Remove any previous exec file. */ exec_close (); @@ -272,7 +412,6 @@ exec_file_attach (const char *filename, int from_tty) int load_via_target = 0; const char *scratch_pathname, *canonical_pathname; int scratch_chan; - struct target_section *sections = NULL, *sections_end = NULL; char **matching; if (is_target_filename (filename)) @@ -298,15 +437,14 @@ exec_file_attach (const char *filename, int from_tty) } else { - char *temp_pathname; - scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, filename, write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, - &temp_pathname); + &scratch_storage); #if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__) if (scratch_chan < 0) { + int first_errno = errno; char *exename = (char *) alloca (strlen (filename) + 5); strcat (strcpy (exename, filename), ".exe"); @@ -314,14 +452,15 @@ exec_file_attach (const char *filename, int from_tty) exename, write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, - &temp_pathname); + &scratch_storage); + if (scratch_chan < 0) + errno = first_errno; } #endif if (scratch_chan < 0) perror_with_name (filename); - scratch_storage.reset (temp_pathname); - scratch_pathname = temp_pathname; + scratch_pathname = scratch_storage.get (); /* gdb_bfd_open (and its variants) prefers canonicalized pathname for better BFD caching. */ @@ -339,36 +478,32 @@ exec_file_attach (const char *filename, int from_tty) if (!exec_bfd) { - error (_("\"%s\": could not open as an executable file: %s."), - scratch_pathname, bfd_errmsg (bfd_get_error ())); + error (_("\"%ps\": could not open as an executable file: %s."), + styled_string (file_name_style.style (), scratch_pathname), + bfd_errmsg (bfd_get_error ())); } /* gdb_realpath_keepfile resolves symlinks on the local filesystem and so cannot be used for "target:" files. */ - gdb_assert (exec_filename == NULL); + gdb_assert (current_program_space->exec_filename == nullptr); if (load_via_target) - exec_filename = xstrdup (bfd_get_filename (exec_bfd)); + current_program_space->exec_filename + = make_unique_xstrdup (bfd_get_filename (exec_bfd)); else - exec_filename = gdb_realpath_keepfile (scratch_pathname).release (); + current_program_space->exec_filename + = gdb_realpath_keepfile (scratch_pathname); if (!bfd_check_format_matches (exec_bfd, bfd_object, &matching)) { /* Make sure to close exec_bfd, or else "run" might try to use it. */ exec_close (); - error (_("\"%s\": not in executable format: %s"), - scratch_pathname, - gdb_bfd_errmsg (bfd_get_error (), matching)); + error (_("\"%ps\": not in executable format: %s"), + styled_string (file_name_style.style (), scratch_pathname), + gdb_bfd_errmsg (bfd_get_error (), matching).c_str ()); } - if (build_section_table (exec_bfd, §ions, §ions_end)) - { - /* Make sure to close exec_bfd, or else "run" might try to use - it. */ - exec_close (); - error (_("\"%s\": can't find the file sections: %s"), - scratch_pathname, bfd_errmsg (bfd_get_error ())); - } + target_section_table sections = build_section_table (exec_bfd); exec_bfd_mtime = bfd_get_mtime (exec_bfd); @@ -379,8 +514,7 @@ exec_file_attach (const char *filename, int from_tty) /* Add the executable's sections to the current address spaces' list of sections. This possibly pushes the exec_ops target. */ - add_target_sections (&exec_bfd, sections, sections_end); - xfree (sections); + add_target_sections (&exec_bfd, sections); /* Tell display code (if any) about the changed file name. */ if (deprecated_exec_file_display_hook) @@ -388,7 +522,7 @@ exec_file_attach (const char *filename, int from_tty) } bfd_cache_close_all (); - observer_notify_executable_changed (); + gdb::observers::executable_changed.notify (); } /* Process the first arg in ARGS as the new exec file. @@ -400,11 +534,9 @@ exec_file_attach (const char *filename, int from_tty) If ARGS is NULL, we just want to close the exec file. */ static void -exec_file_command (char *args, int from_tty) +exec_file_command (const char *args, int from_tty) { - char *filename; - - if (from_tty && target_has_execution + if (from_tty && target_has_execution () && !query (_("A program is being debugged already.\n" "Are you sure you want to change the file? "))) error (_("File not changed.")); @@ -435,7 +567,7 @@ exec_file_command (char *args, int from_tty) command was added? */ static void -file_command (char *arg, int from_tty) +file_command (const char *arg, int from_tty) { /* FIXME, if we lose on reading the symbol file, we should revert the exec file, but that's rough. */ @@ -446,91 +578,33 @@ file_command (char *arg, int from_tty) } -/* Locate all mappable sections of a BFD file. - table_pp_char is a char * to get it through bfd_map_over_sections; - we cast it back to its proper type. */ +/* Builds a section table, given args BFD, TABLE. */ -static void -add_to_section_table (bfd *abfd, struct bfd_section *asect, - void *table_pp_char) +target_section_table +build_section_table (struct bfd *some_bfd) { - struct target_section **table_pp = (struct target_section **) table_pp_char; - flagword aflag; - - gdb_assert (abfd == asect->owner); - - /* Check the section flags, but do not discard zero-length sections, since - some symbols may still be attached to this section. For instance, we - encountered on sparc-solaris 2.10 a shared library with an empty .bss - section to which a symbol named "_end" was attached. The address - of this symbol still needs to be relocated. */ - aflag = bfd_get_section_flags (abfd, asect); - if (!(aflag & SEC_ALLOC)) - return; - - (*table_pp)->owner = NULL; - (*table_pp)->the_bfd_section = asect; - (*table_pp)->addr = bfd_section_vma (abfd, asect); - (*table_pp)->endaddr = (*table_pp)->addr + bfd_section_size (abfd, asect); - (*table_pp)++; -} + target_section_table table; -/* See exec.h. */ - -void -clear_section_table (struct target_section_table *table) -{ - xfree (table->sections); - table->sections = table->sections_end = NULL; -} - -/* Resize section table TABLE by ADJUSTMENT. - ADJUSTMENT may be negative, in which case the caller must have already - removed the sections being deleted. - Returns the old size. */ - -static int -resize_section_table (struct target_section_table *table, int adjustment) -{ - int old_count; - int new_count; - - old_count = table->sections_end - table->sections; - - new_count = adjustment + old_count; - - if (new_count) + for (asection *asect : gdb_bfd_sections (some_bfd)) { - table->sections = XRESIZEVEC (struct target_section, table->sections, - new_count); - table->sections_end = table->sections + new_count; - } - else - clear_section_table (table); - - return old_count; -} + flagword aflag; + + /* Check the section flags, but do not discard zero-length + sections, since some symbols may still be attached to this + section. For instance, we encountered on sparc-solaris 2.10 + a shared library with an empty .bss section to which a symbol + named "_end" was attached. The address of this symbol still + needs to be relocated. */ + aflag = bfd_section_flags (asect); + if (!(aflag & SEC_ALLOC)) + continue; -/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR. - Returns 0 if OK, 1 on error. */ + table.emplace_back (bfd_section_vma (asect), + bfd_section_vma (asect) + bfd_section_size (asect), + asect); + } -int -build_section_table (struct bfd *some_bfd, struct target_section **start, - struct target_section **end) -{ - unsigned count; - - count = bfd_count_sections (some_bfd); - if (*start) - xfree (* start); - *start = XNEWVEC (struct target_section, count); - *end = *start; - bfd_map_over_sections (some_bfd, add_to_section_table, (char *) end); - if (*end > *start + count) - internal_error (__FILE__, __LINE__, - _("failed internal consistency check")); - /* We could realloc the table, but it probably loses for most files. */ - return 0; + return table; } /* Add the sections array defined by [SECTIONS..SECTIONS_END[ to the @@ -538,29 +612,35 @@ build_section_table (struct bfd *some_bfd, struct target_section **start, void add_target_sections (void *owner, - struct target_section *sections, - struct target_section *sections_end) + const target_section_table §ions) { - int count; - struct target_section_table *table = current_target_sections; + target_section_table *table = current_target_sections; - count = sections_end - sections; - - if (count > 0) + if (!sections.empty ()) { - int space = resize_section_table (table, count); - int i; - - for (i = 0; i < count; ++i) + for (const target_section &s : sections) { - table->sections[space + i] = sections[i]; - table->sections[space + i].owner = owner; + table->push_back (s); + table->back ().owner = owner; } + scoped_restore_current_pspace_and_thread restore_pspace_thread; + program_space *curr_pspace = current_program_space; + /* If these are the first file sections we can provide memory - from, push the file_stratum target. */ - if (!target_is_pushed (&exec_ops)) - push_target (&exec_ops); + from, push the file_stratum target. Must do this in all + inferiors sharing the program space. */ + for (inferior *inf : all_inferiors ()) + { + if (inf->pspace != curr_pspace) + continue; + + if (inf->target_is_pushed (&exec_ops)) + continue; + + switch_to_inferior_no_thread (inf); + push_target (&exec_ops); + } } } @@ -569,43 +649,20 @@ add_target_sections (void *owner, void add_target_sections_of_objfile (struct objfile *objfile) { - struct target_section_table *table = current_target_sections; + target_section_table *table = current_target_sections; struct obj_section *osect; - int space; - unsigned count = 0; - struct target_section *ts; - if (objfile == NULL) - return; + gdb_assert (objfile != nullptr); /* Compute the number of sections to add. */ ALL_OBJFILE_OSECTIONS (objfile, osect) { - if (bfd_get_section_size (osect->the_bfd_section) == 0) + if (bfd_section_size (osect->the_bfd_section) == 0) continue; - count++; - } - - if (count == 0) - return; - space = resize_section_table (table, count); - - ts = table->sections + space; - - ALL_OBJFILE_OSECTIONS (objfile, osect) - { - if (bfd_get_section_size (osect->the_bfd_section) == 0) - continue; - - gdb_assert (ts < table->sections + space + count); - - ts->addr = obj_section_addr (osect); - ts->endaddr = obj_section_endaddr (osect); - ts->the_bfd_section = osect->the_bfd_section; - ts->owner = (void *) objfile; - - ts++; + table->emplace_back (obj_section_addr (osect), + obj_section_endaddr (osect), + osect->the_bfd_section, (void *) objfile); } } @@ -615,44 +672,49 @@ add_target_sections_of_objfile (struct objfile *objfile) void remove_target_sections (void *owner) { - struct target_section *src, *dest; - struct target_section_table *table = current_target_sections; + target_section_table *table = current_target_sections; gdb_assert (owner != NULL); - dest = table->sections; - for (src = table->sections; src < table->sections_end; src++) - if (src->owner != owner) - { - /* Keep this section. */ - if (dest < src) - *dest = *src; - dest++; - } - - /* If we've dropped any sections, resize the section table. */ - if (dest < src) + auto it = std::remove_if (table->begin (), + table->end (), + [&] (target_section §) + { + return sect.owner == owner; + }); + table->erase (it, table->end ()); + + /* If we don't have any more sections to read memory from, + remove the file_stratum target from the stack of each + inferior sharing the program space. */ + if (table->empty ()) { - int old_count; - - old_count = resize_section_table (table, dest - src); + scoped_restore_current_pspace_and_thread restore_pspace_thread; + program_space *curr_pspace = current_program_space; - /* If we don't have any more sections to read memory from, - remove the file_stratum target from the stack. */ - if (old_count + (dest - src) == 0) + for (inferior *inf : all_inferiors ()) { - struct program_space *pspace; + if (inf->pspace != curr_pspace) + continue; - ALL_PSPACES (pspace) - if (pspace->target_sections.sections - != pspace->target_sections.sections_end) - return; + if (!inf->pspace->target_sections.empty ()) + continue; + switch_to_inferior_no_thread (inf); unpush_target (&exec_ops); } } } +/* See exec.h. */ + +void +exec_on_vfork () +{ + if (!current_program_space->target_sections.empty ()) + push_target (&exec_ops); +} + enum target_xfer_status @@ -675,7 +737,7 @@ exec_read_partial_read_only (gdb_byte *readbuf, ULONGEST offset, continue; vma = s->vma; - size = bfd_get_section_size (s); + size = bfd_section_size (s); if (vma <= offset && offset < (vma + size)) { ULONGEST amt; @@ -702,42 +764,36 @@ exec_read_partial_read_only (gdb_byte *readbuf, ULONGEST offset, return TARGET_XFER_E_IO; } -/* Appends all read-only memory ranges found in the target section +/* Return all read-only memory ranges found in the target section table defined by SECTIONS and SECTIONS_END, starting at (and - intersected with) MEMADDR for LEN bytes. Returns the augmented - VEC. */ - -static VEC(mem_range_s) * -section_table_available_memory (VEC(mem_range_s) *memory, - CORE_ADDR memaddr, ULONGEST len, - struct target_section *sections, - struct target_section *sections_end) + intersected with) MEMADDR for LEN bytes. */ + +static std::vector +section_table_available_memory (CORE_ADDR memaddr, ULONGEST len, + const target_section_table §ions) { - struct target_section *p; + std::vector memory; - for (p = sections; p < sections_end; p++) + for (const target_section &p : sections) { - if ((bfd_get_section_flags (p->the_bfd_section->owner, - p->the_bfd_section) - & SEC_READONLY) == 0) + if ((bfd_section_flags (p.the_bfd_section) & SEC_READONLY) == 0) continue; /* Copy the meta-data, adjusted. */ - if (mem_ranges_overlap (p->addr, p->endaddr - p->addr, memaddr, len)) + if (mem_ranges_overlap (p.addr, p.endaddr - p.addr, memaddr, len)) { ULONGEST lo1, hi1, lo2, hi2; - struct mem_range *r; lo1 = memaddr; hi1 = memaddr + len; - lo2 = p->addr; - hi2 = p->endaddr; + lo2 = p.addr; + hi2 = p.endaddr; - r = VEC_safe_push (mem_range_s, memory, NULL); + CORE_ADDR start = std::max (lo1, lo2); + int length = std::min (hi1, hi2) - start; - r->start = std::max (lo1, lo2); - r->length = std::min (hi1, hi2) - r->start; + memory.emplace_back (start, length); } } @@ -748,51 +804,36 @@ enum target_xfer_status section_table_read_available_memory (gdb_byte *readbuf, ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) { - VEC(mem_range_s) *available_memory = NULL; - struct target_section_table *table; - struct cleanup *old_chain; - mem_range_s *r; - int i; - - table = target_get_section_table (&exec_ops); - available_memory = section_table_available_memory (available_memory, - offset, len, - table->sections, - table->sections_end); - - old_chain = make_cleanup (VEC_cleanup(mem_range_s), - &available_memory); - - normalize_mem_ranges (available_memory); - - for (i = 0; - VEC_iterate (mem_range_s, available_memory, i, r); - i++) + target_section_table *table = target_get_section_table (&exec_ops); + std::vector available_memory + = section_table_available_memory (offset, len, *table); + + normalize_mem_ranges (&available_memory); + + for (const mem_range &r : available_memory) { - if (mem_ranges_overlap (r->start, r->length, offset, len)) + if (mem_ranges_overlap (r.start, r.length, offset, len)) { CORE_ADDR end; enum target_xfer_status status; /* Get the intersection window. */ - end = std::min (offset + len, r->start + r->length); + end = std::min (offset + len, r.start + r.length); gdb_assert (end - offset <= len); - if (offset >= r->start) + if (offset >= r.start) status = exec_read_partial_read_only (readbuf, offset, end - offset, xfered_len); else { - *xfered_len = r->start - offset; + *xfered_len = r.start - offset; status = TARGET_XFER_UNAVAILABLE; } - do_cleanups (old_chain); return status; } } - do_cleanups (old_chain); *xfered_len = len; return TARGET_XFER_UNAVAILABLE; @@ -802,38 +843,35 @@ enum target_xfer_status section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, ULONGEST *xfered_len, - struct target_section *sections, - struct target_section *sections_end, - const char *section_name) + const target_section_table §ions, + gdb::function_view match_cb) { int res; - struct target_section *p; ULONGEST memaddr = offset; ULONGEST memend = memaddr + len; - if (len == 0) - internal_error (__FILE__, __LINE__, - _("failed internal consistency check")); + gdb_assert (len != 0); - for (p = sections; p < sections_end; p++) + for (const target_section &p : sections) { - struct bfd_section *asect = p->the_bfd_section; + struct bfd_section *asect = p.the_bfd_section; bfd *abfd = asect->owner; - if (section_name && strcmp (section_name, asect->name) != 0) + if (match_cb != nullptr && !match_cb (&p)) continue; /* not the section we need. */ - if (memaddr >= p->addr) + if (memaddr >= p.addr) { - if (memend <= p->endaddr) + if (memend <= p.endaddr) { /* Entire transfer is within this section. */ if (writebuf) res = bfd_set_section_contents (abfd, asect, - writebuf, memaddr - p->addr, + writebuf, memaddr - p.addr, len); else res = bfd_get_section_contents (abfd, asect, - readbuf, memaddr - p->addr, + readbuf, memaddr - p.addr, len); if (res != 0) @@ -844,7 +882,7 @@ section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf, else return TARGET_XFER_EOF; } - else if (memaddr >= p->endaddr) + else if (memaddr >= p.endaddr) { /* This section ends before the transfer starts. */ continue; @@ -852,14 +890,14 @@ section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf, else { /* This section overlaps the transfer. Just do half. */ - len = p->endaddr - memaddr; + len = p.endaddr - memaddr; if (writebuf) res = bfd_set_section_contents (abfd, asect, - writebuf, memaddr - p->addr, + writebuf, memaddr - p.addr, len); else res = bfd_get_section_contents (abfd, asect, - readbuf, memaddr - p->addr, + readbuf, memaddr - p.addr, len); if (res != 0) { @@ -875,40 +913,39 @@ section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf, return TARGET_XFER_EOF; /* We can't help. */ } -static struct target_section_table * -exec_get_section_table (struct target_ops *ops) +target_section_table * +exec_target::get_section_table () { return current_target_sections; } -static enum target_xfer_status -exec_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) +enum target_xfer_status +exec_target::xfer_partial (enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) { - struct target_section_table *table = target_get_section_table (ops); + target_section_table *table = get_section_table (); if (object == TARGET_OBJECT_MEMORY) return section_table_xfer_memory_partial (readbuf, writebuf, offset, len, xfered_len, - table->sections, - table->sections_end, - NULL); + *table); else return TARGET_XFER_E_IO; } void -print_section_info (struct target_section_table *t, bfd *abfd) +print_section_info (target_section_table *t, bfd *abfd) { struct gdbarch *gdbarch = gdbarch_from_bfd (abfd); - struct target_section *p; /* FIXME: 16 is not wide enough when gdbarch_addr_bit > 64. */ int wid = gdbarch_addr_bit (gdbarch) <= 32 ? 8 : 16; - printf_filtered ("\t`%s', ", bfd_get_filename (abfd)); + printf_filtered ("\t`%ps', ", + styled_string (file_name_style.style (), + bfd_get_filename (abfd))); wrap_here (" "); printf_filtered (_("file type %s.\n"), bfd_get_target (abfd)); if (abfd == exec_bfd) @@ -917,27 +954,29 @@ print_section_info (struct target_section_table *t, bfd *abfd)

sections_end>. */ bfd_vma displacement = 0; bfd_vma entry_point; + bool found = false; - for (p = t->sections; p < t->sections_end; p++) + for (const target_section &p : *t) { - struct bfd_section *psect = p->the_bfd_section; - bfd *pbfd = psect->owner; + struct bfd_section *psect = p.the_bfd_section; - if ((bfd_get_section_flags (pbfd, psect) & (SEC_ALLOC | SEC_LOAD)) + if ((bfd_section_flags (psect) & (SEC_ALLOC | SEC_LOAD)) != (SEC_ALLOC | SEC_LOAD)) continue; - if (bfd_get_section_vma (pbfd, psect) <= abfd->start_address - && abfd->start_address < (bfd_get_section_vma (pbfd, psect) - + bfd_get_section_size (psect))) + if (bfd_section_vma (psect) <= abfd->start_address + && abfd->start_address < (bfd_section_vma (psect) + + bfd_section_size (psect))) { - displacement = p->addr - bfd_get_section_vma (pbfd, psect); + displacement = p.addr - bfd_section_vma (psect); + found = true; break; } } - if (p == t->sections_end) - warning (_("Cannot find section for the entry point of %s."), - bfd_get_filename (abfd)); + if (!found) + warning (_("Cannot find section for the entry point of %ps."), + styled_string (file_name_style.style (), + bfd_get_filename (abfd))); entry_point = gdbarch_addr_bits_remove (gdbarch, bfd_get_start_address (abfd) @@ -945,13 +984,13 @@ print_section_info (struct target_section_table *t, bfd *abfd) printf_filtered (_("\tEntry point: %s\n"), paddress (gdbarch, entry_point)); } - for (p = t->sections; p < t->sections_end; p++) + for (const target_section &p : *t) { - struct bfd_section *psect = p->the_bfd_section; + struct bfd_section *psect = p.the_bfd_section; bfd *pbfd = psect->owner; - printf_filtered ("\t%s", hex_string_custom (p->addr, wid)); - printf_filtered (" - %s", hex_string_custom (p->endaddr, wid)); + printf_filtered ("\t%s", hex_string_custom (p.addr, wid)); + printf_filtered (" - %s", hex_string_custom (p.endaddr, wid)); /* FIXME: A format of "08l" is not wide enough for file offsets larger than 4GB. OTOH, making it "016l" isn't desirable either @@ -962,15 +1001,17 @@ print_section_info (struct target_section_table *t, bfd *abfd) if (info_verbose) printf_filtered (" @ %s", hex_string_custom (psect->filepos, 8)); - printf_filtered (" is %s", bfd_section_name (pbfd, psect)); + printf_filtered (" is %s", bfd_section_name (psect)); if (pbfd != abfd) - printf_filtered (" in %s", bfd_get_filename (pbfd)); + printf_filtered (" in %ps", + styled_string (file_name_style.style (), + bfd_get_filename (pbfd))); printf_filtered ("\n"); } } -static void -exec_files_info (struct target_ops *t) +void +exec_target::files_info () { if (exec_bfd) print_section_info (current_target_sections, exec_bfd); @@ -979,15 +1020,13 @@ exec_files_info (struct target_ops *t) } static void -set_section_command (char *args, int from_tty) +set_section_command (const char *args, int from_tty) { - struct target_section *p; - char *secname; + const char *secname; unsigned seclen; unsigned long secaddr; char secprint[100]; long offset; - struct target_section_table *table; if (args == 0) error (_("Must specify section name and its virtual address")); @@ -999,18 +1038,16 @@ set_section_command (char *args, int from_tty) /* Parse out new virtual address. */ secaddr = parse_and_eval_address (args); - table = current_target_sections; - for (p = table->sections; p < table->sections_end; p++) + for (target_section &p : *current_target_sections) { - if (!strncmp (secname, bfd_section_name (p->bfd, - p->the_bfd_section), seclen) - && bfd_section_name (p->bfd, p->the_bfd_section)[seclen] == '\0') + if (!strncmp (secname, bfd_section_name (p.the_bfd_section), seclen) + && bfd_section_name (p.the_bfd_section)[seclen] == '\0') { - offset = secaddr - p->addr; - p->addr += offset; - p->endaddr += offset; + offset = secaddr - p.addr; + p.addr += offset; + p.endaddr += offset; if (from_tty) - exec_files_info (&exec_ops); + exec_ops.files_info (); return; } } @@ -1027,88 +1064,44 @@ set_section_command (char *args, int from_tty) void exec_set_section_address (const char *filename, int index, CORE_ADDR address) { - struct target_section *p; - struct target_section_table *table; - - table = current_target_sections; - for (p = table->sections; p < table->sections_end; p++) + for (target_section &p : *current_target_sections) { - if (filename_cmp (filename, p->the_bfd_section->owner->filename) == 0 - && index == p->the_bfd_section->index) + if (filename_cmp (filename, + bfd_get_filename (p.the_bfd_section->owner)) == 0 + && index == p.the_bfd_section->index) { - p->endaddr += address - p->addr; - p->addr = address; + p.endaddr += address - p.addr; + p.addr = address; } } } -/* If mourn is being called in all the right places, this could be say - `gdb internal error' (since generic_mourn calls - breakpoint_init_inferior). */ - -static int -ignore (struct target_ops *ops, struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) -{ - return 0; -} - -/* Implement the to_remove_breakpoint method. */ - -static int -exec_remove_breakpoint (struct target_ops *ops, struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt, - enum remove_bp_reason reason) -{ - return 0; -} - -static int -exec_has_memory (struct target_ops *ops) +bool +exec_target::has_memory () { /* We can provide memory if we have any file/target sections to read from. */ - return (current_target_sections->sections - != current_target_sections->sections_end); + return !current_target_sections->empty (); } -static char * -exec_make_note_section (struct target_ops *self, bfd *obfd, int *note_size) +gdb::unique_xmalloc_ptr +exec_target::make_corefile_notes (bfd *obfd, int *note_size) { error (_("Can't create a corefile")); } -/* Fill in the exec file target vector. Very few entries need to be - defined. */ - -static void -init_exec_ops (void) +int +exec_target::find_memory_regions (find_memory_region_ftype func, void *data) { - exec_ops.to_shortname = "exec"; - exec_ops.to_longname = "Local exec file"; - exec_ops.to_doc = "Use an executable file as a target.\n\ -Specify the filename of the executable file."; - exec_ops.to_open = exec_open; - exec_ops.to_close = exec_close_1; - exec_ops.to_xfer_partial = exec_xfer_partial; - exec_ops.to_get_section_table = exec_get_section_table; - exec_ops.to_files_info = exec_files_info; - exec_ops.to_insert_breakpoint = ignore; - exec_ops.to_remove_breakpoint = exec_remove_breakpoint; - exec_ops.to_stratum = file_stratum; - exec_ops.to_has_memory = exec_has_memory; - exec_ops.to_make_corefile_notes = exec_make_note_section; - exec_ops.to_find_memory_regions = objfile_find_memory_regions; - exec_ops.to_magic = OPS_MAGIC; + return objfile_find_memory_regions (this, func, data); } +void _initialize_exec (); void -_initialize_exec (void) +_initialize_exec () { struct cmd_list_element *c; - init_exec_ops (); - if (!dbx_commands) { c = add_cmd ("file", class_files, file_command, _("\ @@ -1142,5 +1135,27 @@ Show writing into executable and core files."), NULL, show_write_files, &setlist, &showlist); - add_target_with_completer (&exec_ops, filename_completer); + add_setshow_enum_cmd ("exec-file-mismatch", class_support, + exec_file_mismatch_names, + &exec_file_mismatch, + _("\ +Set exec-file-mismatch handling (ask|warn|off)."), + _("\ +Show exec-file-mismatch handling (ask|warn|off)."), + _("\ +Specifies how to handle a mismatch between the current exec-file\n\ +loaded by GDB and the exec-file automatically determined when attaching\n\ +to a process:\n\n\ + ask - warn the user and ask whether to load the determined exec-file.\n\ + warn - warn the user, but do not change the exec-file.\n\ + off - do not check for mismatch.\n\ +\n\ +GDB detects a mismatch by comparing the build IDs of the files.\n\ +If the user confirms loading the determined exec-file, then its symbols\n\ +will be loaded as well."), + set_exec_file_mismatch_command, + show_exec_file_mismatch_command, + &setlist, &showlist); + + add_target (exec_target_info, exec_target_open, filename_completer); }