libdwfl/ 2007-10-17 Roland McGrath * dwfl_module_getsym.c (dwfl_module_getsym): Apply MOD->symfile->bias to relocated st_value. * dwfl_report_elf.c (__libdwfl_report_elf): Align initial BASE for ET_REL to 0x100. 2007-10-16 Roland McGrath * dwfl_report_elf.c (__libdwfl_report_elf): Readjust BASE when a later section has larger alignment requirements not met by the original BASE, rather than padding more between sections. * dwfl_report_elf.c (__libdwfl_report_elf): Fix bias calculation. * dwfl_module_build_id.c (__libdwfl_find_build_id): Apply module bias to sh_addr value. * dwfl_report_elf.c (__libdwfl_report_elf): Don't be confused by BASE at zero in ET_REL case. Adjust BASE to necessary alignment. * dwfl_module_build_id.c (check_notes): Take -1, not 0, as stub value for DATA_VADDR. (__libdwfl_find_build_id): Update caller. * relocate.c (__libdwfl_relocate_value): Don't use sh_offset. * dwfl_report_elf.c (__libdwfl_report_elf): Likewise. * offline.c (dwfl_offline_section_address): Bail early if there is separate debug file. * relocate.c (__libdwfl_relocate): Don't return DWFL_E_NO_DWARF. src/ 2007-10-16 Roland McGrath * readelf.c (hex_dump): Fix rounding error in whitespace calculation. tests/ 2007-10-16 Roland McGrath * test-subr.sh (remove_files): Don't pass -Bb to diff. ============================================================ --- libdwfl/dwfl_module_build_id.c ae14fc9f3be468ffff14b4f6247ad38898705132 +++ libdwfl/dwfl_module_build_id.c c67b9be68b69c98f6fd1024f521acdab0678ea02 @@ -73,6 +73,8 @@ found_build_id (Dwfl_Module *mod, bool s return len; } +#define NO_VADDR ((GElf_Addr) -1l) + static int check_notes (Dwfl_Module *mod, bool set, Elf_Data *data, GElf_Addr data_vaddr) { @@ -86,7 +88,7 @@ check_notes (Dwfl_Module *mod, bool set, "GNU", sizeof "GNU")) return found_build_id (mod, set, data->d_buf + desc_pos, nhdr.n_descsz, - data_vaddr == 0 ? 0 : data_vaddr + pos); + data_vaddr == NO_VADDR ? 0 : data_vaddr + pos); return 0; } @@ -129,7 +131,7 @@ __libdwfl_find_build_id (Dwfl_Module *mo if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE) result = check_notes (mod, set, elf_getdata (scn, NULL), (shdr->sh_flags & SHF_ALLOC) - ? shdr->sh_addr : 0); + ? shdr->sh_addr + mod->main.bias : NO_VADDR); } while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL); ============================================================ --- libdwfl/dwfl_module_getsym.c 5596a4a3df363bb27759a0c26519b9818475aa80 +++ libdwfl/dwfl_module_getsym.c c1a0448eecebc039393fb884ff7d0684d1d5001f @@ -85,10 +85,7 @@ dwfl_module_getsym (Dwfl_Module *mod, in break; default: - if (mod->e_type != ET_REL) - /* Apply the bias to the symbol value. */ - sym->st_value += mod->symfile->bias; - else + if (mod->e_type == ET_REL) { /* In an ET_REL file, the symbol table values are relative to the section, not to the module's load base. */ @@ -102,6 +99,8 @@ dwfl_module_getsym (Dwfl_Module *mod, in return NULL; } } + /* Apply the bias to the symbol value. */ + sym->st_value += mod->symfile->bias; break; } ============================================================ --- libdwfl/dwfl_report_elf.c d9db919b103fc3411d240f3a096af5e57a3adce6 +++ libdwfl/dwfl_report_elf.c ee4a17cd0e3bf27c306b484ab38c34a7de2b7c0e @@ -51,6 +51,14 @@ #include #include + +/* We start every ET_REL module at a moderately aligned boundary. + This keeps the low addresses easy to read compared to a layout + starting at 0 (as when using -e). It also makes it unlikely + that a middle section will have a larger alignment and require + rejiggering (see below). */ +#define REL_MIN_ALIGN ((GElf_Xword) 0x100) + Dwfl_Module * internal_function __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name, @@ -72,41 +80,91 @@ __libdwfl_report_elf (Dwfl *dwfl, const By updating the section header in place, we leave the layout information to be found by relocation. */ - start = end = base; + start = end = base = (base + REL_MIN_ALIGN - 1) & -REL_MIN_ALIGN; + bool first = true; Elf_Scn *scn = NULL; while ((scn = elf_nextscn (elf, scn)) != NULL) { GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr == NULL) + if (unlikely (shdr == NULL)) goto elf_error; if (shdr->sh_flags & SHF_ALLOC) { const GElf_Xword align = shdr->sh_addralign ?: 1; - if (shdr->sh_addr == 0 || (bias == 0 && end > start)) + const GElf_Addr next = (end + align - 1) & -align; + if (shdr->sh_addr == 0 + /* Once we've started doing layout we have to do it all, + unless we just layed out the first section at 0 when + it already was at 0. */ + || (bias == 0 && end > start && end != next)) { - shdr->sh_addr = (end + align - 1) & -align; + shdr->sh_addr = next; if (end == base) /* This is the first section assigned a location. Use its aligned address as the module's base. */ - start = shdr->sh_addr; + start = base = shdr->sh_addr; + else if (unlikely (base & (align - 1))) + { + /* If BASE has less than the maximum alignment of + any section, we eat more than the optimal amount + of padding and so make the module's apparent + size come out larger than it would when placed + at zero. So reset the layout with a better base. */ + + start = end = base = (base + align - 1) & -align; + Elf_Scn *prev_scn = NULL; + do + { + prev_scn = elf_nextscn (elf, prev_scn); + GElf_Shdr prev_shdr_mem; + GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn, + &prev_shdr_mem); + if (unlikely (prev_shdr == NULL)) + goto elf_error; + if (prev_shdr->sh_flags & SHF_ALLOC) + { + const GElf_Xword prev_align + = prev_shdr->sh_addralign ?: 1; + + prev_shdr->sh_addr + = (end + prev_align - 1) & -prev_align; + end = prev_shdr->sh_addr + prev_shdr->sh_size; + + if (unlikely (! gelf_update_shdr (prev_scn, + prev_shdr))) + goto elf_error; + } + } + while (prev_scn != scn); + continue; + } + end = shdr->sh_addr + shdr->sh_size; - if (shdr->sh_addr == 0) - /* This is a marker that this was resolved to zero, - to prevent a callback. */ - shdr->sh_offset = 0; - if (! gelf_update_shdr (scn, shdr)) + if (likely (shdr->sh_addr != 0) + && unlikely (! gelf_update_shdr (scn, shdr))) goto elf_error; } else { - if (bias == 0 || end < shdr->sh_addr + shdr->sh_size) + /* The address is already assigned. Just track it. */ + if (first || end < shdr->sh_addr + shdr->sh_size) end = shdr->sh_addr + shdr->sh_size; - if (bias == 0 || bias > shdr->sh_addr) + if (first || bias > shdr->sh_addr) + /* This is the lowest address in the module. */ bias = shdr->sh_addr; + + if ((shdr->sh_addr - bias + base) & (align - 1)) + /* This section winds up misaligned using BASE. + Adjust BASE upwards to make it congruent to + the lowest section address in the file modulo ALIGN. */ + base = (((base + align - 1) & -align) + + (bias & (align - 1))); } + + first = false; } } @@ -117,7 +175,7 @@ __libdwfl_report_elf (Dwfl *dwfl, const Now just compute the bias from the requested base. */ start = base; end = end - bias + start; - bias -= start; + bias = start - bias; } break; @@ -133,7 +191,7 @@ __libdwfl_report_elf (Dwfl *dwfl, const for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i) { GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem); - if (ph == NULL) + if (unlikely (ph == NULL)) goto elf_error; if (ph->p_type == PT_LOAD) { @@ -148,7 +206,7 @@ __libdwfl_report_elf (Dwfl *dwfl, const for (uint_fast16_t i = ehdr->e_phnum; i-- > 0;) { GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem); - if (ph == NULL) + if (unlikely (ph == NULL)) goto elf_error; if (ph->p_type == PT_LOAD) { ============================================================ --- libdwfl/offline.c 1508fb5c96e46f5bf3bbdaa0e18921243cf2ab8b +++ libdwfl/offline.c d8dc43d35ecff3200099ec421a93cfadbd5a2e17 @@ -53,8 +53,9 @@ /* Since dwfl_report_elf lays out the sections already, this will only be called when the section headers of the debuginfo file are being - consulted instead. With binutils strip-to-debug, the symbol table is in - the debuginfo file and relocation looks there. */ + consulted instead, or for the section placed at 0. With binutils + strip-to-debug, the symbol table is in the debuginfo file and relocation + looks there. */ int dwfl_offline_section_address (Dwfl_Module *mod, void **userdata __attribute__ ((unused)), @@ -69,6 +70,11 @@ dwfl_offline_section_address (Dwfl_Modul assert (shdr->sh_addr == 0); assert (shdr->sh_flags & SHF_ALLOC); + if (mod->debug.elf == NULL) + /* We are only here because sh_addr is zero even though layout is complete. + The first section in the first file under -e is placed at 0. */ + return 0; + /* The section numbers might not match between the two files. The best we can rely on is the order of SHF_ALLOC sections. */ ============================================================ --- libdwfl/relocate.c 5a08921fcd4b957b0d768e7a140eb5187dcaf69e +++ libdwfl/relocate.c 51258c3bf6a18602dbd3fd2d8b721d4f7a9aef60 @@ -64,9 +64,7 @@ __libdwfl_relocate_value (Dwfl_Module *m if (refshdr == NULL) return DWFL_E_LIBELF; - if (refshdr->sh_addr == 0 - && (refshdr->sh_flags & SHF_ALLOC) - && refshdr->sh_offset != 0) + if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC)) { /* This is a loaded section. Find its actual address and update the section header. */ @@ -89,13 +87,11 @@ __libdwfl_relocate_value (Dwfl_Module *m don't really care. */ refshdr->sh_addr = 0; /* Make no adjustment below. */ - /* Mark it so we don't check it again for the next relocation. */ - refshdr->sh_offset = 0; - /* Update the in-core file's section header to show the final load address (or unloadedness). This serves as a cache, so we won't get here again for the same section. */ - if (unlikely (! gelf_update_shdr (refscn, refshdr))) + if (likely (refshdr->sh_addr != 0) + && unlikely (! gelf_update_shdr (refscn, refshdr))) return DWFL_E_LIBELF; } @@ -202,7 +198,7 @@ __libdwfl_relocate (Dwfl_Module *mod, El /* Look at each section in the debuginfo file, and process the relocation sections for debugging sections. */ - Dwfl_Error result = DWFL_E_NO_DWARF; + Dwfl_Error result = DWFL_E_NOERROR; Elf_Scn *scn = NULL; while ((scn = elf_nextscn (debugfile, scn)) != NULL) { @@ -369,7 +365,6 @@ __libdwfl_relocate (Dwfl_Module *mod, El if (reldata == NULL) return DWFL_E_LIBELF; - result = DWFL_E_NOERROR; size_t nrels = shdr->sh_size / shdr->sh_entsize; if (shdr->sh_type == SHT_REL) for (size_t relidx = 0; !result && relidx < nrels; ++relidx) ============================================================ --- src/readelf.c a0d9bd8c3fb36429895ee314dd3a874af3f8866e +++ src/readelf.c 06970982eff8d85287725619dd9eefc51c1bf1c0 @@ -5888,7 +5888,7 @@ hex_dump (const uint8_t *data, size_t le printf ("%02x", data[pos + i]); if (chunk < 16) - printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk) / 4), ""); + printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk + 3) / 4), ""); for (size_t i = 0; i < chunk; ++i) { ============================================================ --- tests/test-subr.sh 5ba4008367c39437a8e8d6ed0b6757d54bc10f4d +++ tests/test-subr.sh ea1d0339bca3d875076ed15e114e9d47b2ea96e2 @@ -1,5 +1,5 @@ #! /bin/sh -# Copyright (C) 2005 Red Hat, Inc. +# Copyright (C) 2005, 2007 Red Hat, Inc. # This file is part of Red Hat elfutils. # # Red Hat elfutils is free software; you can redistribute it and/or modify @@ -58,7 +58,7 @@ testrun_compare() { outfile="${1##*/}.out" testrun_out $outfile "$@" - diff -Bbu $outfile - + diff -u $outfile - # diff's exit status will kill the script. }