When using PE format names greater than 8 characters are placed in the
string table, and a reference using the '/<offset>' format is placed in the
name field.  Read the string table if present, and decode names as
required.

No functional change intended, but the name references printed in error
messages are now human readable:

Warning: relocation to r/o section /4:00042d43

Becomes:

Warning: relocation to r/o section .init.text:000446c3

Note the introduced helper to print names relies on a static internal
buffer to make sure the returned string are always null terminated.
This is enough for the current use-case, but if the returned value is to
stay valid between calls the current static buffer won't work as expected.

Signed-off-by: Roger Pau Monné <roger....@citrix.com>
---
 xen/arch/x86/efi/mkreloc.c | 69 +++++++++++++++++++++++++++++++++-----
 1 file changed, 61 insertions(+), 8 deletions(-)

diff --git a/xen/arch/x86/efi/mkreloc.c b/xen/arch/x86/efi/mkreloc.c
index 1a6cfc845cba..cc106bd875ba 100644
--- a/xen/arch/x86/efi/mkreloc.c
+++ b/xen/arch/x86/efi/mkreloc.c
@@ -17,6 +17,12 @@
 #define PE_BASE_RELOC_HIGHLOW  3
 #define PE_BASE_RELOC_DIR64   10
 
+/* The size of a symbol table entry is always 18 bytes. */
+#define SYM_SIZE 18
+
+const char *string_table;
+unsigned int string_table_size;
+
 static void usage(const char *cmd, int rc)
 {
     fprintf(rc ? stderr : stdout,
@@ -25,6 +31,28 @@ static void usage(const char *cmd, int rc)
     exit(rc);
 }
 
+const char *get_name(const char *name)
+{
+    static char buffer[sizeof(((struct section_header *)NULL)->name) + 1] = {};
+    unsigned long offset;
+
+    if ( name[0] != '/' )
+    {
+        /*
+         * Use a temporary buffer in case the name is 8 characters long, as
+         * then there's no terminating null character in the input string.
+         */
+        strncpy(buffer, name, sizeof(buffer) - 1);
+        return buffer;
+    }
+
+    offset = strtoul(&name[1], NULL, 10);
+    if ( !string_table || offset < 4 || offset >= string_table_size )
+        return name;
+
+    return &string_table[offset - 4];
+}
+
 static unsigned int load(const char *name, int *handle,
                          struct section_header **sections,
                          uint_fast64_t *image_base,
@@ -83,6 +111,31 @@ static unsigned int load(const char *name, int *handle,
         exit(3);
     }
 
+    if ( !string_table && pe_hdr.symbol_table )
+    {
+        char *strings;
+
+        if ( lseek(in, pe_hdr.symbol_table + pe_hdr.symbols * SYM_SIZE,
+                   SEEK_SET) < 0 ||
+             read(in, &string_table_size, sizeof(string_table_size)) !=
+             sizeof(string_table_size) )
+        {
+            perror(name);
+            exit(3);
+        }
+
+        string_table_size -= sizeof(string_table_size);
+        strings = malloc(string_table_size);
+
+        if ( read(in, strings, string_table_size) != string_table_size )
+        {
+            perror(name);
+            exit(3);
+        }
+
+        string_table = strings;
+    }
+
     *sections = malloc(pe_hdr.sections * sizeof(**sections));
     if ( !*sections )
     {
@@ -173,8 +226,8 @@ static void diff_sections(const unsigned char *ptr1, const 
unsigned char *ptr2,
         if ( i < disp || i + width - disp > sec->raw_data_size )
         {
             fprintf(stderr,
-                    "Bogus difference at %.8s:%08" PRIxFAST32 "\n",
-                    sec->name, i);
+                    "Bogus difference at %s:%08" PRIxFAST32 "\n",
+                    get_name(sec->name), i);
             exit(3);
         }
 
@@ -184,9 +237,9 @@ static void diff_sections(const unsigned char *ptr1, const 
unsigned char *ptr2,
         if ( delta != diff )
         {
             fprintf(stderr,
-                    "Difference at %.8s:%08" PRIxFAST32 " is %#" PRIxFAST64
+                    "Difference at %s:%08" PRIxFAST32 " is %#" PRIxFAST64
                     " (expected %#" PRIxFAST64 ")\n",
-                    sec->name, i - disp, delta, diff);
+                    get_name(sec->name), i - disp, delta, diff);
             continue;
         }
         if ( width == 8 && (val1.u64 < base || val1.u64 > end) )
@@ -210,15 +263,15 @@ static void diff_sections(const unsigned char *ptr1, 
const unsigned char *ptr2,
         else if ( rva != cur_rva )
         {
             fprintf(stderr,
-                    "Cannot handle decreasing RVA (at %.8s:%08" PRIxFAST32 
")\n",
-                    sec->name, i - disp);
+                    "Cannot handle decreasing RVA (at %s:%08" PRIxFAST32 ")\n",
+                    get_name(sec->name), i - disp);
             exit(3);
         }
 
         if ( !(sec->flags & IMAGE_SCN_MEM_WRITE) )
             fprintf(stderr,
-                    "Warning: relocation to r/o section %.8s:%08" PRIxFAST32 
"\n",
-                    sec->name, i - disp);
+                    "Warning: relocation to r/o section %s:%08" PRIxFAST32 
"\n",
+                    get_name(sec->name), i - disp);
 
         printf("\t.word (%u << 12) | 0x%03" PRIxFAST32 "\n",
                reloc, sec->rva + i - disp - rva);
-- 
2.48.1


Reply via email to