#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"
#ifdef USG
#include <sys/types.h>
#endif
#include <fcntl.h>
#include <readline/readline.h>
#include "gdb_string.h"
#include "gdbcore.h"
#include <ctype.h>
#include "gdb_stat.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
#include "xcoffsolib.h"
#ifndef TEXT_SECTION_NAME
#define TEXT_SECTION_NAME ".text"
#endif
#ifndef DATA_SECTION_NAME
#define DATA_SECTION_NAME ".data"
#endif
static void
standard_async (void (*callback) (enum inferior_event_type event_type,
void *context), void *context)
{
return;
}
int standard_is_async_p (void)
{
return (current_target.to_async_mask_value);
}
int standard_can_async_p (void)
{
return (current_target.to_async_mask_value);
}
struct vmap *map_vmap (bfd *, bfd *);
void (*file_changed_hook) (char *);
static void add_to_section_table (bfd *, sec_ptr, void *);
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 bfdsec_to_vmap (bfd *, sec_ptr, void *);
static int ignore (CORE_ADDR, char *);
void init_exec_ops (void);
void _initialize_exec (void);
struct target_ops exec_ops;
bfd *exec_bfd = NULL;
int write_files = 0;
#ifndef NEED_TEXT_START_END
#define NEED_TEXT_START_END (0)
#endif
CORE_ADDR text_end = 0;
struct vmap *vmap;
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 (vp->objfile)
{
free_objfile (vp->objfile);
need_symtab_cleanup = 1;
}
else if (vp->bfd != exec_bfd)
if (!bfd_close (vp->bfd))
warning ("cannot close \"%s\": %s",
vp->name, bfd_errmsg (bfd_get_error ()));
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)
{
target_resize_to_sections
(&exec_ops, exec_ops.to_sections_end - exec_ops.to_sections);
}
#if 0
#ifdef NM_NEXTSTEP
if (! quitting)
macosx_init_dyld_symfile (symfile_objfile, exec_bfd);
#endif
#endif
}
void
exec_file_clear (int from_tty)
{
unpush_target (&exec_ops);
if (from_tty)
printf_unfiltered ("No executable file now.\n");
}
#ifdef SOLIB_ADD
static int
solib_add_stub (PTR from_ttyp)
{
SOLIB_ADD (NULL, *(int *) from_ttyp, ¤t_target, auto_solib_add);
re_enable_breakpoints_in_shlibs (0);
return 0;
}
#endif
void
exec_file_attach (char *filename, int from_tty)
{
unpush_target (&exec_ops);
if (!filename)
{
if (from_tty)
printf_unfiltered ("No executable file now.\n");
}
else
{
char *scratch_pathname;
int scratch_chan;
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
#ifdef NM_NEXTSTEP
if (scratch_chan < 0)
{
char *wrapped_filename = macosx_filename_in_bundle (filename, 1);
if (wrapped_filename != NULL)
{
scratch_chan = openp (getenv ("PATH"), 1, wrapped_filename,
write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY, 0,
&scratch_pathname);
xfree (wrapped_filename);
}
}
#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 ()));
scratch_pathname = xstrdup (scratch_pathname);
make_cleanup (xfree, scratch_pathname);
if (bfd_check_format (exec_bfd, bfd_archive))
{
bfd *abfd = NULL;
#if defined (TARGET_POWERPC)
const bfd_arch_info_type *thisarch = bfd_lookup_arch (bfd_arch_powerpc, 0);
#elif defined (TARGET_I386)
const bfd_arch_info_type *thisarch = bfd_lookup_arch (bfd_arch_i386, 0);
#else
const bfd_arch_info_type *thisarch = bfd_lookup_arch (bfd_arch_powerpc, 0);
#endif
for (;;)
{
abfd = bfd_openr_next_archived_file (exec_bfd, abfd);
if (abfd == NULL)
{
break;
}
if (!bfd_check_format (abfd, bfd_object))
{
abfd = NULL;
break;
}
if (thisarch == NULL)
{
abfd = NULL;
break;
}
if (bfd_default_compatible (bfd_get_arch_info (abfd), thisarch))
{
break;
}
}
if (abfd != NULL)
{
exec_bfd = abfd;
}
}
if (!bfd_check_format (exec_bfd, bfd_object))
{
exec_close (0);
error ("\"%s\": not in executable format: %s",
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
#ifdef IBM6000_TARGET
map_vmap (exec_bfd, 0);
if (vmap == NULL)
{
exec_close (0);
error ("\"%s\": can't find the file sections: %s",
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
#endif
if (build_section_table (exec_bfd, &exec_ops.to_sections,
&exec_ops.to_sections_end))
{
exec_close (0);
error ("\"%s\": can't find the file sections: %s",
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
if (NEED_TEXT_START_END)
{
struct section_table *p;
CORE_ADDR 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_gdbarch_from_file (exec_bfd);
push_target (&exec_ops);
#ifdef NM_NEXTSTEP
macosx_init_dyld_symfile (symfile_objfile, exec_bfd);
#endif
#ifdef SOLIB_ADD
catch_errors (solib_add_stub, &from_tty, (char *) 0,
RETURN_MASK_ALL);
#endif
if (exec_file_display_hook)
(*exec_file_display_hook) (filename);
}
}
static void
exec_file_command (char *args, int from_tty)
{
char **argv;
char *filename;
target_preopen (from_tty);
if (args)
{
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);
}
static void
file_command (char *arg, int from_tty)
{
exec_file_command (arg, from_tty);
symbol_file_command (arg, from_tty);
if (file_changed_hook)
file_changed_hook (arg);
}
static void
add_to_section_table (bfd *abfd, sec_ptr 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)++;
}
int
build_section_table (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");
return 0;
}
static void
bfdsec_to_vmap (bfd *abfd, sec_ptr 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 (STREQ (bfd_section_name (abfd, sect), TEXT_SECTION_NAME))
{
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 (STREQ (bfd_section_name (abfd, sect), DATA_SECTION_NAME))
{
vp->dstart = bfd_section_vma (abfd, sect);
vp->dend = vp->dstart + bfd_section_size (abfd, sect);
vp->dvma = bfd_section_vma (abfd, sect);
}
}
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);
for (vpp = &vmap; *vpp; vpp = &(*vpp)->nxt)
;
*vpp = vp;
return vp;
}
int
xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
struct mem_attrib *attrib,
struct target_ops *target)
{
int res;
struct section_table *p;
CORE_ADDR nextsectaddr, memend;
int (*xfer_fn) (bfd *, sec_ptr, void *, file_ptr, bfd_size_type);
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;
xfer_fn = write ? bfd_set_section_contents : bfd_get_section_contents;
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;
if (memaddr >= p->addr)
{
if (memend <= p->endaddr)
{
res = xfer_fn (p->bfd, p->the_bfd_section, myaddr,
memaddr - p->addr, len);
return (res != 0) ? len : 0;
}
else if (memaddr >= p->endaddr)
{
continue;
}
else
{
len = p->endaddr - memaddr;
res = xfer_fn (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;
else
return -(nextsectaddr - memaddr);
}
void
print_section_info_objfile (struct objfile *o)
{
struct obj_section *p;
ui_out_list_begin (uiout, "section-info");
ui_out_text (uiout, "\t");
ui_out_field_string (uiout, "filename", bfd_get_filename (o->obfd));
ui_out_text (uiout, ", ");
ui_out_wrap_hint (uiout, " ");
ui_out_text (uiout, "file type ");
ui_out_field_string (uiout, "filetype", bfd_get_target (o->obfd));
ui_out_text (uiout, ", ");
ui_out_wrap_hint (uiout, " ");
ui_out_text (uiout, "symbol prefix ");
ui_out_field_string (uiout, "prefix", o->prefix);
ui_out_text (uiout, ".\n");
ui_out_list_begin (uiout, "sections");
for (p = o->sections; p < o->sections_end; p++)
{
ui_out_list_begin (uiout, "section");
ui_out_text (uiout, "\t");
ui_out_field_core_addr (uiout, "addr", p->addr);
ui_out_text (uiout, " - ");
ui_out_field_core_addr (uiout, "endaddr", p->endaddr);
if (info_verbose)
{
ui_out_text (uiout, " @ ");
ui_out_field_core_addr (uiout, "filepos", p->the_bfd_section->filepos);
}
ui_out_text (uiout, " is ");
ui_out_field_string (uiout, "name", bfd_section_name (p->bfd, p->the_bfd_section));
ui_out_text (uiout, "\n");
ui_out_list_end (uiout);
}
ui_out_list_end (uiout);
ui_out_list_end (uiout);
}
void
print_section_info (struct target_ops *t, bfd *abfd)
{
struct section_table *p;
char *fmt = TARGET_ADDR_BIT <= 32 ? "08l" : "016l";
ui_out_list_begin (uiout, "section-info");
ui_out_text (uiout, "\t");
ui_out_field_string (uiout, "filename", bfd_get_filename (abfd));
ui_out_text (uiout, ", ");
ui_out_wrap_hint (uiout, " ");
ui_out_text (uiout, "file type ");
ui_out_field_string (uiout, "filetype", bfd_get_target (abfd));
ui_out_text (uiout, ".\n");
if (abfd == exec_bfd)
{
ui_out_text (uiout, "\tEntry point: ");
ui_out_field_core_addr (uiout, "entry-point", bfd_get_start_address (abfd));
ui_out_text (uiout, "\n");
}
ui_out_list_begin (uiout, "sections");
for (p = t->to_sections; p < t->to_sections_end; p++)
{
ui_out_list_begin (uiout, "section");
ui_out_text (uiout, "\t");
ui_out_field_core_addr (uiout, "addr", p->addr);
ui_out_text (uiout, " - ");
ui_out_field_core_addr (uiout, "endaddr", p->endaddr);
if (info_verbose)
{
ui_out_text (uiout, " @ ");
ui_out_field_core_addr (uiout, "filepos", p->the_bfd_section->filepos);
}
ui_out_text (uiout, " is ");
ui_out_field_string (uiout, "name", bfd_section_name (p->bfd, p->the_bfd_section));
if (p->bfd != abfd)
{
ui_out_text (uiout, " in ");
ui_out_field_string (uiout, "filename", bfd_get_filename (p->bfd));
}
ui_out_text (uiout, "\n");
ui_out_list_end (uiout);
}
ui_out_list_end (uiout);
ui_out_list_end (uiout);
}
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 ? ")" : "");
}
}
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");
for (secname = args; !isspace (*args); args++);
seclen = args - secname;
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);
}
static int
ignore (CORE_ADDR addr, char *contents)
{
return 0;
}
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 *);
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;
exec_ops.to_can_async_p = standard_can_async_p;
exec_ops.to_is_async_p = standard_is_async_p;
exec_ops.to_async = standard_async;
exec_ops.to_async_mask_value = 1;
}
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_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");
}