[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [LIBELF] Prefer PT_NOTE segments to SHT_NOTE sections for ELF notes.



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.