X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fexec.c;h=7719ac8feee28bf14f4d0e36bba3d63faeb3c303;hb=ce7d45220e4ed342d4a77fcd2f312e85e1100971;hp=eefe77223ac0de9ffe602e27c58698969e1ff1f1;hpb=3c0c9328b9c299580bcf8cb6fdb3b71d5a0525ff;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/exec.c b/gdb/exec.c index eefe77223a..7719ac8fee 100644 --- a/gdb/exec.c +++ b/gdb/exec.c @@ -1,350 +1,762 @@ /* Work with executable files, for GDB. - Copyright (C) 1988, 1989 Free Software Foundation, Inc. -This file is part of GDB. + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, + 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, + Inc. -GDB 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 1, or (at your option) -any later version. + This file is part of GDB. -GDB 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. + 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. -You should have received a copy of the GNU General Public License -along with GDB; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ -#include #include "defs.h" -#include "param.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" #ifdef USG #include #endif -#include #include +#include "readline/readline.h" +#include "gdb_string.h" #include "gdbcore.h" -#ifdef STILL_NEEDED_FOR_DECSTATION -#include /* For DECstations */ -#include /* After a.out.h */ -#include +#include +#include "gdb_stat.h" +#ifndef O_BINARY +#define O_BINARY 0 #endif -#include +#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 int ignore (CORE_ADDR, char *); + +static void init_exec_ops (void); + +void _initialize_exec (void); -extern char *getenv(); -extern void child_create_inferior (), child_attach (); -extern void symbol_file_command (); +/* The target vector for executable files. */ + +struct target_ops exec_ops; /* The Binary File Descriptor handle for the executable file. */ bfd *exec_bfd = NULL; -/* The base and bounds of the table of the exec file's sections. */ - -struct section_table *exec_sections, *exec_sections_end; +/* Whether to open exec and core files read-only or read-write. */ -/* Forward decl */ +int write_files = 0; -extern struct target_ops exec_ops; +struct vmap *vmap; void -exec_close (quitting) - int quitting; +exec_open (char *args, int from_tty) { - if (exec_bfd) { - bfd_close (exec_bfd); - exec_bfd = NULL; - } + 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_command (filename, from_tty) - char *filename; - int from_tty; +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 (!filename) + { + if (from_tty) + printf_unfiltered ("No executable file now.\n"); + } + else { char *scratch_pathname; int scratch_chan; - - filename = tilde_expand (filename); - make_cleanup (free, filename); - -/* FIXME, if writeable is set, open for read/write. */ - scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + + scratch_chan = openp (getenv ("PATH"), 1, 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"), 1, 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_fdopenr (scratch_pathname, gnutarget, scratch_chan); - exec_bfd = bfd_fdopenr (scratch_pathname, NULL, scratch_chan); if (!exec_bfd) - error ("Could not open `%s' as an executable file: %s", - scratch_pathname, bfd_errmsg (bfd_error)); + 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)) - error ("\"%s\": not in executable format: %s.", - scratch_pathname, bfd_errmsg (bfd_error)); - -#if FIXME -/* This code needs to be incorporated into BFD */ -#ifdef COFF_ENCAPSULATE - /* If we have a coff header, it can give us better values for - text_start and exec_data_start. This is particularly useful - for remote debugging of embedded systems. */ - if (N_FLAGS(exec_aouthdr) & N_FLAGS_COFF_ENCAPSULATE) { - struct coffheader ch; - int val; - val = lseek (execchan, -(sizeof (AOUTHDR) + sizeof (ch)), 1); - if (val == -1) - perror_with_name (filename); - val = myread (execchan, &ch, sizeof (ch)); - if (val < 0) - perror_with_name (filename); - text_start = ch.text_start; - exec_data_start = ch.data_start; - } else -#endif - { - text_start = - IS_OBJECT_FILE (exec_aouthdr) ? 0 : N_TXTADDR (exec_aouthdr); - exec_data_start = IS_OBJECT_FILE (exec_aouthdr) - ? exec_aouthdr.a_text : N_DATADDR (exec_aouthdr); + /* 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 FIXME +#endif /* DEPRECATED_IBM6000_TARGET */ - if (build_section_table (exec_bfd, &exec_sections, &exec_sections_end)) - error ("Can't find the file sections in `%s': %s", - exec_bfd->filename, bfd_errmsg (bfd_error)); + 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 ())); + } + +#ifdef DEPRECATED_HPUX_TEXT_END + DEPRECATED_HPUX_TEXT_END (&exec_ops); +#endif validate_files (); + set_gdbarch_from_file (exec_bfd); + push_target (&exec_ops); /* Tell display code (if any) about the changed file name. */ - if (exec_file_display_hook) - (*exec_file_display_hook) (filename); + if (deprecated_exec_file_display_hook) + (*deprecated_exec_file_display_hook) (filename); } - else if (from_tty) - printf ("No exec file now.\n"); + bfd_cache_close_all (); +} + +/* 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; + + target_preopen (from_tty); + + 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? */ -void -file_command (arg, from_tty) - char *arg; - int from_tty; +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. */ -void -add_to_section_table (abfd, asect, table_pp) - bfd *abfd; - sec_ptr asect; - struct section_table **table_pp; +/* 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); - /* FIXME, we need to handle BSS segment here...it alloc's but doesn't load */ - if (!(aflag & SEC_LOAD)) + if (!(aflag & SEC_ALLOC)) return; - (*table_pp)->sec_ptr = asect; + 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 (some_bfd, start, end) - bfd *some_bfd; - struct section_table **start, **end; +build_section_table (struct bfd *some_bfd, struct section_table **start, + struct section_table **end) { unsigned count; count = bfd_count_sections (some_bfd); - if (count == 0) - abort(); /* return 1? */ + if (*start) + xfree (* start); *start = (struct section_table *) xmalloc (count * sizeof (**start)); *end = *start; - bfd_map_over_sections (some_bfd, add_to_section_table, end); + bfd_map_over_sections (some_bfd, add_to_section_table, (char *) end); if (*end > *start + count) - abort(); + 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 (DEPRECATED_STREQ (bfd_section_name (abfd, sect), ".text")) + { + 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 (DEPRECATED_STREQ (bfd_section_name (abfd, sect), ".data")) + { + 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 exec file, address within gdb address-space, + 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. + 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. */ + 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 (memaddr, myaddr, len, write, abfd, sections, sections_end) - CORE_ADDR memaddr; - char *myaddr; - int len; - int write; - bfd *abfd; - struct section_table *sections, *sections_end; +xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, + struct mem_attrib *attrib, + struct target_ops *target) { - boolean res; + int res; struct section_table *p; CORE_ADDR nextsectaddr, memend; - boolean (*xfer_fn) (); + asection *section = NULL; if (len <= 0) - abort(); + 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; - xfer_fn = write? bfd_set_section_contents: bfd_get_section_contents; nextsectaddr = memend; - for (p = sections; p < sections_end; p++) + for (p = target->to_sections; p < target->to_sections_end; p++) { - if (p->addr <= memaddr) - if (p->endaddr >= memend) - { - /* Entire transfer is within this section. */ - res = xfer_fn (abfd, p->sec_ptr, myaddr, memaddr - p->addr, len); - return (res != false)? len: 0; - } - else if (p->endaddr <= memaddr) - { - /* This section ends before the transfer starts. */ - continue; - } - else - { - /* This section overlaps the transfer. Just do half. */ - len = p->endaddr - memaddr; - res = xfer_fn (abfd, p->sec_ptr, myaddr, memaddr - p->addr, len); - return (res != false)? len: 0; - } - else if (p->addr < nextsectaddr) - nextsectaddr = p->addr; + 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 */ + return 0; /* We can't help */ else - return - (nextsectaddr - memaddr); /* Next boundary where we can help */ + return -(nextsectaddr - memaddr); /* Next boundary where we can help */ } + -/* The function called by target_xfer_memory via our target_ops */ +void +print_section_info (struct target_ops *t, bfd *abfd) +{ + struct section_table *p; + /* FIXME: "016l" is not wide enough when TARGET_ADDR_BIT > 64. */ + char *fmt = TARGET_ADDR_BIT <= 32 ? "08l" : "016l"; -int -exec_xfer_memory (memaddr, myaddr, len, write) - CORE_ADDR memaddr; - char *myaddr; - int len; - int write; + 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: "); + 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", local_hex_string_custom (p->addr, fmt)); + printf_filtered (" - %s", local_hex_string_custom (p->endaddr, fmt)); + + /* 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. */ + if (info_verbose) + printf_filtered (" @ %s", + local_hex_string_custom (p->the_bfd_section->filepos, "08l")); + 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) { - return xfer_memory (memaddr, myaddr, len, write, - exec_bfd, exec_sections, exec_sections_end); + 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; + } + } +} -#ifdef FIXME -#ifdef REG_STACK_SEGMENT -/* MOVE TO BFD... */ - /* Pyramids and AM29000s have an extra segment in the virtual address space - for the (control) stack of register-window frames. The AM29000 folk - call it the "register stack" rather than the "memory stack". */ - else if (memaddr >= reg_stack_start && memaddr < reg_stack_end) - { - i = min (len, reg_stack_end - memaddr); - fileptr = memaddr - reg_stack_start + reg_stack_offset; - wanna_xfer = coredata; - } -#endif /* REG_STACK_SEGMENT */ -#endif FIXME - static void -exec_files_info () +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 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 (CORE_ADDR addr, char *contents) +{ + return 0; +} - printf ("\tExecutable file `%s'.\n", bfd_get_filename(exec_bfd)); +/* Find mapped memory. */ - for (p = exec_sections; p < exec_sections_end; p++) - printf("\texecutable from 0x%08x to 0x%08x is %s\n", - p->addr, p->endaddr, - bfd_section_name (exec_bfd, p->sec_ptr)); +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; } -struct target_ops exec_ops = { - "exec", "Local exec file", - exec_file_command, exec_close, /* open, close */ - child_attach, 0, 0, 0, /* attach, detach, resume, wait, */ - 0, 0, /* fetch_registers, store_registers, */ - 0, 0, 0, /* prepare_to_store, conv_to, conv_from, */ - exec_xfer_memory, exec_files_info, - 0, 0, /* insert_breakpoint, remove_breakpoint, */ - 0, 0, 0, 0, 0, /* terminal stuff */ - 0, 0, 0, 0, 0, /* kill, load, add_syms, call fn, lookup sym */ - child_create_inferior, - 0, /* mourn_inferior */ - file_stratum, 0, /* next */ - 0, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */ - OPS_MAGIC, /* Always the last thing */ -}; +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.to_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() +_initialize_exec (void) { + struct cmd_list_element *c; + + init_exec_ops (); - add_com ("file", class_files, file_command, - "Use FILE as program to be debugged.\n\ + 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."); +No arg means to have no executable file and no symbols.", &cmdlist); + set_cmd_completer (c, filename_completer); + } - add_com ("exec-file", class_files, exec_file_command, - "Use FILE as program for getting contents of pure memory.\n\ + 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."); +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."); + + deprecated_add_show_from_set + (add_set_cmd ("write", class_support, var_boolean, (char *) &write_files, + "Set writing into executable and core files.", + &setlist), + &showlist); add_target (&exec_ops); } + +static char * +exec_make_note_section (bfd *obfd, int *note_size) +{ + error ("Can't create a corefile"); +}