macosx-nat-dyld-io.c [plain text]
#include "defs.h"
#include "inferior.h"
#include "symfile.h"
#include "symtab.h"
#include "gdbcmd.h"
#include "objfiles.h"
#include "target.h"
#include "exceptions.h"
#include "gdbcore.h"
#include <string.h>
#include <sys/stat.h>
#include <mach-o/nlist.h>
#include <mach-o/loader.h>
#include "libbfd.h"
#include "mach-o.h"
#include "macosx-nat-inferior.h"
#include "macosx-nat-mutils.h"
#include "macosx-nat-dyld-info.h"
struct inferior_info
{
bfd_vma addr;
bfd_vma offset;
bfd_vma len;
void *read;
};
static void *
inferior_open (bfd *abfd, void *open_closure)
{
struct inferior_info *in = NULL;
struct inferior_info *ret = NULL;
in = (struct inferior_info *) open_closure;
ret = bfd_zalloc (abfd, sizeof (struct inferior_info));
*ret = *in;
return ret;
}
static int
valid_target_for_inferior_bfd ()
{
return strcmp (current_target.to_shortname, "macos-child") == 0
|| target_is_remote ()
|| strcmp (current_target.to_shortname, "core-macho") == 0;
}
static int
bfd_target_is_mach_o (bfd *abfd)
{
return strcmp (bfd_get_target (abfd), "mach-o-be") == 0
|| strcmp (bfd_get_target (abfd), "mach-o-le") == 0
|| strcmp (bfd_get_target (abfd), "mach-o") == 0;
}
size_t
inferior_read_memory_partial (CORE_ADDR addr, int nbytes, gdb_byte *mbuf)
{
size_t nbytes_read = 0;
int error = 0;
volatile struct gdb_exception except;
int old_trust_readonly = set_trust_readonly (0);
TRY_CATCH (except, RETURN_MASK_ERROR)
{
nbytes_read = target_read (¤t_target, TARGET_OBJECT_MEMORY, NULL,
mbuf, addr, nbytes);
}
set_trust_readonly (old_trust_readonly);
if (nbytes_read == 0)
{
bfd_set_error (bfd_error_system_call);
}
else if (nbytes_read < nbytes)
{
memset (mbuf + nbytes_read, 0, nbytes - nbytes_read);
}
return nbytes_read;
}
static file_ptr
inferior_read_generic (bfd *abfd, void *stream, void *data, file_ptr nbytes, file_ptr offset)
{
struct inferior_info *iptr = (struct inferior_info *) stream;
CHECK_FATAL (iptr != NULL);
if (!valid_target_for_inferior_bfd ())
{
bfd_set_error (bfd_error_no_contents);
return 0;
}
if (offset > iptr->len)
{
bfd_set_error (bfd_error_no_contents);
return 0;
}
return inferior_read_memory_partial (iptr->addr + offset, nbytes, data);
}
static file_ptr
inferior_read_mach_o (bfd *abfd, void *stream, void *data, file_ptr nbytes, file_ptr offset)
{
struct inferior_info *iptr = (struct inferior_info *) stream;
unsigned int i;
CHECK_FATAL (iptr != NULL);
if (!valid_target_for_inferior_bfd ())
{
bfd_set_error (bfd_error_no_contents);
return 0;
}
if (!bfd_target_is_mach_o (abfd))
{
bfd_set_error (bfd_error_invalid_target);
return 0;
}
{
struct mach_o_data_struct *mdata = NULL;
CHECK_FATAL (bfd_mach_o_valid (abfd));
mdata = abfd->tdata.mach_o_data;
if (mdata->scanning_load_cmds == 1)
{
bfd_set_error (bfd_error_invalid_target);
return 0;
}
for (i = 0; i < mdata->header.ncmds; i++)
{
struct bfd_mach_o_load_command *cmd = &mdata->commands[i];
if (cmd->type == 0)
break;
if (cmd->type == BFD_MACH_O_LC_SEGMENT
|| cmd->type == BFD_MACH_O_LC_SEGMENT_64)
{
struct bfd_mach_o_segment_command *segment =
&cmd->command.segment;
if ((offset >= segment->fileoff)
&& (offset < (segment->fileoff + segment->filesize)))
{
bfd_vma infaddr =
(segment->vmaddr + (offset - segment->fileoff));
if (iptr->offset == INVALID_ADDRESS)
{
asection *text_sect;
text_sect = bfd_get_section_by_name (abfd,
TEXT_SEGMENT_NAME);
if (text_sect)
{
bfd_vma slide = iptr->addr -
bfd_section_vma (abfd, text_sect);
infaddr = infaddr + slide;
}
}
else
{
infaddr = infaddr + iptr->offset;
}
return inferior_read_memory_partial (infaddr, nbytes, data);
}
}
}
}
bfd_set_error (bfd_error_no_contents);
return 0;
}
static file_ptr
inferior_read (bfd *abfd, void *stream, void *data, file_ptr nbytes, file_ptr offset)
{
file_ptr bytes_read = 0;
if (bfd_target_is_mach_o (abfd) && bfd_mach_o_valid (abfd))
{
bytes_read = inferior_read_mach_o (abfd, stream, data, nbytes, offset);
}
if (bytes_read == 0)
bytes_read = inferior_read_generic (abfd, stream, data, nbytes, offset);
return bytes_read;
}
static int
inferior_close (bfd *abfd, void *stream)
{
return 0;
}
static bfd *
inferior_bfd_generic (const char *name, CORE_ADDR addr, CORE_ADDR offset,
CORE_ADDR len)
{
struct inferior_info info;
char *filename = NULL;
bfd *abfd = NULL;
info.addr = addr;
info.offset = offset;
info.len = len;
info.read = 0;
if (name != NULL)
{
if (len == INVALID_ADDRESS)
xasprintf (&filename, "[memory object \"%s\" at 0x%s]",
name, paddr_nz (addr));
else
xasprintf (&filename, "[memory object \"%s\" at 0x%s for 0x%s]",
name, paddr_nz (addr), paddr_nz (len));
}
else
{
xasprintf (&filename, "[memory object at 0x%s for 0x%s]",
paddr_nz (addr), paddr_nz (len));
}
if (filename == NULL)
{
warning ("unable to allocate memory for filename for \"%s\"", name);
return NULL;
}
abfd = bfd_openr_iovec (filename, NULL,
inferior_open, &info,
inferior_read, inferior_close);
if (abfd == NULL)
{
warning ("Unable to open memory image for \"%s\"; skipping", name);
return NULL;
}
if (!bfd_check_format (abfd, bfd_object))
{
warning ("Unable to read symbols from %s: %s.", bfd_get_filename (abfd),
bfd_errmsg (bfd_get_error ()));
bfd_close (abfd);
return NULL;
}
return abfd;
}
bfd *
inferior_bfd (const char *name, CORE_ADDR addr, CORE_ADDR offset, CORE_ADDR len)
{
bfd *abfd = inferior_bfd_generic (name, addr, offset, len);
if (abfd == NULL)
return abfd;
return abfd;
}
int
macosx_bfd_is_in_memory (bfd *abfd)
{
if (abfd)
{
if (abfd->flags & BFD_IN_MEMORY)
return 1;
if (abfd->filename != NULL
&& strstr (abfd->filename, "[memory object") == abfd->filename)
return 1;
}
return 0;
}