diff options
author | Ian Campbell <ian.campbell@xensource.com> | 2007-02-19 12:21:41 +0000 |
---|---|---|
committer | Ian Campbell <ian.campbell@xensource.com> | 2007-02-19 12:21:41 +0000 |
commit | 6f1113b5c511bb7bea956eb9a0063e3908b781e1 (patch) | |
tree | 4f8258d1b29b265205a94175a2b92ce406e87d88 /xen/common | |
parent | 4fca2a798152dccd59ccd5ffb12a5d3c596d9656 (diff) | |
download | xen-6f1113b5c511bb7bea956eb9a0063e3908b781e1.tar.gz xen-6f1113b5c511bb7bea956eb9a0063e3908b781e1.tar.bz2 xen-6f1113b5c511bb7bea956eb9a0063e3908b781e1.zip |
[LIBELF] Prefer PT_NOTE segments to SHT_NOTE sections for ELF notes.
It's always an error to try to use sections on an executable; the
segments in the phdr are definitive.
Unfortunately we cannot drop SHT_NOTE support completely due to a
binutils bug which causes kernels to have the offset field of the
PT_NOTE phdr set to zero:
http://sourceware.org/bugzilla/show_bug.cgi?id=594
This bug is present in binutils 2.17 although some distros have
backported the fix.
Therefore we simply prefer a PT_NOTE segment if we find one otherwise
we still use the SHT_NOTE section (and then the old __xen_guest
section).
Based on a patch from Jeremy Fitzhardinge.
Also added XEN_ELFNOTE_HV_START_LOW to readnotes.
Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
Diffstat (limited to 'xen/common')
-rw-r--r-- | xen/common/libelf/libelf-dominfo.c | 109 | ||||
-rw-r--r-- | xen/common/libelf/libelf-tools.c | 11 |
2 files changed, 98 insertions, 22 deletions
diff --git a/xen/common/libelf/libelf-dominfo.c b/xen/common/libelf/libelf-dominfo.c index bbe9235309..9425d85cc1 100644 --- a/xen/common/libelf/libelf-dominfo.c +++ b/xen/common/libelf/libelf-dominfo.c @@ -178,6 +178,28 @@ int elf_xen_parse_note(struct elf_binary *elf, return 0; } +static int elf_xen_parse_notes(struct elf_binary *elf, + struct elf_dom_parms *parms, + const void *start, const void *end) +{ + int xen_elfnotes = 0; + const elf_note *note; + + parms->elf_note_start = start; + parms->elf_note_end = end; + for ( note = parms->elf_note_start; + (void *)note < parms->elf_note_end; + note = elf_note_next(elf, note) ) + { + if ( strcmp(elf_note_name(elf, note), "Xen") ) + continue; + if ( elf_xen_parse_note(elf, parms, note) ) + return -1; + xen_elfnotes++; + } + return xen_elfnotes; +} + /* ------------------------------------------------------------------------ */ /* __xen_guest section */ @@ -377,10 +399,10 @@ static int elf_xen_addr_calc_check(struct elf_binary *elf, int elf_xen_parse(struct elf_binary *elf, struct elf_dom_parms *parms) { - const elf_note *note; const elf_shdr *shdr; + const elf_phdr *phdr; int xen_elfnotes = 0; - int i, count; + int i, count, rc; memset(parms, 0, sizeof(*parms)); parms->virt_base = UNSET_ADDR; @@ -389,36 +411,79 @@ int elf_xen_parse(struct elf_binary *elf, parms->virt_hv_start_low = UNSET_ADDR; parms->elf_paddr_offset = UNSET_ADDR; - /* find and parse elf notes */ - count = elf_shdr_count(elf); + /* Find and parse elf notes. */ + count = elf_phdr_count(elf); for ( i = 0; i < count; i++ ) { - shdr = elf_shdr_by_index(elf, i); - if ( !strcmp(elf_section_name(elf, shdr), "__xen_guest") ) - parms->guest_info = elf_section_start(elf, shdr); - if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE ) + phdr = elf_phdr_by_index(elf, i); + if ( elf_uval(elf, phdr, p_type) != PT_NOTE ) continue; - parms->elf_note_start = elf_section_start(elf, shdr); - parms->elf_note_end = elf_section_end(elf, shdr); - for ( note = parms->elf_note_start; - (void *)note < parms->elf_note_end; - note = elf_note_next(elf, note) ) + + /* + * Some versions of binutils do not correctly set p_offset for + * note segments. + */ + if (elf_uval(elf, phdr, p_offset) == 0) + continue; + + rc = elf_xen_parse_notes(elf, parms, + elf_segment_start(elf, phdr), + elf_segment_end(elf, phdr)); + if ( rc == -1 ) + return -1; + + xen_elfnotes += rc; + } + + /* + * Fall back to any SHT_NOTE sections if no valid note segments + * were found. + */ + if ( xen_elfnotes == 0 ) + { + count = elf_shdr_count(elf); + for ( i = 0; i < count; i++ ) { - if ( strcmp(elf_note_name(elf, note), "Xen") ) + shdr = elf_shdr_by_index(elf, i); + + if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE ) continue; - if ( elf_xen_parse_note(elf, parms, note) ) + + rc = elf_xen_parse_notes(elf, parms, + elf_section_start(elf, shdr), + elf_section_end(elf, shdr)); + + if ( rc == -1 ) return -1; - xen_elfnotes++; + + if ( xen_elfnotes == 0 && rc > 0 ) + elf_msg(elf, "%s: using notes from SHT_NOTE section\n", __FUNCTION__); + + xen_elfnotes += rc; } + } - if ( !xen_elfnotes && parms->guest_info ) + /* + * Finally fall back to the __xen_guest section. + */ + if ( xen_elfnotes == 0 ) { - parms->elf_note_start = NULL; - parms->elf_note_end = NULL; - elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__, - parms->guest_info); - elf_xen_parse_guest_info(elf, parms); + count = elf_shdr_count(elf); + for ( i = 0; i < count; i++ ) + { + shdr = elf_shdr_by_name(elf, "__xen_guest"); + if ( shdr ) + { + parms->guest_info = elf_section_start(elf, shdr); + parms->elf_note_start = NULL; + parms->elf_note_end = NULL; + elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__, + parms->guest_info); + elf_xen_parse_guest_info(elf, parms); + break; + } + } } if ( elf_xen_note_check(elf, parms) != 0 ) diff --git a/xen/common/libelf/libelf-tools.c b/xen/common/libelf/libelf-tools.c index fb73c4664e..99a0a91576 100644 --- a/xen/common/libelf/libelf-tools.c +++ b/xen/common/libelf/libelf-tools.c @@ -144,6 +144,17 @@ const void *elf_section_end(struct elf_binary *elf, const elf_shdr * shdr) + elf_uval(elf, shdr, sh_offset) + elf_uval(elf, shdr, sh_size); } +const void *elf_segment_start(struct elf_binary *elf, const elf_phdr * phdr) +{ + return elf->image + elf_uval(elf, phdr, p_offset); +} + +const void *elf_segment_end(struct elf_binary *elf, const elf_phdr * phdr) +{ + return elf->image + + elf_uval(elf, phdr, p_offset) + elf_uval(elf, phdr, p_filesz); +} + const elf_sym *elf_sym_by_name(struct elf_binary *elf, const char *symbol) { const void *ptr = elf_section_start(elf, elf->sym_tab); |