This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [ppc64-linux]: correctly find a BFD's code entry point address
Kevin Buettner <kevinb@redhat.com> writes:
> On Jun 12, 6:12pm, Jim Blandy wrote:
>
> > + /* Return the unrelocated code address at which execution begins for
> > + ABFD, under the 64-bit PowerPC Linux ABI. On that system, the ELF
> > + header e_entry field (which is what bfd_get_start_address gives
> > + you) is the address of the function descriptor for the startup
> > + function, not the address of the actual machine instruction you
> > + jump to.
> > +
> > + This function doesn't just go and read the entry point from the
> > + function descriptor. We need it to work when ABFD is the dynamic
> > + linker, immediately after an exec. But ld.so is a dynamic
> > + executable itself on PPC64 Linux, so it appears in memory whereever
> > + the kernel drops it; this means that bfd_get_start_address's result
> > + needs to be adjusted --- by some offset we don't know. So we can't
> > + find the descriptor's address in memory to read the entry point
> > + from it.
> > +
> > + Instead, we do it all based on ABFD's symbol table. We take the
> > + address from bfd_get_start_address, find each symbol at that
> > + address, stick a '.' on the front of its name to get the entry
> > + point symbol name, try to look that up, and return the value of
> > + what we find, if anything. We never touch memory, or talk with the
> > + kernel about the inferior at all.
> > +
> > + Now, this address we return is straight from the symbol table, so
> > + it hasn't been adjusted to take into account where ABFD was loaded.
> > + But that's okay --- our job is just to return the unrelocated code
> > + address. */
>
> This approach strikes me as somewhat more complicated (and fragile)
> than need be. I think it would be preferable to simply fetch the
> necessary bytes from the address given by bfd_get_start_address in the
> executable (or object) file.
>
> Nice description though; I really appreciate comments like this.
Thanks! I redid the patch as you suggest, and it's much smaller and
simpler. How's this:
2003-06-12 Jim Blandy <jimb@redhat.com>
* ppc-linux-tdep.c (ppc64_linux_bfd_entry_point): New function.
(ppc_linux_init_abi): Register it as our bfd_entry_point method.
Index: gdb/ppc-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-linux-tdep.c,v
retrieving revision 1.32
diff -c -r1.32 ppc-linux-tdep.c
*** gdb/ppc-linux-tdep.c 13 Jun 2003 00:06:11 -0000 1.32
--- gdb/ppc-linux-tdep.c 13 Jun 2003 22:46:59 -0000
***************
*** 884,889 ****
--- 884,935 ----
}
+ /* Return the unrelocated code address at which execution begins for
+ ABFD, under the 64-bit PowerPC Linux ABI.
+
+ On that system, the ELF header's e_entry field (which is what
+ bfd_get_start_address gives you) is not the address of the actual
+ machine instruction you need to jump to, as it is on almost every
+ other target. Instead, it's the address of a function descriptor
+ for the start function. A function descriptor is a structure
+ containing three addresses: the entry point, the TOC pointer for
+ the function, and an environment pointer for the function. The
+ first field is what we want to return.
+
+ So all we do is find the section containing the start address, read
+ the address-sized word there out of the BFD, and return that. */
+ static CORE_ADDR
+ ppc64_linux_bfd_entry_point (struct gdbarch *gdbarch, bfd *abfd)
+ {
+ CORE_ADDR start_address = bfd_get_start_address (abfd);
+ CORE_ADDR addr_size = (bfd_arch_bits_per_address (abfd)
+ / bfd_arch_bits_per_byte (abfd));
+ unsigned char *entry_pt_buf = alloca (addr_size);
+ asection *sec;
+
+ /* Find a data section containing an address word at the start
+ address. */
+ for (sec = abfd->sections; sec; sec = sec->next)
+ if (bfd_get_section_vma (sec) <= start_address
+ && ((start_address + addr_size)
+ <= (bfd_get_section_vma (sec) + bfd_section_size (sec))))
+ break;
+ if (! sec)
+ return 0;
+
+ /* Seek to the start address, and read the address word there. */
+ if (bfd_seek (abfd,
+ sec->filepos + (start_address - bfd_get_section_vma (sec)),
+ SEEK_SET)
+ || bfd_bread (entry_pt_buf, addr_size, abfd) != addr_size)
+ return 0;
+
+ /* That's the actual code entry point. */
+ return (CORE_ADDR) bfd_get (bfd_arch_bits_per_address (abfd),
+ abfd, entry_pt_buf);
+ }
+
+
enum {
ELF_NGREG = 48,
ELF_NFPREG = 33,
***************
*** 1008,1013 ****
--- 1054,1061 ----
set_gdbarch_in_solib_call_trampoline
(gdbarch, ppc64_in_solib_call_trampoline);
set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
+
+ set_gdbarch_bfd_entry_point (gdbarch, ppc64_linux_bfd_entry_point);
}
}