X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fexec.c;h=efc504eca47fd9a7128940087a2f1c204577e6fd;hb=268e4f09144c48e02f01d82ab3aab359457df214;hp=9b95e028ea4216ad688391480465cd9fc58b6d95;hpb=64c311498e46cef6b70aa88577e7d7c382e0f7cc;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/exec.c b/gdb/exec.c index 9b95e028ea..efc504eca4 100644 --- a/gdb/exec.c +++ b/gdb/exec.c @@ -1,6 +1,6 @@ /* Work with executable files, for GDB. - Copyright (C) 1988-2003, 2007-2012 Free Software Foundation, Inc. + Copyright (C) 1988-2019 Free Software Foundation, Inc. This file is part of GDB. @@ -29,49 +29,62 @@ #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 "gdb_bfd.h" +#include "gcore.h" +#include "source.h" #include -#include "readline/readline.h" -#include "gdb_string.h" - +#include "readline/tilde.h" #include "gdbcore.h" #include -#include "gdb_stat.h" - -#include "xcoffsolib.h" - -struct vmap *map_vmap (bfd *, bfd *); +#include +#include "solist.h" +#include +#include "gdbsupport/pathstuff.h" -void (*deprecated_file_changed_hook) (char *); +void (*deprecated_file_changed_hook) (const char *); -/* Prototypes for local functions */ +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.") +}; -static void file_command (char *, int); - -static void set_section_command (char *, int); - -static void exec_files_info (struct target_ops *); +/* The target vector for executable files. */ -static void init_exec_ops (void); +struct exec_target final : public target_ops +{ + const target_info &info () const override + { return exec_target_info; } -void _initialize_exec (void); + strata stratum () const override { return file_stratum; } -/* The target vector for executable files. */ + 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; + struct target_section_table *get_section_table () override; + void files_info () override; -struct target_ops exec_ops; + bool has_memory () override; + char *make_corefile_notes (bfd *, int *) override; + int find_memory_regions (find_memory_region_ftype func, void *data) override; +}; -/* True if the exec target is pushed on the stack. */ -static int using_exec_ops; +static exec_target exec_ops; /* 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) @@ -81,10 +94,8 @@ show_write_files (struct ui_file *file, int from_tty, } -struct vmap *vmap; - static void -exec_open (char *args, int from_tty) +exec_target_open (const char *args, int from_tty) { target_preopen (from_tty); exec_file_attach (args, from_tty); @@ -107,71 +118,111 @@ exec_close (void) exec_bfd = NULL; exec_bfd_mtime = 0; - remove_target_sections (abfd); + remove_target_sections (&exec_bfd); + + xfree (exec_filename); + exec_filename = NULL; } } /* This is the target_close implementation. Clears all target sections and closes all executable bfds from all program spaces. */ -static void -exec_close_1 (int quitting) +void +exec_target::close () { - int need_symtab_cleanup = 0; - struct vmap *vp, *nxt; - - using_exec_ops = 0; + struct program_space *ss; + scoped_restore_current_program_space restore_pspace; - for (nxt = vmap; nxt != NULL;) + ALL_PSPACES (ss) { - vp = nxt; - nxt = vp->nxt; - - /* if there is an objfile associated with this bfd, - free_objfile() will do proper cleanup of objfile *and* bfd. */ + set_current_program_space (ss); + clear_section_table (current_target_sections); + exec_close (); + } +} - if (vp->objfile) - { - free_objfile (vp->objfile); - need_symtab_cleanup = 1; - } - else if (vp->bfd != exec_bfd) - gdb_bfd_unref (vp->bfd); +/* See gdbcore.h. */ - xfree (vp); - } +void +try_open_exec_file (const char *exec_file_host, struct inferior *inf, + symfile_add_flags add_flags) +{ + struct gdb_exception prev_err; - vmap = NULL; + /* exec_file_attach and symbol_file_add_main may throw an error if the file + cannot be opened either locally or remotely. - { - struct program_space *ss; - struct cleanup *old_chain; + This happens for example, when the file is first found in the local + sysroot (above), and then disappears (a TOCTOU race), or when it doesn't + exist in the target filesystem, or when the file does exist, but + is not readable. - old_chain = save_current_program_space (); - ALL_PSPACES (ss) + 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 { - set_current_program_space (ss); - - /* Delete all target sections. */ - resize_section_table - (current_target_sections, - -resize_section_table (current_target_sections, 0)); + /* 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 (gdb_exception_error &err) + { + if (err.message != NULL) + warning ("%s", err.what ()); - exec_close (); + prev_err = std::move (err); } - do_cleanups (old_chain); - } + if (exec_file_host != NULL) + { + try + { + symbol_file_add_main (exec_file_host, add_flags); + } + catch (const gdb_exception_error &err) + { + if (!exception_print_same (prev_err, err)) + warning ("%s", err.what ()); + } + } } +/* See gdbcore.h. */ + void -exec_file_clear (int from_tty) +exec_file_locate_attach (int pid, int defer_bp_reset, int from_tty) { - /* Remove exec file. */ - exec_close (); + char *exec_file_target; + symfile_add_flags add_flags = 0; + + /* Do nothing if we already have an executable filename. */ + if (get_exec_file (0) != NULL) + return; + + /* Try to determine a filename from the process itself. */ + exec_file_target = target_pid_to_exec_file (pid); + if (exec_file_target == NULL) + { + warning (_("No executable has been specified and target does not " + "support\n" + "determining executable automatically. " + "Try using the \"file\" command.")); + return; + } + + gdb::unique_xmalloc_ptr exec_file_host + = exec_file_find (exec_file_target, NULL); + + if (defer_bp_reset) + add_flags |= SYMFILE_DEFER_BP_RESET; if (from_tty) - printf_unfiltered (_("No executable file now.\n")); + add_flags |= SYMFILE_VERBOSE; + + /* Attempt to open the exec file. */ + try_open_exec_file (exec_file_host.get (), current_inferior (), add_flags); } /* Set FILENAME as the new exec file. @@ -192,8 +243,13 @@ exec_file_clear (int from_tty) we're supplying the exec pathname late for good reason.) */ void -exec_file_attach (char *filename, int from_tty) +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_ptr exec_bfd_holder = gdb_bfd_ref_ptr::new_reference (exec_bfd); + /* Remove any previous exec file. */ exec_close (); @@ -208,41 +264,85 @@ exec_file_attach (char *filename, int from_tty) } else { - struct cleanup *cleanups; - char *scratch_pathname; + int load_via_target = 0; + const char *scratch_pathname, *canonical_pathname; int scratch_chan; struct target_section *sections = NULL, *sections_end = NULL; char **matching; - scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, filename, - write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, - &scratch_pathname); -#if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__) - if (scratch_chan < 0) + if (is_target_filename (filename)) { - char *exename = alloca (strlen (filename) + 5); + if (target_filesystem_is_local ()) + filename += strlen (TARGET_SYSROOT_PREFIX); + else + load_via_target = 1; + } - strcat (strcpy (exename, filename), ".exe"); - scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, exename, - write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, - &scratch_pathname); + gdb::unique_xmalloc_ptr canonical_storage, scratch_storage; + if (load_via_target) + { + /* gdb_bfd_fopen does not support "target:" filenames. */ + if (write_files) + warning (_("writing into executable files is " + "not supported for %s sysroots"), + TARGET_SYSROOT_PREFIX); + + scratch_pathname = filename; + scratch_chan = -1; + canonical_pathname = scratch_pathname; } + else + { + scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, + filename, write_files ? + O_RDWR | O_BINARY : O_RDONLY | O_BINARY, + &scratch_storage); +#if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__) + if (scratch_chan < 0) + { + char *exename = (char *) alloca (strlen (filename) + 5); + + strcat (strcpy (exename, filename), ".exe"); + scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, + exename, write_files ? + O_RDWR | O_BINARY + : O_RDONLY | O_BINARY, + &scratch_storage); + } #endif + if (scratch_chan < 0) + perror_with_name (filename); - cleanups = make_cleanup (xfree, scratch_pathname); + scratch_pathname = scratch_storage.get (); + + /* gdb_bfd_open (and its variants) prefers canonicalized + pathname for better BFD caching. */ + canonical_storage = gdb_realpath (scratch_pathname); + canonical_pathname = canonical_storage.get (); + } - if (scratch_chan < 0) - perror_with_name (filename); - exec_bfd = gdb_bfd_fopen (scratch_pathname, gnutarget, - write_files ? FOPEN_RUB : FOPEN_RB, - scratch_chan); + gdb_bfd_ref_ptr temp; + if (write_files && !load_via_target) + temp = gdb_bfd_fopen (canonical_pathname, gnutarget, + FOPEN_RUB, scratch_chan); + else + temp = gdb_bfd_open (canonical_pathname, gnutarget, scratch_chan); + exec_bfd = temp.release (); if (!exec_bfd) { - error (_("\"%s\": could not open as an executable file: %s"), + error (_("\"%s\": could not open as an executable file: %s."), 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); + if (load_via_target) + exec_filename = xstrdup (bfd_get_filename (exec_bfd)); + else + exec_filename = gdb_realpath_keepfile (scratch_pathname).release (); + if (!bfd_check_format_matches (exec_bfd, bfd_object, &matching)) { /* Make sure to close exec_bfd, or else "run" might try to use @@ -250,25 +350,9 @@ exec_file_attach (char *filename, int from_tty) exec_close (); error (_("\"%s\": not in executable format: %s"), scratch_pathname, - gdb_bfd_errmsg (bfd_get_error (), matching)); + gdb_bfd_errmsg (bfd_get_error (), matching).c_str ()); } - /* FIXME - This should only be run for RS6000, but the ifdef is a poor - way to accomplish. */ -#ifdef DEPRECATED_IBM6000_TARGET - /* Setup initial vmap. */ - - map_vmap (exec_bfd, 0); - if (vmap == NULL) - { - /* 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 ())); - } -#endif /* DEPRECATED_IBM6000_TARGET */ - if (build_section_table (exec_bfd, §ions, §ions_end)) { /* Make sure to close exec_bfd, or else "run" might try to use @@ -287,17 +371,16 @@ exec_file_attach (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 (sections, sections_end); + add_target_sections (&exec_bfd, sections, sections_end); xfree (sections); /* Tell display code (if any) about the changed file name. */ if (deprecated_exec_file_display_hook) (*deprecated_exec_file_display_hook) (filename); - - do_cleanups (cleanups); } + bfd_cache_close_all (); - observer_notify_executable_changed (); + gdb::observers::executable_changed.notify (); } /* Process the first arg in ARGS as the new exec file. @@ -309,11 +392,8 @@ exec_file_attach (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 **argv; - char *filename; - if (from_tty && target_has_execution && !query (_("A program is being debugged already.\n" "Are you sure you want to change the file? "))) @@ -321,13 +401,11 @@ exec_file_command (char *args, int from_tty) if (args) { - struct cleanup *cleanups; - /* Scan through the args and pick up the first non option arg as the filename. */ - argv = gdb_buildargv (args); - cleanups = make_cleanup_freeargv (argv); + gdb_argv built_argv (args); + char **argv = built_argv.get (); for (; (*argv != NULL) && (**argv == '-'); argv++) {; @@ -335,11 +413,8 @@ exec_file_command (char *args, int from_tty) if (*argv == NULL) error (_("No executable file name was specified")); - filename = tilde_expand (*argv); - make_cleanup (xfree, filename); - exec_file_attach (filename, from_tty); - - do_cleanups (cleanups); + gdb::unique_xmalloc_ptr filename (tilde_expand (*argv)); + exec_file_attach (filename.get (), from_tty); } else exec_file_attach (NULL, from_tty); @@ -350,7 +425,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. */ @@ -372,45 +447,56 @@ add_to_section_table (bfd *abfd, struct bfd_section *asect, 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); + aflag = bfd_section_flags (asect); if (!(aflag & SEC_ALLOC)) return; - (*table_pp)->bfd = abfd; + (*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)->addr = bfd_section_vma (asect); + (*table_pp)->endaddr = (*table_pp)->addr + bfd_section_size (asect); (*table_pp)++; } -int -resize_section_table (struct target_section_table *table, int num_added) +/* 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) { - struct target_section *old_value; int old_count; int new_count; - old_value = table->sections; old_count = table->sections_end - table->sections; - new_count = num_added + old_count; + new_count = adjustment + old_count; if (new_count) { - table->sections = xrealloc (table->sections, - sizeof (struct target_section) * new_count); + table->sections = XRESIZEVEC (struct target_section, table->sections, + new_count); table->sections_end = table->sections + new_count; } else - { - xfree (table->sections); - table->sections = table->sections_end = NULL; - } + clear_section_table (table); return old_count; } @@ -427,7 +513,7 @@ build_section_table (struct bfd *some_bfd, struct target_section **start, count = bfd_count_sections (some_bfd); if (*start) xfree (* start); - *start = (struct target_section *) xmalloc (count * sizeof (**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) @@ -441,7 +527,8 @@ build_section_table (struct bfd *some_bfd, struct target_section **start, current set of target sections. */ void -add_target_sections (struct target_section *sections, +add_target_sections (void *owner, + struct target_section *sections, struct target_section *sections_end) { int count; @@ -452,31 +539,80 @@ add_target_sections (struct target_section *sections, if (count > 0) { int space = resize_section_table (table, count); + int i; - memcpy (table->sections + space, - sections, count * sizeof (sections[0])); + for (i = 0; i < count; ++i) + { + table->sections[space + i] = sections[i]; + table->sections[space + i].owner = owner; + } /* If these are the first file sections we can provide memory from, push the file_stratum target. */ - if (!using_exec_ops) - { - using_exec_ops = 1; - push_target (&exec_ops); - } + if (!target_is_pushed (&exec_ops)) + push_target (&exec_ops); + } +} + +/* Add the sections of OBJFILE to the current set of target sections. */ + +void +add_target_sections_of_objfile (struct objfile *objfile) +{ + struct target_section_table *table = current_target_sections; + struct obj_section *osect; + int space; + unsigned count = 0; + struct target_section *ts; + + if (objfile == NULL) + return; + + /* Compute the number of sections to add. */ + ALL_OBJFILE_OSECTIONS (objfile, osect) + { + 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_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++; } } -/* Remove all target sections taken from ABFD. */ +/* Remove all target sections owned by OWNER. + OWNER must be the same value passed to add_target_sections. */ void -remove_target_sections (bfd *abfd) +remove_target_sections (void *owner) { struct target_section *src, *dest; struct 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->bfd != abfd) + if (src->owner != owner) { /* Keep this section. */ if (dest < src) @@ -508,81 +644,74 @@ remove_target_sections (bfd *abfd) } -static void -bfdsec_to_vmap (struct bfd *abfd, struct bfd_section *sect, void *arg3) + +enum target_xfer_status +exec_read_partial_read_only (gdb_byte *readbuf, ULONGEST offset, + ULONGEST len, ULONGEST *xfered_len) { - struct vmap_and_bfd *vmap_bfd = (struct vmap_and_bfd *) arg3; - struct vmap *vp; + /* It's unduly pedantic to refuse to look at the executable for + read-only pieces; so do the equivalent of readonly regions aka + QTro packet. */ + if (exec_bfd != NULL) + { + asection *s; + bfd_size_type size; + bfd_vma vma; - vp = vmap_bfd->pvmap; + for (s = exec_bfd->sections; s; s = s->next) + { + if ((s->flags & SEC_LOAD) == 0 + || (s->flags & SEC_READONLY) == 0) + continue; - if ((bfd_get_section_flags (abfd, sect) & SEC_LOAD) == 0) - return; + vma = s->vma; + size = bfd_section_size (s); + if (vma <= offset && offset < (vma + size)) + { + ULONGEST amt; - if (strcmp (bfd_section_name (abfd, sect), ".text") == 0) - { - vp->tstart = bfd_section_vma (abfd, sect); - vp->tend = vp->tstart + bfd_section_size (abfd, sect); - vp->tvma = bfd_section_vma (abfd, sect); - vp->toffs = sect->filepos; - } - else if (strcmp (bfd_section_name (abfd, sect), ".data") == 0) - { - vp->dstart = bfd_section_vma (abfd, sect); - vp->dend = vp->dstart + bfd_section_size (abfd, sect); - vp->dvma = bfd_section_vma (abfd, sect); - } - /* Silently ignore other types of sections. (FIXME?) */ -} + amt = (vma + size) - offset; + if (amt > len) + amt = len; -/* Make a vmap for ABFD which might be a member of the archive ARCH. - Return the new vmap. */ + amt = bfd_get_section_contents (exec_bfd, s, + readbuf, offset - vma, amt); -struct vmap * -map_vmap (bfd *abfd, bfd *arch) -{ - struct vmap_and_bfd vmap_bfd; - struct vmap *vp, **vpp; - - vp = (struct vmap *) xmalloc (sizeof (*vp)); - memset ((char *) vp, '\0', sizeof (*vp)); - vp->nxt = 0; - vp->bfd = abfd; - vp->name = bfd_get_filename (arch ? arch : abfd); - vp->member = arch ? bfd_get_filename (abfd) : ""; - - vmap_bfd.pbfd = arch; - vmap_bfd.pvmap = vp; - bfd_map_over_sections (abfd, bfdsec_to_vmap, &vmap_bfd); - - /* Find the end of the list and append. */ - for (vpp = &vmap; *vpp; vpp = &(*vpp)->nxt) - ; - *vpp = vp; - - return vp; + if (amt == 0) + return TARGET_XFER_EOF; + else + { + *xfered_len = amt; + return TARGET_XFER_OK; + } + } + } + } + + /* Indicate failure to find the requested memory block. */ + return TARGET_XFER_E_IO; } - -VEC(mem_range_s) * -section_table_available_memory (VEC(mem_range_s) *memory, - CORE_ADDR memaddr, ULONGEST len, +/* 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. */ + +static std::vector +section_table_available_memory (CORE_ADDR memaddr, ULONGEST len, struct target_section *sections, struct target_section *sections_end) { - struct target_section *p; + std::vector memory; - for (p = sections; p < sections_end; p++) + for (target_section *p = sections; p < sections_end; p++) { - if ((bfd_get_section_flags (p->bfd, 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)) { ULONGEST lo1, hi1, lo2, hi2; - struct mem_range *r; lo1 = memaddr; hi1 = memaddr + len; @@ -590,19 +719,60 @@ section_table_available_memory (VEC(mem_range_s) *memory, 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 = max (lo1, lo2); - r->length = min (hi1, hi2) - r->start; + memory.emplace_back (start, length); } } return memory; } -int +enum target_xfer_status +section_table_read_available_memory (gdb_byte *readbuf, ULONGEST offset, + ULONGEST len, ULONGEST *xfered_len) +{ + target_section_table *table = target_get_section_table (&exec_ops); + std::vector available_memory + = section_table_available_memory (offset, len, + table->sections, table->sections_end); + + normalize_mem_ranges (&available_memory); + + for (const mem_range &r : available_memory) + { + 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); + + gdb_assert (end - offset <= len); + + if (offset >= r.start) + status = exec_read_partial_read_only (readbuf, offset, + end - offset, + xfered_len); + else + { + *xfered_len = r.start - offset; + status = TARGET_XFER_UNAVAILABLE; + } + return status; + } + } + + *xfered_len = len; + return TARGET_XFER_UNAVAILABLE; +} + +enum target_xfer_status section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len, + ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len, struct target_section *sections, struct target_section *sections_end, const char *section_name) @@ -612,13 +782,16 @@ section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST memaddr = offset; ULONGEST memend = memaddr + len; - if (len <= 0) + if (len == 0) internal_error (__FILE__, __LINE__, _("failed internal consistency check")); for (p = sections; p < sections_end; p++) { - if (section_name && strcmp (section_name, p->the_bfd_section->name) != 0) + struct bfd_section *asect = p->the_bfd_section; + bfd *abfd = asect->owner; + + if (section_name && strcmp (section_name, asect->name) != 0) continue; /* not the section we need. */ if (memaddr >= p->addr) { @@ -626,14 +799,21 @@ section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf, { /* Entire transfer is within this section. */ if (writebuf) - res = bfd_set_section_contents (p->bfd, p->the_bfd_section, + res = bfd_set_section_contents (abfd, asect, writebuf, memaddr - p->addr, len); else - res = bfd_get_section_contents (p->bfd, p->the_bfd_section, + res = bfd_get_section_contents (abfd, asect, readbuf, memaddr - p->addr, len); - return (res != 0) ? len : 0; + + if (res != 0) + { + *xfered_len = len; + return TARGET_XFER_OK; + } + else + return TARGET_XFER_EOF; } else if (memaddr >= p->endaddr) { @@ -645,43 +825,49 @@ section_table_xfer_memory_partial (gdb_byte *readbuf, const gdb_byte *writebuf, /* This section overlaps the transfer. Just do half. */ len = p->endaddr - memaddr; if (writebuf) - res = bfd_set_section_contents (p->bfd, p->the_bfd_section, + res = bfd_set_section_contents (abfd, asect, writebuf, memaddr - p->addr, len); else - res = bfd_get_section_contents (p->bfd, p->the_bfd_section, + res = bfd_get_section_contents (abfd, asect, readbuf, memaddr - p->addr, len); - return (res != 0) ? len : 0; + if (res != 0) + { + *xfered_len = len; + return TARGET_XFER_OK; + } + else + return TARGET_XFER_EOF; } } } - return 0; /* We can't help. */ + return TARGET_XFER_EOF; /* We can't help. */ } -static struct target_section_table * -exec_get_section_table (struct target_ops *ops) +struct target_section_table * +exec_target::get_section_table () { return current_target_sections; } -static LONGEST -exec_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, LONGEST 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); + struct target_section_table *table = get_section_table (); if (object == TARGET_OBJECT_MEMORY) return section_table_xfer_memory_partial (readbuf, writebuf, - offset, len, + offset, len, xfered_len, table->sections, table->sections_end, NULL); else - return -1; + return TARGET_XFER_E_IO; } @@ -705,17 +891,17 @@ print_section_info (struct target_section_table *t, bfd *abfd) for (p = t->sections; p < t->sections_end; p++) { - asection *asect = p->the_bfd_section; + struct bfd_section *psect = p->the_bfd_section; - if ((bfd_get_section_flags (abfd, asect) & (SEC_ALLOC | SEC_LOAD)) + if ((bfd_section_flags (psect) & (SEC_ALLOC | SEC_LOAD)) != (SEC_ALLOC | SEC_LOAD)) continue; - if (bfd_get_section_vma (abfd, asect) <= abfd->start_address - && abfd->start_address < (bfd_get_section_vma (abfd, asect) - + bfd_get_section_size (asect))) + 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 (abfd, asect); + displacement = p->addr - bfd_section_vma (psect); break; } } @@ -731,6 +917,9 @@ print_section_info (struct target_section_table *t, bfd *abfd) } for (p = t->sections; p < t->sections_end; p++) { + 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)); @@ -742,54 +931,28 @@ print_section_info (struct target_section_table *t, bfd *abfd) /* FIXME: i18n: Need to rewrite this sentence. */ if (info_verbose) printf_filtered (" @ %s", - hex_string_custom (p->the_bfd_section->filepos, 8)); - printf_filtered (" is %s", bfd_section_name (p->bfd, - p->the_bfd_section)); - if (p->bfd != abfd) - printf_filtered (" in %s", bfd_get_filename (p->bfd)); + hex_string_custom (psect->filepos, 8)); + printf_filtered (" is %s", bfd_section_name (psect)); + if (pbfd != abfd) + printf_filtered (" in %s", 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); else puts_filtered (_("\t\n")); - - if (vmap) - { - int addr_size = gdbarch_addr_bit (target_gdbarch) / 8; - struct vmap *vp; - - printf_unfiltered (_("\tMapping info for file `%s'.\n"), vmap->name); - printf_unfiltered ("\t %*s %*s %*s %*s %8.8s %s\n", - addr_size * 2, "tstart", - addr_size * 2, "tend", - addr_size * 2, "dstart", - addr_size * 2, "dend", - "section", - "file(member)"); - - for (vp = vmap; vp; vp = vp->nxt) - printf_unfiltered ("\t0x%s 0x%s 0x%s 0x%s %s%s%s%s\n", - phex (vp->tstart, addr_size), - phex (vp->tend, addr_size), - phex (vp->dstart, addr_size), - phex (vp->dend, addr_size), - vp->name, - *vp->member ? "(" : "", vp->member, - *vp->member ? ")" : ""); - } } 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]; @@ -809,15 +972,14 @@ set_section_command (char *args, int from_tty) table = current_target_sections; for (p = table->sections; p < table->sections_end; p++) { - 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; if (from_tty) - exec_files_info (&exec_ops); + exec_ops.files_info (); return; } } @@ -840,7 +1002,7 @@ exec_set_section_address (const char *filename, int index, CORE_ADDR address) table = current_target_sections; for (p = table->sections; p < table->sections_end; p++) { - if (filename_cmp (filename, p->bfd->filename) == 0 + if (filename_cmp (filename, p->the_bfd_section->owner->filename) == 0 && index == p->the_bfd_section->index) { p->endaddr += address - p->addr; @@ -849,18 +1011,8 @@ exec_set_section_address (const char *filename, int index, CORE_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 gdbarch *gdbarch, struct bp_target_info *bp_tgt) -{ - 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. */ @@ -868,39 +1020,16 @@ exec_has_memory (struct target_ops *ops) != current_target_sections->sections_end); } -/* Find mapped memory. */ - -extern void -exec_set_find_memory_regions (int (*func) (find_memory_region_ftype, void *)) +char * +exec_target::make_corefile_notes (bfd *obfd, int *note_size) { - exec_ops.to_find_memory_regions = func; + error (_("Can't create a corefile")); } -static char *exec_make_note_section (bfd *, int *); - -/* 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_attach = find_default_attach; - 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 = ignore; - exec_ops.to_create_inferior = find_default_create_inferior; - 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_magic = OPS_MAGIC; + return objfile_find_memory_regions (this, func, data); } void @@ -908,8 +1037,6 @@ _initialize_exec (void) { struct cmd_list_element *c; - init_exec_ops (); - if (!dbx_commands) { c = add_cmd ("file", class_files, file_command, _("\ @@ -943,11 +1070,5 @@ Show writing into executable and core files."), NULL, show_write_files, &setlist, &showlist); - add_target (&exec_ops); -} - -static char * -exec_make_note_section (bfd *obfd, int *note_size) -{ - error (_("Can't create a corefile")); + add_target (exec_target_info, exec_target_open, filename_completer); }