From 1f6b58b323f669293b4ef8d497fe7867d1411143 Mon Sep 17 00:00:00 2001 From: Kazuhito Hagio Date: Wed, 7 Dec 2022 09:46:56 +0900 Subject: [PATCH 48/89] x86_64: Fix for move of per-cpu variables into struct pcpu_hot The following kernel commits, which are contained in Linux 6.2-rc1 and later kernels, introduced struct pcpu_hot and moved several per-cpu variables into it. d7b6d709a76a x86/percpu: Move irq_stack variables next to current_task 7443b296e699 x86/percpu: Move cpu_number next to current_task e57ef2ed97c1 x86: Put hot per CPU variables into a struct Without the patch, crash fails to start session with the following error: $ crash vmlinux vmcore ... bt: invalid size request: 0 type: "stack contents" bt: read of stack at 0 failed Signed-off-by: Kazuhito Hagio Signed-off-by: Lianbo Jiang --- x86_64.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/x86_64.c b/x86_64.c index 292c240e887e..1113a1055f77 100644 --- a/x86_64.c +++ b/x86_64.c @@ -1287,12 +1287,15 @@ x86_64_per_cpu_init(void) { int i, cpus, cpunumber; struct machine_specific *ms; - struct syment *irq_sp, *curr_sp, *cpu_sp, *hardirq_stack_ptr_sp; + struct syment *irq_sp, *curr_sp, *cpu_sp, *hardirq_stack_ptr_sp, *pcpu_sp; ulong hardirq_stack_ptr; ulong __per_cpu_load = 0; + long hardirq_addr = 0, cpu_addr = 0, curr_addr = 0; ms = machdep->machspec; + pcpu_sp = per_cpu_symbol_search("pcpu_hot"); + hardirq_stack_ptr_sp = per_cpu_symbol_search("hardirq_stack_ptr"); irq_sp = per_cpu_symbol_search("per_cpu__irq_stack_union"); cpu_sp = per_cpu_symbol_search("per_cpu__cpu_number"); @@ -1321,7 +1324,7 @@ x86_64_per_cpu_init(void) return; } - if (!cpu_sp || (!irq_sp && !hardirq_stack_ptr_sp)) + if (!pcpu_sp && (!cpu_sp || (!irq_sp && !hardirq_stack_ptr_sp))) return; if (MEMBER_EXISTS("irq_stack_union", "irq_stack")) @@ -1334,10 +1337,21 @@ x86_64_per_cpu_init(void) if (kernel_symbol_exists("__per_cpu_load")) __per_cpu_load = symbol_value("__per_cpu_load"); + if (pcpu_sp) { + hardirq_addr = pcpu_sp->value + MEMBER_OFFSET("pcpu_hot", "hardirq_stack_ptr"); + cpu_addr = pcpu_sp->value + MEMBER_OFFSET("pcpu_hot", "cpu_number"); + curr_addr = pcpu_sp->value + MEMBER_OFFSET("pcpu_hot", "current_task"); + } else { + if (hardirq_stack_ptr_sp) + hardirq_addr = hardirq_stack_ptr_sp->value; + cpu_addr = cpu_sp->value; + curr_addr = curr_sp->value; + } + for (i = cpus = 0; i < NR_CPUS; i++) { if (__per_cpu_load && kt->__per_cpu_offset[i] == __per_cpu_load) break; - if (!readmem(cpu_sp->value + kt->__per_cpu_offset[i], + if (!readmem(cpu_addr + kt->__per_cpu_offset[i], KVADDR, &cpunumber, sizeof(int), "cpu number (per_cpu)", QUIET|RETURN_ON_ERROR)) break; @@ -1346,8 +1360,8 @@ x86_64_per_cpu_init(void) break; cpus++; - if (hardirq_stack_ptr_sp) { - if (!readmem(hardirq_stack_ptr_sp->value + kt->__per_cpu_offset[i], + if (pcpu_sp || hardirq_stack_ptr_sp) { + if (!readmem(hardirq_addr + kt->__per_cpu_offset[i], KVADDR, &hardirq_stack_ptr, sizeof(void *), "hardirq_stack_ptr (per_cpu)", QUIET|RETURN_ON_ERROR)) continue; @@ -1370,13 +1384,13 @@ x86_64_per_cpu_init(void) else kt->cpus = cpus; - if (DUMPFILE() && curr_sp) { + if (DUMPFILE() && (pcpu_sp || curr_sp)) { if ((ms->current = calloc(kt->cpus, sizeof(ulong))) == NULL) error(FATAL, "cannot calloc %d x86_64 current pointers!\n", kt->cpus); for (i = 0; i < kt->cpus; i++) - if (!readmem(curr_sp->value + kt->__per_cpu_offset[i], + if (!readmem(curr_addr + kt->__per_cpu_offset[i], KVADDR, &ms->current[i], sizeof(ulong), "current_task (per_cpu)", RETURN_ON_ERROR)) continue; @@ -5622,11 +5636,19 @@ x86_64_get_smp_cpus(void) char *cpu_pda_buf; ulong level4_pgt, cpu_pda_addr; struct syment *sp; - ulong __per_cpu_load = 0; + ulong __per_cpu_load = 0, cpu_addr; if (!VALID_STRUCT(x8664_pda)) { - if (!(sp = per_cpu_symbol_search("per_cpu__cpu_number")) || - !(kt->flags & PER_CPU_OFF)) + + if (!(kt->flags & PER_CPU_OFF)) + return 1; + + if ((sp = per_cpu_symbol_search("pcpu_hot")) && + (cpu_addr = MEMBER_OFFSET("pcpu_hot", "cpu_number")) != INVALID_OFFSET) + cpu_addr += sp->value; + else if ((sp = per_cpu_symbol_search("per_cpu__cpu_number"))) + cpu_addr = sp->value; + else return 1; if (kernel_symbol_exists("__per_cpu_load")) @@ -5635,7 +5657,7 @@ x86_64_get_smp_cpus(void) for (i = cpus = 0; i < NR_CPUS; i++) { if (__per_cpu_load && kt->__per_cpu_offset[i] == __per_cpu_load) break; - if (!readmem(sp->value + kt->__per_cpu_offset[i], + if (!readmem(cpu_addr + kt->__per_cpu_offset[i], KVADDR, &cpunumber, sizeof(int), "cpu number (per_cpu)", QUIET|RETURN_ON_ERROR)) break; -- 2.37.1