 
                                        
                                
                         
                        
                                
                                
                                        
                                                
                                        
                                        
                                        [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, 10 months
                        
                        
                 
         
 
        
            
        
        
        
                
                        
                                
                                 
                                        
                                
                         
                        
                                
                                
                                        
                                                
                                        
                                        
                                        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, 10 months
                        
                        
                 
         
 
        
            
        
        
        
                
                        
                                
                                 
                                        
                                
                         
                        
                                
                                
                                        
                                                
                                        
                                        
                                        [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, 10 months
                        
                        
                 
         
 
        
            
        
        
        
                
                        
                                
                                 
                                        
                                
                         
                        
                                
                                
                                        
                                                
                                        
                                        
                                        [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, 10 months
                        
                        
                 
         
 
        
            
        
        
        
                
                        
                                
                                 
                                        
                                
                         
                        
                                
                                
                                        
                                                
                                        
                                        
                                        [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, 10 months
                        
                        
                 
         
 
        
            
        
        
        
                
                        
                        
                                
                                
                                        
                                                
                                        
                                        
                                        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, 10 months
                        
                        
                 
         
 
        
            
        
        
        
                
                        
                                
                                 
                                        
                                
                         
                        
                                
                                
                                        
                                                
                                        
                                        
                                        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, 10 months
                        
                        
                 
         
 
        
            
        
        
        
            
        
        
        
                
                        
                                
                                 
                                        
                                
                         
                        
                                
                                
                                        
                                                
                                        
                                        
                                        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, 10 months
                        
                        
                 
         
 
        
            
        
        
        
                
                        
                                
                                 
                                        
                                
                         
                        
                                
                                
                                        
                                                
                                        
                                        
                                        [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, 10 months