|  | /* Work with executable files, for GDB. | 
|  |  | 
|  | Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, | 
|  | 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, | 
|  | Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 2 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program; if not, write to the Free Software | 
|  | Foundation, Inc., 51 Franklin Street, Fifth Floor, | 
|  | Boston, MA 02110-1301, USA.  */ | 
|  |  | 
|  | #include "defs.h" | 
|  | #include "frame.h" | 
|  | #include "inferior.h" | 
|  | #include "target.h" | 
|  | #include "gdbcmd.h" | 
|  | #include "language.h" | 
|  | #include "symfile.h" | 
|  | #include "objfiles.h" | 
|  | #include "completer.h" | 
|  | #include "value.h" | 
|  | #include "exec.h" | 
|  | #include "observer.h" | 
|  |  | 
|  | #include <fcntl.h> | 
|  | #include "readline/readline.h" | 
|  | #include "gdb_string.h" | 
|  |  | 
|  | #include "gdbcore.h" | 
|  |  | 
|  | #include <ctype.h> | 
|  | #include "gdb_stat.h" | 
|  |  | 
|  | #include "xcoffsolib.h" | 
|  |  | 
|  | struct vmap *map_vmap (bfd *, bfd *); | 
|  |  | 
|  | void (*deprecated_file_changed_hook) (char *); | 
|  |  | 
|  | /* Prototypes for local functions */ | 
|  |  | 
|  | static void exec_close (int); | 
|  |  | 
|  | 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); | 
|  |  | 
|  | /* The target vector for executable files.  */ | 
|  |  | 
|  | struct target_ops exec_ops; | 
|  |  | 
|  | /* The Binary File Descriptor handle for the executable file.  */ | 
|  |  | 
|  | bfd *exec_bfd = NULL; | 
|  |  | 
|  | /* Whether to open exec and core files read-only or read-write.  */ | 
|  |  | 
|  | int write_files = 0; | 
|  | static void | 
|  | show_write_files (struct ui_file *file, int from_tty, | 
|  | struct cmd_list_element *c, const char *value) | 
|  | { | 
|  | fprintf_filtered (file, _("Writing into executable and core files is %s.\n"), | 
|  | value); | 
|  | } | 
|  |  | 
|  |  | 
|  | struct vmap *vmap; | 
|  |  | 
|  | static void | 
|  | exec_open (char *args, int from_tty) | 
|  | { | 
|  | target_preopen (from_tty); | 
|  | exec_file_attach (args, from_tty); | 
|  | } | 
|  |  | 
|  | static void | 
|  | exec_close (int quitting) | 
|  | { | 
|  | int need_symtab_cleanup = 0; | 
|  | struct vmap *vp, *nxt; | 
|  |  | 
|  | for (nxt = vmap; nxt != NULL;) | 
|  | { | 
|  | vp = nxt; | 
|  | nxt = vp->nxt; | 
|  |  | 
|  | /* if there is an objfile associated with this bfd, | 
|  | free_objfile() will do proper cleanup of objfile *and* bfd. */ | 
|  |  | 
|  | if (vp->objfile) | 
|  | { | 
|  | free_objfile (vp->objfile); | 
|  | need_symtab_cleanup = 1; | 
|  | } | 
|  | else if (vp->bfd != exec_bfd) | 
|  | /* FIXME-leak: We should be freeing vp->name too, I think.  */ | 
|  | if (!bfd_close (vp->bfd)) | 
|  | warning (_("cannot close \"%s\": %s"), | 
|  | vp->name, bfd_errmsg (bfd_get_error ())); | 
|  |  | 
|  | /* FIXME: This routine is #if 0'd in symfile.c.  What should we | 
|  | be doing here?  Should we just free everything in | 
|  | vp->objfile->symtabs?  Should free_objfile do that? | 
|  | FIXME-as-well: free_objfile already free'd vp->name, so it isn't | 
|  | valid here.  */ | 
|  | free_named_symtabs (vp->name); | 
|  | xfree (vp); | 
|  | } | 
|  |  | 
|  | vmap = NULL; | 
|  |  | 
|  | if (exec_bfd) | 
|  | { | 
|  | char *name = bfd_get_filename (exec_bfd); | 
|  |  | 
|  | if (!bfd_close (exec_bfd)) | 
|  | warning (_("cannot close \"%s\": %s"), | 
|  | name, bfd_errmsg (bfd_get_error ())); | 
|  | xfree (name); | 
|  | exec_bfd = NULL; | 
|  | } | 
|  |  | 
|  | if (exec_ops.to_sections) | 
|  | { | 
|  | xfree (exec_ops.to_sections); | 
|  | exec_ops.to_sections = NULL; | 
|  | exec_ops.to_sections_end = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | exec_file_clear (int from_tty) | 
|  | { | 
|  | /* Remove exec file.  */ | 
|  | unpush_target (&exec_ops); | 
|  |  | 
|  | if (from_tty) | 
|  | printf_unfiltered (_("No executable file now.\n")); | 
|  | } | 
|  |  | 
|  | /*  Process the first arg in ARGS as the new exec file. | 
|  |  | 
|  | This function is intended to be behave essentially the same | 
|  | as exec_file_command, except that the latter will detect when | 
|  | a target is being debugged, and will ask the user whether it | 
|  | should be shut down first.  (If the answer is "no", then the | 
|  | new file is ignored.) | 
|  |  | 
|  | This file is used by exec_file_command, to do the work of opening | 
|  | and processing the exec file after any prompting has happened. | 
|  |  | 
|  | And, it is used by child_attach, when the attach command was | 
|  | given a pid but not a exec pathname, and the attach command could | 
|  | figure out the pathname from the pid.  (In this case, we shouldn't | 
|  | ask the user whether the current target should be shut down -- | 
|  | we're supplying the exec pathname late for good reason.) | 
|  |  | 
|  | ARGS is assumed to be the filename. */ | 
|  |  | 
|  | void | 
|  | exec_file_attach (char *filename, int from_tty) | 
|  | { | 
|  | /* Remove any previous exec file.  */ | 
|  | unpush_target (&exec_ops); | 
|  |  | 
|  | /* Now open and digest the file the user requested, if any.  */ | 
|  |  | 
|  | if (!filename) | 
|  | { | 
|  | if (from_tty) | 
|  | printf_unfiltered (_("No executable file now.\n")); | 
|  |  | 
|  | set_gdbarch_from_file (NULL); | 
|  | } | 
|  | else | 
|  | { | 
|  | char *scratch_pathname; | 
|  | int scratch_chan; | 
|  |  | 
|  | scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, filename, | 
|  | write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, 0, | 
|  | &scratch_pathname); | 
|  | #if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__) | 
|  | if (scratch_chan < 0) | 
|  | { | 
|  | char *exename = 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, 0, | 
|  | &scratch_pathname); | 
|  | } | 
|  | #endif | 
|  | if (scratch_chan < 0) | 
|  | perror_with_name (filename); | 
|  | exec_bfd = bfd_fopen (scratch_pathname, gnutarget, | 
|  | write_files ? FOPEN_RUB : FOPEN_RB, | 
|  | scratch_chan); | 
|  |  | 
|  | if (!exec_bfd) | 
|  | error (_("\"%s\": could not open as an executable file: %s"), | 
|  | scratch_pathname, bfd_errmsg (bfd_get_error ())); | 
|  |  | 
|  | /* At this point, scratch_pathname and exec_bfd->name both point to the | 
|  | same malloc'd string.  However exec_close() will attempt to free it | 
|  | via the exec_bfd->name pointer, so we need to make another copy and | 
|  | leave exec_bfd as the new owner of the original copy. */ | 
|  | scratch_pathname = xstrdup (scratch_pathname); | 
|  | make_cleanup (xfree, scratch_pathname); | 
|  |  | 
|  | if (!bfd_check_format (exec_bfd, bfd_object)) | 
|  | { | 
|  | /* Make sure to close exec_bfd, or else "run" might try to use | 
|  | it.  */ | 
|  | exec_close (0); | 
|  | error (_("\"%s\": not in executable format: %s"), | 
|  | scratch_pathname, bfd_errmsg (bfd_get_error ())); | 
|  | } | 
|  |  | 
|  | /* 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 (0); | 
|  | 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, &exec_ops.to_sections, | 
|  | &exec_ops.to_sections_end)) | 
|  | { | 
|  | /* Make sure to close exec_bfd, or else "run" might try to use | 
|  | it.  */ | 
|  | exec_close (0); | 
|  | error (_("\"%s\": can't find the file sections: %s"), | 
|  | scratch_pathname, bfd_errmsg (bfd_get_error ())); | 
|  | } | 
|  |  | 
|  | validate_files (); | 
|  |  | 
|  | set_gdbarch_from_file (exec_bfd); | 
|  |  | 
|  | push_target (&exec_ops); | 
|  |  | 
|  | /* Tell display code (if any) about the changed file name.  */ | 
|  | if (deprecated_exec_file_display_hook) | 
|  | (*deprecated_exec_file_display_hook) (filename); | 
|  | } | 
|  | bfd_cache_close_all (); | 
|  | observer_notify_executable_changed (NULL); | 
|  | } | 
|  |  | 
|  | /*  Process the first arg in ARGS as the new exec file. | 
|  |  | 
|  | Note that we have to explicitly ignore additional args, since we can | 
|  | be called from file_command(), which also calls symbol_file_command() | 
|  | which can take multiple args. | 
|  |  | 
|  | If ARGS is NULL, we just want to close the exec file. */ | 
|  |  | 
|  | static void | 
|  | exec_file_command (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? "))) | 
|  | error (_("File not changed.")); | 
|  |  | 
|  | if (args) | 
|  | { | 
|  | /* Scan through the args and pick up the first non option arg | 
|  | as the filename.  */ | 
|  |  | 
|  | argv = buildargv (args); | 
|  | if (argv == NULL) | 
|  | nomem (0); | 
|  |  | 
|  | make_cleanup_freeargv (argv); | 
|  |  | 
|  | for (; (*argv != NULL) && (**argv == '-'); argv++) | 
|  | {; | 
|  | } | 
|  | if (*argv == NULL) | 
|  | error (_("No executable file name was specified")); | 
|  |  | 
|  | filename = tilde_expand (*argv); | 
|  | make_cleanup (xfree, filename); | 
|  | exec_file_attach (filename, from_tty); | 
|  | } | 
|  | else | 
|  | exec_file_attach (NULL, from_tty); | 
|  | } | 
|  |  | 
|  | /* Set both the exec file and the symbol file, in one command. | 
|  | What a novelty.  Why did GDB go through four major releases before this | 
|  | command was added?  */ | 
|  |  | 
|  | static void | 
|  | file_command (char *arg, int from_tty) | 
|  | { | 
|  | /* FIXME, if we lose on reading the symbol file, we should revert | 
|  | the exec file, but that's rough.  */ | 
|  | exec_file_command (arg, from_tty); | 
|  | symbol_file_command (arg, from_tty); | 
|  | if (deprecated_file_changed_hook) | 
|  | deprecated_file_changed_hook (arg); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* 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.  */ | 
|  |  | 
|  | static void | 
|  | add_to_section_table (bfd *abfd, struct bfd_section *asect, | 
|  | void *table_pp_char) | 
|  | { | 
|  | struct section_table **table_pp = (struct section_table **) table_pp_char; | 
|  | flagword aflag; | 
|  |  | 
|  | aflag = bfd_get_section_flags (abfd, asect); | 
|  | if (!(aflag & SEC_ALLOC)) | 
|  | return; | 
|  | if (0 == bfd_section_size (abfd, asect)) | 
|  | return; | 
|  | (*table_pp)->bfd = abfd; | 
|  | (*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)++; | 
|  | } | 
|  |  | 
|  | /* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR. | 
|  | Returns 0 if OK, 1 on error.  */ | 
|  |  | 
|  | int | 
|  | build_section_table (struct bfd *some_bfd, struct section_table **start, | 
|  | struct section_table **end) | 
|  | { | 
|  | unsigned count; | 
|  |  | 
|  | count = bfd_count_sections (some_bfd); | 
|  | if (*start) | 
|  | xfree (* start); | 
|  | *start = (struct section_table *) xmalloc (count * sizeof (**start)); | 
|  | *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; | 
|  | } | 
|  |  | 
|  | static void | 
|  | bfdsec_to_vmap (struct bfd *abfd, struct bfd_section *sect, void *arg3) | 
|  | { | 
|  | struct vmap_and_bfd *vmap_bfd = (struct vmap_and_bfd *) arg3; | 
|  | struct vmap *vp; | 
|  |  | 
|  | vp = vmap_bfd->pvmap; | 
|  |  | 
|  | if ((bfd_get_section_flags (abfd, sect) & SEC_LOAD) == 0) | 
|  | return; | 
|  |  | 
|  | 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?)  */ | 
|  | } | 
|  |  | 
|  | /* Make a vmap for ABFD which might be a member of the archive ARCH. | 
|  | Return the new vmap.  */ | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /* Read or write the exec file. | 
|  |  | 
|  | Args are address within a BFD file, address within gdb address-space, | 
|  | length, and a flag indicating whether to read or write. | 
|  |  | 
|  | Result is a length: | 
|  |  | 
|  | 0:    We cannot handle this address and length. | 
|  | > 0:  We have handled N bytes starting at this address. | 
|  | (If N == length, we did it all.)  We might be able | 
|  | to handle more bytes beyond this length, but no | 
|  | promises. | 
|  | < 0:  We cannot handle this address, but if somebody | 
|  | else handles (-N) bytes, we can start from there. | 
|  |  | 
|  | The same routine is used to handle both core and exec files; | 
|  | we just tail-call it with more arguments to select between them.  */ | 
|  |  | 
|  | int | 
|  | xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write, | 
|  | struct mem_attrib *attrib, struct target_ops *target) | 
|  | { | 
|  | int res; | 
|  | struct section_table *p; | 
|  | CORE_ADDR nextsectaddr, memend; | 
|  | asection *section = NULL; | 
|  |  | 
|  | if (len <= 0) | 
|  | internal_error (__FILE__, __LINE__, _("failed internal consistency check")); | 
|  |  | 
|  | if (overlay_debugging) | 
|  | { | 
|  | section = find_pc_overlay (memaddr); | 
|  | if (pc_in_unmapped_range (memaddr, section)) | 
|  | memaddr = overlay_mapped_address (memaddr, section); | 
|  | } | 
|  |  | 
|  | memend = memaddr + len; | 
|  | nextsectaddr = memend; | 
|  |  | 
|  | for (p = target->to_sections; p < target->to_sections_end; p++) | 
|  | { | 
|  | if (overlay_debugging && section && p->the_bfd_section && | 
|  | strcmp (section->name, p->the_bfd_section->name) != 0) | 
|  | continue;		/* not the section we need */ | 
|  | if (memaddr >= p->addr) | 
|  | { | 
|  | if (memend <= p->endaddr) | 
|  | { | 
|  | /* Entire transfer is within this section.  */ | 
|  | if (write) | 
|  | res = bfd_set_section_contents (p->bfd, p->the_bfd_section, | 
|  | myaddr, memaddr - p->addr, | 
|  | len); | 
|  | else | 
|  | res = bfd_get_section_contents (p->bfd, p->the_bfd_section, | 
|  | myaddr, memaddr - p->addr, | 
|  | len); | 
|  | return (res != 0) ? len : 0; | 
|  | } | 
|  | else if (memaddr >= p->endaddr) | 
|  | { | 
|  | /* This section ends before the transfer starts.  */ | 
|  | continue; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* This section overlaps the transfer.  Just do half.  */ | 
|  | len = p->endaddr - memaddr; | 
|  | if (write) | 
|  | res = bfd_set_section_contents (p->bfd, p->the_bfd_section, | 
|  | myaddr, memaddr - p->addr, | 
|  | len); | 
|  | else | 
|  | res = bfd_get_section_contents (p->bfd, p->the_bfd_section, | 
|  | myaddr, memaddr - p->addr, | 
|  | len); | 
|  | return (res != 0) ? len : 0; | 
|  | } | 
|  | } | 
|  | else | 
|  | nextsectaddr = min (nextsectaddr, p->addr); | 
|  | } | 
|  |  | 
|  | if (nextsectaddr >= memend) | 
|  | return 0;			/* We can't help */ | 
|  | else | 
|  | return -(nextsectaddr - memaddr);	/* Next boundary where we can help */ | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | print_section_info (struct target_ops *t, bfd *abfd) | 
|  | { | 
|  | struct section_table *p; | 
|  | /* FIXME: 16 is not wide enough when TARGET_ADDR_BIT > 64.  */ | 
|  | int wid = TARGET_ADDR_BIT <= 32 ? 8 : 16; | 
|  |  | 
|  | printf_filtered ("\t`%s', ", bfd_get_filename (abfd)); | 
|  | wrap_here ("        "); | 
|  | printf_filtered (_("file type %s.\n"), bfd_get_target (abfd)); | 
|  | if (abfd == exec_bfd) | 
|  | { | 
|  | printf_filtered (_("\tEntry point: ")); | 
|  | deprecated_print_address_numeric (bfd_get_start_address (abfd), 1, gdb_stdout); | 
|  | printf_filtered ("\n"); | 
|  | } | 
|  | for (p = t->to_sections; p < t->to_sections_end; p++) | 
|  | { | 
|  | 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 | 
|  | since most output will then be much wider than necessary.  It | 
|  | may make sense to test the size of the file and choose the | 
|  | format string accordingly.  */ | 
|  | /* 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)); | 
|  | printf_filtered ("\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | exec_files_info (struct target_ops *t) | 
|  | { | 
|  | print_section_info (t, exec_bfd); | 
|  |  | 
|  | if (vmap) | 
|  | { | 
|  | struct vmap *vp; | 
|  |  | 
|  | printf_unfiltered (_("\tMapping info for file `%s'.\n"), vmap->name); | 
|  | printf_unfiltered ("\t  %*s   %*s   %*s   %*s %8.8s %s\n", | 
|  | strlen_paddr (), "tstart", | 
|  | strlen_paddr (), "tend", | 
|  | strlen_paddr (), "dstart", | 
|  | strlen_paddr (), "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", | 
|  | paddr (vp->tstart), | 
|  | paddr (vp->tend), | 
|  | paddr (vp->dstart), | 
|  | paddr (vp->dend), | 
|  | vp->name, | 
|  | *vp->member ? "(" : "", vp->member, | 
|  | *vp->member ? ")" : ""); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* msnyder 5/21/99: | 
|  | exec_set_section_offsets sets the offsets of all the sections | 
|  | in the exec objfile.  */ | 
|  |  | 
|  | void | 
|  | exec_set_section_offsets (bfd_signed_vma text_off, bfd_signed_vma data_off, | 
|  | bfd_signed_vma bss_off) | 
|  | { | 
|  | struct section_table *sect; | 
|  |  | 
|  | for (sect = exec_ops.to_sections; | 
|  | sect < exec_ops.to_sections_end; | 
|  | sect++) | 
|  | { | 
|  | flagword flags; | 
|  |  | 
|  | flags = bfd_get_section_flags (exec_bfd, sect->the_bfd_section); | 
|  |  | 
|  | if (flags & SEC_CODE) | 
|  | { | 
|  | sect->addr += text_off; | 
|  | sect->endaddr += text_off; | 
|  | } | 
|  | else if (flags & (SEC_DATA | SEC_LOAD)) | 
|  | { | 
|  | sect->addr += data_off; | 
|  | sect->endaddr += data_off; | 
|  | } | 
|  | else if (flags & SEC_ALLOC) | 
|  | { | 
|  | sect->addr += bss_off; | 
|  | sect->endaddr += bss_off; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | set_section_command (char *args, int from_tty) | 
|  | { | 
|  | struct section_table *p; | 
|  | char *secname; | 
|  | unsigned seclen; | 
|  | unsigned long secaddr; | 
|  | char secprint[100]; | 
|  | long offset; | 
|  |  | 
|  | if (args == 0) | 
|  | error (_("Must specify section name and its virtual address")); | 
|  |  | 
|  | /* Parse out section name */ | 
|  | for (secname = args; !isspace (*args); args++); | 
|  | seclen = args - secname; | 
|  |  | 
|  | /* Parse out new virtual address */ | 
|  | secaddr = parse_and_eval_address (args); | 
|  |  | 
|  | for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) | 
|  | { | 
|  | if (!strncmp (secname, bfd_section_name (exec_bfd, p->the_bfd_section), seclen) | 
|  | && bfd_section_name (exec_bfd, p->the_bfd_section)[seclen] == '\0') | 
|  | { | 
|  | offset = secaddr - p->addr; | 
|  | p->addr += offset; | 
|  | p->endaddr += offset; | 
|  | if (from_tty) | 
|  | exec_files_info (&exec_ops); | 
|  | return; | 
|  | } | 
|  | } | 
|  | if (seclen >= sizeof (secprint)) | 
|  | seclen = sizeof (secprint) - 1; | 
|  | strncpy (secprint, secname, seclen); | 
|  | secprint[seclen] = '\0'; | 
|  | error (_("Section %s not found"), secprint); | 
|  | } | 
|  |  | 
|  | /* If we can find a section in FILENAME with BFD index INDEX, and the | 
|  | user has not assigned an address to it yet (via "set section"), adjust it | 
|  | to ADDRESS.  */ | 
|  |  | 
|  | void | 
|  | exec_set_section_address (const char *filename, int index, CORE_ADDR address) | 
|  | { | 
|  | struct section_table *p; | 
|  |  | 
|  | for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++) | 
|  | { | 
|  | if (strcmp (filename, p->bfd->filename) == 0 | 
|  | && index == p->the_bfd_section->index | 
|  | && p->addr == 0) | 
|  | { | 
|  | p->addr = address; | 
|  | p->endaddr += 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 bp_target_info *bp_tgt) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Find mapped memory. */ | 
|  |  | 
|  | extern void | 
|  | exec_set_find_memory_regions (int (*func) (int (*) (CORE_ADDR, | 
|  | unsigned long, | 
|  | int, int, int, | 
|  | void *), | 
|  | void *)) | 
|  | { | 
|  | exec_ops.to_find_memory_regions = func; | 
|  | } | 
|  |  | 
|  | 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) | 
|  | { | 
|  | 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; | 
|  | exec_ops.to_attach = find_default_attach; | 
|  | exec_ops.deprecated_xfer_memory = xfer_memory; | 
|  | 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 = 1; | 
|  | exec_ops.to_make_corefile_notes = exec_make_note_section; | 
|  | exec_ops.to_magic = OPS_MAGIC; | 
|  | } | 
|  |  | 
|  | void | 
|  | _initialize_exec (void) | 
|  | { | 
|  | struct cmd_list_element *c; | 
|  |  | 
|  | init_exec_ops (); | 
|  |  | 
|  | if (!dbx_commands) | 
|  | { | 
|  | c = add_cmd ("file", class_files, file_command, _("\ | 
|  | Use FILE as program to be debugged.\n\ | 
|  | It is read for its symbols, for getting the contents of pure memory,\n\ | 
|  | and it is the program executed when you use the `run' command.\n\ | 
|  | If FILE cannot be found as specified, your execution directory path\n\ | 
|  | ($PATH) is searched for a command of that name.\n\ | 
|  | No arg means to have no executable file and no symbols."), &cmdlist); | 
|  | set_cmd_completer (c, filename_completer); | 
|  | } | 
|  |  | 
|  | c = add_cmd ("exec-file", class_files, exec_file_command, _("\ | 
|  | Use FILE as program for getting contents of pure memory.\n\ | 
|  | If FILE cannot be found as specified, your execution directory path\n\ | 
|  | is searched for a command of that name.\n\ | 
|  | No arg means have no executable file."), &cmdlist); | 
|  | set_cmd_completer (c, filename_completer); | 
|  |  | 
|  | add_com ("section", class_files, set_section_command, _("\ | 
|  | Change the base address of section SECTION of the exec file to ADDR.\n\ | 
|  | This can be used if the exec file does not contain section addresses,\n\ | 
|  | (such as in the a.out format), or when the addresses specified in the\n\ | 
|  | file itself are wrong.  Each section must be changed separately.  The\n\ | 
|  | ``info files'' command lists all the sections and their addresses.")); | 
|  |  | 
|  | add_setshow_boolean_cmd ("write", class_support, &write_files, _("\ | 
|  | Set writing into executable and core files."), _("\ | 
|  | Show writing into executable and core files."), NULL, | 
|  | 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")); | 
|  | } |