# HG changeset patch
# User Ian Campbell <ian.campbell@xxxxxxxxxxxxx>
# Date 1171887701 0
# Node ID 5a07ea77a61daee5ab5fa15a20ad24f87bc97dae
# Parent b5fc88aad1b0eb35d12e503982c70fdc27f0544a
[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@xxxxxxxxxxxxx>
---
tools/xcutils/readnotes.c | 138 +++++++++++++++++++++++--------------
xen/common/libelf/libelf-dominfo.c | 119 ++++++++++++++++++++++++-------
xen/common/libelf/libelf-tools.c | 11 ++
xen/include/public/elfnote.h | 2
xen/include/public/libelf.h | 3
xen/include/xen/sched.h | 9 --
6 files changed, 196 insertions(+), 86 deletions(-)
diff -r b5fc88aad1b0 -r 5a07ea77a61d tools/xcutils/readnotes.c
--- a/tools/xcutils/readnotes.c Sun Feb 18 15:29:40 2007 +0000
+++ b/tools/xcutils/readnotes.c Mon Feb 19 12:21:41 2007 +0000
@@ -31,6 +31,65 @@ static void print_numeric_note(const cha
prefix, 2+2*descsz, value, descsz);
}
+static int print_notes(struct elf_binary *elf, const elf_note *start, const
elf_note *end)
+{
+ const elf_note *note;
+ int notes_found = 0;
+
+ for ( note = start; note < end; note = elf_note_next(elf, note) )
+ {
+ if (0 != strcmp(elf_note_name(elf, note), "Xen"))
+ continue;
+
+ notes_found++;
+
+ switch(elf_uval(elf, note, type))
+ {
+ case XEN_ELFNOTE_INFO:
+ print_string_note("INFO", elf , note);
+ break;
+ case XEN_ELFNOTE_ENTRY:
+ print_numeric_note("ENTRY", elf , note);
+ break;
+ case XEN_ELFNOTE_HYPERCALL_PAGE:
+ print_numeric_note("HYPERCALL_PAGE", elf , note);
+ break;
+ case XEN_ELFNOTE_VIRT_BASE:
+ print_numeric_note("VIRT_BASE", elf , note);
+ break;
+ case XEN_ELFNOTE_PADDR_OFFSET:
+ print_numeric_note("PADDR_OFFSET", elf , note);
+ break;
+ case XEN_ELFNOTE_XEN_VERSION:
+ print_string_note("XEN_VERSION", elf , note);
+ break;
+ case XEN_ELFNOTE_GUEST_OS:
+ print_string_note("GUEST_OS", elf , note);
+ break;
+ case XEN_ELFNOTE_GUEST_VERSION:
+ print_string_note("GUEST_VERSION", elf , note);
+ break;
+ case XEN_ELFNOTE_LOADER:
+ print_string_note("LOADER", elf , note);
+ break;
+ case XEN_ELFNOTE_PAE_MODE:
+ print_string_note("PAE_MODE", elf , note);
+ break;
+ case XEN_ELFNOTE_FEATURES:
+ print_string_note("FEATURES", elf , note);
+ break;
+ case XEN_ELFNOTE_HV_START_LOW:
+ print_numeric_note("HV_START_LOW", elf, note);
+ break;
+ default:
+ printf("unknown note type %#x\n",
+ (int)elf_uval(elf, note, type));
+ break;
+ }
+ }
+ return notes_found;
+}
+
int main(int argc, char **argv)
{
const char *f;
@@ -39,7 +98,7 @@ int main(int argc, char **argv)
struct stat st;
struct elf_binary elf;
const elf_shdr *shdr;
- const elf_note *note, *end;
+ int notes_found = 0;
if (argc != 2)
{
@@ -85,59 +144,40 @@ int main(int argc, char **argv)
}
elf_set_logfile(&elf, stderr, 0);
- count = elf_shdr_count(&elf);
+ count = elf_phdr_count(&elf);
for ( h=0; h < count; h++)
{
- shdr = elf_shdr_by_index(&elf, h);
- if (elf_uval(&elf, shdr, sh_type) != SHT_NOTE)
+ const elf_phdr *phdr;
+ phdr = elf_phdr_by_index(&elf, h);
+ if (elf_uval(&elf, phdr, p_type) != PT_NOTE)
continue;
- end = elf_section_end(&elf, shdr);
- for (note = elf_section_start(&elf, shdr);
- 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;
+
+ notes_found = print_notes(&elf,
+ elf_segment_start(&elf, phdr),
+ elf_segment_end(&elf, phdr));
+ }
+
+ if ( notes_found == 0 )
+ {
+ count = elf_shdr_count(&elf);
+ for ( h=0; h < count; h++)
{
- if (0 != strcmp(elf_note_name(&elf, note), "Xen"))
+ const elf_shdr *shdr;
+ shdr = elf_shdr_by_index(&elf, h);
+ if (elf_uval(&elf, shdr, sh_type) != SHT_NOTE)
continue;
- switch(elf_uval(&elf, note, type))
- {
- case XEN_ELFNOTE_INFO:
- print_string_note("INFO", &elf , note);
- break;
- case XEN_ELFNOTE_ENTRY:
- print_numeric_note("ENTRY", &elf , note);
- break;
- case XEN_ELFNOTE_HYPERCALL_PAGE:
- print_numeric_note("HYPERCALL_PAGE", &elf ,
note);
- break;
- case XEN_ELFNOTE_VIRT_BASE:
- print_numeric_note("VIRT_BASE", &elf , note);
- break;
- case XEN_ELFNOTE_PADDR_OFFSET:
- print_numeric_note("PADDR_OFFSET", &elf , note);
- break;
- case XEN_ELFNOTE_XEN_VERSION:
- print_string_note("XEN_VERSION", &elf , note);
- break;
- case XEN_ELFNOTE_GUEST_OS:
- print_string_note("GUEST_OS", &elf , note);
- break;
- case XEN_ELFNOTE_GUEST_VERSION:
- print_string_note("GUEST_VERSION", &elf , note);
- break;
- case XEN_ELFNOTE_LOADER:
- print_string_note("LOADER", &elf , note);
- break;
- case XEN_ELFNOTE_PAE_MODE:
- print_string_note("PAE_MODE", &elf , note);
- break;
- case XEN_ELFNOTE_FEATURES:
- print_string_note("FEATURES", &elf , note);
- break;
- default:
- printf("unknown note type %#x\n",
- (int)elf_uval(&elf, note, type));
- break;
- }
+ notes_found = print_notes(&elf,
+ elf_section_start(&elf, shdr),
+ elf_section_end(&elf, shdr));
+ if ( notes_found )
+ fprintf(stderr, "using notes from SHT_NOTE
section\n");
+
}
}
diff -r b5fc88aad1b0 -r 5a07ea77a61d xen/common/libelf/libelf-dominfo.c
--- a/xen/common/libelf/libelf-dominfo.c Sun Feb 18 15:29:40 2007 +0000
+++ b/xen/common/libelf/libelf-dominfo.c Mon Feb 19 12:21:41 2007 +0000
@@ -178,6 +178,28 @@ int elf_xen_parse_note(struct elf_binary
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 @@ int elf_xen_parse(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) )
- {
- if ( strcmp(elf_note_name(elf, note), "Xen") )
+
+ /*
+ * 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++ )
+ {
+ 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 && parms->guest_info )
- {
- 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);
+
+ if ( xen_elfnotes == 0 && rc > 0 )
+ elf_msg(elf, "%s: using notes from SHT_NOTE section\n",
__FUNCTION__);
+
+ xen_elfnotes += rc;
+ }
+
+ }
+
+ /*
+ * Finally fall back to the __xen_guest section.
+ */
+ if ( xen_elfnotes == 0 )
+ {
+ 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 -r b5fc88aad1b0 -r 5a07ea77a61d xen/common/libelf/libelf-tools.c
--- a/xen/common/libelf/libelf-tools.c Sun Feb 18 15:29:40 2007 +0000
+++ b/xen/common/libelf/libelf-tools.c Mon Feb 19 12:21:41 2007 +0000
@@ -142,6 +142,17 @@ const void *elf_section_end(struct elf_b
{
return elf->image
+ 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)
diff -r b5fc88aad1b0 -r 5a07ea77a61d xen/include/public/elfnote.h
--- a/xen/include/public/elfnote.h Sun Feb 18 15:29:40 2007 +0000
+++ b/xen/include/public/elfnote.h Mon Feb 19 12:21:41 2007 +0000
@@ -28,7 +28,7 @@
#define __XEN_PUBLIC_ELFNOTE_H__
/*
- * The notes should live in a SHT_NOTE segment and have "Xen" in the
+ * The notes should live in a PT_NOTE segment and have "Xen" in the
* name field.
*
* Numeric types are either 4 or 8 bytes depending on the content of
diff -r b5fc88aad1b0 -r 5a07ea77a61d xen/include/public/libelf.h
--- a/xen/include/public/libelf.h Sun Feb 18 15:29:40 2007 +0000
+++ b/xen/include/public/libelf.h Mon Feb 19 12:21:41 2007 +0000
@@ -133,6 +133,9 @@ const char *elf_section_name(struct elf_
const char *elf_section_name(struct elf_binary *elf, const elf_shdr * shdr);
const void *elf_section_start(struct elf_binary *elf, const elf_shdr * shdr);
const void *elf_section_end(struct elf_binary *elf, const elf_shdr * shdr);
+
+const void *elf_segment_start(struct elf_binary *elf, const elf_phdr * phdr);
+const void *elf_segment_end(struct elf_binary *elf, const elf_phdr * phdr);
const elf_sym *elf_sym_by_name(struct elf_binary *elf, const char *symbol);
const elf_sym *elf_sym_by_index(struct elf_binary *elf, int index);
diff -r b5fc88aad1b0 -r 5a07ea77a61d xen/include/xen/sched.h
--- a/xen/include/xen/sched.h Sun Feb 18 15:29:40 2007 +0000
+++ b/xen/include/xen/sched.h Mon Feb 19 12:21:41 2007 +0000
@@ -216,15 +216,6 @@ struct domain_setup_info
unsigned int load_symtab;
unsigned long symtab_addr;
unsigned long symtab_len;
- /*
- * Only one of __elfnote_* or __xen_guest_string will be
- * non-NULL.
- *
- * You should use the xen_elfnote_* accessors below in order to
- * pickup the correct one and retain backwards compatibility.
- */
- const void *__elfnote_section, *__elfnote_section_end;
- const char *__xen_guest_string;
};
extern struct vcpu *idle_vcpu[NR_CPUS];
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|