[PATCH] SLUB: Fix for offset change of struct slab members on Linux 6.2-rc1
by HAGIO KAZUHITO(萩尾 一仁)
From: Kazuhito Hagio <k-hagio-ab(a)nec.com>
The following kernel commits split slab info from struct page into
struct slab in Linux 5.17.
d122019bf061 ("mm: Split slab into its own type")
07f910f9b729 ("mm: Remove slab from struct page")
Crash commit 5f390ed811b0 followed the change for SLUB, but crash still
uses the offset of page.lru inappropriately. It could happen to work
well because it was the same value as the offset of slab.slab_list until
Linux 6.1.
However, kernel commit 130d4df57390 ("mm/sl[au]b: rearrange struct slab
fields to allow larger rcu_head") in Linux 6.2-rc1 changed the offset of
slab.slab_list. As a result, without the patch, "kmem -s|-S" options
print the following errors and fail to print values correctly for
kernels configured with CONFIG_SLUB.
crash> kmem -S filp
CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME
kmem: filp: partial list slab: ffffcc650405ab88 invalid page.inuse: -1
ffff8fa0401eca00 232 1267 1792 56 8k filp
...
KMEM_CACHE_NODE NODE SLABS PARTIAL PER-CPU
ffff8fa0401cb8c0 0 56 24 8
NODE 0 PARTIAL:
SLAB MEMORY NODE TOTAL ALLOCATED FREE
kmem: filp: invalid partial list slab pointer: ffffcc650405ab88
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
defs.h | 1 +
memory.c | 16 ++++++++++------
symbols.c | 1 +
3 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/defs.h b/defs.h
index 04476b3ff62e..57c1acc4e8df 100644
--- a/defs.h
+++ b/defs.h
@@ -2182,6 +2182,7 @@ struct offset_table { /* stash of commonly-used offsets */
long blk_mq_tags_rqs;
long request_queue_hctx_table;
long percpu_counter_counters;
+ long slab_slab_list;
};
struct size_table { /* stash of commonly-used sizes */
diff --git a/memory.c b/memory.c
index 9d003713534b..d05737cc1429 100644
--- a/memory.c
+++ b/memory.c
@@ -781,6 +781,8 @@ vm_init(void)
if (INVALID_MEMBER(page_slab))
MEMBER_OFFSET_INIT(page_slab, "slab", "slab_cache");
+ MEMBER_OFFSET_INIT(slab_slab_list, "slab", "slab_list");
+
MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page");
if (INVALID_MEMBER(page_slab_page))
ANON_MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page");
@@ -19474,6 +19476,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node)
{
ulong next, last, list_head, flags;
int first;
+ long list_off = VALID_MEMBER(slab_slab_list) ? OFFSET(slab_slab_list) : OFFSET(page_lru);
if (!node_ptr)
return;
@@ -19487,7 +19490,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node)
next == list_head ? " (empty)\n" : "");
first = 0;
while (next != list_head) {
- si->slab = last = next - OFFSET(page_lru);
+ si->slab = last = next - list_off;
if (first++ == 0)
fprintf(fp, " %s", slab_hdr);
@@ -19510,7 +19513,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node)
if (!IS_KVADDR(next) ||
((next != list_head) &&
- !is_page_ptr(next - OFFSET(page_lru), NULL))) {
+ !is_page_ptr(next - list_off, NULL))) {
error(INFO,
"%s: partial list slab: %lx invalid page.lru.next: %lx\n",
si->curname, last, next);
@@ -19537,7 +19540,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node)
next == list_head ? " (empty)\n" : "");
first = 0;
while (next != list_head) {
- si->slab = next - OFFSET(page_lru);
+ si->slab = next - list_off;
if (first++ == 0)
fprintf(fp, " %s", slab_hdr);
@@ -19754,6 +19757,7 @@ count_partial(ulong node, struct meminfo *si, ulong *free)
short inuse, objects;
ulong total_inuse;
ulong count = 0;
+ long list_off = VALID_MEMBER(slab_slab_list) ? OFFSET(slab_slab_list) : OFFSET(page_lru);
count = 0;
total_inuse = 0;
@@ -19765,12 +19769,12 @@ count_partial(ulong node, struct meminfo *si, ulong *free)
hq_open();
while (next != list_head) {
- if (!readmem(next - OFFSET(page_lru) + OFFSET(page_inuse),
+ if (!readmem(next - list_off + OFFSET(page_inuse),
KVADDR, &inuse, sizeof(ushort), "page.inuse", RETURN_ON_ERROR)) {
hq_close();
return -1;
}
- last = next - OFFSET(page_lru);
+ last = next - list_off;
if (inuse == -1) {
error(INFO,
@@ -19796,7 +19800,7 @@ count_partial(ulong node, struct meminfo *si, ulong *free)
}
if (!IS_KVADDR(next) ||
((next != list_head) &&
- !is_page_ptr(next - OFFSET(page_lru), NULL))) {
+ !is_page_ptr(next - list_off, NULL))) {
error(INFO, "%s: partial list slab: %lx invalid page.lru.next: %lx\n",
si->curname, last, next);
break;
diff --git a/symbols.c b/symbols.c
index e279cfa68490..66158dcf1744 100644
--- a/symbols.c
+++ b/symbols.c
@@ -9700,6 +9700,7 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(slab_inuse));
fprintf(fp, " slab_free: %ld\n",
OFFSET(slab_free));
+ fprintf(fp, " slab_slab_list: %ld\n", OFFSET(slab_slab_list));
fprintf(fp, " kmem_cache_size: %ld\n",
OFFSET(kmem_cache_size));
--
2.31.1
2 years
Re: [Crash-utility] [PATCH v2] Fix for mm_struct.rss_stat conversion into percpu_counter
by lijiang
On Thu, Dec 15, 2022 at 10:45 AM <crash-utility-request(a)redhat.com> wrote:
> Date: Thu, 15 Dec 2022 02:31:38 +0000
> From: HAGIO KAZUHITO(?????) <k-hagio-ab(a)nec.com>
> To: "crash-utility(a)redhat.com" <crash-utility(a)redhat.com>
> Subject: [Crash-utility] [PATCH v2] Fix for mm_struct.rss_stat
> conversion into percpu_counter
> Message-ID: <1671071492-12338-1-git-send-email-k-hagio-ab(a)nec.com>
> Content-Type: text/plain; charset="iso-2022-jp"
>
> Kernel commit f1a7941243c1 ("mm: convert mm's rss stats into
> percpu_counter"), which is contained in Linux 6.2-rc1 and later
> kernels, changed mm_struct.rss_stat from struct mm_rss_stat into an
> array of struct percpu_counter.
>
> Without the patch, "ps" and several commands fail with the following
> error message:
>
> ps: invalid structure member offset: mm_rss_stat_count
> FILE: memory.c LINE: 4724 FUNCTION: get_task_mem_usage()
>
> Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
> ---
> v1 -> v2
> - Fix broken indent
> - Update commit log
>
> Hi Lianbo, I've updated the patch as the kernel patch is merged into
> the mainline. And the indent issue is fixed with this patch?
>
Thank you for the update, Kazu.
Yes, the indent issue has been fixed in the v2, it works well when I
use the git am or git apply command.
> defs.h | 3 +++
> kernel.c | 2 ++
> memory.c | 14 +++++++++++++-
> symbols.c | 6 ++++--
> tools.c | 28 ++++++++++++++++++++++++++++
> 5 files changed, 50 insertions(+), 3 deletions(-)
>
The v2 looks good. So: Ack.
Thanks.
Lianbo
> diff --git a/defs.h b/defs.h
> index afdcf6c4ac20..005b79cf9e74 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -2181,6 +2181,7 @@ struct offset_table { /* stash of commonly-used offsets */
> long blk_mq_tags_nr_reserved_tags;
> long blk_mq_tags_rqs;
> long request_queue_hctx_table;
> + long percpu_counter_counters;
> };
>
> struct size_table { /* stash of commonly-used sizes */
> @@ -2351,6 +2352,7 @@ struct size_table { /* stash of commonly-used sizes */
> long sbitmap_queue;
> long sbq_wait_state;
> long blk_mq_tags;
> + long percpu_counter;
> };
>
> struct array_table {
> @@ -5305,6 +5307,7 @@ struct rb_node *rb_right(struct rb_node *, struct rb_node *);
> struct rb_node *rb_left(struct rb_node *, struct rb_node *);
> struct rb_node *rb_next(struct rb_node *);
> struct rb_node *rb_last(struct rb_root *);
> +long percpu_counter_sum_positive(ulong fbc);
>
> /*
> * symbols.c
> diff --git a/kernel.c b/kernel.c
> index aa030e8097ea..a42e6ad7d78c 100644
> --- a/kernel.c
> +++ b/kernel.c
> @@ -316,6 +316,8 @@ kernel_init()
> }
>
> MEMBER_OFFSET_INIT(percpu_counter_count, "percpu_counter", "count");
> + MEMBER_OFFSET_INIT(percpu_counter_counters, "percpu_counter", "counters");
> + STRUCT_SIZE_INIT(percpu_counter, "percpu_counter");
>
> if (STRUCT_EXISTS("runqueue")) {
> rqstruct = "runqueue";
> diff --git a/memory.c b/memory.c
> index 9c15c1b745ef..dc658bc14c33 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -4713,7 +4713,7 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm)
> /*
> * Latest kernels have mm_struct.mm_rss_stat[].
> */
> - if (VALID_MEMBER(mm_struct_rss_stat)) {
> + if (VALID_MEMBER(mm_struct_rss_stat) && VALID_MEMBER(mm_rss_stat_count)) {
> long anonpages, filepages, count;
>
> anonpages = tt->anonpages;
> @@ -4737,6 +4737,18 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm)
> (anonpages * sizeof(long)));
> if (count > 0)
> rss += count;
> +
> + } else if (VALID_MEMBER(mm_struct_rss_stat)) {
> + /* Linux v6.2: struct percpu_counter rss_stat[NR_MM_COUNTERS] */
> + ulong fbc;
> +
> + fbc = tc->mm_struct + OFFSET(mm_struct_rss_stat) +
> + (tt->filepages * SIZE(percpu_counter));
> + rss += percpu_counter_sum_positive(fbc);
> +
> + fbc = tc->mm_struct + OFFSET(mm_struct_rss_stat) +
> + (tt->anonpages * SIZE(percpu_counter));
> + rss += percpu_counter_sum_positive(fbc);
> }
>
> /* Check whether SPLIT_RSS_COUNTING is enabled */
> diff --git a/symbols.c b/symbols.c
> index 42c4eb400044..e279cfa68490 100644
> --- a/symbols.c
> +++ b/symbols.c
> @@ -10633,8 +10633,8 @@ dump_offset_table(char *spec, ulong makestruct)
> OFFSET(ktime_t_nsec));
> fprintf(fp, " atomic_t_counter: %ld\n",
> OFFSET(atomic_t_counter));
> - fprintf(fp, " percpu_counter_count: %ld\n",
> - OFFSET(percpu_counter_count));
> + fprintf(fp, " percpu_counter_count: %ld\n", OFFSET(percpu_counter_count));
> + fprintf(fp, " percpu_counter_counters: %ld\n", OFFSET(percpu_counter_counters));
> fprintf(fp, " sk_buff_head_next: %ld\n",
> OFFSET(sk_buff_head_next));
> fprintf(fp, " sk_buff_head_qlen: %ld\n",
> @@ -11028,6 +11028,8 @@ dump_offset_table(char *spec, ulong makestruct)
> fprintf(fp, " sbq_wait_state: %ld\n", SIZE(sbq_wait_state));
> fprintf(fp, " blk_mq_tags: %ld\n", SIZE(blk_mq_tags));
>
> + fprintf(fp, " percpu_counter: %ld\n", SIZE(percpu_counter));
> +
> fprintf(fp, "\n array_table:\n");
> /*
> * Use get_array_length() for those fields not set up at init-time;
> diff --git a/tools.c b/tools.c
> index 39306c18c98f..5f86771f5327 100644
> --- a/tools.c
> +++ b/tools.c
> @@ -6902,3 +6902,31 @@ rb_last(struct rb_root *root)
>
> return node;
> }
> +
> +long
> +percpu_counter_sum_positive(ulong fbc)
> +{
> + int i, count;
> + ulong addr;
> + long ret;
> +
> + if (INVALID_MEMBER(percpu_counter_count))
> + return 0;
> +
> + readmem(fbc + OFFSET(percpu_counter_count), KVADDR, &ret,
> + sizeof(long long), "percpu_counter.count", FAULT_ON_ERROR);
> +
> + if (INVALID_MEMBER(percpu_counter_counters)) /* !CONFIG_SMP */
> + return (ret < 0) ? 0 : ret;
> +
> + readmem(fbc + OFFSET(percpu_counter_counters), KVADDR, &addr,
> + sizeof(void *), "percpu_counter.counters", FAULT_ON_ERROR);
> +
> + for (i = 0; i < kt->cpus; i++) {
> + readmem(addr + kt->__per_cpu_offset[i], KVADDR, &count,
> + sizeof(int), "percpu_counter.counters count", FAULT_ON_ERROR);
> + ret += count;
> + }
> +
> + return (ret < 0) ? 0 : ret;
> +}
> --
> 2.31.1
2 years
[PATCH] x86_64: Fix for move of per-cpu variables into struct pcpu_hot
by HAGIO KAZUHITO(萩尾 一仁)
The following kernel commits (in linux-next now, to be updated)
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:
bt: invalid size request: 0 type: "stack contents"
bt: read of stack at 0 failed
<segmentation violation in gdb>
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
x86_64.c | 44 +++++++++++++++++++++++++++++++++-----------
1 file changed, 33 insertions(+), 11 deletions(-)
diff --git a/x86_64.c b/x86_64.c
index 74bd1bbde41c..7a5d6f050c89 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -1290,12 +1290,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");
@@ -1324,7 +1327,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"))
@@ -1337,10 +1340,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;
@@ -1349,8 +1363,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;
@@ -1373,13 +1387,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;
@@ -5625,11 +5639,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"))
@@ -5638,7 +5660,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.31.1
2 years
[PATCH v2] Fix for mm_struct.rss_stat conversion into percpu_counter
by HAGIO KAZUHITO(萩尾 一仁)
Kernel commit f1a7941243c1 ("mm: convert mm's rss stats into
percpu_counter"), which is contained in Linux 6.2-rc1 and later
kernels, changed mm_struct.rss_stat from struct mm_rss_stat into an
array of struct percpu_counter.
Without the patch, "ps" and several commands fail with the following
error message:
ps: invalid structure member offset: mm_rss_stat_count
FILE: memory.c LINE: 4724 FUNCTION: get_task_mem_usage()
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
v1 -> v2
- Fix broken indent
- Update commit log
Hi Lianbo, I've updated the patch as the kernel patch is merged into
the mainline. And the indent issue is fixed with this patch?
defs.h | 3 +++
kernel.c | 2 ++
memory.c | 14 +++++++++++++-
symbols.c | 6 ++++--
tools.c | 28 ++++++++++++++++++++++++++++
5 files changed, 50 insertions(+), 3 deletions(-)
diff --git a/defs.h b/defs.h
index afdcf6c4ac20..005b79cf9e74 100644
--- a/defs.h
+++ b/defs.h
@@ -2181,6 +2181,7 @@ struct offset_table { /* stash of commonly-used offsets */
long blk_mq_tags_nr_reserved_tags;
long blk_mq_tags_rqs;
long request_queue_hctx_table;
+ long percpu_counter_counters;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2351,6 +2352,7 @@ struct size_table { /* stash of commonly-used sizes */
long sbitmap_queue;
long sbq_wait_state;
long blk_mq_tags;
+ long percpu_counter;
};
struct array_table {
@@ -5305,6 +5307,7 @@ struct rb_node *rb_right(struct rb_node *, struct rb_node *);
struct rb_node *rb_left(struct rb_node *, struct rb_node *);
struct rb_node *rb_next(struct rb_node *);
struct rb_node *rb_last(struct rb_root *);
+long percpu_counter_sum_positive(ulong fbc);
/*
* symbols.c
diff --git a/kernel.c b/kernel.c
index aa030e8097ea..a42e6ad7d78c 100644
--- a/kernel.c
+++ b/kernel.c
@@ -316,6 +316,8 @@ kernel_init()
}
MEMBER_OFFSET_INIT(percpu_counter_count, "percpu_counter", "count");
+ MEMBER_OFFSET_INIT(percpu_counter_counters, "percpu_counter", "counters");
+ STRUCT_SIZE_INIT(percpu_counter, "percpu_counter");
if (STRUCT_EXISTS("runqueue")) {
rqstruct = "runqueue";
diff --git a/memory.c b/memory.c
index 9c15c1b745ef..dc658bc14c33 100644
--- a/memory.c
+++ b/memory.c
@@ -4713,7 +4713,7 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm)
/*
* Latest kernels have mm_struct.mm_rss_stat[].
*/
- if (VALID_MEMBER(mm_struct_rss_stat)) {
+ if (VALID_MEMBER(mm_struct_rss_stat) && VALID_MEMBER(mm_rss_stat_count)) {
long anonpages, filepages, count;
anonpages = tt->anonpages;
@@ -4737,6 +4737,18 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm)
(anonpages * sizeof(long)));
if (count > 0)
rss += count;
+
+ } else if (VALID_MEMBER(mm_struct_rss_stat)) {
+ /* Linux v6.2: struct percpu_counter rss_stat[NR_MM_COUNTERS] */
+ ulong fbc;
+
+ fbc = tc->mm_struct + OFFSET(mm_struct_rss_stat) +
+ (tt->filepages * SIZE(percpu_counter));
+ rss += percpu_counter_sum_positive(fbc);
+
+ fbc = tc->mm_struct + OFFSET(mm_struct_rss_stat) +
+ (tt->anonpages * SIZE(percpu_counter));
+ rss += percpu_counter_sum_positive(fbc);
}
/* Check whether SPLIT_RSS_COUNTING is enabled */
diff --git a/symbols.c b/symbols.c
index 42c4eb400044..e279cfa68490 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10633,8 +10633,8 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(ktime_t_nsec));
fprintf(fp, " atomic_t_counter: %ld\n",
OFFSET(atomic_t_counter));
- fprintf(fp, " percpu_counter_count: %ld\n",
- OFFSET(percpu_counter_count));
+ fprintf(fp, " percpu_counter_count: %ld\n", OFFSET(percpu_counter_count));
+ fprintf(fp, " percpu_counter_counters: %ld\n", OFFSET(percpu_counter_counters));
fprintf(fp, " sk_buff_head_next: %ld\n",
OFFSET(sk_buff_head_next));
fprintf(fp, " sk_buff_head_qlen: %ld\n",
@@ -11028,6 +11028,8 @@ dump_offset_table(char *spec, ulong makestruct)
fprintf(fp, " sbq_wait_state: %ld\n", SIZE(sbq_wait_state));
fprintf(fp, " blk_mq_tags: %ld\n", SIZE(blk_mq_tags));
+ fprintf(fp, " percpu_counter: %ld\n", SIZE(percpu_counter));
+
fprintf(fp, "\n array_table:\n");
/*
* Use get_array_length() for those fields not set up at init-time;
diff --git a/tools.c b/tools.c
index 39306c18c98f..5f86771f5327 100644
--- a/tools.c
+++ b/tools.c
@@ -6902,3 +6902,31 @@ rb_last(struct rb_root *root)
return node;
}
+
+long
+percpu_counter_sum_positive(ulong fbc)
+{
+ int i, count;
+ ulong addr;
+ long ret;
+
+ if (INVALID_MEMBER(percpu_counter_count))
+ return 0;
+
+ readmem(fbc + OFFSET(percpu_counter_count), KVADDR, &ret,
+ sizeof(long long), "percpu_counter.count", FAULT_ON_ERROR);
+
+ if (INVALID_MEMBER(percpu_counter_counters)) /* !CONFIG_SMP */
+ return (ret < 0) ? 0 : ret;
+
+ readmem(fbc + OFFSET(percpu_counter_counters), KVADDR, &addr,
+ sizeof(void *), "percpu_counter.counters", FAULT_ON_ERROR);
+
+ for (i = 0; i < kt->cpus; i++) {
+ readmem(addr + kt->__per_cpu_offset[i], KVADDR, &count,
+ sizeof(int), "percpu_counter.counters count", FAULT_ON_ERROR);
+ ret += count;
+ }
+
+ return (ret < 0) ? 0 : ret;
+}
--
2.31.1
2 years
[PATCH] Fix for mm_struct.rss_stat conversion into percpu_counter
by HAGIO KAZUHITO(萩尾 一仁)
Kernel commit f1a7941243c1 ("mm: convert mm's rss stats into
percpu_counter") changed mm_struct.rss_stat from struct mm_rss_stat
into an array of struct percpu_counter. (currently in linux-next)
Without the patch, "ps" and several commands fail with the following
error message:
ps: invalid structure member offset: mm_rss_stat_count
FILE: memory.c LINE: 4724 FUNCTION: get_task_mem_usage()
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
defs.h | 3 +++
kernel.c | 2 ++
memory.c | 14 +++++++++++++-
symbols.c | 6 ++++--
tools.c | 28 ++++++++++++++++++++++++++++
5 files changed, 50 insertions(+), 3 deletions(-)
diff --git a/defs.h b/defs.h
index afdcf6c4ac20..005b79cf9e74 100644
--- a/defs.h
+++ b/defs.h
@@ -2181,6 +2181,7 @@ struct offset_table { /* stash of commonly-used offsets */
long blk_mq_tags_nr_reserved_tags;
long blk_mq_tags_rqs;
long request_queue_hctx_table;
+ long percpu_counter_counters;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2351,6 +2352,7 @@ struct size_table { /* stash of commonly-used sizes */
long sbitmap_queue;
long sbq_wait_state;
long blk_mq_tags;
+ long percpu_counter;
};
struct array_table {
@@ -5305,6 +5307,7 @@ struct rb_node *rb_right(struct rb_node *, struct rb_node *);
struct rb_node *rb_left(struct rb_node *, struct rb_node *);
struct rb_node *rb_next(struct rb_node *);
struct rb_node *rb_last(struct rb_root *);
+long percpu_counter_sum_positive(ulong fbc);
/*
* symbols.c
diff --git a/kernel.c b/kernel.c
index aa030e8097ea..a42e6ad7d78c 100644
--- a/kernel.c
+++ b/kernel.c
@@ -316,6 +316,8 @@ kernel_init()
}
MEMBER_OFFSET_INIT(percpu_counter_count, "percpu_counter", "count");
+ MEMBER_OFFSET_INIT(percpu_counter_counters, "percpu_counter", "counters");
+ STRUCT_SIZE_INIT(percpu_counter, "percpu_counter");
if (STRUCT_EXISTS("runqueue")) {
rqstruct = "runqueue";
diff --git a/memory.c b/memory.c
index 9c15c1b745ef..dc658bc14c33 100644
--- a/memory.c
+++ b/memory.c
@@ -4713,7 +4713,7 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm)
/*
* Latest kernels have mm_struct.mm_rss_stat[].
*/
- if (VALID_MEMBER(mm_struct_rss_stat)) {
+ if (VALID_MEMBER(mm_struct_rss_stat) && VALID_MEMBER(mm_rss_stat_count)) {
long anonpages, filepages, count;
anonpages = tt->anonpages;
@@ -4737,6 +4737,18 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm)
(anonpages * sizeof(long)));
if (count > 0)
rss += count;
+
+ } else if (VALID_MEMBER(mm_struct_rss_stat)) {
+ /* Linux v6.2: struct percpu_counter rss_stat[NR_MM_COUNTERS] */
+ ulong fbc;
+
+ fbc = tc->mm_struct + OFFSET(mm_struct_rss_stat) +
+ (tt->filepages * SIZE(percpu_counter));
+ rss += percpu_counter_sum_positive(fbc);
+
+ fbc = tc->mm_struct + OFFSET(mm_struct_rss_stat) +
+ (tt->anonpages * SIZE(percpu_counter));
+ rss += percpu_counter_sum_positive(fbc);
}
/* Check whether SPLIT_RSS_COUNTING is enabled */
diff --git a/symbols.c b/symbols.c
index 42c4eb400044..e279cfa68490 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10633,8 +10633,8 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(ktime_t_nsec));
fprintf(fp, " atomic_t_counter: %ld\n",
OFFSET(atomic_t_counter));
- fprintf(fp, " percpu_counter_count: %ld\n",
- OFFSET(percpu_counter_count));
+ fprintf(fp, " percpu_counter_count: %ld\n", OFFSET(percpu_counter_count));
+ fprintf(fp, " percpu_counter_counters: %ld\n", OFFSET(percpu_counter_counters));
fprintf(fp, " sk_buff_head_next: %ld\n",
OFFSET(sk_buff_head_next));
fprintf(fp, " sk_buff_head_qlen: %ld\n",
@@ -11028,6 +11028,8 @@ dump_offset_table(char *spec, ulong makestruct)
fprintf(fp, " sbq_wait_state: %ld\n", SIZE(sbq_wait_state));
fprintf(fp, " blk_mq_tags: %ld\n", SIZE(blk_mq_tags));
+ fprintf(fp, " percpu_counter: %ld\n", SIZE(percpu_counter));
+
fprintf(fp, "\n array_table:\n");
/*
* Use get_array_length() for those fields not set up at init-time;
diff --git a/tools.c b/tools.c
index 39306c18c98f..5f86771f5327 100644
--- a/tools.c
+++ b/tools.c
@@ -6902,3 +6902,31 @@ rb_last(struct rb_root *root)
return node;
}
+
+long
+percpu_counter_sum_positive(ulong fbc)
+{
+ int i, count;
+ ulong addr;
+ long ret;
+
+ if (INVALID_MEMBER(percpu_counter_count))
+ return 0;
+
+ readmem(fbc + OFFSET(percpu_counter_count), KVADDR, &ret,
+ sizeof(long long), "percpu_counter.count", FAULT_ON_ERROR);
+
+ if (INVALID_MEMBER(percpu_counter_counters)) /* !CONFIG_SMP */
+ return (ret < 0) ? 0 : ret;
+
+ readmem(fbc + OFFSET(percpu_counter_counters), KVADDR, &addr,
+ sizeof(void *), "percpu_counter.counters", FAULT_ON_ERROR);
+
+ for (i = 0; i < kt->cpus; i++) {
+ readmem(addr + kt->__per_cpu_offset[i], KVADDR, &count,
+ sizeof(int), "percpu_counter.counters count", FAULT_ON_ERROR);
+ ret += count;
+ }
+
+ return (ret < 0) ? 0 : ret;
+}
--
2.31.1
2 years
Re: [Crash-utility] EPPIC extension support for crach_8.X+gdb_10.X
by lijiang
On Sat, Dec 10, 2022 at 3:43 AM <crash-utility-request(a)redhat.com> wrote:
> Date: Fri, 9 Dec 2022 11:42:59 -0800
> From: Luc Park-Chouinard <lucchouina(a)gmail.com>
> To: crash-utility(a)redhat.com
> Subject: [Crash-utility] [PATCH] EPPIC extension support for
> crach_8.X+gdb_10.X
> Message-ID:
> <CAM7e1qRZU6VytoERxx6TY52V+pdu0-fT_9PYNPTHKE654gpwDw(a)mail.gmail.com>
> Content-Type: text/plain; charset="utf-8"
>
> Please find attached.
> Thanks for the offline reviews Kazu and Lianbo!
>
Thank you for the update, Luc.
For the patch: Ack.
Thanks.
Lianbo
> --
>
> - Luc
>
2 years
Re: [Crash-utility] [PATCH] arm64: handle vabits_actual symbol missing case
by lijiang
Thank you for the update, Pavankumar.
On Thu, Dec 8, 2022 at 1:08 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Thu, 8 Dec 2022 09:55:07 +0530
> From: Pavankumar Kondeti <quic_pkondeti(a)quicinc.com>
> To: <crash-utility(a)redhat.com>, <k-hagio-ab(a)nec.com>
> Cc: <quic_ankban(a)quicinc.com>, Pavankumar Kondeti
> <quic_pkondeti(a)quicinc.com>
> Subject: [Crash-utility] [PATCH] arm64: handle vabits_actual symbol
> missing case
> Message-ID:
> <1670473507-29911-1-git-send-email-quic_pkondeti(a)quicinc.com>
> Content-Type: text/plain
>
> After the commit 0d9b1ffefabe ("arm64: mm: make vabits_actual
> a build time constant if possible") introduced in v5.19
> Linux kernel, the crash will not find vabits_actual symbol
> if if VA_BITS <= 48. Add a fallback option to initialize VA_BITS
^^^^
> based on the user supplied machdep option.
>
> Tested ramdumps loading in both 6.0 and 5.15 kernels.
>
> Signed-off-by: Pavankumar Kondeti <quic_pkondeti(a)quicinc.com>
> ---
> arm64.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/arm64.c b/arm64.c
> index c3e26a3..7125458 100644
> --- a/arm64.c
> +++ b/arm64.c
> @@ -4671,6 +4671,10 @@ arm64_calc_VA_BITS(void)
> return;
> } else if (arm64_set_va_bits_by_tcr()) {
> return;
> + } else if (machdep->machspec->VA_BITS_ACTUAL) {
> + machdep->machspec->VA_BITS = machdep->machspec->VA_BITS_ACTUAL;
> + machdep->machspec->VA_START = _VA_START(machdep->machspec->VA_BITS_ACTUAL);
> + return;
> }
>
Looks good to me, for the v2: Ack
Thanks.
Lianbo
> if (!(sp = symbol_search("swapper_pg_dir")) &&
> --
> 2.7.4
2 years
Re: [Crash-utility] [PATCH] arm64: fix backtraces of KASAN kernel dumpfile truncated
by lijiang
Hi, Ding
Thank you for the fix.
On Thu, Dec 1, 2022 at 8:00 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Thu, 1 Dec 2022 15:01:45 +0800
> From: Ding Hui <dinghui(a)sangfor.com.cn>
> To: crash-utility(a)redhat.com
> Cc: Ding Hui <dinghui(a)sangfor.com.cn>
> Subject: [Crash-utility] [PATCH] arm64: fix backtraces of KASAN kernel
> dumpfile truncated
> Message-ID: <20221201070145.10830-1-dinghui(a)sangfor.com.cn>
> Content-Type: text/plain; charset="US-ASCII"; x-default=true
>
> We met "bt" cmd on KASAN kernel vmcore display truncated backtraces
> like this:
>
> crash> bt
> PID: 4131 TASK: ffff8001521df000 CPU: 3 COMMAND: "bash"
> #0 [ffff2000224b0cb0] machine_kexec_prepare at ffff2000200bff4c
>
Can you help explain how to reproduce this issue? Or what's the
critical configuration of the kernel? Can this issue be always
reproduced?
I tried to reproduce it on the latest kernel(commit bce9332220bd )
with the CONFIG_KASAN*=y, but can not reproduce this error.
crash> bt
PID: 23838 TASK: ffff3d83abe61300 CPU: 2 COMMAND: "bash"
#0 [ffff800010587650] machine_kexec at ffffbb61b39bd460
#1 [ffff8000105876a0] __crash_kexec at ffffbb61b3b8e2fc
#2 [ffff8000105878c0] panic at ffffbb61b4b6c158
#3 [ffff8000105879f0] sysrq_handle_crash at ffffbb61b43b1144
#4 [ffff800010587a00] __handle_sysrq at ffffbb61b43b1ddc
#5 [ffff800010587a80] write_sysrq_trigger at ffffbb61b43b26e0
#6 [ffff800010587ab0] proc_reg_write at ffffbb61b3f9c4ac
#7 [ffff800010587af0] vfs_write at ffffbb61b3ebeaf4
#8 [ffff800010587c30] ksys_write at ffffbb61b3ebf054
#9 [ffff800010587cd0] __arm64_sys_write at ffffbb61b3ebf144
#10 [ffff800010587df0] invoke_syscall.constprop.0 at ffffbb61b39afc88
#11 [ffff800010587e30] el0_svc_common.constprop.0 at ffffbb61b39afeac
#12 [ffff800010587e60] do_el0_svc at ffffbb61b39aff08
#13 [ffff800010587e80] el0_svc at ffffbb61b4b8defc
#14 [ffff800010587ea0] el0t_64_sync_handler at ffffbb61b4b8e274
#15 [ffff800010587fe0] el0t_64_sync at ffffbb61b39915bc
PC: 0000ffffa42a4880 LR: 0000ffffa424321c SP: 0000ffffe889dd60
X29: 0000ffffe889dd60 X28: 0000000000000000 X27: 0000aaaad1c10000
X26: 0000aaaad1c73018 X25: 0000aaaad1cb89bc X24: 0000000000000002
X23: 0000aaaadd9ce140 X22: 0000ffffa43e77e0 X21: 0000ffffa436a5c0
X20: 0000aaaadd9ce140 X19: 0000000000000001 X18: 0000000000000000
X17: 0000ffffa423ff50 X16: 0000ffffa4244600 X15: 0000ffffa4311350
X14: 0000000000000000 X13: 0000000000000000 X12: 0000000000000000
X11: 0000000000000020 X10: 0000000000000063 X9: 0000aaaadd9dc2c0
X8: 0000000000000040 X7: 00000000ffffffff X6: 0000000000000063
X5: 0000aaaadd9ce141 X4: 0000aaaadd9dc2c1 X3: 0000ffffa43e7020
X2: 0000000000000002 X1: 0000aaaadd9ce140 X0: 0000000000000001
ORIG_X0: 0000000000000001 SYSCALLNO: 40 PSTATE: 20000000
crash>
Thanks.
Lianbo
> After digging the root cause, it turns out that arm64_in_kdump_text()
> found wrong bt->bptr at "machine_kexec" branch.
>
> Disassemble machine_kexec() of KASAN vmlinux (gcc 7.3.0):
>
> crash> dis -x machine_kexec
> 0xffff2000200bff50 <machine_kexec>: stp x29, x30, [sp,#-208]!
> 0xffff2000200bff54 <machine_kexec+0x4>: mov x29, sp
> 0xffff2000200bff58 <machine_kexec+0x8>: stp x19, x20, [sp,#16]
> 0xffff2000200bff5c <machine_kexec+0xc>: str x24, [sp,#56]
> 0xffff2000200bff60 <machine_kexec+0x10>: str x26, [sp,#72]
> 0xffff2000200bff64 <machine_kexec+0x14>: mov x2, #0x8ab3
> 0xffff2000200bff68 <machine_kexec+0x18>: add x1, x29, #0x70
> 0xffff2000200bff6c <machine_kexec+0x1c>: lsr x1, x1, #3
> 0xffff2000200bff70 <machine_kexec+0x20>: movk x2, #0x41b5, lsl #16
> 0xffff2000200bff74 <machine_kexec+0x24>: mov x19, #0x200000000000
> 0xffff2000200bff78 <machine_kexec+0x28>: adrp x3, 0xffff2000224b0000
> 0xffff2000200bff7c <machine_kexec+0x2c>: movk x19, #0xdfff, lsl #48
> 0xffff2000200bff80 <machine_kexec+0x30>: add x3, x3, #0xcb0
> 0xffff2000200bff84 <machine_kexec+0x34>: add x4, x1, x19
> 0xffff2000200bff88 <machine_kexec+0x38>: stp x2, x3, [x29,#112]
> 0xffff2000200bff8c <machine_kexec+0x3c>: adrp x2, 0xffff2000200bf000 <swsusp_arch_resume+0x1e8>
> 0xffff2000200bff90 <machine_kexec+0x40>: add x2, x2, #0xf50
> 0xffff2000200bff94 <machine_kexec+0x44>: str x2, [x29,#128]
> 0xffff2000200bff98 <machine_kexec+0x48>: mov w2, #0xf1f1f1f1
> 0xffff2000200bff9c <machine_kexec+0x4c>: str w2, [x1,x19]
> 0xffff2000200bffa0 <machine_kexec+0x50>: mov w2, #0xf200
> 0xffff2000200bffa4 <machine_kexec+0x54>: mov w1, #0xf3f3f3f3
> 0xffff2000200bffa8 <machine_kexec+0x58>: movk w2, #0xf2f2, lsl #16
> 0xffff2000200bffac <machine_kexec+0x5c>: stp w2, w1, [x4,#4]
>
> We notice that:
> 1. machine_kexec() start address is 0xffff2000200bff50
> 2. the instruction at machine_kexec+0x44 store the same value
> 0xffff2000200bff50 (comes from 0xffff2000200bf000 + 0xf50)
> into stack postion [x29,#128].
>
> When arm64_in_kdump_text() search LR from stack, it met
> 0xffff2000200bff50 firstly, so got wrong bt->bptr.
>
> We know that the real LR is always great than the start address
> of a function, so let's fix it by change the search conditon to
> (*ptr > xxx_start) && (*ptr < xxx_end).
>
> Signed-off-by: Ding Hui <dinghui(a)sangfor.com.cn>
> ---
> arm64.c | 18 +++++++++---------
> 1 file changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/arm64.c b/arm64.c
> index c3e26a3..7e8a7db 100644
> --- a/arm64.c
> +++ b/arm64.c
> @@ -3479,7 +3479,7 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
> ms = machdep->machspec;
> for (ptr = start - 8; ptr >= base; ptr--) {
> if (bt->flags & BT_OPT_BACK_TRACE) {
> - if ((*ptr >= ms->crash_kexec_start) &&
> + if ((*ptr > ms->crash_kexec_start) &&
> (*ptr < ms->crash_kexec_end) &&
> INSTACK(*(ptr - 1), bt)) {
> bt->bptr = ((ulong)(ptr - 1) - (ulong)base)
> @@ -3488,7 +3488,7 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
> fprintf(fp, "%lx: %lx (crash_kexec)\n", bt->bptr, *ptr);
> return TRUE;
> }
> - if ((*ptr >= ms->crash_save_cpu_start) &&
> + if ((*ptr > ms->crash_save_cpu_start) &&
> (*ptr < ms->crash_save_cpu_end) &&
> INSTACK(*(ptr - 1), bt)) {
> bt->bptr = ((ulong)(ptr - 1) - (ulong)base)
> @@ -3498,14 +3498,14 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
> return TRUE;
> }
> } else {
> - if ((*ptr >= ms->machine_kexec_start) && (*ptr < ms->machine_kexec_end)) {
> + if ((*ptr > ms->machine_kexec_start) && (*ptr < ms->machine_kexec_end)) {
> bt->bptr = ((ulong)ptr - (ulong)base)
> + task_to_stackbase(bt->tc->task);
> if (CRASHDEBUG(1))
> fprintf(fp, "%lx: %lx (machine_kexec)\n", bt->bptr, *ptr);
> return TRUE;
> }
> - if ((*ptr >= ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
> + if ((*ptr > ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
> /*
> * Stash the first crash_kexec frame in case the machine_kexec
> * frame is not found.
> @@ -3519,7 +3519,7 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
> }
> continue;
> }
> - if ((*ptr >= ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
> + if ((*ptr > ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
> bt->bptr = ((ulong)ptr - (ulong)base)
> + task_to_stackbase(bt->tc->task);
> if (CRASHDEBUG(1))
> @@ -3566,7 +3566,7 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
>
> for (ptr = start - 8; ptr >= base; ptr--) {
> if (bt->flags & BT_OPT_BACK_TRACE) {
> - if ((*ptr >= ms->crash_kexec_start) &&
> + if ((*ptr > ms->crash_kexec_start) &&
> (*ptr < ms->crash_kexec_end) &&
> INSTACK(*(ptr - 1), bt)) {
> bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase;
> @@ -3576,7 +3576,7 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
> FREEBUF(stackbuf);
> return TRUE;
> }
> - if ((*ptr >= ms->crash_save_cpu_start) &&
> + if ((*ptr > ms->crash_save_cpu_start) &&
> (*ptr < ms->crash_save_cpu_end) &&
> INSTACK(*(ptr - 1), bt)) {
> bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase;
> @@ -3587,7 +3587,7 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
> return TRUE;
> }
> } else {
> - if ((*ptr >= ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
> + if ((*ptr > ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
> bt->bptr = ((ulong)ptr - (ulong)base) + stackbase;
> if (CRASHDEBUG(1))
> fprintf(fp, "%lx: %lx (crash_kexec on IRQ stack)\n",
> @@ -3595,7 +3595,7 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
> FREEBUF(stackbuf);
> return TRUE;
> }
> - if ((*ptr >= ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
> + if ((*ptr > ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
> bt->bptr = ((ulong)ptr - (ulong)base) + stackbase;
> if (CRASHDEBUG(1))
> fprintf(fp, "%lx: %lx (crash_save_cpu on IRQ stack)\n",
> --
> 2.17.1
2 years
[PATCH] arm64: fix backtraces of KASAN kernel dumpfile truncated
by Ding Hui
We met "bt" cmd on KASAN kernel vmcore display truncated backtraces
like this:
crash> bt
PID: 4131 TASK: ffff8001521df000 CPU: 3 COMMAND: "bash"
#0 [ffff2000224b0cb0] machine_kexec_prepare at ffff2000200bff4c
After digging the root cause, it turns out that arm64_in_kdump_text()
found wrong bt->bptr at "machine_kexec" branch.
Disassemble machine_kexec() of KASAN vmlinux (gcc 7.3.0):
crash> dis -x machine_kexec
0xffff2000200bff50 <machine_kexec>: stp x29, x30, [sp,#-208]!
0xffff2000200bff54 <machine_kexec+0x4>: mov x29, sp
0xffff2000200bff58 <machine_kexec+0x8>: stp x19, x20, [sp,#16]
0xffff2000200bff5c <machine_kexec+0xc>: str x24, [sp,#56]
0xffff2000200bff60 <machine_kexec+0x10>: str x26, [sp,#72]
0xffff2000200bff64 <machine_kexec+0x14>: mov x2, #0x8ab3
0xffff2000200bff68 <machine_kexec+0x18>: add x1, x29, #0x70
0xffff2000200bff6c <machine_kexec+0x1c>: lsr x1, x1, #3
0xffff2000200bff70 <machine_kexec+0x20>: movk x2, #0x41b5, lsl #16
0xffff2000200bff74 <machine_kexec+0x24>: mov x19, #0x200000000000
0xffff2000200bff78 <machine_kexec+0x28>: adrp x3, 0xffff2000224b0000
0xffff2000200bff7c <machine_kexec+0x2c>: movk x19, #0xdfff, lsl #48
0xffff2000200bff80 <machine_kexec+0x30>: add x3, x3, #0xcb0
0xffff2000200bff84 <machine_kexec+0x34>: add x4, x1, x19
0xffff2000200bff88 <machine_kexec+0x38>: stp x2, x3, [x29,#112]
0xffff2000200bff8c <machine_kexec+0x3c>: adrp x2, 0xffff2000200bf000 <swsusp_arch_resume+0x1e8>
0xffff2000200bff90 <machine_kexec+0x40>: add x2, x2, #0xf50
0xffff2000200bff94 <machine_kexec+0x44>: str x2, [x29,#128]
0xffff2000200bff98 <machine_kexec+0x48>: mov w2, #0xf1f1f1f1
0xffff2000200bff9c <machine_kexec+0x4c>: str w2, [x1,x19]
0xffff2000200bffa0 <machine_kexec+0x50>: mov w2, #0xf200
0xffff2000200bffa4 <machine_kexec+0x54>: mov w1, #0xf3f3f3f3
0xffff2000200bffa8 <machine_kexec+0x58>: movk w2, #0xf2f2, lsl #16
0xffff2000200bffac <machine_kexec+0x5c>: stp w2, w1, [x4,#4]
We notice that:
1. machine_kexec() start address is 0xffff2000200bff50
2. the instruction at machine_kexec+0x44 store the same value
0xffff2000200bff50 (comes from 0xffff2000200bf000 + 0xf50)
into stack postion [x29,#128].
When arm64_in_kdump_text() search LR from stack, it met
0xffff2000200bff50 firstly, so got wrong bt->bptr.
We know that the real LR is always great than the start address
of a function, so let's fix it by change the search conditon to
(*ptr > xxx_start) && (*ptr < xxx_end).
Signed-off-by: Ding Hui <dinghui(a)sangfor.com.cn>
---
arm64.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/arm64.c b/arm64.c
index c3e26a3..7e8a7db 100644
--- a/arm64.c
+++ b/arm64.c
@@ -3479,7 +3479,7 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
ms = machdep->machspec;
for (ptr = start - 8; ptr >= base; ptr--) {
if (bt->flags & BT_OPT_BACK_TRACE) {
- if ((*ptr >= ms->crash_kexec_start) &&
+ if ((*ptr > ms->crash_kexec_start) &&
(*ptr < ms->crash_kexec_end) &&
INSTACK(*(ptr - 1), bt)) {
bt->bptr = ((ulong)(ptr - 1) - (ulong)base)
@@ -3488,7 +3488,7 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
fprintf(fp, "%lx: %lx (crash_kexec)\n", bt->bptr, *ptr);
return TRUE;
}
- if ((*ptr >= ms->crash_save_cpu_start) &&
+ if ((*ptr > ms->crash_save_cpu_start) &&
(*ptr < ms->crash_save_cpu_end) &&
INSTACK(*(ptr - 1), bt)) {
bt->bptr = ((ulong)(ptr - 1) - (ulong)base)
@@ -3498,14 +3498,14 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
return TRUE;
}
} else {
- if ((*ptr >= ms->machine_kexec_start) && (*ptr < ms->machine_kexec_end)) {
+ if ((*ptr > ms->machine_kexec_start) && (*ptr < ms->machine_kexec_end)) {
bt->bptr = ((ulong)ptr - (ulong)base)
+ task_to_stackbase(bt->tc->task);
if (CRASHDEBUG(1))
fprintf(fp, "%lx: %lx (machine_kexec)\n", bt->bptr, *ptr);
return TRUE;
}
- if ((*ptr >= ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
+ if ((*ptr > ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
/*
* Stash the first crash_kexec frame in case the machine_kexec
* frame is not found.
@@ -3519,7 +3519,7 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
}
continue;
}
- if ((*ptr >= ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
+ if ((*ptr > ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
bt->bptr = ((ulong)ptr - (ulong)base)
+ task_to_stackbase(bt->tc->task);
if (CRASHDEBUG(1))
@@ -3566,7 +3566,7 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
for (ptr = start - 8; ptr >= base; ptr--) {
if (bt->flags & BT_OPT_BACK_TRACE) {
- if ((*ptr >= ms->crash_kexec_start) &&
+ if ((*ptr > ms->crash_kexec_start) &&
(*ptr < ms->crash_kexec_end) &&
INSTACK(*(ptr - 1), bt)) {
bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase;
@@ -3576,7 +3576,7 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
FREEBUF(stackbuf);
return TRUE;
}
- if ((*ptr >= ms->crash_save_cpu_start) &&
+ if ((*ptr > ms->crash_save_cpu_start) &&
(*ptr < ms->crash_save_cpu_end) &&
INSTACK(*(ptr - 1), bt)) {
bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase;
@@ -3587,7 +3587,7 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
return TRUE;
}
} else {
- if ((*ptr >= ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
+ if ((*ptr > ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) {
bt->bptr = ((ulong)ptr - (ulong)base) + stackbase;
if (CRASHDEBUG(1))
fprintf(fp, "%lx: %lx (crash_kexec on IRQ stack)\n",
@@ -3595,7 +3595,7 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
FREEBUF(stackbuf);
return TRUE;
}
- if ((*ptr >= ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
+ if ((*ptr > ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) {
bt->bptr = ((ulong)ptr - (ulong)base) + stackbase;
if (CRASHDEBUG(1))
fprintf(fp, "%lx: %lx (crash_save_cpu on IRQ stack)\n",
--
2.17.1
2 years