/* Work with executable files, for GDB.
- Copyright 1988, 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1997, 1998
+ Free Software Foundation, Inc.
This file is part of GDB.
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "frame.h"
#include <sys/types.h>
#endif
-#include <sys/param.h>
#include <fcntl.h>
-#include <string.h>
+#include "gdb_string.h"
#include "gdbcore.h"
#include <ctype.h>
-#include <sys/stat.h>
+#include "gdb_stat.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
struct vmap *map_vmap PARAMS ((bfd *, bfd *));
+void (*file_changed_hook) PARAMS ((char *));
+
/* Prototypes for local functions */
static void add_to_section_table PARAMS ((bfd *, sec_ptr, PTR));
static void exec_files_info PARAMS ((struct target_ops *));
+static void bfdsec_to_vmap PARAMS ((bfd *, sec_ptr, PTR));
+
+static int ignore PARAMS ((CORE_ADDR, char *));
+
extern int info_verbose;
/* The Binary File Descriptor handle for the executable file. */
/* Text start and end addresses (KLUDGE) if needed */
-#ifdef NEED_TEXT_START_END
+#ifndef NEED_TEXT_START_END
+#define NEED_TEXT_START_END (0)
+#endif
CORE_ADDR text_start = 0;
CORE_ADDR text_end = 0;
-#endif
struct vmap *vmap;
need_symtab_cleanup = 1;
}
else if (vp->bfd != exec_bfd)
- bfd_close (vp->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? */
+ 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);
free (vp);
}
-
+
vmap = NULL;
if (exec_bfd)
{
char *name = bfd_get_filename (exec_bfd);
- bfd_close (exec_bfd);
+ if (!bfd_close (exec_bfd))
+ warning ("cannot close \"%s\": %s",
+ name, bfd_errmsg (bfd_get_error ()));
free (name);
exec_bfd = 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. */
+ 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.) */
void
-exec_file_command (args, from_tty)
+exec_file_attach (args, from_tty)
char *args;
int from_tty;
{
char **argv;
char *filename;
- target_preopen (from_tty);
-
/* Remove any previous exec file. */
unpush_target (&exec_ops);
if (argv == NULL)
nomem (0);
- make_cleanup (freeargv, (char *) argv);
+ make_cleanup ((make_cleanup_func) freeargv, (char *) argv);
for (; (*argv != NULL) && (**argv == '-'); argv++) {;}
if (*argv == NULL)
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)
+ 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);
+
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 = strdup (scratch_pathname);
+ make_cleanup (free, scratch_pathname);
+
if (!bfd_check_format (exec_bfd, bfd_object))
{
/* Make sure to close exec_bfd, or else "run" might try to use
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
-#ifdef NEED_TEXT_START_END
-
/* text_end is sometimes used for where to put call dummies. A
few ports use these for other purposes too. */
-
- {
- struct section_table *p;
-
- /* Set text_start to the lowest address of the start of any
- readonly code section and set text_end to the highest
- address of the end of any readonly code section. */
-
- text_start = ~(CORE_ADDR)0;
- text_end = (CORE_ADDR)0;
- for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++)
- if (bfd_get_section_flags (p->bfd, p->the_bfd_section)
- & (SEC_CODE | SEC_READONLY))
- {
- if (text_start > p->addr)
- text_start = p->addr;
- if (text_end < p->endaddr)
- text_end = p->endaddr;
- }
- }
-#endif
+ if (NEED_TEXT_START_END)
+ {
+ struct section_table *p;
+
+ /* Set text_start to the lowest address of the start of any
+ readonly code section and set text_end to the highest
+ address of the end of any readonly code section. */
+ /* FIXME: The comment above does not match the code. The
+ code checks for sections with are either code *or*
+ readonly. */
+ text_start = ~(CORE_ADDR)0;
+ text_end = (CORE_ADDR)0;
+ for (p = exec_ops.to_sections; p < exec_ops.to_sections_end; p++)
+ if (bfd_get_section_flags (p->bfd, p->the_bfd_section)
+ & (SEC_CODE | SEC_READONLY))
+ {
+ if (text_start > p->addr)
+ text_start = p->addr;
+ if (text_end < p->endaddr)
+ text_end = p->endaddr;
+ }
+ }
validate_files ();
- set_endian_from_file (exec_bfd);
+ set_gdbarch_from_file (exec_bfd);
push_target (&exec_ops);
(*exec_file_display_hook) (filename);
}
else if (from_tty)
- printf_unfiltered ("No exec file now.\n");
+ printf_unfiltered ("No executable file now.\n");
+}
+
+/* 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. */
+
+void
+exec_file_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char **argv;
+ char *filename;
+
+ target_preopen (from_tty);
+
+ exec_file_attach (args, from_tty);
}
/* Set both the exec file and the symbol file, in one command.
the exec file, but that's rough. */
exec_file_command (arg, from_tty);
symbol_file_command (arg, from_tty);
+ if (file_changed_hook)
+ file_changed_hook (arg);
}
\f
if (STREQ (bfd_section_name (abfd, sect), ".text"))
{
- vp->tstart = 0;
+ vp->tstart = bfd_section_vma (abfd, sect);
vp->tend = vp->tstart + bfd_section_size (abfd, sect);
-
- /* When it comes to this adjustment value, in contrast to our previous
- belief shared objects should behave the same as the main load segment.
- This is the offset from the beginning of text section to the first
- real instruction. */
-
- vp->tadj = sect->filepos - bfd_section_vma (abfd, sect);
+ vp->tvma = bfd_section_vma (abfd, sect);
+ vp->toffs = sect->filepos;
}
else if (STREQ (bfd_section_name (abfd, sect), ".data"))
{
- vp->dstart = 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?) */
}
struct vmap_and_bfd vmap_bfd;
struct vmap *vp, **vpp;
- vp = (PTR) xmalloc (sizeof (*vp));
+ vp = (struct vmap *) xmalloc (sizeof (*vp));
memset ((char *) vp, '\0', sizeof (*vp));
vp->nxt = 0;
vp->bfd = abfd;
struct section_table *p;
CORE_ADDR nextsectaddr, memend;
boolean (*xfer_fn) PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type));
+ asection *section;
if (len <= 0)
abort();
+ 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;
+#if 0 /* Stu's implementation */
+/* If a section has been specified, try to use it. Note that we cannot use the
+ specified section directly. This is because it usually comes from the
+ symbol file, which may be different from the exec or core file. Instead, we
+ have to lookup the specified section by name in the bfd associated with
+ to_sections. */
+
+ if (target_memory_bfd_section)
+ {
+ asection *s;
+ bfd *abfd;
+ asection *target_section;
+ bfd *target_bfd;
+
+ s = target_memory_bfd_section;
+ abfd = s->owner;
+
+ target_bfd = target->to_sections->bfd;
+ target_section = bfd_get_section_by_name (target_bfd, bfd_section_name (abfd, s));
+
+ if (target_section)
+ {
+ bfd_vma sec_addr;
+ bfd_size_type sec_size;
+
+ sec_addr = bfd_section_vma (target_bfd, target_section);
+ sec_size = target_section->_raw_size;
+
+ /* Make sure the requested memory starts inside the section. */
+
+ if (memaddr >= sec_addr
+ && memaddr < sec_addr + sec_size)
+ {
+ /* Cut back length in case request overflows the end of the section. */
+ len = min (len, sec_addr + sec_size - memaddr);
+
+ res = xfer_fn (target_bfd, target_section, myaddr, memaddr - sec_addr, len);
+
+ return res ? len : 0;
+ }
+ }
+ }
+#endif /* 0, Stu's implementation */
for (p = target->to_sections; p < target->to_sections_end; p++)
{
- if (p->addr <= memaddr)
- if (p->endaddr >= memend)
+ 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. */
res = xfer_fn (p->bfd, p->the_bfd_section, myaddr,
memaddr - p->addr, len);
return (res != 0) ? len : 0;
}
- else if (p->endaddr <= memaddr)
+ else if (memaddr >= p->endaddr)
{
/* This section ends before the transfer starts. */
continue;
memaddr - p->addr, len);
return (res != 0) ? len : 0;
}
- else if (p->addr < nextsectaddr)
- nextsectaddr = p->addr;
+ else
+ nextsectaddr = min (nextsectaddr, p->addr);
}
if (nextsectaddr >= memend)
}
struct target_ops exec_ops = {
- "exec", "Local exec file",
- "Use an executable file as a target.\n\
-Specify the filename of the executable file.",
- exec_file_command, exec_close, /* open, close */
- find_default_attach, 0, 0, 0, /* attach, detach, resume, wait, */
- 0, 0, /* fetch_registers, store_registers, */
- 0, /* prepare_to_store, */
- xfer_memory, exec_files_info,
- ignore, ignore, /* insert_breakpoint, remove_breakpoint, */
- 0, 0, 0, 0, 0, /* terminal stuff */
- 0, 0, /* kill, load */
- 0, /* lookup sym */
- find_default_create_inferior,
- 0, /* mourn_inferior */
- 0, /* can_run */
- 0, /* notice_signals */
- file_stratum, 0, /* next */
- 0, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */
- 0, 0, /* section pointers */
- OPS_MAGIC, /* Always the last thing */
+ "exec", /* to_shortname */
+ "Local exec file", /* to_longname */
+ "Use an executable file as a target.\n\
+Specify the filename of the executable file.", /* to_doc */
+ exec_file_command, /* to_open */
+ exec_close, /* to_close */
+ find_default_attach, /* to_attach */
+ NULL, /* to_post_attach */
+ find_default_require_attach, /* to_require_attach */
+ 0, /* to_detach */
+ find_default_require_detach, /* to_require_detach */
+ 0, /* to_resume */
+ 0, /* to_wait */
+ NULL, /* to_post_wait */
+ 0, /* to_fetch_registers */
+ 0, /* to_store_registers */
+ 0, /* to_prepare_to_store */
+ xfer_memory, /* to_xfer_memory */
+ exec_files_info, /* to_files_info */
+ ignore, /* to_insert_breakpoint */
+ ignore, /* to_remove_breakpoint */
+ 0, /* to_terminal_init */
+ 0, /* to_terminal_inferior */
+ 0, /* to_terminal_ours_for_output */
+ 0, /* to_terminal_ours */
+ 0, /* to_terminal_info */
+ 0, /* to_kill */
+ 0, /* to_load */
+ 0, /* to_lookup_symbol */
+ find_default_create_inferior, /* to_create_inferior */
+ NULL, /* to_post_startup_inferior */
+ NULL, /* to_acknowledge_created_inferior */
+ find_default_clone_and_follow_inferior, /* to_clone_and_follow_inferior */
+ NULL, /* to_post_follow_inferior_by_clone */
+ NULL, /* to_insert_fork_catchpoint */
+ NULL, /* to_remove_fork_catchpoint */
+ NULL, /* to_insert_vfork_catchpoint */
+ NULL, /* to_remove_vfork_catchpoint */
+ NULL, /* to_has_forked */
+ NULL, /* to_has_vforked */
+ NULL, /* to_can_follow_vfork_prior_to_exec */
+ NULL, /* to_post_follow_vfork */
+ NULL, /* to_insert_exec_catchpoint */
+ NULL, /* to_remove_exec_catchpoint */
+ NULL, /* to_has_execd */
+ NULL, /* to_reported_exec_events_per_exec_call */
+ NULL, /* to_has_syscall_event */
+ NULL, /* to_has_exited */
+ 0, /* to_mourn_inferior */
+ 0, /* to_can_run */
+ 0, /* to_notice_signals */
+ 0, /* to_thread_alive */
+ 0, /* to_stop */
+ NULL, /* to_enable_exception_callback */
+ NULL, /* to_get_current_exception_event */
+ NULL, /* to_pid_to_exec_file */
+ NULL, /* to_core_file_to_sym_file */
+ file_stratum, /* to_stratum */
+ 0, /* to_next */
+ 0, /* to_has_all_memory */
+ 1, /* to_has_memory */
+ 0, /* to_has_stack */
+ 0, /* to_has_registers */
+ 0, /* to_has_execution */
+ 0, /* to_sections */
+ 0, /* to_sections_end */
+ OPS_MAGIC, /* to_magic */
};
void
{
struct cmd_list_element *c;
- c = add_cmd ("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.", &cmdlist);
- c->completer = filename_completer;
+ c->completer = filename_completer;
+ }
c = add_cmd ("exec-file", class_files, exec_file_command,
"Use FILE as program for getting contents of pure memory.\n\