aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@xensource.com>2007-02-19 12:21:41 +0000
committerIan Campbell <ian.campbell@xensource.com>2007-02-19 12:21:41 +0000
commit6f1113b5c511bb7bea956eb9a0063e3908b781e1 (patch)
tree4f8258d1b29b265205a94175a2b92ce406e87d88 /xen/common
parent4fca2a798152dccd59ccd5ffb12a5d3c596d9656 (diff)
downloadxen-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.c109
-rw-r--r--xen/common/libelf/libelf-tools.c11
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);