Per email from Harish Babu (harish.b310@gmail.com)
Hi,
I have a question regarding the code for ELF files parsing(Linux).
Looking at the code below it appears the relative offset address is sent
like the below code:
os::dll_address_to_function_name() {
....
Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
buf, buflen, offset, dlinfo.dli_fname))
....
}
This works well for most of the libraries which are not prelinked at
particular address where the symbol tables are relative offsets.
But when the libraries are prelinked at an address this does not work well.
Like libc,
readelf -l /lib64/libc.so.6
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x00000038e7400040 0x00000038e7400040
0x0000000000000230 0x0000000000000230 R E 8
INTERP 0x000000000013ff60 0x00000038e753ff60 0x00000038e753ff60
0x000000000000001c 0x000000000000001c R 10
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x00000038e7400000 0x00000038e7400000
0x000000000016f150 0x000000000016f150 R E 200000
LOAD 0x000000000016f720 0x00000038e776f720 0x00000038e776f720
0x0000000000004678 0x0000000000009188 RW 200000
Where libc may(or may not) be loaded at a base address 0x38e7400000, and
the addresses are the absolute address rather than relative offsets.
131: 00000038e74274b0 192 FUNC LOCAL DEFAULT 12 open_translit
132: 00000038e7773f78 4 OBJECT LOCAL DEFAULT 34 lock
133: 00000038e7427c82 31 FUNC LOCAL DEFAULT 12 _L_lock_107
134: 00000038e7427810 11 FUNC LOCAL DEFAULT 12 trans_compare
135: 00000038e7773f70 8 OBJECT LOCAL DEFAULT 34 search_tree
136: 00000038e7427ca1 31 FUNC LOCAL DEFAULT 12 _L_unlock_135
For pthread(which is not prelinked to an address) which the current code
deals with correctly there is only relative addresses in the ELF file:
121: 000000000000da48 19 FUNC LOCAL DEFAULT 14 sem_wait_cleanup
122: 000000000000dc15 19 FUNC LOCAL DEFAULT 14
sem_timedwait_cleanup
123: 000000000000dc28 31 FUNC LOCAL DEFAULT 14
sem_timedwait_cleanup2
124: 000000000000df50 33 FUNC LOCAL DEFAULT 14 unwind_cleanup
125: 000000000000df80 287 FUNC LOCAL DEFAULT 14 unwind_stop
126: 000000000000e800 237 FUNC LOCAL DEFAULT 14 do_fcntl
So like I mentioned earlier, the code os::dll_address_to_function_name
subtracts the base address where the library was loaded from the current
pc. This results in relative offset which may not work well for the
libraries which are prelinked to an address.
Please let me know if I got it completely wrong.
Thanks,
Harish
Here is my current idea for the fix
FWIK, the first PT_LOAD.p_vaddr in the program header holds the base address for the library which hints the loader and all the other addresses in the file are based on this address. So for each .so file we can remember this in a class variable of ElfFile. And change the call in ElfFile::decode to:
symbol_table->lookup(addr+(First_PT_LOAD.p_vaddr), &string_table_index, &pos_in_string_table, &off)
Should probably fix the issue for all the cases.
Thanks,
Harish
Hi,
I have a question regarding the code for ELF files parsing(Linux).
Looking at the code below it appears the relative offset address is sent
like the below code:
os::dll_address_to_function_name() {
....
Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
buf, buflen, offset, dlinfo.dli_fname))
....
}
This works well for most of the libraries which are not prelinked at
particular address where the symbol tables are relative offsets.
But when the libraries are prelinked at an address this does not work well.
Like libc,
readelf -l /lib64/libc.so.6
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x00000038e7400040 0x00000038e7400040
0x0000000000000230 0x0000000000000230 R E 8
INTERP 0x000000000013ff60 0x00000038e753ff60 0x00000038e753ff60
0x000000000000001c 0x000000000000001c R 10
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x00000038e7400000 0x00000038e7400000
0x000000000016f150 0x000000000016f150 R E 200000
LOAD 0x000000000016f720 0x00000038e776f720 0x00000038e776f720
0x0000000000004678 0x0000000000009188 RW 200000
Where libc may(or may not) be loaded at a base address 0x38e7400000, and
the addresses are the absolute address rather than relative offsets.
131: 00000038e74274b0 192 FUNC LOCAL DEFAULT 12 open_translit
132: 00000038e7773f78 4 OBJECT LOCAL DEFAULT 34 lock
133: 00000038e7427c82 31 FUNC LOCAL DEFAULT 12 _L_lock_107
134: 00000038e7427810 11 FUNC LOCAL DEFAULT 12 trans_compare
135: 00000038e7773f70 8 OBJECT LOCAL DEFAULT 34 search_tree
136: 00000038e7427ca1 31 FUNC LOCAL DEFAULT 12 _L_unlock_135
For pthread(which is not prelinked to an address) which the current code
deals with correctly there is only relative addresses in the ELF file:
121: 000000000000da48 19 FUNC LOCAL DEFAULT 14 sem_wait_cleanup
122: 000000000000dc15 19 FUNC LOCAL DEFAULT 14
sem_timedwait_cleanup
123: 000000000000dc28 31 FUNC LOCAL DEFAULT 14
sem_timedwait_cleanup2
124: 000000000000df50 33 FUNC LOCAL DEFAULT 14 unwind_cleanup
125: 000000000000df80 287 FUNC LOCAL DEFAULT 14 unwind_stop
126: 000000000000e800 237 FUNC LOCAL DEFAULT 14 do_fcntl
So like I mentioned earlier, the code os::dll_address_to_function_name
subtracts the base address where the library was loaded from the current
pc. This results in relative offset which may not work well for the
libraries which are prelinked to an address.
Please let me know if I got it completely wrong.
Thanks,
Harish
Here is my current idea for the fix
FWIK, the first PT_LOAD.p_vaddr in the program header holds the base address for the library which hints the loader and all the other addresses in the file are based on this address. So for each .so file we can remember this in a class variable of ElfFile. And change the call in ElfFile::decode to:
symbol_table->lookup(addr+(First_PT_LOAD.p_vaddr), &string_table_index, &pos_in_string_table, &off)
Should probably fix the issue for all the cases.
Thanks,
Harish