Hi,
the code in xen_hyper_init() tries to determine the per-cpu shift from the
__per_cpu_shift symbol if available. This doesn't work because the symbol's
value is outside the kernel text address range. This patch makes a special
case for this symbol on Xen targets, so it can be used later.
Without this patch, crash initialization fails on SLES11 Xen hypervisor dumps,
because on incorrect per-cpu offset is assumed. The failure can't be fixed
simply by adding a version check, because SLES11 Xen is patched to increase
the per-cpu shift in order to support more CPUs.
It is also important not to try to relocate ABSOLUTE symbol (such as this
one), so add this condition in store_symbols().
Signed-off-by: Petr Tesarik <ptesarik(a)suse.cz>
---
ia64.c | 22 ++++++++++++++++++++--
symbols.c | 3 ++-
x86.c | 22 ++++++++++++++++++++--
x86_64.c | 22 ++++++++++++++++++++--
4 files changed, 62 insertions(+), 7 deletions(-)
--- a/ia64.c
+++ b/ia64.c
@@ -20,6 +20,7 @@
#include <sys/prctl.h>
static int ia64_verify_symbol(const char *, ulong, char);
+static int ia64_hyper_verify_symbol(const char *, ulong, char);
static int ia64_eframe_search(struct bt_info *);
static void ia64_back_trace_cmd(struct bt_info *);
static void ia64_old_unwind(struct bt_info *);
@@ -571,7 +572,12 @@ ia64_dump_machdep_table(ulong arg)
fprintf(fp, " memory_size: generic_memory_size()\n");
fprintf(fp, " vmalloc_start: ia64_vmalloc_start()\n");
fprintf(fp, " is_task_addr: ia64_is_task_addr()\n");
- fprintf(fp, " verify_symbol: ia64_verify_symbol()\n");
+ if (machdep->verify_symbol == ia64_verify_symbol)
+ fprintf(fp, " verify_symbol: ia64_verify_symbol()\n");
+ else if (machdep->verify_symbol == ia64_hyper_verify_symbol)
+ fprintf(fp, " verify_symbol: ia64_hyper_verify_symbol()\n");
+ else
+ fprintf(fp, " verify_symbol: %lx\n", (ulong)machdep->verify_symbol);
fprintf(fp, " dis_filter: ia64_dis_filter()\n");
fprintf(fp, " cmd_mach: ia64_cmd_mach()\n");
fprintf(fp, " get_smp_cpus: ia64_get_smp_cpus()\n");
@@ -724,6 +730,18 @@ ia64_verify_symbol(const char *name, ulo
(region == KERNEL_VMALLOC_REGION)));
}
+static int
+ia64_hyper_verify_symbol(const char *name, ulong value, char type)
+{
+ if (ia64_verify_symbol(name, value, type))
+ return TRUE;
+
+ if (STREQ(name, "__per_cpu_shift"))
+ return TRUE;
+
+ return FALSE;
+}
+
/*
* Look for likely exception frames in a stack.
@@ -4225,7 +4243,7 @@ ia64_init_hyper(int when)
break;
case PRE_SYMTAB:
- machdep->verify_symbol = ia64_verify_symbol;
+ machdep->verify_symbol = ia64_hyper_verify_symbol;
machdep->machspec = &ia64_machine_specific;
if (pc->flags & KERNEL_DEBUG_QUERY)
return;
--- a/symbols.c
+++ b/symbols.c
@@ -568,7 +568,8 @@ store_symbols(bfd *abfd, int dynamic, vo
bfd_get_symbol_info(abfd, sym, &syminfo);
if (machdep->verify_symbol(syminfo.name, syminfo.value,
syminfo.type)) {
- if (kt->flags & (RELOC_SET|RELOC_FORCE))
+ if ((kt->flags & (RELOC_SET|RELOC_FORCE)) &&
+ sym->section != &bfd_abs_section)
sp->value = relocate(syminfo.value,
(char *)syminfo.name, !(first++));
else
--- a/x86.c
+++ b/x86.c
@@ -986,6 +986,7 @@ static void eframe_init(void);
static char *extract_idt_function(ulong *, char *, ulong *);
static int x86_is_task_addr(ulong);
static int x86_verify_symbol(const char *, ulong, char);
+static int x86_hyper_verify_symbol(const char *, ulong, char);
static int x86_eframe_search(struct bt_info *);
static ulong x86_in_irqstack(ulong);
static int x86_dis_filter(ulong, char *);
@@ -3254,7 +3255,12 @@ x86_dump_machdep_table(ulong arg)
fprintf(fp, " memory_size: x86_memory_size()\n");
fprintf(fp, " vmalloc_start: x86_vmalloc_start()\n");
fprintf(fp, " is_task_addr: x86_is_task_addr()\n");
- fprintf(fp, " verify_symbol: x86_verify_symbol()\n");
+ if (machdep->verify_symbol == x86_verify_symbol)
+ fprintf(fp, " verify_symbol: x86_verify_symbol()\n");
+ else if (machdep->verify_symbol == x86_hyper_verify_symbol)
+ fprintf(fp, " verify_symbol: x86_hyper_verify_symbol()\n");
+ else
+ fprintf(fp, " verify_symbol: %lx\n", (ulong)machdep->verify_symbol);
fprintf(fp, " dis_filter: x86_dis_filter()\n");
fprintf(fp, " cmd_mach: x86_cmd_mach()\n");
fprintf(fp, " get_smp_cpus: x86_get_smp_cpus()\n");
@@ -3789,6 +3795,18 @@ x86_verify_symbol(const char *name, ulon
return TRUE;
}
+static int
+x86_hyper_verify_symbol(const char *name, ulong value, char type)
+{
+ if (x86_verify_symbol(name, value, type))
+ return TRUE;
+
+ if (STREQ(name, "__per_cpu_shift"))
+ return TRUE;
+
+ return FALSE;
+}
+
/*
* Filter disassembly output if the output radix is not gdb's default 10
*/
@@ -4967,7 +4985,7 @@ x86_init_hyper(int when)
switch (when)
{
case PRE_SYMTAB:
- machdep->verify_symbol = x86_verify_symbol;
+ machdep->verify_symbol = x86_hyper_verify_symbol;
if (pc->flags & KERNEL_DEBUG_QUERY)
return;
machdep->pagesize = memory_page_size();
--- a/x86_64.c
+++ b/x86_64.c
@@ -27,6 +27,7 @@ static int x86_64_uvtop_level4_rhel4_xen
static ulong x86_64_vmalloc_start(void);
static int x86_64_is_task_addr(ulong);
static int x86_64_verify_symbol(const char *, ulong, char);
+static int x86_64_hyper_verify_symbol(const char *, ulong, char);
static ulong x86_64_get_task_pgd(ulong);
static int x86_64_translate_pte(ulong, void *, ulonglong);
static ulong x86_64_processor_speed(void);
@@ -491,7 +492,12 @@ x86_64_dump_machdep_table(ulong arg)
fprintf(fp, " memory_size: generic_memory_size()\n");
fprintf(fp, " vmalloc_start: x86_64_vmalloc_start()\n");
fprintf(fp, " is_task_addr: x86_64_is_task_addr()\n");
- fprintf(fp, " verify_symbol: x86_64_verify_symbol()\n");
+ if (machdep->verify_symbol == x86_64_verify_symbol)
+ fprintf(fp, " verify_symbol: x86_64_verify_symbol()\n");
+ else if (machdep->verify_symbol == x86_64_hyper_verify_symbol)
+ fprintf(fp, " verify_symbol: x86_64_hyper_verify_symbol()\n");
+ else
+ fprintf(fp, " verify_symbol: %lx\n", (ulong)machdep->verify_symbol);
fprintf(fp, " dis_filter: x86_64_dis_filter()\n");
fprintf(fp, " cmd_mach: x86_64_cmd_mach()\n");
fprintf(fp, " get_smp_cpus: x86_64_get_smp_cpus()\n");
@@ -1978,6 +1984,18 @@ x86_64_verify_symbol(const char *name, u
return TRUE;
}
+static int
+x86_64_hyper_verify_symbol(const char *name, ulong value, char type)
+{
+ if (x86_64_verify_symbol(name, value, type))
+ return TRUE;
+
+ if (STREQ(name, "__per_cpu_shift"))
+ return TRUE;
+
+ return FALSE;
+}
+
/*
* Get the relevant page directory pointer from a task structure.
@@ -5949,7 +5967,7 @@ x86_64_init_hyper(int when)
switch (when)
{
case PRE_SYMTAB:
- machdep->verify_symbol = x86_64_verify_symbol;
+ machdep->verify_symbol = x86_64_hyper_verify_symbol;
machdep->machspec = &x86_64_machine_specific;
if (pc->flags & KERNEL_DEBUG_QUERY)
return;