From dwfl_module_getdwarf: @@ -96,11 +100,18 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file) goto elf_error; if (ph->p_type == PT_LOAD) { - file->bias = ((mod->low_addr & -ph->p_align) - - (ph->p_vaddr & -ph->p_align)); + // Align the vaddr. + fprintf(stderr, "mod->low_addr 0x%lx\n", mod->low_addr); + fprintf(stderr, "ph->p_align 0x%lx\n", ph->p_align); + Dwarf_Addr vaddr = ph->p_vaddr & -ph->p_align; + fprintf(stderr, "vaddr 0x%lx\n", vaddr); + file->bias = (mod->low_addr - (ph->p_vaddr & -ph->p_align)); + fprintf(stderr, "setting file bias to something complex 0x%lx\n", + file->bias); break; } } + }
for instance, an solib mapped at: low 0x2aaab0508000 high 0x2aaab07dc000 with alignment 0x200000, will result in a bias of 0x2aaab0400000, when it should just be the low address
Created attachment 308608 [details] don't align module's load address
Andrew, your patch looks sensible to me. Having a testcase would be a plus. How did you triggered this code path? I tried a few things and I invariably find mod->main.elf != NULL here, thus open_elf (where you fixed file->bias calculation) is not reached: find_file (Dwfl_Module *mod) { if (mod->main.elf != NULL /* Already done. */ || mod->elferr != DWFL_E_NOERROR) /* Cached failure. */ return; mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod), &mod->main.name, &mod->main.elf); mod->elferr = open_elf (mod, &mod->main);
(In reply to comment #3) > Andrew, your patch looks sensible to me. Having a testcase would be a plus. > > How did you triggered this code path? I tried a few things and I invariably > find mod->main.elf != NULL here, thus open_elf (where you fixed file->bias > calculation) is not reached: Good question, my only note is that it occures with a shared executable, not the main program.
I was trying to find a way to trigger this bug using freshly built elfutils. The closest thing I came up with is: Make a split debug info out of a .so file foo=src/libld_elf_i386.so cp $foo $foo.backup objcopy --only-keep-debug $foo $foo.dbg objcopy --strip-debug $foo objcopy --add-gnu-debuglink=$foo.dbg $foo and then run readelf on it: LD_LIBRARY_PATH=libelf:libdw:backends src/readelf -w src/libld_elf_i386.so My instrumented version prints: __libdwfl_report_elf: entered __libdwfl_report_elf: ET_DYN __libdwfl_report_elf: default base 0x0 ph->p_align 0x200000 start 0x0 bias 0x0 ZZ ->main.elf:=0x11bb070, ->main.bias:=0 HERE2: dwfl_module_getelf HERE3: dwfl_module_getelf HERE4: find_file mod->main.elf:0x11bb070 HERE4: find_file mod->main.elf:0x11bb070 find_debuglink: return 'libld_elf_i386.so.dbg' HERE6: open_elf open_elf:63 open_elf:66 open_elf: file->name:'(null)' return CBFAIL src/readelf: cannot get debug context descriptor: No DWARF information found Had open_elf() non-NULL finename, it would open it and try to calculate bias. But readelf seems to be restricted to not read separate debug infos, thus it has NULL name there.
This message is a reminder that Fedora 8 is nearing its end of life. Approximately 30 (thirty) days from now Fedora will stop maintaining and issuing updates for Fedora 8. It is Fedora's policy to close all bug reports from releases that are no longer maintained. At that time this bug will be closed as WONTFIX if it remains open with a Fedora 'version' of '8'. Package Maintainer: If you wish for this bug to remain open because you plan to fix it in a currently maintained version, simply change the 'version' to a later Fedora version prior to Fedora 8's end of life. Bug Reporter: Thank you for reporting this issue and we are sorry that we may not be able to fix it before Fedora 8 is end of life. If you would still like to see this bug fixed and are able to reproduce it against a later version of Fedora please change the 'version' of this bug to the applicable version. If you are unable to change the version, please add a comment here and someone will do it for you. Although we aim to fix as many bugs as possible during every release's lifetime, sometimes those efforts are overtaken by events. Often a more recent Fedora release includes newer upstream software that fixes bugs or makes them obsolete. The process we are following is described here: http://fedoraproject.org/wiki/BugZappers/HouseKeeping
Still a bug I think, should cons a proper test case.
Constructing a testcase is slightly hard since it seems to involve (according to comment #1) a shared library with a PT_LOAD address (the mod->low_addr) that is not aligned according to ph->p_align. I am unsure how to construct such a thing. The best I can do is something like in comment #5, take any library foo and do something like: cp $foo $foo.backup objcopy --only-keep-debug $foo $foo.dbg objcopy --strip-debug $foo objcopy --add-gnu-debuglink=$foo.dbg $foo prelink -v -r 0x650000 $foo except that last command will not work: prelink: liblibrary.so: PT_LOAD 00000000 0650000 0x200000 would be not properly aligned But the above would give you something which you can then process with: cat rh450218.c #include <stdio.h> #include <stdlib.h> #include <elfutils/libdw.h> #include <elfutils/libdwfl.h> static void error () { printf ("dwfl_errmsg: %s\n", dwfl_errmsg(-1)); abort (); } static int query_module (Dwfl_Module *mod, void **user, const char *name, Dwarf_Addr base, void *arg) { Dwarf_Addr dwarf_bias; Dwarf *dwarf = dwfl_module_getdwarf(mod, &dwarf_bias); if (! dwarf) error(); printf("dwarf_bias: %#llx\n", (unsigned long long int) dwarf_bias); Dwarf_Addr start, end, dwbias, symbias; const char *mainfile, *debugfile; const char *info = dwfl_module_info (mod, NULL, &start, &end, &dwbias, &symbias, &mainfile, &debugfile); printf("Module: %s@%#llx\n", name, (unsigned long long int) base); printf("info: %s, start@%#llx, end@%#llx\n", info, (unsigned long long int) start, (unsigned long long int) end); printf(" dwbias:%#llx, symbias:%#llx\n", (unsigned long long int) dwbias, (unsigned long long int) symbias); printf(" %s:%s\n", mainfile, debugfile); return DWARF_CB_OK; } int main (int argc, const char **argv) { int i, r; printf("Processing... %s\n", argv[1]); static char *debugpath = "+:.debug:/usr/lib/debug:build"; static const Dwfl_Callbacks user_callbacks = { NULL, dwfl_standard_find_debuginfo, dwfl_offline_section_address, &debugpath }; Dwfl *dwfl = dwfl_begin (&user_callbacks); if (! dwfl) error (); dwfl_report_begin (dwfl); for (i = 1; i < argc; i++) { Dwfl_Module *m = dwfl_report_offline (dwfl, argv[i], argv[i], -1); if (! m) error (); } r = dwfl_report_end (dwfl, NULL, NULL); if (r != 0) error(); r = dwfl_getmodules (dwfl, &query_module, NULL, 0); if (r == -1) error(); printf ("Done...\n"); return 0; } gcc -ldw -o rh450218 rh450218.c ./rh450218 liblibrary.so Processing... liblibrary.so dwarf_bias: 0x64200000 Module: liblibrary.so@0x64200000 info: liblibrary.so, start@0x64200000, end@0x64400860 dwbias:0x64200000, symbias:0xffffffffffffffff liblibrary.so:liblibrary.so.dbg Done...
Right, prelink won't do it, but it could happen at runtime. p_align says the smallest alignment that we can assume at build time (and prelink time) the system will enforce when it uses the object. The actual alignment (i.e. page size) used at run time might be smaller than that (but never larger). prelink correctly refuses to leave the binary on disk such that it would require a smaller largest page size than the original binary did. So the test you need is using a Dwfl not in offline mode but some other way, where you can arrange that the runtime load address is off-aligned. You could create that with an explicit mmap of a DSO (doesn't really matter if it is loaded properly, just mapped into memory makes libdwfl see it) using MAP_FIXED, and then use -p or suchlike. Probably simplest is to just create the situation synthetically using dwfl_report_elf with a chosen address.
I see frysk used elf_from_remote_memory () supplying its own read_memory () implementation to feed libdwfl either a ptraced proc or core file. But elf_from_remote_memory doesn't seem to actually be provided in any header though it is exported. Using that is extremely sneaky. You won't get something like that even with dwfl_report_elf () since it will sanitize the given base against ph->p_align for ET_DYN and just ignore it for ET_EXEC and ET_CORE.
Oh, dwfl_report_elf shaving the address more than dwfl->segment_align is a bug.
This message is a reminder that Fedora 10 is nearing its end of life. Approximately 30 (thirty) days from now Fedora will stop maintaining and issuing updates for Fedora 10. It is Fedora's policy to close all bug reports from releases that are no longer maintained. At that time this bug will be closed as WONTFIX if it remains open with a Fedora 'version' of '10'. Package Maintainer: If you wish for this bug to remain open because you plan to fix it in a currently maintained version, simply change the 'version' to a later Fedora version prior to Fedora 10's end of life. Bug Reporter: Thank you for reporting this issue and we are sorry that we may not be able to fix it before Fedora 10 is end of life. If you would still like to see this bug fixed and are able to reproduce it against a later version of Fedora please change the 'version' of this bug to the applicable version. If you are unable to change the version, please add a comment here and someone will do it for you. Although we aim to fix as many bugs as possible during every release's lifetime, sometimes those efforts are overtaken by events. Often a more recent Fedora release includes newer upstream software that fixes bugs or makes them obsolete. The process we are following is described here: http://fedoraproject.org/wiki/BugZappers/HouseKeeping
Fedora 10 changed to end-of-life (EOL) status on 2009-12-17. Fedora 10 is no longer maintained, which means that it will not receive any further security or bug fix updates. As a result we are closing this bug. If you can reproduce this bug against a currently maintained version of Fedora please feel free to reopen this bug against that version. Thank you for reporting this bug and we are sorry it could not be fixed.