summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2003-05-21 00:56:05 +0000
committerRoland McGrath <roland@gnu.org>2003-05-21 00:56:05 +0000
commitaf627aec280d9e941b2d5085faf84d1af04ed4f7 (patch)
tree72e59c7821919078b8bce97760e191b4b1136a1e
parentb839f0f0f960a704184ba4b84e2b560d3870c9cd (diff)
downloadgdb-af627aec280d9e941b2d5085faf84d1af04ed4f7.tar.gz
2003-05-19 Roland McGrath <roland@redhat.com>
* elf.c (bfd_elf_bfd_from_remote_memory): New function. * bfd-in.h: Declare it. * elfcode.h (NAME(_bfd_elf,bfd_from_remote_memory)): New function. * elf-bfd.h (struct elf_backend_data): New function pointer member elf_backend_bfd_from_remote_memory. (_bfd_elf32_bfd_from_remote_memory, _bfd_elf64_bfd_from_remote_memory): Declare them. * elfxx-target.h (elf_backend_bfd_from_remote_memory): New macro. (elfNN_bed): Add that to the initializer.
-rw-r--r--bfd/bfd-in.h17
-rw-r--r--bfd/elf-bfd.h13
-rw-r--r--bfd/elfcode.h226
-rw-r--r--bfd/elfxx-target.h4
4 files changed, 259 insertions, 1 deletions
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 93fd0fd13b3..703f328bfbe 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -694,6 +694,22 @@ extern long bfd_get_elf_phdr_upper_bound
extern int bfd_get_elf_phdrs
PARAMS ((bfd *abfd, void *phdrs));
+/* Create a new BFD as if by bfd_openr. Rather than opening a file,
+ reconstruct an ELF file by reading the segments out of remote memory
+ based on the ELF file header at EHDR_VMA and the ELF program headers it
+ points to. If not null, *LOADBASEP is filled in with the difference
+ between the VMAs from which the segments were read, and the VMAs the
+ file headers (and hence BFD's idea of each section's VMA) put them at.
+
+ The function TARGET_READ_MEMORY is called to copy LEN bytes from the
+ remote memory at target address VMA into the local buffer at MYADDR; it
+ should return zero on success or an `errno' code on failure. TEMPL must
+ be a BFD for an ELF target with the word size and byte order found in
+ the remote memory. */
+extern bfd *bfd_elf_bfd_from_remote_memory
+ PARAMS ((bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep,
+ int (*target_read_memory) (bfd_vma vma, char *myaddr, int len)));
+
/* Return the arch_size field of an elf bfd, or -1 if not elf. */
extern int bfd_get_arch_size
PARAMS ((bfd *));
@@ -849,4 +865,3 @@ extern void bfd_ticoff_set_section_load_page
extern int bfd_ticoff_get_section_load_page
PARAMS ((struct sec *));
-
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 46f612a63d2..1da605502b5 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -875,6 +875,12 @@ struct elf_backend_data
Used for the MIPS ELF .mdebug section. */
const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap;
+ /* This function implements `bfd_elf_bfd_from_remote_memory';
+ see elf.c, elfcode.h. */
+ bfd *(*elf_backend_bfd_from_remote_memory)
+ PARAMS ((bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep,
+ int (*target_read_memory) (bfd_vma vma, char *myaddr, int len)));
+
/* Alternate EM_xxxx machine codes for this backend. */
int elf_machine_alt1;
int elf_machine_alt2;
@@ -1750,6 +1756,13 @@ extern char *elfcore_write_prxfpreg
extern char *elfcore_write_lwpstatus
PARAMS ((bfd *, char *, int *, long, int, const PTR));
+extern bfd *_bfd_elf32_bfd_from_remote_memory
+ PARAMS ((bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep,
+ int (*target_read_memory) (bfd_vma, char *, int)));
+extern bfd *_bfd_elf64_bfd_from_remote_memory
+ PARAMS ((bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep,
+ int (*target_read_memory) (bfd_vma, char *, int)));
+
/* SH ELF specific routine. */
extern bfd_boolean _sh_elf_set_mach_from_flags
diff --git a/bfd/elfcode.h b/bfd/elfcode.h
index 0be8048a041..55c5b4264e0 100644
--- a/bfd/elfcode.h
+++ b/bfd/elfcode.h
@@ -1568,6 +1568,232 @@ elf_symbol_flags (flags)
}
#endif
+/* Create a new BFD as if by bfd_openr. Rather than opening a file,
+ reconstruct an ELF file by reading the segments out of remote memory
+ based on the ELF file header at EHDR_VMA and the ELF program headers it
+ points to. If not null, *LOADBASEP is filled in with the difference
+ between the VMAs from which the segments were read, and the VMAs the
+ file headers (and hence BFD's idea of each section's VMA) put them at.
+
+ The function TARGET_READ_MEMORY is called to copy LEN bytes from the
+ remote memory at target address VMA into the local buffer at MYADDR; it
+ should return zero on success or an `errno' code on failure. TEMPL must
+ be a BFD for a target with the word size and byte order found in the
+ remote memory. */
+
+bfd *
+NAME(_bfd_elf,bfd_from_remote_memory) (templ, ehdr_vma, loadbasep,
+ target_read_memory)
+ bfd *templ;
+ bfd_vma ehdr_vma;
+ bfd_vma *loadbasep;
+ int (*target_read_memory) PARAMS ((bfd_vma vma, char *myaddr, int len));
+{
+ Elf_External_Ehdr x_ehdr; /* Elf file header, external form */
+ Elf_Internal_Ehdr i_ehdr; /* Elf file header, internal form */
+ Elf_External_Phdr *x_phdrs;
+ Elf_Internal_Phdr *i_phdrs, *last_phdr;
+ bfd *nbfd;
+ struct bfd_in_memory *bim;
+ int contents_size;
+ char *contents;
+ int err;
+ unsigned int i;
+ bfd_vma loadbase;
+
+ /* Read in the ELF header in external format. */
+ err = target_read_memory (ehdr_vma, (char *) &x_ehdr, sizeof x_ehdr);
+ if (err)
+ {
+ bfd_set_error (bfd_error_system_call);
+ errno = err;
+ return NULL;
+ }
+
+ /* Now check to see if we have a valid ELF file, and one that BFD can
+ make use of. The magic number must match, the address size ('class')
+ and byte-swapping must match our XVEC entry. */
+
+ if (! elf_file_p (&x_ehdr)
+ || x_ehdr.e_ident[EI_VERSION] != EV_CURRENT
+ || x_ehdr.e_ident[EI_CLASS] != ELFCLASS)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ /* Check that file's byte order matches xvec's */
+ switch (x_ehdr.e_ident[EI_DATA])
+ {
+ case ELFDATA2MSB: /* Big-endian */
+ if (! bfd_header_big_endian (templ))
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+ break;
+ case ELFDATA2LSB: /* Little-endian */
+ if (! bfd_header_little_endian (templ))
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+ break;
+ case ELFDATANONE: /* No data encoding specified */
+ default: /* Unknown data encoding specified */
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ elf_swap_ehdr_in (templ, &x_ehdr, &i_ehdr);
+
+ /* The file header tells where to find the program headers.
+ These are what we use to actually choose what to read. */
+
+ if (i_ehdr.e_phentsize != sizeof (Elf_External_Phdr) || i_ehdr.e_phnum == 0)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ x_phdrs = (Elf_External_Phdr *)
+ bfd_malloc (i_ehdr.e_phnum * (sizeof *x_phdrs + sizeof *i_phdrs));
+ if (x_phdrs == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ err = target_read_memory (ehdr_vma + i_ehdr.e_phoff, (char *) x_phdrs,
+ i_ehdr.e_phnum * sizeof x_phdrs[0]);
+ if (err)
+ {
+ free (x_phdrs);
+ bfd_set_error (bfd_error_system_call);
+ errno = err;
+ return NULL;
+ }
+ i_phdrs = (Elf_Internal_Phdr *) &x_phdrs[i_ehdr.e_phnum];
+
+ contents_size = 0;
+ last_phdr = NULL;
+ loadbase = ehdr_vma;
+ for (i = 0; i < i_ehdr.e_phnum; ++i)
+ {
+ elf_swap_phdr_in (templ, &x_phdrs[i], &i_phdrs[i]);
+ if (i_phdrs[i].p_type == PT_LOAD)
+ {
+ bfd_vma segment_end;
+ segment_end = (i_phdrs[i].p_offset + i_phdrs[i].p_filesz
+ + i_phdrs[i].p_align - 1) & -i_phdrs[i].p_align;
+ if (segment_end > (bfd_vma) contents_size)
+ contents_size = segment_end;
+
+ if ((i_phdrs[i].p_offset & -i_phdrs[i].p_align) == 0)
+ loadbase = ehdr_vma - (i_phdrs[i].p_vaddr & -i_phdrs[i].p_align);
+
+ last_phdr = &i_phdrs[i];
+ }
+ }
+ if (last_phdr == NULL)
+ {
+ /* There were no PT_LOAD segments, so we don't have anything to read. */
+ free (x_phdrs);
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ /* Trim the last segment so we don't bother with zeros in the last page
+ that are off the end of the file. However, if the extra bit in that
+ page includes the section headers, keep them. */
+ if ((bfd_vma) contents_size > last_phdr->p_offset + last_phdr->p_filesz
+ && (bfd_vma) contents_size >= (i_ehdr.e_shoff
+ + i_ehdr.e_shnum * i_ehdr.e_shentsize))
+ {
+ contents_size = last_phdr->p_offset + last_phdr->p_filesz;
+ if ((bfd_vma) contents_size < (i_ehdr.e_shoff
+ + i_ehdr.e_shnum * i_ehdr.e_shentsize))
+ contents_size = i_ehdr.e_shoff + i_ehdr.e_shnum * i_ehdr.e_shentsize;
+ }
+ else
+ contents_size = last_phdr->p_offset + last_phdr->p_filesz;
+
+ /* Now we know the size of the whole image we want read in. */
+ contents = (char *) bfd_zmalloc ((bfd_size_type) contents_size);
+ if (contents == NULL)
+ {
+ free (x_phdrs);
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ for (i = 0; i < i_ehdr.e_phnum; ++i)
+ if (i_phdrs[i].p_type == PT_LOAD)
+ {
+ bfd_vma start = i_phdrs[i].p_offset & -i_phdrs[i].p_align;
+ bfd_vma end = (i_phdrs[i].p_offset + i_phdrs[i].p_filesz
+ + i_phdrs[i].p_align - 1) & -i_phdrs[i].p_align;
+ if (end > (bfd_vma) contents_size)
+ end = contents_size;
+ err = target_read_memory ((loadbase + i_phdrs[i].p_vaddr)
+ & -i_phdrs[i].p_align,
+ contents + start, end - start);
+ if (err)
+ {
+ free (x_phdrs);
+ free (contents);
+ bfd_set_error (bfd_error_system_call);
+ errno = err;
+ return NULL;
+ }
+ }
+ free (x_phdrs);
+
+ /* If the segments visible in memory didn't include the section headers,
+ then clear them from the file header. */
+ if ((bfd_vma) contents_size < (i_ehdr.e_shoff
+ + i_ehdr.e_shnum * i_ehdr.e_shentsize))
+ {
+ memset (&x_ehdr.e_shoff, 0, sizeof x_ehdr.e_shoff);
+ memset (&x_ehdr.e_shnum, 0, sizeof x_ehdr.e_shnum);
+ memset (&x_ehdr.e_shstrndx, 0, sizeof x_ehdr.e_shstrndx);
+ }
+
+ /* This will normally have been in the first PT_LOAD segment. But it
+ conceivably could be missing, and we might have just changed it. */
+ memcpy (contents, &x_ehdr, sizeof x_ehdr);
+
+ /* Now we have a memory image of the ELF file contents. Make a BFD. */
+ bim = ((struct bfd_in_memory *)
+ bfd_malloc ((bfd_size_type) sizeof (struct bfd_in_memory)));
+ if (bim == NULL)
+ {
+ free (contents);
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ nbfd = _bfd_new_bfd ();
+ if (nbfd == NULL)
+ {
+ free (bim);
+ free (contents);
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ nbfd->filename = "<in-memory>";
+ nbfd->xvec = templ->xvec;
+ bim->size = contents_size;
+ bim->buffer = contents;
+ nbfd->iostream = (PTR) bim;
+ nbfd->flags = BFD_IN_MEMORY;
+ nbfd->direction = read_direction;
+ nbfd->mtime = time (NULL);
+ nbfd->mtime_set = TRUE;
+
+ if (loadbasep)
+ *loadbasep = loadbase;
+ return nbfd;
+}
+
#include "elfcore.h"
#include "elflink.h"
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 734d78bb75e..58a96b14a01 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -338,6 +338,9 @@
#ifndef elf_backend_ecoff_debug_swap
#define elf_backend_ecoff_debug_swap 0
#endif
+#ifndef elf_backend_bfd_from_remote_memory
+#define elf_backend_bfd_from_remote_memory _bfd_elfNN_bfd_from_remote_memory
+#endif
#ifndef elf_backend_got_header_size
#define elf_backend_got_header_size 0
#endif
@@ -490,6 +493,7 @@ static const struct elf_backend_data elfNN_bed =
elf_backend_mips_irix_compat,
elf_backend_mips_rtype_to_howto,
elf_backend_ecoff_debug_swap,
+ elf_backend_bfd_from_remote_memory,
ELF_MACHINE_ALT1,
ELF_MACHINE_ALT2,
&elf_backend_size_info,