This is the mail archive of the
binutils@sourceware.cygnus.com
mailing list for the binutils project.
Patch: access to an ELF file's program header table
- To: binutils at sourceware dot cygnus dot com
- Subject: Patch: access to an ELF file's program header table
- From: Jim Blandy <jimb at cygnus dot com>
- Date: Tue, 23 Nov 1999 14:34:14 -0500 (EST)
I've encountered a situation where I believe I need access to an ELF
file's program header table. I'll below why I think I need it, and
then include a patch which implements this. I'd be happy to hear
ideas about other ways to accomplish what I need to do, or suggestions
for better ways to extend BFD's interface. I'd also be happy to hear
that you like the patch as it stands. :)
HP-UX 11.00 running on a PA2.0 in wide mode uses ELF object files,
executables, and shared libraries. Cygnus has prepared a toolchain
that supports this configuration on a branch; I'm working on merging
the GDB-related changes into the main sources.
In order to debug code in a shared library, GDB needs to know the
offset between the load addresses given in the shared library file and
the addresses at which the dynamic linker actually loaded those parts
of the library. I think the ABI calls this the shared object file's
`base address', in Chapter 5. GDB uses the base address to find the
true addresses of things referred to in the debugging info.
Using the extant BFD interface, GDB can only find the load addresses
of *sections* in the shared library file. However, the HP-UX
interface to the dynamic linker provides only the addresses at which
it loaded the shared library's *segments*.
As I understand the ABI, there's no necessary relationship between the
segments and the sections. Segments may contain `holes' that are not
part of any section; a segment may even start with a hole. So, given
only the information mentioned above, GDB cannot compute the shared
library's base address, because it cannot assume any relationship
between the segments' loaded addresses and the section's addresses as
given in the ELF file.
In fact, HP-UX lays out its shared libraries like this:
$ readelf -l shr1.sl
Elf file is DYN (Shared object file)
Entry point 0x40000000000018b0
There are 4 program headers, starting at offset 40:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x4000000000001040 0x00000000 0x000e0 0x000e0 R E 0x8
LOAD 0x000000 0x4000000000001000 0x4000000000001000 0x00ad4 0x00ad4 RWE 0x1000
LOAD 0x001000 0x8000000000001000 0x8000000000001000 0x000c0 0x000c0 RW 0x1000
DYNAMIC 0x000120 0x4000000000001120 0x4000000000001120 0x000f0 0x000f0 RW 0x8
Section to Segment mapping:
Segment Sections...
00
01 .dynamic .hash .dynsym .dynstr .rela.opd .rela.dlt .rela.plt .text .rodata .PARISC.unwind
02 .data .opd .plt .dlt
03 .dynamic
$ objdump -h shr1.sl
shr1.sl: file format elf64-hppa
Sections:
Idx Name Size VMA LMA File off Algn
0 .dynamic 000000f0 4000000000001120 4000000000001120 00000120 2**3
CONTENTS, ALLOC, LOAD, DATA
1 .hash 00000140 4000000000001210 4000000000001210 00000210 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .dynsym 000003d8 4000000000001350 4000000000001350 00000350 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .dynstr 00000091 4000000000001728 4000000000001728 00000728 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .rela.opd 00000048 40000000000017c0 40000000000017c0 000007c0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .rela.dlt 00000090 4000000000001808 4000000000001808 00000808 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .rela.plt 00000018 4000000000001898 4000000000001898 00000898 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .init 00000000 40000000000018b0 40000000000018b0 000010c0 2**0
CONTENTS
8 .text 000001c4 40000000000018b0 40000000000018b0 000008b0 2**3
CONTENTS, ALLOC, LOAD, READONLY, CODE
9 .fini 00000000 4000000000001a74 4000000000001a74 000010c0 2**0
CONTENTS
10 .rodata 00000020 4000000000001a74 4000000000001a74 00000a74 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
11 .PARISC.unwind 00000040 4000000000001a94 4000000000001a94 00000a94 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
12 .data 0000001c 8000000000001000 8000000000001000 00001000 2**2
CONTENTS, ALLOC, LOAD, DATA
13 .opd 00000060 8000000000001020 8000000000001020 00001020 2**3
CONTENTS, ALLOC, LOAD, DATA
14 .plt 00000010 8000000000001080 8000000000001080 00001080 2**3
CONTENTS, ALLOC, LOAD, DATA
15 .dlt 00000030 8000000000001090 8000000000001090 00001090 2**3
CONTENTS, ALLOC, LOAD, DATA
16 .bss 00000000 80000000000010c0 80000000000010c0 000010c0 2**0
ALLOC
17 .debug_aranges 00000030 0000000000000000 0000000000000000 000010c0 2**0
CONTENTS, READONLY, DEBUGGING
18 .debug_pubnames 00000047 0000000000000000 0000000000000000 000010f0 2**0
CONTENTS, READONLY, DEBUGGING
19 .debug_info 00000d30 0000000000000000 0000000000000000 00001137 2**0
CONTENTS, READONLY, DEBUGGING
20 .debug_abbrev 00000116 0000000000000000 0000000000000000 00001e67 2**0
CONTENTS, READONLY, DEBUGGING
21 .debug_line 000000a3 0000000000000000 0000000000000000 00001f7d 2**0
CONTENTS, READONLY, DEBUGGING
Note that the text segment starts at file offset zero, while there is
no section which begins at file offset zero. Since the dynamic
linker's debug interface tells GDB only the address at which the text
segment was loaded, GDB needs to know the address attributed to the
text segment in the ELF file.
Here is a patch which gives BFD clients the ability to read an ELF
file's program header table, in its byte-swapped form:
1999-11-11 Jim Blandy <jimb@cris.red-bean.com>
* elf.c (bfd_get_elf_phdrs, bfd_get_elf_phdr_upper_bound): New
functions.
* bfd-in2.h (bfd_get_elf_phdrs, bfd_get_elf_phdr_upper_bound): New
declarations.
Index: bfd/bfd-in2.h
===================================================================
RCS file: /cvs/cvsfiles/devo/bfd/bfd-in2.h,v
retrieving revision 1.347.8.1
diff -c -r1.347.8.1 bfd-in2.h
*** bfd/bfd-in2.h 1999/09/19 00:59:41 1.347.8.1
--- bfd/bfd-in2.h 1999/11/15 17:57:13
***************
*** 3074,3079 ****
--- 3074,3095 ----
CONST char *
bfd_format_string PARAMS ((bfd_format format));
+
+ /* Return an upper bound on the number of bytes required to store a
+ copy of ABFD's program header table entries. Return -1 if an error
+ occurs; bfd_get_error will return an appropriate code. */
+ extern long bfd_get_elf_phdr_upper_bound PARAMS ((bfd *abfd));
+
+ /* Copy ABFD's program header table entries to *PHDRS. The entries
+ will be stored as an array of Elf_Internal_Phdr structures, as
+ defined in include/elf/internal.h. To find out how large the
+ buffer needs to be, call bfd_get_elf_phdr_upper_bound.
+
+ Return the number of program header table entries read, or -1 if an
+ error occurs; bfd_get_error will return an appropriate code. */
+ extern int bfd_get_elf_phdrs PARAMS ((bfd *abfd, void *phdrs));
+
+
#ifdef __cplusplus
}
#endif
Index: bfd/elf.c
===================================================================
RCS file: /cvs/cvsfiles/devo/bfd/elf.c,v
retrieving revision 1.240.24.3
diff -c -r1.240.24.3 elf.c
*** bfd/elf.c 1999/10/26 20:20:31 1.240.24.3
--- bfd/elf.c 1999/11/15 17:57:15
***************
*** 5344,5346 ****
--- 5344,5394 ----
return true;
}
+
+
+ /* Providing external access to the ELF program header table. */
+
+ /* Return an upper bound on the number of bytes required to store a
+ copy of ABFD's program header table entries. Return -1 if an error
+ occurs; bfd_get_error will return an appropriate code. */
+ long
+ bfd_get_elf_phdr_upper_bound (abfd)
+ bfd *abfd;
+ {
+ if (abfd->xvec->flavour != bfd_target_elf_flavour)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return -1;
+ }
+
+ return (elf_elfheader (abfd)->e_phnum
+ * sizeof (Elf_Internal_Phdr));
+ }
+
+
+ /* Copy ABFD's program header table entries to *PHDRS. The entries
+ will be stored as an array of Elf_Internal_Phdr structures, as
+ defined in include/elf/internal.h. To find out how large the
+ buffer needs to be, call bfd_get_elf_phdr_upper_bound.
+
+ Return the number of program header table entries read, or -1 if an
+ error occurs; bfd_get_error will return an appropriate code. */
+ int
+ bfd_get_elf_phdrs (abfd, phdrs)
+ bfd *abfd;
+ void *phdrs;
+ {
+ int num_phdrs;
+
+ if (abfd->xvec->flavour != bfd_target_elf_flavour)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return -1;
+ }
+
+ num_phdrs = elf_elfheader (abfd)->e_phnum;
+ memcpy (phdrs, elf_tdata (abfd)->phdr,
+ num_phdrs * sizeof (Elf_Internal_Phdr));
+
+ return num_phdrs;
+ }