Rebase to upstream crash-8.0.3
Release: crash-8.0.3-1 Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
This commit is contained in:
		
							parent
							
								
									f24b8df61c
								
							
						
					
					
						commit
						922cb60578
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -47,5 +47,6 @@ crash-5.0.6.tar.gz | |||||||
| /crash-8.0.0.tar.gz | /crash-8.0.0.tar.gz | ||||||
| /crash-8.0.1.tar.gz | /crash-8.0.1.tar.gz | ||||||
| /crash-8.0.2.tar.gz | /crash-8.0.2.tar.gz | ||||||
|  | /crash-8.0.3.tar.gz | ||||||
| /gdb-7.6.tar.gz | /gdb-7.6.tar.gz | ||||||
| /gdb-10.2.tar.gz | /gdb-10.2.tar.gz | ||||||
|  | |||||||
| @ -1,72 +0,0 @@ | |||||||
| From 9f1256958d2b18953b4c8b244d88c023048a964f Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Aaron Tomlin <atomlin@redhat.com> |  | ||||||
| Date: Tue, 29 Nov 2022 14:05:26 +0000 |  | ||||||
| Subject: [PATCH 01/28] ps: Provide an option to display no header line |  | ||||||
| 
 |  | ||||||
| One might often find it useful to redirect/or filter the output |  | ||||||
| generated by the 'ps' command. This simple patch provides an option |  | ||||||
| (i.e. '-H') to display no header line so it does not need to be |  | ||||||
| considered e.g. |  | ||||||
| 
 |  | ||||||
| crash> ps -u -H | head -5 |  | ||||||
|         1       0   1  ffff956e8028d280  IN   0.0   174276     9272  systemd |  | ||||||
|      1067       1   2  ffff956e81380000  IN   0.1    59480    15788  systemd-journal |  | ||||||
|      1080       1   0  ffff956e8d152940  IN   0.0    36196     3548  systemd-udevd |  | ||||||
|      1278       1   6  ffff956e8aa60000  IN   0.0    17664     3072  systemd-oomd |  | ||||||
|      1366       1   7  ffff956e88548000  IN   0.0    10868     2328  dbus-broker-lau |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Aaron Tomlin <atomlin@atomlin.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  help.c | 3 ++- |  | ||||||
|  task.c | 6 +++++- |  | ||||||
|  2 files changed, 7 insertions(+), 2 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/help.c b/help.c
 |  | ||||||
| index 99214c1590fa..14981cd01d48 100644
 |  | ||||||
| --- a/help.c
 |  | ||||||
| +++ b/help.c
 |  | ||||||
| @@ -1379,7 +1379,7 @@ NULL
 |  | ||||||
|  char *help_ps[] = { |  | ||||||
|  "ps", |  | ||||||
|  "display process status information", |  | ||||||
| -"[-k|-u|-G|-y policy] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S|-A]\n     [pid | task | command] ...",
 |  | ||||||
| +"[-k|-u|-G|-y policy] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S|-A|-H]\n     [pid | task | command] ...",
 |  | ||||||
|  "  This command displays process status for selected, or all, processes" , |  | ||||||
|  "  in the system.  If no arguments are entered, the process data is", |  | ||||||
|  "  is displayed for all processes.  Specific processes may be selected", |  | ||||||
| @@ -1458,6 +1458,7 @@ char *help_ps[] = {
 |  | ||||||
|  "       -r  display resource limits (rlimits) of selected, or all, tasks.", |  | ||||||
|  "       -S  display a summary consisting of the number of tasks in a task state.", |  | ||||||
|  "       -A  display only the active task on each cpu.", |  | ||||||
| +"       -H  display no header line.",
 |  | ||||||
|  "\nEXAMPLES", |  | ||||||
|  "  Show the process status of all current tasks:\n", |  | ||||||
|  "    %s> ps", |  | ||||||
| diff --git a/task.c b/task.c
 |  | ||||||
| index db2abc8106a2..88941c7b0e4d 100644
 |  | ||||||
| --- a/task.c
 |  | ||||||
| +++ b/task.c
 |  | ||||||
| @@ -3504,7 +3504,7 @@ cmd_ps(void)
 |  | ||||||
|  	cpuspec = NULL; |  | ||||||
|  	flag = 0; |  | ||||||
|   |  | ||||||
| -        while ((c = getopt(argcnt, args, "ASgstcpkuGlmarC:y:")) != EOF) {
 |  | ||||||
| +        while ((c = getopt(argcnt, args, "HASgstcpkuGlmarC:y:")) != EOF) {
 |  | ||||||
|                  switch(c) |  | ||||||
|  		{ |  | ||||||
|  		case 'k': |  | ||||||
| @@ -3615,6 +3615,10 @@ cmd_ps(void)
 |  | ||||||
|  			flag |= PS_ACTIVE; |  | ||||||
|  			break; |  | ||||||
|   |  | ||||||
| +		case 'H':
 |  | ||||||
| +			flag |= PS_NO_HEADER;
 |  | ||||||
| +			break;
 |  | ||||||
| +
 |  | ||||||
|  		default: |  | ||||||
|  			argerrs++; |  | ||||||
|  			break; |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,150 +0,0 @@ | |||||||
| From 5f27639196c3240810fbf30d367da0063a6612ff Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Ding Hui <dinghui@sangfor.com.cn> |  | ||||||
| Date: Thu, 1 Dec 2022 15:01:45 +0800 |  | ||||||
| Subject: [PATCH 02/28] arm64: fix backtraces of KASAN kernel dumpfile |  | ||||||
|  truncated |  | ||||||
| 
 |  | ||||||
| We met "bt" command 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 stores the same value |  | ||||||
|    0xffff2000200bff50 (comes from 0xffff2000200bf000 + 0xf50) |  | ||||||
|    into stack postion [x29,#128]. |  | ||||||
| 
 |  | ||||||
| When arm64_in_kdump_text() searches for LR from stack, it met |  | ||||||
| 0xffff2000200bff50 firstly, so got wrong bt->bptr. |  | ||||||
| 
 |  | ||||||
| We know that the real LR is always greater than the start address |  | ||||||
| of a function, so let's fix it by changing the search conditon to |  | ||||||
| (*ptr > xxx_start) && (*ptr < xxx_end). |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Ding Hui <dinghui@sangfor.com.cn> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  arm64.c | 18 +++++++++--------- |  | ||||||
|  1 file changed, 9 insertions(+), 9 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/arm64.c b/arm64.c
 |  | ||||||
| index c3e26a371a61..7e8a7db1fcc4 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.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,37 +0,0 @@ | |||||||
| From 141e75f3c11cc9342f11418e0bec86877424bef8 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Pavankumar Kondeti <quic_pkondeti@quicinc.com> |  | ||||||
| Date: Thu, 8 Dec 2022 09:55:07 +0530 |  | ||||||
| Subject: [PATCH 03/28] arm64: handle vabits_actual symbol missing case |  | ||||||
| 
 |  | ||||||
| After kernel commit 0d9b1ffefabe ("arm64: mm: make vabits_actual |  | ||||||
| a build time constant if possible") introduced in Linux v5.19, |  | ||||||
| the crash will not find vabits_actual symbol 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@quicinc.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  arm64.c | 4 ++++ |  | ||||||
|  1 file changed, 4 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/arm64.c b/arm64.c
 |  | ||||||
| index 7e8a7db1fcc4..56fb841f43f8 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;
 |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
|  	if (!(sp = symbol_search("swapper_pg_dir")) && |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,479 +0,0 @@ | |||||||
| From 2f1085df4dc9c197be9a7a6828a381785058c7b7 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Luc Chouinard <lucchouina@gmail.com> |  | ||||||
| Date: Fri, 9 Dec 2022 11:19:17 -0800 |  | ||||||
| Subject: [PATCH 04/28] EPPIC extension support for crash-8.x + gdb-10.x |  | ||||||
| 
 |  | ||||||
| The previous version of the interface between eppic and crash/gdb was |  | ||||||
| messy and not portable. This new version uses a clean interface with |  | ||||||
| execution through the standard gnu_request and gdb command funnel. |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Luc Chouinard <lucchouina@gmail.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  defs.h              |  20 +++ |  | ||||||
|  extensions/eppic.mk |  80 ++++++------ |  | ||||||
|  gdb-10.2.patch      | 302 ++++++++++++++++++++++++++++++++++++++++++++ |  | ||||||
|  3 files changed, 364 insertions(+), 38 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index afdcf6c4ac20..67c9df2130a6 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -4768,6 +4768,23 @@ static inline unsigned int __const_hweight8(unsigned long w)
 |  | ||||||
|   |  | ||||||
|  #endif /* !GDB_COMMON */ |  | ||||||
|   |  | ||||||
| +typedef enum drill_ops_s {
 |  | ||||||
| +	EOP_MEMBER_SIZES,
 |  | ||||||
| +	EOP_MEMBER_NAME,
 |  | ||||||
| +	EOP_POINTER,
 |  | ||||||
| +	EOP_TYPEDEF,
 |  | ||||||
| +	EOP_INT,
 |  | ||||||
| +	EOP_VALUE,
 |  | ||||||
| +	EOP_ARRAY,
 |  | ||||||
| +	EOP_UNION,
 |  | ||||||
| +	EOP_ENUM,
 |  | ||||||
| +	EOP_ENUMVAL,
 |  | ||||||
| +	EOP_STRUCT,
 |  | ||||||
| +	EOP_FUNCTION,
 |  | ||||||
| +	EOP_DONE,
 |  | ||||||
| +	EOP_OOPS
 |  | ||||||
| +} drill_ops_t;
 |  | ||||||
| +
 |  | ||||||
|  /* |  | ||||||
|   *  Common request structure for BFD or GDB data or commands. |  | ||||||
|   */ |  | ||||||
| @@ -4818,6 +4835,9 @@ struct gnu_request {
 |  | ||||||
|  	char *member_target_type_name; |  | ||||||
|  	char *member_target_type_tag_name; |  | ||||||
|  	char *type_tag_name; |  | ||||||
| +	/* callback function for 3rd party symbol and type (EPPIC for now) */
 |  | ||||||
| +	void *priv;
 |  | ||||||
| +	int (*tcb)(drill_ops_t, struct gnu_request *, const void *, const void *, const void *, const void *);
 |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
|  /* |  | ||||||
| diff --git a/extensions/eppic.mk b/extensions/eppic.mk
 |  | ||||||
| index b9c046b710ad..943579346ece 100644
 |  | ||||||
| --- a/extensions/eppic.mk
 |  | ||||||
| +++ b/extensions/eppic.mk
 |  | ||||||
| @@ -11,64 +11,68 @@
 |  | ||||||
|   |  | ||||||
|  TARGET_FLAGS = -D$(TARGET) |  | ||||||
|  ifeq ($(TARGET), PPC64) |  | ||||||
| -        TARGET_FLAGS += -m64
 |  | ||||||
| +	TARGET_FLAGS += -m64
 |  | ||||||
|  endif |  | ||||||
|  ifeq ($(TARGET), ARM) |  | ||||||
| -        TARGET_FLAGS += -m32
 |  | ||||||
| +	TARGET_FLAGS += -m32
 |  | ||||||
|  endif |  | ||||||
|  ifeq ($(TARGET), MIPS) |  | ||||||
| -        TARGET_FLAGS += -m32
 |  | ||||||
| +	TARGET_FLAGS += -m32
 |  | ||||||
|  endif |  | ||||||
|  ifeq ($(TARGET), X86) |  | ||||||
| -        TARGET_FLAGS += -m32
 |  | ||||||
| +	TARGET_FLAGS += -m32
 |  | ||||||
|  endif |  | ||||||
|   |  | ||||||
|  APPFILE=eppic/applications/crash/eppic.c |  | ||||||
|  GIT := $(shell which git 2> /dev/null) |  | ||||||
| +# crash 8 with gdb 10 uses new third party callback (tcb) API
 |  | ||||||
| +EPPIC_BRANCH=v5.0
 |  | ||||||
|   |  | ||||||
|  all: |  | ||||||
| -	@if [ -f /usr/bin/flex ] && [ -f /usr/bin/bison ]; then \
 |  | ||||||
| -	  if [ -f ../$(GDB)/crash.target ]; \
 |  | ||||||
| -        then \
 |  | ||||||
| -        if  [ ! -f $(APPFILE) ]; \
 |  | ||||||
| -        then \
 |  | ||||||
| -          if [ -f "$(GIT)" ]; \
 |  | ||||||
| -          then \
 |  | ||||||
| -             if [ -n "$(EPPIC_GIT_URL)" ]; then \
 |  | ||||||
| -               git clone $(EPPIC_GIT_OPTIONS) $(EPPIC_GIT_URL) eppic; \
 |  | ||||||
| -             else \
 |  | ||||||
| -	          if ping -c 1 -W 5 github.com >/dev/null ; then \
 |  | ||||||
| -		    git clone $(EPPIC_GIT_OPTIONS) https://github.com/lucchouina/eppic.git eppic; \
 |  | ||||||
| -	          fi; \
 |  | ||||||
| -             fi; \
 |  | ||||||
| -          else \
 |  | ||||||
| -	     if [ ! -f "$(GIT)" ]; then \
 |  | ||||||
| -	         echo "eppic.so: git command is needed for pulling eppic extension code"; \
 |  | ||||||
| -	     fi; \
 |  | ||||||
| -          fi; \
 |  | ||||||
| -        fi; \
 |  | ||||||
| -        if  [ -f $(APPFILE) ]; \
 |  | ||||||
| -        then \
 |  | ||||||
| -	        make -f eppic.mk eppic.so; \
 |  | ||||||
| -        else \
 |  | ||||||
| -            echo "eppic.so: failed to pull eppic code from git repo"; \
 |  | ||||||
| -        fi; \
 |  | ||||||
| -      else \
 |  | ||||||
| -	    echo "eppic.so: build failed: requires the crash $(GDB) module"; \
 |  | ||||||
| -      fi ;\
 |  | ||||||
| +	@if [ -f /usr/bin/flex ] && [ -f /usr/bin/bison ]; \
 |  | ||||||
| +	then \
 |  | ||||||
| +		if [ -f ../$(GDB)/crash.target ]; \
 |  | ||||||
| +		then \
 |  | ||||||
| +			if  [ ! -f $(APPFILE) ]; \
 |  | ||||||
| +			then \
 |  | ||||||
| +				if [ -f "$(GIT)" ]; \
 |  | ||||||
| +				then \
 |  | ||||||
| +					if [ -n "$(EPPIC_GIT_URL)" ]; \
 |  | ||||||
| +					then \
 |  | ||||||
| +						git clone $(EPPIC_GIT_OPTIONS) $(EPPIC_GIT_URL) eppic; \
 |  | ||||||
| +					else \
 |  | ||||||
| +						if ping -c 1 -W 5 github.com >/dev/null ; then \
 |  | ||||||
| +							git clone -b $(EPPIC_BRANCH) $(EPPIC_GIT_OPTIONS) https://github.com/lucchouina/eppic.git eppic; \
 |  | ||||||
| +						fi; \
 |  | ||||||
| +					fi; \
 |  | ||||||
| +				else \
 |  | ||||||
| +					if [ ! -f "$(GIT)" ]; then \
 |  | ||||||
| +						echo "eppic.so: git command is needed for pulling eppic extension code"; \
 |  | ||||||
| +					fi; \
 |  | ||||||
| +				fi; \
 |  | ||||||
| +			fi; \
 |  | ||||||
| +			if  [ -f $(APPFILE) ]; \
 |  | ||||||
| +			then \
 |  | ||||||
| +				make -f eppic.mk eppic.so; \
 |  | ||||||
| +			else \
 |  | ||||||
| +				echo "eppic.so: failed to pull eppic code from git repo"; \
 |  | ||||||
| +			fi; \
 |  | ||||||
| +		else \
 |  | ||||||
| +			echo "eppic.so: build failed: requires the crash $(GDB) module"; \
 |  | ||||||
| +		fi ;\
 |  | ||||||
|  	else \ |  | ||||||
| -	  echo "eppic.so: build failed: requires /usr/bin/flex and /usr/bin/bison"; \
 |  | ||||||
| -    fi
 |  | ||||||
| +		echo "eppic.so: build failed: requires /usr/bin/flex and /usr/bin/bison"; \
 |  | ||||||
| +	fi
 |  | ||||||
|   |  | ||||||
|  lib-eppic:  |  | ||||||
|  	cd eppic/libeppic && make |  | ||||||
| -            
 |  | ||||||
| +
 |  | ||||||
|  eppic.so: ../defs.h $(APPFILE) lib-eppic |  | ||||||
| -	gcc -g -Ieppic/libeppic -I../$(GDB)/gdb -I../$(GDB)/bfd -I../$(GDB)/include -I../$(GDB)/gdb/config -I../$(GDB)/gdb/common -I../$(GDB) -nostartfiles -shared -rdynamic -o eppic.so $(APPFILE) -fPIC $(TARGET_FLAGS) $(GDB_FLAGS) -Leppic/libeppic -leppic 
 |  | ||||||
| +	gcc -g -O0 -Ieppic/libeppic -I.. -nostartfiles -shared -rdynamic -o eppic.so $(APPFILE) -fPIC $(TARGET_FLAGS) $(GDB_FLAGS) -Leppic/libeppic -leppic
 |  | ||||||
|   |  | ||||||
|  clean: |  | ||||||
|  	if  [ -d eppic/libeppic ]; \ |  | ||||||
|  	then \ |  | ||||||
| -	  cd eppic/libeppic && make -i clean; \
 |  | ||||||
| +		cd eppic/libeppic && make -i clean; \
 |  | ||||||
|  	fi |  | ||||||
|  	rm -f eppic.so |  | ||||||
| diff --git a/gdb-10.2.patch b/gdb-10.2.patch
 |  | ||||||
| index 91edfb338445..7055f6e0fb0b 100644
 |  | ||||||
| --- a/gdb-10.2.patch
 |  | ||||||
| +++ b/gdb-10.2.patch
 |  | ||||||
| @@ -1737,3 +1737,305 @@ exit 0
 |  | ||||||
|           struct field *nextfield; |  | ||||||
|           short nfields; |  | ||||||
|           struct type *typedef_type, *target_type; |  | ||||||
| +--- gdb-10.2/gdb/symtab.c.orig
 |  | ||||||
| ++++ gdb-10.2/gdb/symtab.c
 |  | ||||||
| +@@ -6913,7 +6913,7 @@
 |  | ||||||
| + #include "../../defs.h"
 |  | ||||||
| + 
 |  | ||||||
| + static void get_member_data(struct gnu_request *, struct type *, long, int);
 |  | ||||||
| +-static void dump_enum(struct type *, struct gnu_request *);
 |  | ||||||
| ++static void walk_enum(struct type *, struct gnu_request *);
 |  | ||||||
| + static void eval_enum(struct type *, struct gnu_request *);
 |  | ||||||
| + static void gdb_get_line_number(struct gnu_request *);
 |  | ||||||
| + static void gdb_get_datatype(struct gnu_request *);
 |  | ||||||
| +@@ -7122,6 +7122,79 @@
 |  | ||||||
| + 
 |  | ||||||
| + 
 |  | ||||||
| + /*
 |  | ||||||
| ++ * Follow the type linkage for full member and value type resolution, with callback
 |  | ||||||
| ++ */
 |  | ||||||
| ++static void drillDownType(struct gnu_request *req, struct type *type)
 |  | ||||||
| ++{
 |  | ||||||
| ++        while (type)
 |  | ||||||
| ++        {
 |  | ||||||
| ++                /* check out for stub types and pull in the definition instead */
 |  | ||||||
| ++                if (TYPE_STUB(type) && TYPE_TAG_NAME(type)) {
 |  | ||||||
| ++                        struct symbol *sym;
 |  | ||||||
| ++                        sym = lookup_symbol(TYPE_TAG_NAME(type), 0, STRUCT_DOMAIN, 0).symbol;
 |  | ||||||
| ++                        if (sym)
 |  | ||||||
| ++                                type = sym->type;
 |  | ||||||
| ++                }
 |  | ||||||
| ++                switch (TYPE_CODE(type)) {
 |  | ||||||
| ++                        drill_ops_t op;
 |  | ||||||
| ++                        long l1, l2;
 |  | ||||||
| ++                        int typecode;
 |  | ||||||
| ++
 |  | ||||||
| ++                case TYPE_CODE_PTR:
 |  | ||||||
| ++                        req->tcb(EOP_POINTER, req, 0, 0, 0, 0);
 |  | ||||||
| ++                        break;
 |  | ||||||
| ++
 |  | ||||||
| ++                case TYPE_CODE_TYPEDEF:
 |  | ||||||
| ++                        req->is_typedef = 1;
 |  | ||||||
| ++                        req->typecode = TYPE_CODE(type);
 |  | ||||||
| ++                        if (!req->tcb(EOP_TYPEDEF, req, TYPE_NAME(type), 0, 0, 0))
 |  | ||||||
| ++                                return;
 |  | ||||||
| ++                        break;
 |  | ||||||
| ++
 |  | ||||||
| ++                case TYPE_CODE_FUNC:
 |  | ||||||
| ++                        req->tcb(EOP_FUNCTION, req, 0, 0, 0, 0);
 |  | ||||||
| ++                        break;
 |  | ||||||
| ++
 |  | ||||||
| ++                case TYPE_CODE_ARRAY:
 |  | ||||||
| ++                        l1 = TYPE_LENGTH (type);
 |  | ||||||
| ++                        l2 = TYPE_LENGTH (check_typedef(TYPE_TARGET_TYPE (type)));
 |  | ||||||
| ++                        req->tcb(EOP_ARRAY, req, &l1, &l2, 0, 0);
 |  | ||||||
| ++                        break;
 |  | ||||||
| ++
 |  | ||||||
| ++                case TYPE_CODE_VOID:
 |  | ||||||
| ++                case TYPE_CODE_INT:
 |  | ||||||
| ++                case TYPE_CODE_BOOL:
 |  | ||||||
| ++                        l1 = TYPE_LENGTH(type);
 |  | ||||||
| ++                        req->tcb(EOP_INT, req, &l1, 0, 0, 0);
 |  | ||||||
| ++                        break;
 |  | ||||||
| ++
 |  | ||||||
| ++                case TYPE_CODE_UNION:
 |  | ||||||
| ++                        op = EOP_UNION;
 |  | ||||||
| ++                        goto label;
 |  | ||||||
| ++
 |  | ||||||
| ++                case TYPE_CODE_ENUM:
 |  | ||||||
| ++                        op = EOP_ENUM;
 |  | ||||||
| ++                        goto label;
 |  | ||||||
| ++
 |  | ||||||
| ++                case TYPE_CODE_STRUCT:
 |  | ||||||
| ++                        op = EOP_STRUCT;
 |  | ||||||
| ++                        goto label;
 |  | ||||||
| ++
 |  | ||||||
| ++                default:
 |  | ||||||
| ++                        typecode = TYPE_CODE(type);
 |  | ||||||
| ++                        req->tcb(EOP_OOPS, req, &typecode, "Unknown typecode", 0, 0);
 |  | ||||||
| ++                        return; /* not reached */
 |  | ||||||
| ++
 |  | ||||||
| ++                label:
 |  | ||||||
| ++                        l1 = TYPE_LENGTH(type);
 |  | ||||||
| ++                        req->tcb(op, req, &l1, type, TYPE_TAG_NAME(type), 0);
 |  | ||||||
| ++                }
 |  | ||||||
| ++                type = TYPE_TARGET_TYPE(type);
 |  | ||||||
| ++        }
 |  | ||||||
| ++        req->tcb(EOP_DONE, req, 0, 0, 0, 0);
 |  | ||||||
| ++}
 |  | ||||||
| ++
 |  | ||||||
| ++/*
 |  | ||||||
| +  *  General purpose routine for determining datatypes.
 |  | ||||||
| +  */
 |  | ||||||
| + 
 |  | ||||||
| +@@ -7149,10 +7222,8 @@
 |  | ||||||
| +                 if (req->member)
 |  | ||||||
| +                         get_member_data(req, sym->type, 0, 1);
 |  | ||||||
| + 
 |  | ||||||
| +-                if (TYPE_CODE(sym->type) == TYPE_CODE_ENUM) {
 |  | ||||||
| +-                        if (req->flags & GNU_PRINT_ENUMERATORS)
 |  | ||||||
| +-                                dump_enum(sym->type, req);
 |  | ||||||
| +-                }
 |  | ||||||
| ++                if (TYPE_CODE(sym->type) == TYPE_CODE_ENUM)
 |  | ||||||
| ++                        walk_enum(sym->type, req);
 |  | ||||||
| + 
 |  | ||||||
| +                 return;
 |  | ||||||
| +         }
 |  | ||||||
| +@@ -7172,17 +7243,25 @@
 |  | ||||||
| +                 if (gdb_CRASHDEBUG(2))
 |  | ||||||
| +                         console("expr->elts[0].opcode: OP_VAR_VALUE\n");
 |  | ||||||
| +                 type = expr.get()->elts[2].symbol->type;
 |  | ||||||
| +-                if (req->flags & GNU_VAR_LENGTH_TYPECODE) {
 |  | ||||||
| ++                if (req->tcb) {
 |  | ||||||
| ++                        long value = SYMBOL_VALUE(expr->elts[2].symbol);
 |  | ||||||
| ++                        /* callback with symbol value */
 |  | ||||||
| +                         req->typecode = TYPE_CODE(type);
 |  | ||||||
| +-                        req->length = TYPE_LENGTH(type);
 |  | ||||||
| +-                }
 |  | ||||||
| +-                if (TYPE_CODE(type) == TYPE_CODE_ENUM) {
 |  | ||||||
| +-                        req->typecode = TYPE_CODE(type);
 |  | ||||||
| +-                        req->value = SYMBOL_VALUE(expr.get()->elts[2].symbol);
 |  | ||||||
| +-                        req->tagname = (char *)TYPE_TAG_NAME(type);
 |  | ||||||
| +-                        if (!req->tagname) {
 |  | ||||||
| +-                                val = evaluate_type(expr.get());
 |  | ||||||
| +-                                eval_enum(value_type(val), req);
 |  | ||||||
| ++                        req->tcb(EOP_VALUE, req, &value, 0, 0, 0);
 |  | ||||||
| ++                        drillDownType(req, type);
 |  | ||||||
| ++                } else {
 |  | ||||||
| ++                        if (req->flags & GNU_VAR_LENGTH_TYPECODE) {
 |  | ||||||
| ++                                req->typecode = TYPE_CODE(type);
 |  | ||||||
| ++                                req->length = TYPE_LENGTH(type);
 |  | ||||||
| ++                        }
 |  | ||||||
| ++                        if (TYPE_CODE(type) == TYPE_CODE_ENUM) {
 |  | ||||||
| ++                                req->typecode = TYPE_CODE(type);
 |  | ||||||
| ++                                req->value = SYMBOL_VALUE(expr->elts[2].symbol);
 |  | ||||||
| ++                                req->tagname = (char *)TYPE_TAG_NAME(type);
 |  | ||||||
| ++                                if (!req->tagname) {
 |  | ||||||
| ++                                        val = evaluate_type(expr.get());
 |  | ||||||
| ++                                        eval_enum(value_type(val), req);
 |  | ||||||
| ++                                }
 |  | ||||||
| +                         }
 |  | ||||||
| +                 }
 |  | ||||||
| +                 break;
 |  | ||||||
| +@@ -7192,26 +7271,21 @@
 |  | ||||||
| +                         console("expr->elts[0].opcode: OP_TYPE\n");
 |  | ||||||
| +                     type = expr.get()->elts[1].type;
 |  | ||||||
| + 
 |  | ||||||
| +-                req->typecode = TYPE_CODE(type);
 |  | ||||||
| +-                req->length = TYPE_LENGTH(type);
 |  | ||||||
| +-
 |  | ||||||
| +-                if (TYPE_CODE(type) == TYPE_CODE_TYPEDEF) {
 |  | ||||||
| +-                        req->is_typedef = TYPE_CODE_TYPEDEF;
 |  | ||||||
| +-                        if ((typedef_type = check_typedef(type))) {
 |  | ||||||
| +-                                req->typecode = TYPE_CODE(typedef_type);
 |  | ||||||
| +-                                req->length = TYPE_LENGTH(typedef_type);
 |  | ||||||
| +-                                type = typedef_type;
 |  | ||||||
| +-                        }
 |  | ||||||
| +-                }
 |  | ||||||
| +-
 |  | ||||||
| +-                if (TYPE_CODE(type) == TYPE_CODE_ENUM) {
 |  | ||||||
| +-                        if (req->is_typedef)
 |  | ||||||
| +-                        if (req->flags & GNU_PRINT_ENUMERATORS) {
 |  | ||||||
| +-                                if (req->is_typedef)
 |  | ||||||
| +-                                        fprintf_filtered(gdb_stdout,
 |  | ||||||
| +-                                                "typedef ");
 |  | ||||||
| +-                                dump_enum(type, req);
 |  | ||||||
| ++                if (req->tcb) {
 |  | ||||||
| ++                        drillDownType(req, type);
 |  | ||||||
| ++                } else {
 |  | ||||||
| ++                        req->typecode = TYPE_CODE(type);
 |  | ||||||
| ++                        req->length = TYPE_LENGTH(type);
 |  | ||||||
| ++                        if (TYPE_CODE(type) == TYPE_CODE_TYPEDEF) {
 |  | ||||||
| ++                                req->is_typedef = TYPE_CODE_TYPEDEF;
 |  | ||||||
| ++                                if ((typedef_type = check_typedef(type))) {
 |  | ||||||
| ++                                        req->typecode = TYPE_CODE(typedef_type);
 |  | ||||||
| ++                                        req->length = TYPE_LENGTH(typedef_type);
 |  | ||||||
| ++                                        type = typedef_type;
 |  | ||||||
| ++                                }
 |  | ||||||
| +                         }
 |  | ||||||
| ++                        if (TYPE_CODE(type) == TYPE_CODE_ENUM)
 |  | ||||||
| ++                                walk_enum(type, req);
 |  | ||||||
| +                 }
 |  | ||||||
| + 
 |  | ||||||
| +                 if (req->member)
 |  | ||||||
| +@@ -7233,36 +7307,38 @@
 |  | ||||||
| +  *  identifier, each on its own line.
 |  | ||||||
| +  */
 |  | ||||||
| + static void
 |  | ||||||
| +-dump_enum(struct type *type, struct gnu_request *req)
 |  | ||||||
| ++walk_enum(struct type *type, struct gnu_request *req)
 |  | ||||||
| + {
 |  | ||||||
| +         int i;
 |  | ||||||
| +-        int len;
 |  | ||||||
| ++        int len, print = (req->flags & GNU_PRINT_ENUMERATORS);
 |  | ||||||
| +         long long lastval;
 |  | ||||||
| + 
 |  | ||||||
| +-        len = TYPE_NFIELDS (type);
 |  | ||||||
| +-        lastval = 0;
 |  | ||||||
| +-        if (TYPE_TAG_NAME(type))
 |  | ||||||
| +-                fprintf_filtered(gdb_stdout,
 |  | ||||||
| +-                        "enum %s {\n", TYPE_TAG_NAME (type));
 |  | ||||||
| +-        else
 |  | ||||||
| +-                fprintf_filtered(gdb_stdout, "enum {\n");
 |  | ||||||
| ++        if (print) {
 |  | ||||||
| ++                if (req->is_typedef)
 |  | ||||||
| ++                        fprintf_filtered(gdb_stdout, "typedef ");
 |  | ||||||
| ++                if (TYPE_TAG_NAME(type))
 |  | ||||||
| ++                        fprintf_filtered(gdb_stdout, "enum %s {\n", TYPE_TAG_NAME (type));
 |  | ||||||
| ++                else
 |  | ||||||
| ++                        fprintf_filtered(gdb_stdout, "enum {\n");
 |  | ||||||
| ++        }
 |  | ||||||
| + 
 |  | ||||||
| ++        len = TYPE_NFIELDS (type);
 |  | ||||||
| +         for (i = 0; i < len; i++) {
 |  | ||||||
| +-                fprintf_filtered(gdb_stdout, "  %s",
 |  | ||||||
| +-                        TYPE_FIELD_NAME (type, i));
 |  | ||||||
| +-                if (lastval != TYPE_FIELD_ENUMVAL (type, i)) {
 |  | ||||||
| +-                        fprintf_filtered (gdb_stdout, " = %s",
 |  | ||||||
| +-                                plongest(TYPE_FIELD_ENUMVAL (type, i)));
 |  | ||||||
| +-                        lastval = TYPE_FIELD_ENUMVAL (type, i);
 |  | ||||||
| +-                } else
 |  | ||||||
| ++                if (print)
 |  | ||||||
| ++                        fprintf_filtered(gdb_stdout, "  %s", TYPE_FIELD_NAME (type, i));
 |  | ||||||
| ++                lastval = TYPE_FIELD_ENUMVAL (type, i);
 |  | ||||||
| ++                if (print) {
 |  | ||||||
| +                         fprintf_filtered(gdb_stdout, " = %s", plongest(lastval));
 |  | ||||||
| +-                fprintf_filtered(gdb_stdout, "\n");
 |  | ||||||
| +-                lastval++;
 |  | ||||||
| ++                        fprintf_filtered(gdb_stdout, "\n");
 |  | ||||||
| ++                } else if (req->tcb)
 |  | ||||||
| ++                        req->tcb(EOP_ENUMVAL, req, TYPE_FIELD_NAME (type, i), &lastval, 0, 0);
 |  | ||||||
| ++        }
 |  | ||||||
| ++        if (print) {
 |  | ||||||
| ++                if (TYPE_TAG_NAME(type))
 |  | ||||||
| ++                        fprintf_filtered(gdb_stdout, "};\n");
 |  | ||||||
| ++                else
 |  | ||||||
| ++                        fprintf_filtered(gdb_stdout, "} %s;\n", req->name);
 |  | ||||||
| +         }
 |  | ||||||
| +-        if (TYPE_TAG_NAME(type))
 |  | ||||||
| +-                fprintf_filtered(gdb_stdout, "};\n");
 |  | ||||||
| +-        else
 |  | ||||||
| +-                fprintf_filtered(gdb_stdout, "} %s;\n", req->name);
 |  | ||||||
| + }
 |  | ||||||
| + 
 |  | ||||||
| + /*
 |  | ||||||
| +@@ -7320,26 +7396,43 @@
 |  | ||||||
| +         }
 |  | ||||||
| + 
 |  | ||||||
| +         for (i = 0; i < nfields; i++) {
 |  | ||||||
| +-                if (STREQ(req->member, nextfield->name)) {
 |  | ||||||
| +-                        req->member_offset = offset + nextfield->loc.bitpos;
 |  | ||||||
| +-                        req->member_length = TYPE_LENGTH(nextfield->type());
 |  | ||||||
| +-                        req->member_typecode = TYPE_CODE(nextfield->type());
 |  | ||||||
| +-                        req->member_main_type_name = (char *)TYPE_NAME(nextfield->type());
 |  | ||||||
| +-                        req->member_main_type_tag_name = (char *)TYPE_TAG_NAME(nextfield->type());
 |  | ||||||
| +-                        target_type = TYPE_TARGET_TYPE(nextfield->type());
 |  | ||||||
| +-                        if (target_type) {
 |  | ||||||
| +-                                req->member_target_type_name = (char *)TYPE_NAME(target_type);
 |  | ||||||
| +-                                req->member_target_type_tag_name = (char *)TYPE_TAG_NAME(target_type);
 |  | ||||||
| +-                        }
 |  | ||||||
| +-                        if ((req->member_typecode == TYPE_CODE_TYPEDEF) &&
 |  | ||||||
| +-                            (typedef_type = check_typedef(nextfield->type())))
 |  | ||||||
| +-                                req->member_length = TYPE_LENGTH(typedef_type);
 |  | ||||||
| +-                        return;
 |  | ||||||
| +-                } else if (*nextfield->name == 0) { /* Anonymous struct/union */
 |  | ||||||
| ++                if (*nextfield->name == 0) { /* Anonymous struct/union */
 |  | ||||||
| +                         get_member_data(req, nextfield->type(),
 |  | ||||||
| +                             offset + nextfield->loc.bitpos, 0);
 |  | ||||||
| +                         if (req->member_offset != -1)
 |  | ||||||
| +                                 return;
 |  | ||||||
| ++                } else {
 |  | ||||||
| ++                        /* callback may be just looking for a specific member name */
 |  | ||||||
| ++                        if (req->tcb) {
 |  | ||||||
| ++                                if (req->tcb(EOP_MEMBER_NAME, req, nextfield->name, 0, 0, 0)) {
 |  | ||||||
| ++                                        long bitpos = FIELD_BITPOS(*nextfield);
 |  | ||||||
| ++                                        long bitsize = FIELD_BITSIZE(*nextfield);
 |  | ||||||
| ++                                        long len = TYPE_LENGTH(nextfield->type());
 |  | ||||||
| ++                                        long byteOffset;
 |  | ||||||
| ++                                        offset += nextfield->loc.bitpos;
 |  | ||||||
| ++                                        byteOffset = offset/8;
 |  | ||||||
| ++                                        console("EOP_MEMBER_SIZES\n");
 |  | ||||||
| ++                                        req->tcb(EOP_MEMBER_SIZES, req, &byteOffset, &len, &bitpos, &bitsize);
 |  | ||||||
| ++                                        /* callback with full type info */
 |  | ||||||
| ++                                        drillDownType(req, nextfield->type());
 |  | ||||||
| ++                                }
 |  | ||||||
| ++                        } else if (STREQ(req->member, nextfield->name)) {
 |  | ||||||
| ++                                req->member_offset = offset + nextfield->loc.bitpos;
 |  | ||||||
| ++                                req->member_length = TYPE_LENGTH(nextfield->type());
 |  | ||||||
| ++                                req->member_typecode = TYPE_CODE(nextfield->type());
 |  | ||||||
| ++                                req->member_main_type_name = (char *)TYPE_NAME(nextfield->type());
 |  | ||||||
| ++                                req->member_main_type_tag_name = (char *)TYPE_TAG_NAME(nextfield->type());
 |  | ||||||
| ++                                target_type = TYPE_TARGET_TYPE(nextfield->type());
 |  | ||||||
| ++                                if (target_type) {
 |  | ||||||
| ++                                        req->member_target_type_name = (char *)TYPE_NAME(target_type);
 |  | ||||||
| ++                                        req->member_target_type_tag_name = (char *)TYPE_TAG_NAME(target_type);
 |  | ||||||
| ++                                }
 |  | ||||||
| ++                                if ((req->member_typecode == TYPE_CODE_TYPEDEF) &&
 |  | ||||||
| ++                                    (typedef_type = check_typedef(nextfield->type()))) {
 |  | ||||||
| ++                                        req->member_length = TYPE_LENGTH(typedef_type);
 |  | ||||||
| ++                                }
 |  | ||||||
| ++                                return;
 |  | ||||||
| ++                        }
 |  | ||||||
| +                 }
 |  | ||||||
| +                 nextfield++;
 |  | ||||||
| +         }
 |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,144 +0,0 @@ | |||||||
| From df1f0cba729fa0e0d8a63220769c42cc9033acc1 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Date: Wed, 7 Dec 2022 09:46:56 +0900 |  | ||||||
| Subject: [PATCH 05/28] x86_64: Fix for move of per-cpu variables into struct |  | ||||||
|  pcpu_hot |  | ||||||
| 
 |  | ||||||
| The following kernel commits, which are contained in Linux 6.2-rc1 and |  | ||||||
| later kernels, introduced struct pcpu_hot and moved several per-cpu |  | ||||||
| variables into it. |  | ||||||
| 
 |  | ||||||
|   d7b6d709a76a x86/percpu: Move irq_stack variables next to current_task |  | ||||||
|   7443b296e699 x86/percpu: Move cpu_number next to current_task |  | ||||||
|   e57ef2ed97c1 x86: Put hot per CPU variables into a struct |  | ||||||
| 
 |  | ||||||
| Without the patch, crash fails to start session with the following |  | ||||||
| error: |  | ||||||
| 
 |  | ||||||
|   $ crash vmlinux vmcore |  | ||||||
|   ... |  | ||||||
|   bt: invalid size request: 0  type: "stack contents" |  | ||||||
|   bt: read of stack at 0 failed |  | ||||||
|      <segmentation violation in gdb> |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.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.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,163 +0,0 @@ | |||||||
| From f182d08bab202dddf20b742fef6cc2bda0a56d6c Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Date: Thu, 15 Dec 2022 11:31:38 +0900 |  | ||||||
| Subject: [PATCH 06/28] Fix for mm_struct.rss_stat conversion into |  | ||||||
|  percpu_counter |  | ||||||
| 
 |  | ||||||
| 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@nec.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.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 67c9df2130a6..04476b3ff62e 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 { |  | ||||||
| @@ -5325,6 +5327,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..9d003713534b 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)) {
 |  | ||||||
| +			/* 6.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.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,48 +0,0 @@ | |||||||
| From 88a4910d95d43a01151ad1d570035b96893bc7f1 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Wed, 21 Dec 2022 17:09:08 +0800 |  | ||||||
| Subject: [PATCH 07/28] Fix "mount" command to appropriately display the mount |  | ||||||
|  dumps |  | ||||||
| 
 |  | ||||||
| Recently the following failure has been observed on some vmcores when |  | ||||||
| using the mount command: |  | ||||||
| 
 |  | ||||||
|   crash> mount |  | ||||||
|        MOUNT           SUPERBLK     TYPE   DEVNAME   DIRNAME |  | ||||||
|   ffff97a4818a3480 ffff979500013800 rootfs none      / |  | ||||||
|   ffff97e4846ca700 ffff97e484653000 sysfs  sysfs     /sys |  | ||||||
|   ... |  | ||||||
|   ffff97b484753420                0 mount: invalid kernel virtual address: 0  type: "super_block buffer" |  | ||||||
| 
 |  | ||||||
| The kernel virtual address of the super_block is zero when the mount |  | ||||||
| command fails with the vfsmnt address 0xffff97b484753420. And the |  | ||||||
| remaining mount information will be discarded. That is not expected. |  | ||||||
| 
 |  | ||||||
| Check the address and skip it with a warning, if this is an invalid |  | ||||||
| kernel virtual address, that can avoid truncating the remaining mount |  | ||||||
| dumps. |  | ||||||
| 
 |  | ||||||
| Reported-by: Dave Wysochanski <dwysocha@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  filesys.c | 4 ++++ |  | ||||||
|  1 file changed, 4 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/filesys.c b/filesys.c
 |  | ||||||
| index c2ea78de821d..d64b54a9b822 100644
 |  | ||||||
| --- a/filesys.c
 |  | ||||||
| +++ b/filesys.c
 |  | ||||||
| @@ -1491,6 +1491,10 @@ show_mounts(ulong one_vfsmount, int flags, struct task_context *namespace_contex
 |  | ||||||
|  		} |  | ||||||
|   |  | ||||||
|  		sbp = ULONG(vfsmount_buf + OFFSET(vfsmount_mnt_sb));  |  | ||||||
| +		if (!IS_KVADDR(sbp)) {
 |  | ||||||
| +			error(WARNING, "cannot get super_block from vfsmnt: 0x%lx\n", *vfsmnt);
 |  | ||||||
| +			continue;
 |  | ||||||
| +		}
 |  | ||||||
|   |  | ||||||
|  		if (flags) |  | ||||||
|  			fprintf(fp, "%s", mount_hdr); |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,692 +0,0 @@ | |||||||
| From 12c31560000adaaf3539f2bcdffff51ec05df447 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Date: Thu, 20 Oct 2022 09:50:06 +0800 |  | ||||||
| Subject: [PATCH 08/28] Add RISCV64 framework code support |  | ||||||
| 
 |  | ||||||
| This patch mainly added some environment configurations, macro definitions, |  | ||||||
| specific architecture structures and some function declarations supported |  | ||||||
| by the RISCV64 architecture. |  | ||||||
| 
 |  | ||||||
| We can use the build command to get the simplest version crash tool: |  | ||||||
| 	make target=RISCV64 -j2 |  | ||||||
| 
 |  | ||||||
| Co-developed-by: Lifang Xia <lifang_xia@linux.alibaba.com> |  | ||||||
| Signed-off-by: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  Makefile            |   7 +- |  | ||||||
|  README              |   6 +- |  | ||||||
|  configure.c         |  43 ++++++++++++- |  | ||||||
|  defs.h              | 154 +++++++++++++++++++++++++++++++++++++++++++- |  | ||||||
|  diskdump.c          |  11 +++- |  | ||||||
|  help.c              |   6 +- |  | ||||||
|  lkcd_vmdump_v1.h    |   8 +-- |  | ||||||
|  lkcd_vmdump_v2_v3.h |   8 +-- |  | ||||||
|  netdump.c           |   9 ++- |  | ||||||
|  ramdump.c           |   2 + |  | ||||||
|  riscv64.c           |  54 ++++++++++++++++ |  | ||||||
|  symbols.c           |  10 +++ |  | ||||||
|  12 files changed, 294 insertions(+), 24 deletions(-) |  | ||||||
|  create mode 100644 riscv64.c |  | ||||||
| 
 |  | ||||||
| diff --git a/Makefile b/Makefile
 |  | ||||||
| index 79aef1769444..1506dd426bc7 100644
 |  | ||||||
| --- a/Makefile
 |  | ||||||
| +++ b/Makefile
 |  | ||||||
| @@ -64,7 +64,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \
 |  | ||||||
|  	kernel.c test.c gdb_interface.c configure.c net.c dev.c bpf.c \ |  | ||||||
|  	printk.c \ |  | ||||||
|  	alpha.c x86.c ppc.c ia64.c s390.c s390x.c s390dbf.c ppc64.c x86_64.c \ |  | ||||||
| -	arm.c arm64.c mips.c mips64.c sparc64.c \
 |  | ||||||
| +	arm.c arm64.c mips.c mips64.c riscv64.c sparc64.c \
 |  | ||||||
|  	extensions.c remote.c va_server.c va_server_v1.c symbols.c cmdline.c \ |  | ||||||
|  	lkcd_common.c lkcd_v1.c lkcd_v2_v3.c lkcd_v5.c lkcd_v7.c lkcd_v8.c\ |  | ||||||
|  	lkcd_fix_mem.c s390_dump.c lkcd_x86_trace.c \ |  | ||||||
| @@ -84,7 +84,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \
 |  | ||||||
|  	build_data.o kernel.o test.o gdb_interface.o net.o dev.o bpf.o \ |  | ||||||
|  	printk.o \ |  | ||||||
|  	alpha.o x86.o ppc.o ia64.o s390.o s390x.o s390dbf.o ppc64.o x86_64.o \ |  | ||||||
| -	arm.o arm64.o mips.o mips64.o sparc64.o \
 |  | ||||||
| +	arm.o arm64.o mips.o mips64.o riscv64.o sparc64.o \
 |  | ||||||
|  	extensions.o remote.o va_server.o va_server_v1.o symbols.o cmdline.o \ |  | ||||||
|  	lkcd_common.o lkcd_v1.o lkcd_v2_v3.o lkcd_v5.o lkcd_v7.o lkcd_v8.o \ |  | ||||||
|  	lkcd_fix_mem.o s390_dump.o netdump.o diskdump.o makedumpfile.o xendump.o \ |  | ||||||
| @@ -438,6 +438,9 @@ mips.o: ${GENERIC_HFILES} ${REDHAT_HFILES} mips.c
 |  | ||||||
|  mips64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} mips64.c |  | ||||||
|  	${CC} -c ${CRASH_CFLAGS} mips64.c ${WARNING_OPTIONS} ${WARNING_ERROR} |  | ||||||
|   |  | ||||||
| +riscv64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} riscv64.c
 |  | ||||||
| +	${CC} -c ${CRASH_CFLAGS} riscv64.c ${WARNING_OPTIONS} ${WARNING_ERROR}
 |  | ||||||
| +
 |  | ||||||
|  sparc64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} sparc64.c |  | ||||||
|  	${CC} -c ${CRASH_CFLAGS} sparc64.c ${WARNING_OPTIONS} ${WARNING_ERROR} |  | ||||||
|   |  | ||||||
| diff --git a/README b/README
 |  | ||||||
| index 1f98fbf71df0..9850a29714b2 100644
 |  | ||||||
| --- a/README
 |  | ||||||
| +++ b/README
 |  | ||||||
| @@ -37,8 +37,8 @@
 |  | ||||||
|    These are the current prerequisites:  |  | ||||||
|   |  | ||||||
|    o  At this point, x86, ia64, x86_64, ppc64, ppc, arm, arm64, alpha, mips, |  | ||||||
| -     mips64, s390 and s390x-based kernels are supported.  Other architectures
 |  | ||||||
| -     may be addressed in the future.
 |  | ||||||
| +     mips64, riscv64, s390 and s390x-based kernels are supported.  Other
 |  | ||||||
| +     architectures may be addressed in the future.
 |  | ||||||
|   |  | ||||||
|    o  One size fits all -- the utility can be run on any Linux kernel version |  | ||||||
|       version dating back to 2.2.5-15.  A primary design goal is to always |  | ||||||
| @@ -98,6 +98,8 @@
 |  | ||||||
|       arm64 dumpfiles may be built by typing "make target=ARM64". |  | ||||||
|    o  On an x86_64 host, an x86_64 binary that can be used to analyze |  | ||||||
|       ppc64le dumpfiles may be built by typing "make target=PPC64". |  | ||||||
| +  o  On an x86_64 host, an x86_64 binary that can be used to analyze
 |  | ||||||
| +     riscv64 dumpfiles may be built by typing "make target=RISCV64".
 |  | ||||||
|   |  | ||||||
|    Traditionally when vmcores are compressed via the makedumpfile(8) facility |  | ||||||
|    the libz compression library is used, and by default the crash utility |  | ||||||
| diff --git a/configure.c b/configure.c
 |  | ||||||
| index 51888519c18c..08b52be85e8d 100644
 |  | ||||||
| --- a/configure.c
 |  | ||||||
| +++ b/configure.c
 |  | ||||||
| @@ -107,6 +107,7 @@ void add_extra_lib(char *);
 |  | ||||||
|  #undef MIPS |  | ||||||
|  #undef SPARC64 |  | ||||||
|  #undef MIPS64 |  | ||||||
| +#undef RISCV64
 |  | ||||||
|   |  | ||||||
|  #define UNKNOWN 0 |  | ||||||
|  #define X86     1 |  | ||||||
| @@ -122,6 +123,7 @@ void add_extra_lib(char *);
 |  | ||||||
|  #define MIPS    11 |  | ||||||
|  #define SPARC64 12 |  | ||||||
|  #define MIPS64  13 |  | ||||||
| +#define RISCV64 14
 |  | ||||||
|   |  | ||||||
|  #define TARGET_X86    "TARGET=X86" |  | ||||||
|  #define TARGET_ALPHA  "TARGET=ALPHA" |  | ||||||
| @@ -136,6 +138,7 @@ void add_extra_lib(char *);
 |  | ||||||
|  #define TARGET_MIPS   "TARGET=MIPS" |  | ||||||
|  #define TARGET_MIPS64 "TARGET=MIPS64" |  | ||||||
|  #define TARGET_SPARC64 "TARGET=SPARC64" |  | ||||||
| +#define TARGET_RISCV64 "TARGET=RISCV64"
 |  | ||||||
|   |  | ||||||
|  #define TARGET_CFLAGS_X86    "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64" |  | ||||||
|  #define TARGET_CFLAGS_ALPHA  "TARGET_CFLAGS=" |  | ||||||
| @@ -158,6 +161,8 @@ void add_extra_lib(char *);
 |  | ||||||
|  #define TARGET_CFLAGS_MIPS_ON_X86_64  "TARGET_CFLAGS=-m32 -D_FILE_OFFSET_BITS=64" |  | ||||||
|  #define TARGET_CFLAGS_MIPS64          "TARGET_CFLAGS=" |  | ||||||
|  #define TARGET_CFLAGS_SPARC64         "TARGET_CFLAGS=" |  | ||||||
| +#define TARGET_CFLAGS_RISCV64         "TARGET_CFLAGS="
 |  | ||||||
| +#define TARGET_CFLAGS_RISCV64_ON_X86_64	"TARGET_CFLAGS="
 |  | ||||||
|   |  | ||||||
|  #define GDB_TARGET_DEFAULT        "GDB_CONF_FLAGS=" |  | ||||||
|  #define GDB_TARGET_ARM_ON_X86     "GDB_CONF_FLAGS=--target=arm-elf-linux" |  | ||||||
| @@ -168,6 +173,7 @@ void add_extra_lib(char *);
 |  | ||||||
|  #define GDB_TARGET_PPC64_ON_X86_64  "GDB_CONF_FLAGS=--target=powerpc64le-unknown-linux-gnu" |  | ||||||
|  #define GDB_TARGET_MIPS_ON_X86     "GDB_CONF_FLAGS=--target=mipsel-elf-linux" |  | ||||||
|  #define GDB_TARGET_MIPS_ON_X86_64  "GDB_CONF_FLAGS=--target=mipsel-elf-linux CFLAGS=-m32 CXXFLAGS=-m32" |  | ||||||
| +#define GDB_TARGET_RISCV64_ON_X86_64  "GDB_CONF_FLAGS=--target=riscv64-unknown-linux-gnu"
 |  | ||||||
|        |  | ||||||
|  /* |  | ||||||
|   *  The original plan was to allow the use of a particular version |  | ||||||
| @@ -404,6 +410,9 @@ get_current_configuration(struct supported_gdb_version *sp)
 |  | ||||||
|  #ifdef __sparc_v9__ |  | ||||||
|  	target_data.target = SPARC64; |  | ||||||
|  #endif |  | ||||||
| +#if defined(__riscv) && (__riscv_xlen == 64)
 |  | ||||||
| +	target_data.target = RISCV64;
 |  | ||||||
| +#endif
 |  | ||||||
|   |  | ||||||
|  	set_initial_target(sp); |  | ||||||
|   |  | ||||||
| @@ -457,6 +466,12 @@ get_current_configuration(struct supported_gdb_version *sp)
 |  | ||||||
|  			if ((target_data.initial_gdb_target != UNKNOWN) && |  | ||||||
|  			    (target_data.host != target_data.initial_gdb_target)) |  | ||||||
|  				arch_mismatch(sp); |  | ||||||
| +		} else if ((target_data.target == X86_64) &&
 |  | ||||||
| +			(name_to_target((char *)target_data.target_as_param) == RISCV64)) {
 |  | ||||||
| +			/*
 |  | ||||||
| +			 *  Build an RISCV64 crash binary on an X86_64 host.
 |  | ||||||
| +			 */
 |  | ||||||
| +			target_data.target = RISCV64;
 |  | ||||||
|  		} else { |  | ||||||
|  			fprintf(stderr, |  | ||||||
|  			    "\ntarget=%s is not supported on the %s host architecture\n\n", |  | ||||||
| @@ -497,6 +512,14 @@ get_current_configuration(struct supported_gdb_version *sp)
 |  | ||||||
|  		    (target_data.target != MIPS64)) |  | ||||||
|  			arch_mismatch(sp); |  | ||||||
|   |  | ||||||
| +		if ((target_data.initial_gdb_target == RISCV64) &&
 |  | ||||||
| +		    (target_data.target != RISCV64)) {
 |  | ||||||
| +			if (target_data.target == X86_64)
 |  | ||||||
| +				target_data.target = RISCV64;
 |  | ||||||
| +			else
 |  | ||||||
| +				arch_mismatch(sp);
 |  | ||||||
| +		}
 |  | ||||||
| +
 |  | ||||||
|  		if ((target_data.initial_gdb_target == X86) && |  | ||||||
|  		    (target_data.target != X86)) { |  | ||||||
|  			if (target_data.target == X86_64)  |  | ||||||
| @@ -660,6 +683,9 @@ show_configuration(void)
 |  | ||||||
|  	case SPARC64: |  | ||||||
|  		printf("TARGET: SPARC64\n"); |  | ||||||
|  		break; |  | ||||||
| +	case RISCV64:
 |  | ||||||
| +		printf("TARGET: RISCV64\n");
 |  | ||||||
| +		break;
 |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
|  	if (strlen(target_data.program)) { |  | ||||||
| @@ -777,6 +803,14 @@ build_configure(struct supported_gdb_version *sp)
 |  | ||||||
|  		target = TARGET_SPARC64; |  | ||||||
|  		target_CFLAGS = TARGET_CFLAGS_SPARC64; |  | ||||||
|  		break; |  | ||||||
| +	case RISCV64:
 |  | ||||||
| +		target = TARGET_RISCV64;
 |  | ||||||
| +		if (target_data.host == X86_64) {
 |  | ||||||
| +			target_CFLAGS = TARGET_CFLAGS_RISCV64_ON_X86_64;
 |  | ||||||
| +			gdb_conf_flags = GDB_TARGET_RISCV64_ON_X86_64;
 |  | ||||||
| +		} else
 |  | ||||||
| +			target_CFLAGS = TARGET_CFLAGS_RISCV64;
 |  | ||||||
| +		break;
 |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
|  	ldflags = get_extra_flags("LDFLAGS.extra", NULL); |  | ||||||
| @@ -1374,7 +1408,7 @@ make_spec_file(struct supported_gdb_version *sp)
 |  | ||||||
|  	printf("Vendor: Red Hat, Inc.\n"); |  | ||||||
|  	printf("Packager: Dave Anderson <anderson@redhat.com>\n"); |  | ||||||
|  	printf("ExclusiveOS: Linux\n"); |  | ||||||
| -	printf("ExclusiveArch: %%{ix86} alpha ia64 ppc ppc64 ppc64pseries ppc64iseries x86_64 s390 s390x arm aarch64 ppc64le mips mipsel mips64el sparc64\n");
 |  | ||||||
| +	printf("ExclusiveArch: %%{ix86} alpha ia64 ppc ppc64 ppc64pseries ppc64iseries x86_64 s390 s390x arm aarch64 ppc64le mips mipsel mips64el sparc64 riscv64\n");
 |  | ||||||
|  	printf("Buildroot: %%{_tmppath}/%%{name}-root\n"); |  | ||||||
|  	printf("BuildRequires: ncurses-devel zlib-devel bison\n"); |  | ||||||
|  	printf("Requires: binutils\n"); |  | ||||||
| @@ -1613,6 +1647,8 @@ set_initial_target(struct supported_gdb_version *sp)
 |  | ||||||
|  		target_data.initial_gdb_target = MIPS; |  | ||||||
|  	else if (strncmp(buf, "SPARC64", strlen("SPARC64")) == 0) |  | ||||||
|  		target_data.initial_gdb_target = SPARC64; |  | ||||||
| +	else if (strncmp(buf, "RISCV64", strlen("RISCV64")) == 0)
 |  | ||||||
| +		target_data.initial_gdb_target = RISCV64;
 |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  char * |  | ||||||
| @@ -1633,6 +1669,7 @@ target_to_name(int target)
 |  | ||||||
|  	case MIPS:   return("MIPS"); |  | ||||||
|  	case MIPS64: return("MIPS64"); |  | ||||||
|  	case SPARC64: return("SPARC64"); |  | ||||||
| +	case RISCV64: return("RISCV64");
 |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
|  	return "UNKNOWN"; |  | ||||||
| @@ -1697,6 +1734,10 @@ name_to_target(char *name)
 |  | ||||||
|  		return MIPS64; |  | ||||||
|  	else if (strncmp(name, "sparc64", strlen("sparc64")) == 0) |  | ||||||
|  		return SPARC64; |  | ||||||
| +	else if (strncmp(name, "RISCV64", strlen("RISCV64")) == 0)
 |  | ||||||
| +		return RISCV64;
 |  | ||||||
| +	else if (strncmp(name, "riscv64", strlen("riscv64")) == 0)
 |  | ||||||
| +		return RISCV64;
 |  | ||||||
|   |  | ||||||
|  	return UNKNOWN; |  | ||||||
|  } |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index 04476b3ff62e..7702ab050f26 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -76,7 +76,7 @@
 |  | ||||||
|  #if !defined(X86) && !defined(X86_64) && !defined(ALPHA) && !defined(PPC) && \ |  | ||||||
|      !defined(IA64) && !defined(PPC64) && !defined(S390) && !defined(S390X) && \ |  | ||||||
|      !defined(ARM) && !defined(ARM64) && !defined(MIPS) && !defined(MIPS64) && \ |  | ||||||
| -    !defined(SPARC64)
 |  | ||||||
| +    !defined(RISCV64) && !defined(SPARC64)
 |  | ||||||
|  #ifdef __alpha__ |  | ||||||
|  #define ALPHA |  | ||||||
|  #endif |  | ||||||
| @@ -118,6 +118,9 @@
 |  | ||||||
|  #ifdef __sparc_v9__ |  | ||||||
|  #define SPARC64 |  | ||||||
|  #endif |  | ||||||
| +#if defined(__riscv) && (__riscv_xlen == 64)
 |  | ||||||
| +#define RISCV64
 |  | ||||||
| +#endif
 |  | ||||||
|  #endif |  | ||||||
|   |  | ||||||
|  #ifdef X86 |  | ||||||
| @@ -159,6 +162,9 @@
 |  | ||||||
|  #ifdef SPARC64 |  | ||||||
|  #define NR_CPUS  (4096) |  | ||||||
|  #endif |  | ||||||
| +#ifdef RISCV64
 |  | ||||||
| +#define NR_CPUS  (256)
 |  | ||||||
| +#endif
 |  | ||||||
|   |  | ||||||
|  #define NR_DEVICE_DUMPS (64) |  | ||||||
|   |  | ||||||
| @@ -3486,6 +3492,63 @@ struct arm64_stackframe {
 |  | ||||||
|  #define _MAX_PHYSMEM_BITS       48 |  | ||||||
|  #endif  /* MIPS64 */ |  | ||||||
|   |  | ||||||
| +#ifdef RISCV64
 |  | ||||||
| +#define _64BIT_
 |  | ||||||
| +#define MACHINE_TYPE		"RISCV64"
 |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| + * Direct memory mapping
 |  | ||||||
| + */
 |  | ||||||
| +#define PTOV(X) 									\
 |  | ||||||
| +	(((unsigned long)(X)+(machdep->kvbase)) - machdep->machspec->phys_base)
 |  | ||||||
| +#define VTOP(X) ({									\
 |  | ||||||
| +	ulong _X = X;									\
 |  | ||||||
| +	(THIS_KERNEL_VERSION >= LINUX(5,13,0) &&					\
 |  | ||||||
| +		(_X) >= machdep->machspec->kernel_link_addr) ?				\
 |  | ||||||
| +		(((unsigned long)(_X)-(machdep->machspec->kernel_link_addr)) +		\
 |  | ||||||
| +		 machdep->machspec->phys_base):						\
 |  | ||||||
| +		(((unsigned long)(_X)-(machdep->kvbase)) +				\
 |  | ||||||
| +		 machdep->machspec->phys_base);						\
 |  | ||||||
| +	})
 |  | ||||||
| +#define PAGEBASE(X)		(((ulong)(X)) & (ulong)machdep->pagemask)
 |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| + * Stack size order
 |  | ||||||
| + */
 |  | ||||||
| +#define THREAD_SIZE_ORDER	2
 |  | ||||||
| +
 |  | ||||||
| +#define PAGE_OFFSET		(machdep->machspec->page_offset)
 |  | ||||||
| +#define VMALLOC_START		(machdep->machspec->vmalloc_start_addr)
 |  | ||||||
| +#define VMALLOC_END		(machdep->machspec->vmalloc_end)
 |  | ||||||
| +#define VMEMMAP_VADDR		(machdep->machspec->vmemmap_vaddr)
 |  | ||||||
| +#define VMEMMAP_END		(machdep->machspec->vmemmap_end)
 |  | ||||||
| +#define MODULES_VADDR		(machdep->machspec->modules_vaddr)
 |  | ||||||
| +#define MODULES_END		(machdep->machspec->modules_end)
 |  | ||||||
| +#define IS_VMALLOC_ADDR(X)	riscv64_IS_VMALLOC_ADDR((ulong)(X))
 |  | ||||||
| +
 |  | ||||||
| +/* from arch/riscv/include/asm/pgtable.h */
 |  | ||||||
| +#define __SWP_TYPE_SHIFT	6
 |  | ||||||
| +#define __SWP_TYPE_BITS 	5
 |  | ||||||
| +#define __SWP_TYPE_MASK 	((1UL << __SWP_TYPE_BITS) - 1)
 |  | ||||||
| +#define __SWP_OFFSET_SHIFT	(__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
 |  | ||||||
| +
 |  | ||||||
| +#define MAX_SWAPFILES_CHECK()	BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)
 |  | ||||||
| +
 |  | ||||||
| +#define SWP_TYPE(entry) 	(((entry) >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
 |  | ||||||
| +#define SWP_OFFSET(entry)	((entry) >> __SWP_OFFSET_SHIFT)
 |  | ||||||
| +#define __swp_type(entry)	SWP_TYPE(entry)
 |  | ||||||
| +#define __swp_offset(entry)	SWP_OFFSET(entry)
 |  | ||||||
| +
 |  | ||||||
| +#define TIF_SIGPENDING		(THIS_KERNEL_VERSION >= LINUX(2,6,23) ? 1 : 2)
 |  | ||||||
| +
 |  | ||||||
| +/* from arch/riscv/include/asm/sparsemem.h */
 |  | ||||||
| +#define _SECTION_SIZE_BITS	27
 |  | ||||||
| +#define _MAX_PHYSMEM_BITS	56 /* 56-bit physical address supported */
 |  | ||||||
| +#define PHYS_MASK_SHIFT 	_MAX_PHYSMEM_BITS
 |  | ||||||
| +#define PHYS_MASK		(((1UL) << PHYS_MASK_SHIFT) - 1)
 |  | ||||||
| +
 |  | ||||||
| +#endif  /* RISCV64 */
 |  | ||||||
| +
 |  | ||||||
|  #ifdef X86 |  | ||||||
|  #define _32BIT_ |  | ||||||
|  #define MACHINE_TYPE       "X86" |  | ||||||
| @@ -4534,6 +4597,10 @@ struct machine_specific {
 |  | ||||||
|  #define MAX_HEXADDR_STRLEN (16) |  | ||||||
|  #define UVADDR_PRLEN      (16) |  | ||||||
|  #endif |  | ||||||
| +#ifdef RISCV64
 |  | ||||||
| +#define MAX_HEXADDR_STRLEN (16)
 |  | ||||||
| +#define UVADDR_PRLEN       (16)
 |  | ||||||
| +#endif
 |  | ||||||
|   |  | ||||||
|  #define BADADDR  ((ulong)(-1)) |  | ||||||
|  #define BADVAL   ((ulong)(-1)) |  | ||||||
| @@ -5149,6 +5216,9 @@ void dump_build_data(void);
 |  | ||||||
|  #ifdef MIPS64 |  | ||||||
|  #define machdep_init(X) mips64_init(X) |  | ||||||
|  #endif |  | ||||||
| +#ifdef RISCV64
 |  | ||||||
| +#define machdep_init(X) riscv64_init(X)
 |  | ||||||
| +#endif
 |  | ||||||
|  #ifdef SPARC64 |  | ||||||
|  #define machdep_init(X) sparc64_init(X) |  | ||||||
|  #endif |  | ||||||
| @@ -5630,6 +5700,9 @@ void display_help_screen(char *);
 |  | ||||||
|  #ifdef SPARC64 |  | ||||||
|  #define dump_machdep_table(X) sparc64_dump_machdep_table(X) |  | ||||||
|  #endif |  | ||||||
| +#ifdef RISCV64
 |  | ||||||
| +#define dump_machdep_table(X) riscv64_dump_machdep_table(X)
 |  | ||||||
| +#endif
 |  | ||||||
|  extern char *help_pointer[]; |  | ||||||
|  extern char *help_alias[]; |  | ||||||
|  extern char *help_ascii[]; |  | ||||||
| @@ -6707,6 +6780,85 @@ struct machine_specific {
 |  | ||||||
|   |  | ||||||
|  #endif /* MIPS64 */ |  | ||||||
|   |  | ||||||
| +/*
 |  | ||||||
| + * riscv64.c
 |  | ||||||
| + */
 |  | ||||||
| +void riscv64_display_regs_from_elf_notes(int, FILE *);
 |  | ||||||
| +
 |  | ||||||
| +#ifdef RISCV64
 |  | ||||||
| +void riscv64_init(int);
 |  | ||||||
| +void riscv64_dump_machdep_table(ulong);
 |  | ||||||
| +int riscv64_IS_VMALLOC_ADDR(ulong);
 |  | ||||||
| +
 |  | ||||||
| +#define display_idt_table() \
 |  | ||||||
| +	error(FATAL, "-d option is not applicable to RISCV64 architecture\n")
 |  | ||||||
| +
 |  | ||||||
| +/* from arch/riscv/include/asm/ptrace.h */
 |  | ||||||
| +struct riscv64_register {
 |  | ||||||
| +	ulong regs[36];
 |  | ||||||
| +};
 |  | ||||||
| +
 |  | ||||||
| +struct riscv64_pt_regs {
 |  | ||||||
| +	ulong badvaddr;
 |  | ||||||
| +	ulong cause;
 |  | ||||||
| +	ulong epc;
 |  | ||||||
| +};
 |  | ||||||
| +
 |  | ||||||
| +struct riscv64_unwind_frame {
 |  | ||||||
| +	ulong fp;
 |  | ||||||
| +	ulong sp;
 |  | ||||||
| +	ulong pc;
 |  | ||||||
| +};
 |  | ||||||
| +
 |  | ||||||
| +#define KSYMS_START	(0x1)
 |  | ||||||
| +
 |  | ||||||
| +struct machine_specific {
 |  | ||||||
| +	ulong phys_base;
 |  | ||||||
| +	ulong page_offset;
 |  | ||||||
| +	ulong vmalloc_start_addr;
 |  | ||||||
| +	ulong vmalloc_end;
 |  | ||||||
| +	ulong vmemmap_vaddr;
 |  | ||||||
| +	ulong vmemmap_end;
 |  | ||||||
| +	ulong modules_vaddr;
 |  | ||||||
| +	ulong modules_end;
 |  | ||||||
| +	ulong kernel_link_addr;
 |  | ||||||
| +
 |  | ||||||
| +	ulong _page_present;
 |  | ||||||
| +	ulong _page_read;
 |  | ||||||
| +	ulong _page_write;
 |  | ||||||
| +	ulong _page_exec;
 |  | ||||||
| +	ulong _page_user;
 |  | ||||||
| +	ulong _page_global;
 |  | ||||||
| +	ulong _page_accessed;
 |  | ||||||
| +	ulong _page_dirty;
 |  | ||||||
| +	ulong _page_soft;
 |  | ||||||
| +
 |  | ||||||
| +	ulong _pfn_shift;
 |  | ||||||
| +
 |  | ||||||
| +	struct riscv64_register *crash_task_regs;
 |  | ||||||
| +};
 |  | ||||||
| +/* from arch/riscv/include/asm/pgtable-bits.h */
 |  | ||||||
| +#define _PAGE_PRESENT	(machdep->machspec->_page_present)
 |  | ||||||
| +#define _PAGE_READ	(machdep->machspec->_page_read)
 |  | ||||||
| +#define _PAGE_WRITE	(machdep->machspec->_page_write)
 |  | ||||||
| +#define _PAGE_EXEC	(machdep->machspec->_page_exec)
 |  | ||||||
| +#define _PAGE_USER	(machdep->machspec->_page_user)
 |  | ||||||
| +#define _PAGE_GLOBAL	(machdep->machspec->_page_global)
 |  | ||||||
| +#define _PAGE_ACCESSED	(machdep->machspec->_page_accessed)
 |  | ||||||
| +#define _PAGE_DIRTY	(machdep->machspec->_page_dirty)
 |  | ||||||
| +#define _PAGE_SOFT	(machdep->machspec->_page_soft)
 |  | ||||||
| +#define _PAGE_SEC	(machdep->machspec->_page_sec)
 |  | ||||||
| +#define _PAGE_SHARE	(machdep->machspec->_page_share)
 |  | ||||||
| +#define _PAGE_BUF	(machdep->machspec->_page_buf)
 |  | ||||||
| +#define _PAGE_CACHE	(machdep->machspec->_page_cache)
 |  | ||||||
| +#define _PAGE_SO	(machdep->machspec->_page_so)
 |  | ||||||
| +#define _PAGE_SPECIAL	_PAGE_SOFT
 |  | ||||||
| +#define _PAGE_TABLE	_PAGE_PRESENT
 |  | ||||||
| +#define _PAGE_PROT_NONE _PAGE_READ
 |  | ||||||
| +#define _PAGE_PFN_SHIFT 10
 |  | ||||||
| +
 |  | ||||||
| +#endif /* RISCV64 */
 |  | ||||||
| +
 |  | ||||||
|  /* |  | ||||||
|   * sparc64.c |  | ||||||
|   */ |  | ||||||
| diff --git a/diskdump.c b/diskdump.c
 |  | ||||||
| index 2c1f9be55c1f..28503bc286f8 100644
 |  | ||||||
| --- a/diskdump.c
 |  | ||||||
| +++ b/diskdump.c
 |  | ||||||
| @@ -622,6 +622,9 @@ restart:
 |  | ||||||
|  	else if (STRNEQ(header->utsname.machine, "aarch64") && |  | ||||||
|  	    machine_type_mismatch(file, "ARM64", NULL, 0)) |  | ||||||
|  		goto err; |  | ||||||
| +	else if (STRNEQ(header->utsname.machine, "riscv64") &&
 |  | ||||||
| +	    machine_type_mismatch(file, "RISCV64", NULL, 0))
 |  | ||||||
| +		goto err;
 |  | ||||||
|   |  | ||||||
|  	if (header->block_size != block_size) { |  | ||||||
|  		block_size = header->block_size; |  | ||||||
| @@ -780,6 +783,8 @@ restart:
 |  | ||||||
|  		dd->machine_type = EM_AARCH64; |  | ||||||
|  	else if (machine_type("SPARC64")) |  | ||||||
|  		dd->machine_type = EM_SPARCV9; |  | ||||||
| +	else if (machine_type("RISCV64"))
 |  | ||||||
| +		dd->machine_type = EM_RISCV;
 |  | ||||||
|  	else { |  | ||||||
|  		error(INFO, "%s: unsupported machine type: %s\n",  |  | ||||||
|  			DISKDUMP_VALID() ? "diskdump" : "compressed kdump", |  | ||||||
| @@ -1751,7 +1756,8 @@ dump_note_offsets(FILE *fp)
 |  | ||||||
|  			qemu = FALSE; |  | ||||||
|  			if (machine_type("X86_64") || machine_type("S390X") || |  | ||||||
|  			    machine_type("ARM64") || machine_type("PPC64") || |  | ||||||
| -			    machine_type("SPARC64") || machine_type("MIPS64")) {
 |  | ||||||
| +			    machine_type("SPARC64") || machine_type("MIPS64") ||
 |  | ||||||
| +			    machine_type("RISCV64")) {
 |  | ||||||
|  				note64 = (void *)dd->notes_buf + tot; |  | ||||||
|  				len = sizeof(Elf64_Nhdr); |  | ||||||
|  				if (STRNEQ((char *)note64 + len, "QEMU")) |  | ||||||
| @@ -2558,7 +2564,8 @@ dump_registers_for_compressed_kdump(void)
 |  | ||||||
|  	if (!KDUMP_CMPRS_VALID() || (dd->header->header_version < 4) || |  | ||||||
|  	    !(machine_type("X86") || machine_type("X86_64") || |  | ||||||
|  	      machine_type("ARM64") || machine_type("PPC64") || |  | ||||||
| -	      machine_type("MIPS") || machine_type("MIPS64")))
 |  | ||||||
| +	      machine_type("MIPS") || machine_type("MIPS64") ||
 |  | ||||||
| +	      machine_type("RISCV64")))
 |  | ||||||
|  		error(FATAL, "-r option not supported for this dumpfile\n"); |  | ||||||
|   |  | ||||||
|  	if (machine_type("ARM64") && (kt->cpus != dd->num_prstatus_notes)) |  | ||||||
| diff --git a/help.c b/help.c
 |  | ||||||
| index 14981cd01d48..367500fc280d 100644
 |  | ||||||
| --- a/help.c
 |  | ||||||
| +++ b/help.c
 |  | ||||||
| @@ -9513,8 +9513,8 @@ char *README[] = {
 |  | ||||||
|  "  These are the current prerequisites: ", |  | ||||||
|  "", |  | ||||||
|  "  o  At this point, x86, ia64, x86_64, ppc64, ppc, arm, arm64, alpha, mips,", |  | ||||||
| -"     mips64, s390 and s390x-based kernels are supported.  Other architectures",
 |  | ||||||
| -"     may be addressed in the future.",
 |  | ||||||
| +"     mips64, riscv64, s390 and s390x-based kernels are supported.  Other",
 |  | ||||||
| +"     architectures may be addressed in the future.",
 |  | ||||||
|  "", |  | ||||||
|  "  o  One size fits all -- the utility can be run on any Linux kernel version", |  | ||||||
|  "     version dating back to 2.2.5-15.  A primary design goal is to always", |  | ||||||
| @@ -9573,6 +9573,8 @@ README_ENTER_DIRECTORY,
 |  | ||||||
|  "     arm64 dumpfiles may be built by typing \"make target=ARM64\".", |  | ||||||
|  "  o  On an x86_64 host, an x86_64 binary that can be used to analyze", |  | ||||||
|  "     ppc64le dumpfiles may be built by typing \"make target=PPC64\".", |  | ||||||
| +"  o  On an x86_64 host, an x86_64 binary that can be used to analyze",
 |  | ||||||
| +"     riscv64 dumpfiles may be built by typing \"make target=RISCV64\".",
 |  | ||||||
|  "", |  | ||||||
|  "  Traditionally when vmcores are compressed via the makedumpfile(8) facility", |  | ||||||
|  "  the libz compression library is used, and by default the crash utility", |  | ||||||
| diff --git a/lkcd_vmdump_v1.h b/lkcd_vmdump_v1.h
 |  | ||||||
| index 4933427fc755..98ee09495869 100644
 |  | ||||||
| --- a/lkcd_vmdump_v1.h
 |  | ||||||
| +++ b/lkcd_vmdump_v1.h
 |  | ||||||
| @@ -114,14 +114,8 @@ typedef struct _dump_header_s {
 |  | ||||||
|  	struct new_utsname   dh_utsname; |  | ||||||
|   |  | ||||||
|  	/* the dump registers */ |  | ||||||
| -#ifndef IA64
 |  | ||||||
| -#ifndef S390
 |  | ||||||
| -#ifndef S390X
 |  | ||||||
| -#ifndef ARM64
 |  | ||||||
| +#if !defined(IA64) && !defined(S390) && !defined(S390X) && !defined(ARM64) && !defined(RISCV64)
 |  | ||||||
|  	struct pt_regs       dh_regs; |  | ||||||
| -#endif
 |  | ||||||
| -#endif
 |  | ||||||
| -#endif
 |  | ||||||
|  #endif |  | ||||||
|   |  | ||||||
|  	/* the address of the current task */ |  | ||||||
| diff --git a/lkcd_vmdump_v2_v3.h b/lkcd_vmdump_v2_v3.h
 |  | ||||||
| index 984c2c25e3c6..ef3067f88e1e 100644
 |  | ||||||
| --- a/lkcd_vmdump_v2_v3.h
 |  | ||||||
| +++ b/lkcd_vmdump_v2_v3.h
 |  | ||||||
| @@ -37,7 +37,7 @@
 |  | ||||||
|   |  | ||||||
|  #if defined(ARM) || defined(X86) || defined(PPC) || defined(S390) || \ |  | ||||||
|  	defined(S390X) || defined(ARM64) || defined(MIPS) || \ |  | ||||||
| -	defined(MIPS64) || defined(SPARC64)
 |  | ||||||
| +	defined(MIPS64) || defined(SPARC64) || defined(RISCV64)
 |  | ||||||
|   |  | ||||||
|  /* |  | ||||||
|   * Kernel header file for Linux crash dumps. |  | ||||||
| @@ -84,13 +84,9 @@ typedef struct _dump_header_asm_s {
 |  | ||||||
|  	uint32_t             dha_eip; |  | ||||||
|   |  | ||||||
|  	/* the dump registers */ |  | ||||||
| -#ifndef S390
 |  | ||||||
| -#ifndef S390X
 |  | ||||||
| -#ifndef ARM64
 |  | ||||||
| +#if !defined(S390) && !defined(S390X) && !defined(ARM64) && !defined(RISCV64)
 |  | ||||||
|  	struct pt_regs       dha_regs; |  | ||||||
|  #endif |  | ||||||
| -#endif
 |  | ||||||
| -#endif
 |  | ||||||
|   |  | ||||||
|  } dump_header_asm_t; |  | ||||||
|   |  | ||||||
| diff --git a/netdump.c b/netdump.c
 |  | ||||||
| index ff273b4fdfab..4ec12a073af6 100644
 |  | ||||||
| --- a/netdump.c
 |  | ||||||
| +++ b/netdump.c
 |  | ||||||
| @@ -300,6 +300,12 @@ is_netdump(char *file, ulong source_query)
 |  | ||||||
|  				goto bailout; |  | ||||||
|  			break; |  | ||||||
|   |  | ||||||
| +		case EM_RISCV:
 |  | ||||||
| +			if (machine_type_mismatch(file, "RISCV64", NULL,
 |  | ||||||
| +			    source_query))
 |  | ||||||
| +				goto bailout;
 |  | ||||||
| +			break;
 |  | ||||||
| +
 |  | ||||||
|  		default: |  | ||||||
|  			if (machine_type_mismatch(file, "(unknown)", NULL, |  | ||||||
|  			    source_query)) |  | ||||||
| @@ -2935,7 +2941,8 @@ dump_registers_for_elf_dumpfiles(void)
 |  | ||||||
|   |  | ||||||
|          if (!(machine_type("X86") || machine_type("X86_64") ||  |  | ||||||
|  	    machine_type("ARM64") || machine_type("PPC64") || |  | ||||||
| -	    machine_type("MIPS") || machine_type("MIPS64")))
 |  | ||||||
| +	    machine_type("MIPS") || machine_type("MIPS64") ||
 |  | ||||||
| +	    machine_type("RISCV64")))
 |  | ||||||
|                  error(FATAL, "-r option not supported for this dumpfile\n"); |  | ||||||
|   |  | ||||||
|  	if (NETDUMP_DUMPFILE()) { |  | ||||||
| diff --git a/ramdump.c b/ramdump.c
 |  | ||||||
| index a206fcbbab3c..d2bd7ffb0b4b 100644
 |  | ||||||
| --- a/ramdump.c
 |  | ||||||
| +++ b/ramdump.c
 |  | ||||||
| @@ -188,6 +188,8 @@ char *ramdump_to_elf(void)
 |  | ||||||
|  		e_machine = EM_MIPS; |  | ||||||
|  	else if (machine_type("X86_64")) |  | ||||||
|  		e_machine = EM_X86_64; |  | ||||||
| +	else if (machine_type("RISCV64"))
 |  | ||||||
| +		e_machine = EM_RISCV;
 |  | ||||||
|  	else |  | ||||||
|  		error(FATAL, "ramdump: unsupported machine type: %s\n",  |  | ||||||
|  			MACHINE_TYPE); |  | ||||||
| diff --git a/riscv64.c b/riscv64.c
 |  | ||||||
| new file mode 100644 |  | ||||||
| index 000000000000..4f858a418a8c
 |  | ||||||
| --- /dev/null
 |  | ||||||
| +++ b/riscv64.c
 |  | ||||||
| @@ -0,0 +1,54 @@
 |  | ||||||
| +/* riscv64.c - core analysis suite
 |  | ||||||
| + *
 |  | ||||||
| + * Copyright (C) 2022 Alibaba Group Holding Limited.
 |  | ||||||
| + *
 |  | ||||||
| + * This program is free software; you can redistribute it and/or modify
 |  | ||||||
| + * it under the terms of the GNU General Public License as published by
 |  | ||||||
| + * the Free Software Foundation; either version 2 of the License, or
 |  | ||||||
| + * (at your option) any later version.
 |  | ||||||
| + *
 |  | ||||||
| + * This program is distributed in the hope that it will be useful,
 |  | ||||||
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 |  | ||||||
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 |  | ||||||
| + * GNU General Public License for more details.
 |  | ||||||
| + */
 |  | ||||||
| +#include "defs.h"
 |  | ||||||
| +#ifdef RISCV64
 |  | ||||||
| +
 |  | ||||||
| +#include <elf.h>
 |  | ||||||
| +
 |  | ||||||
| +void
 |  | ||||||
| +riscv64_dump_machdep_table(ulong arg)
 |  | ||||||
| +{
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| + *  Include both vmalloc'd and module address space as VMALLOC space.
 |  | ||||||
| + */
 |  | ||||||
| +int
 |  | ||||||
| +riscv64_IS_VMALLOC_ADDR(ulong vaddr)
 |  | ||||||
| +{
 |  | ||||||
| +	return ((vaddr >= VMALLOC_START && vaddr <= VMALLOC_END) ||
 |  | ||||||
| +		(vaddr >= VMEMMAP_VADDR && vaddr <= VMEMMAP_END) ||
 |  | ||||||
| +		(vaddr >= MODULES_VADDR && vaddr <= MODULES_END));
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +void
 |  | ||||||
| +riscv64_init(int when)
 |  | ||||||
| +{
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +void
 |  | ||||||
| +riscv64_display_regs_from_elf_notes(int cpu, FILE *ofp)
 |  | ||||||
| +{
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +#else /* !RISCV64 */
 |  | ||||||
| +
 |  | ||||||
| +void
 |  | ||||||
| +riscv64_display_regs_from_elf_notes(int cpu, FILE *ofp)
 |  | ||||||
| +{
 |  | ||||||
| +	return;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +#endif /* !RISCV64 */
 |  | ||||||
| diff --git a/symbols.c b/symbols.c
 |  | ||||||
| index e279cfa68490..cb5b508dcc50 100644
 |  | ||||||
| --- a/symbols.c
 |  | ||||||
| +++ b/symbols.c
 |  | ||||||
| @@ -3743,6 +3743,11 @@ is_kernel(char *file)
 |  | ||||||
|  				goto bailout; |  | ||||||
|  			break; |  | ||||||
|   |  | ||||||
| +		case EM_RISCV:
 |  | ||||||
| +			if (machine_type_mismatch(file, "RISCV64", NULL, 0))
 |  | ||||||
| +				goto bailout;
 |  | ||||||
| +			break;
 |  | ||||||
| +
 |  | ||||||
|  		default: |  | ||||||
|  			if (machine_type_mismatch(file, "(unknown)", NULL, 0)) |  | ||||||
|  				goto bailout; |  | ||||||
| @@ -4002,6 +4007,11 @@ is_shared_object(char *file)
 |  | ||||||
|  			if (machine_type("MIPS64")) |  | ||||||
|  				return TRUE; |  | ||||||
|  			break; |  | ||||||
| +
 |  | ||||||
| +		case EM_RISCV:
 |  | ||||||
| +			if (machine_type("RISCV64"))
 |  | ||||||
| +				return TRUE;
 |  | ||||||
| +			break;
 |  | ||||||
|  		} |  | ||||||
|   |  | ||||||
|  		if (CRASHDEBUG(1)) |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,44 +0,0 @@ | |||||||
| From b410e14f7865e8c0e28cf2fb7a0092e3a8735645 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Date: Thu, 20 Oct 2022 09:50:08 +0800 |  | ||||||
| Subject: [PATCH 10/28] RISCV64: Add 'dis' command support |  | ||||||
| 
 |  | ||||||
| Use generic_dis_filter() function to support dis command implementation. |  | ||||||
| 
 |  | ||||||
| With this patch, we can get the disassembled code, |  | ||||||
| crash> dis __crash_kexec |  | ||||||
| 0xffffffff80088580 <__crash_kexec>:     addi    sp,sp,-352 |  | ||||||
| 0xffffffff80088582 <__crash_kexec+2>:   sd      s0,336(sp) |  | ||||||
| 0xffffffff80088584 <__crash_kexec+4>:   sd      s1,328(sp) |  | ||||||
| 0xffffffff80088586 <__crash_kexec+6>:   sd      s2,320(sp) |  | ||||||
| 0xffffffff80088588 <__crash_kexec+8>:   addi    s0,sp,352 |  | ||||||
| 0xffffffff8008858a <__crash_kexec+10>:  sd      ra,344(sp) |  | ||||||
| 0xffffffff8008858c <__crash_kexec+12>:  sd      s3,312(sp) |  | ||||||
| 0xffffffff8008858e <__crash_kexec+14>:  sd      s4,304(sp) |  | ||||||
| 0xffffffff80088590 <__crash_kexec+16>:  auipc   s2,0x1057 |  | ||||||
| 0xffffffff80088594 <__crash_kexec+20>:  addi    s2,s2,-1256 |  | ||||||
| 0xffffffff80088598 <__crash_kexec+24>:  ld      a5,0(s2) |  | ||||||
| 0xffffffff8008859c <__crash_kexec+28>:  mv      s1,a0 |  | ||||||
| 0xffffffff8008859e <__crash_kexec+30>:  auipc   a0,0xfff |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  riscv64.c | 1 + |  | ||||||
|  1 file changed, 1 insertion(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/riscv64.c b/riscv64.c
 |  | ||||||
| index d8de3d56e1b7..1e20a09a81ae 100644
 |  | ||||||
| --- a/riscv64.c
 |  | ||||||
| +++ b/riscv64.c
 |  | ||||||
| @@ -988,6 +988,7 @@ riscv64_init(int when)
 |  | ||||||
|  		machdep->is_task_addr = riscv64_is_task_addr; |  | ||||||
|  		machdep->get_smp_cpus = riscv64_get_smp_cpus; |  | ||||||
|  		machdep->value_to_symbol = generic_machdep_value_to_symbol; |  | ||||||
| +		machdep->dis_filter = generic_dis_filter;
 |  | ||||||
|  		machdep->show_interrupts = generic_show_interrupts; |  | ||||||
|  		machdep->get_irq_affinity = generic_get_irq_affinity; |  | ||||||
|  		machdep->init_kernel_pgd = NULL; /* pgd set by symbol_value("swapper_pg_dir") */ |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,36 +0,0 @@ | |||||||
| From 67216c741c4ebe8494f74f1ceabff9cdafb67883 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Date: Thu, 20 Oct 2022 09:50:09 +0800 |  | ||||||
| Subject: [PATCH 11/28] RISCV64: Add irq command support |  | ||||||
| 
 |  | ||||||
| With the patch, we can get the irq info, |  | ||||||
| crash> irq |  | ||||||
|  IRQ   IRQ_DESC/_DATA      IRQACTION      NAME |  | ||||||
|  0       (unused)          (unused) |  | ||||||
|  1   ff60000001329600  ff60000001d17180  "101000.rtc" |  | ||||||
|  2   ff60000001329800  ff60000001d17680  "ttyS0" |  | ||||||
|  3   ff60000001329a00  ff60000001c33c00  "virtio0" |  | ||||||
|  4   ff60000001329c00  ff60000001c33f80  "virtio1" |  | ||||||
|  5   ff6000000120f400  ff60000001216000  "riscv-timer" |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  riscv64.c | 1 + |  | ||||||
|  1 file changed, 1 insertion(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/riscv64.c b/riscv64.c
 |  | ||||||
| index 1e20a09a81ae..2355daca7aac 100644
 |  | ||||||
| --- a/riscv64.c
 |  | ||||||
| +++ b/riscv64.c
 |  | ||||||
| @@ -989,6 +989,7 @@ riscv64_init(int when)
 |  | ||||||
|  		machdep->get_smp_cpus = riscv64_get_smp_cpus; |  | ||||||
|  		machdep->value_to_symbol = generic_machdep_value_to_symbol; |  | ||||||
|  		machdep->dis_filter = generic_dis_filter; |  | ||||||
| +		machdep->dump_irq = generic_dump_irq;
 |  | ||||||
|  		machdep->show_interrupts = generic_show_interrupts; |  | ||||||
|  		machdep->get_irq_affinity = generic_get_irq_affinity; |  | ||||||
|  		machdep->init_kernel_pgd = NULL; /* pgd set by symbol_value("swapper_pg_dir") */ |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,413 +0,0 @@ | |||||||
| From 0d9fcbe3803c684fbfee893837a94d3c8f377805 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Date: Thu, 20 Oct 2022 09:50:10 +0800 |  | ||||||
| Subject: [PATCH 12/28] RISCV64: Add 'bt' command support |  | ||||||
| 
 |  | ||||||
| 1, Add the implementation to get stack frame from active & inactive |  | ||||||
|    task's stack. |  | ||||||
| 2, Add 'bt -l' command support get a line number associated with a |  | ||||||
|    current pc address. |  | ||||||
| 3, Add 'bt -f' command support to display all stack data contained |  | ||||||
|    in a frame |  | ||||||
| 
 |  | ||||||
| With the patch, we can get the backtrace, |  | ||||||
| crash> bt |  | ||||||
| PID: 113      TASK: ff6000000226c200  CPU: 0    COMMAND: "sh" |  | ||||||
|  #0 [ff20000010333b90] riscv_crash_save_regs at ffffffff800078f8 |  | ||||||
|  #1 [ff20000010333cf0] panic at ffffffff806578c6 |  | ||||||
|  #2 [ff20000010333d50] sysrq_reset_seq_param_set at ffffffff8038c03c |  | ||||||
|  #3 [ff20000010333da0] __handle_sysrq at ffffffff8038c604 |  | ||||||
|  #4 [ff20000010333e00] write_sysrq_trigger at ffffffff8038cae4 |  | ||||||
|  #5 [ff20000010333e20] proc_reg_write at ffffffff801b7ee8 |  | ||||||
|  #6 [ff20000010333e40] vfs_write at ffffffff80152bb2 |  | ||||||
|  #7 [ff20000010333e80] ksys_write at ffffffff80152eda |  | ||||||
|  #8 [ff20000010333ed0] sys_write at ffffffff80152f52 |  | ||||||
| 
 |  | ||||||
| crash> bt -l |  | ||||||
| PID: 113      TASK: ff6000000226c200  CPU: 0    COMMAND: "sh" |  | ||||||
|  #0 [ff20000010333b90] riscv_crash_save_regs at ffffffff800078f8 |  | ||||||
|     /buildroot/qemu_riscv64_virt_defconfig/build/linux-custom/arch/riscv/kernel/crash_save_regs.S: 47 |  | ||||||
|  #1 [ff20000010333cf0] panic at ffffffff806578c6 |  | ||||||
|     /buildroot/qemu_riscv64_virt_defconfig/build/linux-custom/kernel/panic.c: 276 |  | ||||||
|  ... ... |  | ||||||
| 
 |  | ||||||
| crash> bt -f |  | ||||||
| PID: 113      TASK: ff6000000226c200  CPU: 0    COMMAND: "sh" |  | ||||||
|  #0 [ff20000010333b90] riscv_crash_save_regs at ffffffff800078f8 |  | ||||||
|     [PC: ffffffff800078f8 RA: ffffffff806578c6 SP: ff20000010333b90 SIZE: 352] |  | ||||||
|     ff20000010333b90: ff20000010333bb0 ffffffff800078f8 |  | ||||||
|     ff20000010333ba0: ffffffff8008862c ff20000010333b90 |  | ||||||
|     ff20000010333bb0: ffffffff810dde38 ff6000000226c200 |  | ||||||
|     ff20000010333bc0: ffffffff8032be68 0720072007200720 |  | ||||||
|  ... ... |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  netdump.c |  13 +++ |  | ||||||
|  riscv64.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ |  | ||||||
|  2 files changed, 296 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/netdump.c b/netdump.c
 |  | ||||||
| index 4ec12a073af6..01af1458d6e8 100644
 |  | ||||||
| --- a/netdump.c
 |  | ||||||
| +++ b/netdump.c
 |  | ||||||
| @@ -42,6 +42,7 @@ static void get_netdump_regs_ppc64(struct bt_info *, ulong *, ulong *);
 |  | ||||||
|  static void get_netdump_regs_arm(struct bt_info *, ulong *, ulong *); |  | ||||||
|  static void get_netdump_regs_arm64(struct bt_info *, ulong *, ulong *); |  | ||||||
|  static void get_netdump_regs_mips(struct bt_info *, ulong *, ulong *); |  | ||||||
| +static void get_netdump_regs_riscv(struct bt_info *, ulong *, ulong *);
 |  | ||||||
|  static void check_dumpfile_size(char *); |  | ||||||
|  static int proc_kcore_init_32(FILE *, int); |  | ||||||
|  static int proc_kcore_init_64(FILE *, int); |  | ||||||
| @@ -2675,6 +2676,10 @@ get_netdump_regs(struct bt_info *bt, ulong *eip, ulong *esp)
 |  | ||||||
|  		return get_netdump_regs_mips(bt, eip, esp); |  | ||||||
|  		break; |  | ||||||
|   |  | ||||||
| +	case EM_RISCV:
 |  | ||||||
| +		get_netdump_regs_riscv(bt, eip, esp);
 |  | ||||||
| +		break;
 |  | ||||||
| +
 |  | ||||||
|  	default: |  | ||||||
|  		error(FATAL,  |  | ||||||
|  		   "support for ELF machine type %d not available\n", |  | ||||||
| @@ -2931,6 +2936,8 @@ display_regs_from_elf_notes(int cpu, FILE *ofp)
 |  | ||||||
|  		mips_display_regs_from_elf_notes(cpu, ofp); |  | ||||||
|  	} else if (machine_type("MIPS64")) { |  | ||||||
|  		mips64_display_regs_from_elf_notes(cpu, ofp); |  | ||||||
| +	} else if (machine_type("RISCV64")) {
 |  | ||||||
| +		riscv64_display_regs_from_elf_notes(cpu, ofp);
 |  | ||||||
|  	} |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| @@ -3877,6 +3884,12 @@ get_netdump_regs_mips(struct bt_info *bt, ulong *eip, ulong *esp)
 |  | ||||||
|  	machdep->get_stack_frame(bt, eip, esp); |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| +static void
 |  | ||||||
| +get_netdump_regs_riscv(struct bt_info *bt, ulong *eip, ulong *esp)
 |  | ||||||
| +{
 |  | ||||||
| +	machdep->get_stack_frame(bt, eip, esp);
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
|  int  |  | ||||||
|  is_partial_netdump(void) |  | ||||||
|  { |  | ||||||
| diff --git a/riscv64.c b/riscv64.c
 |  | ||||||
| index 2355daca7aac..4c9b35bb93f2 100644
 |  | ||||||
| --- a/riscv64.c
 |  | ||||||
| +++ b/riscv64.c
 |  | ||||||
| @@ -33,6 +33,17 @@ static int riscv64_uvtop(struct task_context *tc, ulong vaddr,
 |  | ||||||
|  static int riscv64_kvtop(struct task_context *tc, ulong kvaddr, |  | ||||||
|  			  physaddr_t *paddr, int verbose); |  | ||||||
|  static void riscv64_cmd_mach(void); |  | ||||||
| +static void riscv64_stackframe_init(void);
 |  | ||||||
| +static void riscv64_back_trace_cmd(struct bt_info *bt);
 |  | ||||||
| +static int riscv64_get_dumpfile_stack_frame(struct bt_info *bt,
 |  | ||||||
| +					     ulong *nip, ulong *ksp);
 |  | ||||||
| +static void riscv64_get_stack_frame(struct bt_info *bt, ulong *pcp,
 |  | ||||||
| +				     ulong *spp);
 |  | ||||||
| +static int riscv64_get_frame(struct bt_info *bt, ulong *pcp,
 |  | ||||||
| +			      ulong *spp);
 |  | ||||||
| +static void riscv64_display_full_frame(struct bt_info *bt,
 |  | ||||||
| +				        struct riscv64_unwind_frame *current,
 |  | ||||||
| +				        struct riscv64_unwind_frame *previous);
 |  | ||||||
|  static int riscv64_translate_pte(ulong, void *, ulonglong); |  | ||||||
|  static int riscv64_init_active_task_regs(void); |  | ||||||
|  static int riscv64_get_crash_notes(void); |  | ||||||
| @@ -498,6 +509,275 @@ no_page:
 |  | ||||||
|  	return FALSE; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| +/*
 |  | ||||||
| + * 'bt -f' command output
 |  | ||||||
| + * Display all stack data contained in a frame
 |  | ||||||
| + */
 |  | ||||||
| +static void
 |  | ||||||
| +riscv64_display_full_frame(struct bt_info *bt, struct riscv64_unwind_frame *current,
 |  | ||||||
| +			  struct riscv64_unwind_frame *previous)
 |  | ||||||
| +{
 |  | ||||||
| +	int i, u_idx;
 |  | ||||||
| +	ulong *up;
 |  | ||||||
| +	ulong words, addr;
 |  | ||||||
| +	char buf[BUFSIZE];
 |  | ||||||
| +
 |  | ||||||
| +	if (previous->sp < current->sp)
 |  | ||||||
| +		return;
 |  | ||||||
| +
 |  | ||||||
| +	if (!(INSTACK(previous->sp, bt) && INSTACK(current->sp, bt)))
 |  | ||||||
| +		return;
 |  | ||||||
| +
 |  | ||||||
| +	words = (previous->sp - current->sp) / sizeof(ulong) + 1;
 |  | ||||||
| +	addr = current->sp;
 |  | ||||||
| +	u_idx = (current->sp - bt->stackbase) / sizeof(ulong);
 |  | ||||||
| +
 |  | ||||||
| +	for (i = 0; i < words; i++, u_idx++) {
 |  | ||||||
| +		if (!(i & 1))
 |  | ||||||
| +			fprintf(fp, "%s    %lx: ", i ? "\n" : "", addr);
 |  | ||||||
| +
 |  | ||||||
| +		up = (ulong *)(&bt->stackbuf[u_idx*sizeof(ulong)]);
 |  | ||||||
| +		fprintf(fp, "%s ", format_stack_entry(bt, buf, *up, 0));
 |  | ||||||
| +		addr += sizeof(ulong);
 |  | ||||||
| +	}
 |  | ||||||
| +	fprintf(fp, "\n");
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void
 |  | ||||||
| +riscv64_stackframe_init(void)
 |  | ||||||
| +{
 |  | ||||||
| +	long task_struct_thread = MEMBER_OFFSET("task_struct", "thread");
 |  | ||||||
| +
 |  | ||||||
| +	/* from arch/riscv/include/asm/processor.h */
 |  | ||||||
| +	long thread_reg_ra = MEMBER_OFFSET("thread_struct", "ra");
 |  | ||||||
| +	long thread_reg_sp = MEMBER_OFFSET("thread_struct", "sp");
 |  | ||||||
| +	long thread_reg_fp = MEMBER_OFFSET("thread_struct", "s");
 |  | ||||||
| +
 |  | ||||||
| +	if ((task_struct_thread == INVALID_OFFSET) ||
 |  | ||||||
| +	    (thread_reg_ra == INVALID_OFFSET) ||
 |  | ||||||
| +	    (thread_reg_sp == INVALID_OFFSET) ||
 |  | ||||||
| +	    (thread_reg_fp == INVALID_OFFSET) )
 |  | ||||||
| +		error(FATAL,
 |  | ||||||
| +		      "cannot determine thread_struct offsets\n");
 |  | ||||||
| +
 |  | ||||||
| +	ASSIGN_OFFSET(task_struct_thread_context_pc) =
 |  | ||||||
| +		task_struct_thread + thread_reg_ra;
 |  | ||||||
| +	ASSIGN_OFFSET(task_struct_thread_context_sp) =
 |  | ||||||
| +		task_struct_thread + thread_reg_sp;
 |  | ||||||
| +	ASSIGN_OFFSET(task_struct_thread_context_fp) =
 |  | ||||||
| +		task_struct_thread + thread_reg_fp;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void
 |  | ||||||
| +riscv64_dump_backtrace_entry(struct bt_info *bt, struct syment *sym,
 |  | ||||||
| +			     struct riscv64_unwind_frame *current,
 |  | ||||||
| +			     struct riscv64_unwind_frame *previous, int level)
 |  | ||||||
| +{
 |  | ||||||
| +	const char *name = sym ? sym->name : "(invalid)";
 |  | ||||||
| +	struct load_module *lm;
 |  | ||||||
| +	char *name_plus_offset = NULL;
 |  | ||||||
| +	struct syment *symp;
 |  | ||||||
| +	ulong symbol_offset;
 |  | ||||||
| +	char buf[BUFSIZE];
 |  | ||||||
| +
 |  | ||||||
| +	if (bt->flags & BT_SYMBOL_OFFSET) {
 |  | ||||||
| +		symp = value_search(current->pc, &symbol_offset);
 |  | ||||||
| +
 |  | ||||||
| +		if (symp && symbol_offset)
 |  | ||||||
| +			name_plus_offset =
 |  | ||||||
| +				value_to_symstr(current->pc, buf, bt->radix);
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	fprintf(fp, "%s#%d [%016lx] %s at %016lx",
 |  | ||||||
| +		level < 10 ? " " : "",
 |  | ||||||
| +		level,
 |  | ||||||
| +		current->sp,
 |  | ||||||
| +		name_plus_offset ? name_plus_offset : name,
 |  | ||||||
| +		current->pc);
 |  | ||||||
| +
 |  | ||||||
| +	if (module_symbol(current->pc, NULL, &lm, NULL, 0))
 |  | ||||||
| +		fprintf(fp, " [%s]", lm->mod_name);
 |  | ||||||
| +
 |  | ||||||
| +	fprintf(fp, "\n");
 |  | ||||||
| +
 |  | ||||||
| +	/*
 |  | ||||||
| +	 * 'bt -l', get a line number associated with a current pc address.
 |  | ||||||
| +	 */
 |  | ||||||
| +	if (bt->flags & BT_LINE_NUMBERS) {
 |  | ||||||
| +		get_line_number(current->pc, buf, FALSE);
 |  | ||||||
| +		if (strlen(buf))
 |  | ||||||
| +			fprintf(fp, "    %s\n", buf);
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	/* bt -f */
 |  | ||||||
| +	if (bt->flags & BT_FULL) {
 |  | ||||||
| +		fprintf(fp, "    "
 |  | ||||||
| +			"[PC: %016lx RA: %016lx SP: %016lx SIZE: %ld]\n",
 |  | ||||||
| +			current->pc,
 |  | ||||||
| +			previous->pc,
 |  | ||||||
| +			current->sp,
 |  | ||||||
| +			previous->sp - current->sp);
 |  | ||||||
| +		riscv64_display_full_frame(bt, current, previous);
 |  | ||||||
| +	}
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| + * Unroll a kernel stack.
 |  | ||||||
| + */
 |  | ||||||
| +static void
 |  | ||||||
| +riscv64_back_trace_cmd(struct bt_info *bt)
 |  | ||||||
| +{
 |  | ||||||
| +	struct riscv64_unwind_frame current, previous;
 |  | ||||||
| +	struct stackframe curr_frame;
 |  | ||||||
| +	int level = 0;
 |  | ||||||
| +
 |  | ||||||
| +	if (bt->flags & BT_REGS_NOT_FOUND)
 |  | ||||||
| +		return;
 |  | ||||||
| +
 |  | ||||||
| +	current.pc = bt->instptr;
 |  | ||||||
| +	current.sp = bt->stkptr;
 |  | ||||||
| +	current.fp = bt->frameptr;
 |  | ||||||
| +
 |  | ||||||
| +	if (!INSTACK(current.sp, bt))
 |  | ||||||
| +		return;
 |  | ||||||
| +
 |  | ||||||
| +	for (;;) {
 |  | ||||||
| +		struct syment *symbol = NULL;
 |  | ||||||
| +		struct stackframe *frameptr;
 |  | ||||||
| +		ulong low, high;
 |  | ||||||
| +		ulong offset;
 |  | ||||||
| +
 |  | ||||||
| +		if (CRASHDEBUG(8))
 |  | ||||||
| +			fprintf(fp, "level %d pc %#lx sp %lx fp 0x%lx\n",
 |  | ||||||
| +				level, current.pc, current.sp, current.fp);
 |  | ||||||
| +
 |  | ||||||
| +		/* Validate frame pointer */
 |  | ||||||
| +		low = current.sp + sizeof(struct stackframe);
 |  | ||||||
| +		high = bt->stacktop;
 |  | ||||||
| +		if (current.fp < low || current.fp > high || current.fp & 0x7) {
 |  | ||||||
| +			if (CRASHDEBUG(8))
 |  | ||||||
| +				fprintf(fp, "fp 0x%lx sp 0x%lx low 0x%lx high 0x%lx\n",
 |  | ||||||
| +					current.fp, current.sp, low, high);
 |  | ||||||
| +			return;
 |  | ||||||
| +		}
 |  | ||||||
| +
 |  | ||||||
| +		symbol = value_search(current.pc, &offset);
 |  | ||||||
| +		if (!symbol)
 |  | ||||||
| +			return;
 |  | ||||||
| +
 |  | ||||||
| +		frameptr = (struct stackframe *)current.fp - 1;
 |  | ||||||
| +		if (!readmem((ulong)frameptr, KVADDR, &curr_frame,
 |  | ||||||
| +		    sizeof(curr_frame), "get stack frame", RETURN_ON_ERROR))
 |  | ||||||
| +			return;
 |  | ||||||
| +
 |  | ||||||
| +		previous.pc = curr_frame.ra;
 |  | ||||||
| +		previous.fp = curr_frame.fp;
 |  | ||||||
| +		previous.sp = current.fp;
 |  | ||||||
| +
 |  | ||||||
| +		riscv64_dump_backtrace_entry(bt, symbol, ¤t, &previous, level++);
 |  | ||||||
| +
 |  | ||||||
| +		current.pc = previous.pc;
 |  | ||||||
| +		current.fp = previous.fp;
 |  | ||||||
| +		current.sp = previous.sp;
 |  | ||||||
| +
 |  | ||||||
| +		if (CRASHDEBUG(8))
 |  | ||||||
| +			fprintf(fp, "next %d pc %#lx sp %#lx fp %lx\n",
 |  | ||||||
| +				level, current.pc, current.sp, current.fp);
 |  | ||||||
| +	}
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| + * Get a stack frame combination of pc and ra from the most relevant spot.
 |  | ||||||
| + */
 |  | ||||||
| +static void
 |  | ||||||
| +riscv64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
 |  | ||||||
| +{
 |  | ||||||
| +	ulong ksp = 0, nip = 0;
 |  | ||||||
| +	int ret = 0;
 |  | ||||||
| +
 |  | ||||||
| +	if (DUMPFILE() && is_task_active(bt->task))
 |  | ||||||
| +		ret = riscv64_get_dumpfile_stack_frame(bt, &nip, &ksp);
 |  | ||||||
| +	else
 |  | ||||||
| +		ret = riscv64_get_frame(bt, &nip, &ksp);
 |  | ||||||
| +
 |  | ||||||
| +	if (!ret)
 |  | ||||||
| +		error(WARNING, "cannot determine starting stack frame for task %lx\n",
 |  | ||||||
| +			bt->task);
 |  | ||||||
| +
 |  | ||||||
| +	if (pcp)
 |  | ||||||
| +		*pcp = nip;
 |  | ||||||
| +	if (spp)
 |  | ||||||
| +		*spp = ksp;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| + * Get the starting point for the active cpu in a diskdump.
 |  | ||||||
| + */
 |  | ||||||
| +static int
 |  | ||||||
| +riscv64_get_dumpfile_stack_frame(struct bt_info *bt, ulong *nip, ulong *ksp)
 |  | ||||||
| +{
 |  | ||||||
| +	const struct machine_specific *ms = machdep->machspec;
 |  | ||||||
| +	struct riscv64_register *regs;
 |  | ||||||
| +	ulong epc, sp;
 |  | ||||||
| +
 |  | ||||||
| +	if (!ms->crash_task_regs) {
 |  | ||||||
| +		bt->flags |= BT_REGS_NOT_FOUND;
 |  | ||||||
| +		return FALSE;
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	/*
 |  | ||||||
| +	 * We got registers for panic task from crash_notes. Just return them.
 |  | ||||||
| +	 */
 |  | ||||||
| +	regs = &ms->crash_task_regs[bt->tc->processor];
 |  | ||||||
| +	epc = regs->regs[RISCV64_REGS_EPC];
 |  | ||||||
| +	sp = regs->regs[RISCV64_REGS_SP];
 |  | ||||||
| +
 |  | ||||||
| +	/*
 |  | ||||||
| +	 * Set stack frame ptr.
 |  | ||||||
| +	 */
 |  | ||||||
| +	bt->frameptr = regs->regs[RISCV64_REGS_FP];
 |  | ||||||
| +
 |  | ||||||
| +	if (nip)
 |  | ||||||
| +		*nip = epc;
 |  | ||||||
| +	if (ksp)
 |  | ||||||
| +		*ksp = sp;
 |  | ||||||
| +
 |  | ||||||
| +	bt->machdep = regs;
 |  | ||||||
| +
 |  | ||||||
| +	return TRUE;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| + * Do the work for riscv64_get_stack_frame() for non-active tasks.
 |  | ||||||
| + * Get SP and PC values for idle tasks.
 |  | ||||||
| + */
 |  | ||||||
| +static int
 |  | ||||||
| +riscv64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
 |  | ||||||
| +{
 |  | ||||||
| +	if (!bt->tc || !(tt->flags & THREAD_INFO))
 |  | ||||||
| +		return FALSE;
 |  | ||||||
| +
 |  | ||||||
| +	if (!readmem(bt->task + OFFSET(task_struct_thread_context_pc),
 |  | ||||||
| +		     KVADDR, pcp, sizeof(*pcp),
 |  | ||||||
| +		     "thread_struct.ra",
 |  | ||||||
| +		     RETURN_ON_ERROR))
 |  | ||||||
| +		return FALSE;
 |  | ||||||
| +
 |  | ||||||
| +	if (!readmem(bt->task + OFFSET(task_struct_thread_context_sp),
 |  | ||||||
| +		     KVADDR, spp, sizeof(*spp),
 |  | ||||||
| +		     "thread_struct.sp",
 |  | ||||||
| +		     RETURN_ON_ERROR))
 |  | ||||||
| +		return FALSE;
 |  | ||||||
| +
 |  | ||||||
| +	if (!readmem(bt->task + OFFSET(task_struct_thread_context_fp),
 |  | ||||||
| +		     KVADDR, &bt->frameptr, sizeof(bt->frameptr),
 |  | ||||||
| +		     "thread_struct.fp",
 |  | ||||||
| +		     RETURN_ON_ERROR))
 |  | ||||||
| +		return FALSE;
 |  | ||||||
| +
 |  | ||||||
| +	return TRUE;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
|  static int |  | ||||||
|  riscv64_vtop_4level_4k(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose) |  | ||||||
|  { |  | ||||||
| @@ -978,6 +1258,8 @@ riscv64_init(int when)
 |  | ||||||
|  		machdep->uvtop = riscv64_uvtop; |  | ||||||
|  		machdep->kvtop = riscv64_kvtop; |  | ||||||
|  		machdep->cmd_mach = riscv64_cmd_mach; |  | ||||||
| +		machdep->get_stack_frame = riscv64_get_stack_frame;
 |  | ||||||
| +		machdep->back_trace = riscv64_back_trace_cmd;
 |  | ||||||
|   |  | ||||||
|  		machdep->vmalloc_start = riscv64_vmalloc_start; |  | ||||||
|  		machdep->processor_speed = riscv64_processor_speed; |  | ||||||
| @@ -998,6 +1280,7 @@ riscv64_init(int when)
 |  | ||||||
|  	case POST_GDB: |  | ||||||
|  		machdep->section_size_bits = _SECTION_SIZE_BITS; |  | ||||||
|  		machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; |  | ||||||
| +		riscv64_stackframe_init();
 |  | ||||||
|  		riscv64_page_type_init(); |  | ||||||
|   |  | ||||||
|  		if (!machdep->hz) |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,80 +0,0 @@ | |||||||
| From 5cfcdb4ebcb159c1c47b7c1805cd9b274ca27ff5 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Date: Thu, 20 Oct 2022 09:50:11 +0800 |  | ||||||
| Subject: [PATCH 13/28] RISCV64: Add 'help -r' command support |  | ||||||
| 
 |  | ||||||
| Add support form printing out the registers from the dump file. |  | ||||||
| 
 |  | ||||||
| With the patch, we can get the regs, |  | ||||||
| crash> help -r |  | ||||||
| CPU 0: |  | ||||||
| epc : 00ffffffa5537400 ra : ffffffff80088620 sp : ff2000001039bb90 |  | ||||||
|  gp : ffffffff810dde38 tp : ff60000002269600 t0 : ffffffff8032be5c |  | ||||||
|  t1 : 0720072007200720 t2 : 666666666666663c s0 : ff2000001039bcf0 |  | ||||||
|  s1 : 0000000000000000 a0 : ff2000001039bb98 a1 : 0000000000000001 |  | ||||||
|  a2 : 0000000000000010 a3 : 0000000000000000 a4 : 0000000000000000 |  | ||||||
|  a5 : ff60000001c7d000 a6 : 000000000000003c a7 : ffffffff8035c998 |  | ||||||
|  s2 : ffffffff810df0a8 s3 : ffffffff810df718 s4 : ff2000001039bb98 |  | ||||||
|  s5 : 0000000000000000 s6 : 0000000000000007 s7 : ffffffff80c4a468 |  | ||||||
|  s8 : 00fffffffde45410 s9 : 0000000000000007 s10: 00aaaaaad1640700 |  | ||||||
|  s11: 0000000000000001 t3 : ff60000001218f00 t4 : ff60000001218f00 |  | ||||||
|  t5 : ff60000001218000 t6 : ff2000001039b988 |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  riscv64.c | 38 ++++++++++++++++++++++++++++++++++++++ |  | ||||||
|  1 file changed, 38 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/riscv64.c b/riscv64.c
 |  | ||||||
| index 4c9b35bb93f2..6d1d3b5f36d1 100644
 |  | ||||||
| --- a/riscv64.c
 |  | ||||||
| +++ b/riscv64.c
 |  | ||||||
| @@ -1320,6 +1320,44 @@ riscv64_init(int when)
 |  | ||||||
|  void |  | ||||||
|  riscv64_display_regs_from_elf_notes(int cpu, FILE *ofp) |  | ||||||
|  { |  | ||||||
| +	const struct machine_specific *ms = machdep->machspec;
 |  | ||||||
| +	struct riscv64_register *regs;
 |  | ||||||
| +
 |  | ||||||
| +	if (!ms->crash_task_regs) {
 |  | ||||||
| +		error(INFO, "registers not collected for cpu %d\n", cpu);
 |  | ||||||
| +		return;
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	regs = &ms->crash_task_regs[cpu];
 |  | ||||||
| +	if (!regs->regs[RISCV64_REGS_SP] && !regs->regs[RISCV64_REGS_EPC]) {
 |  | ||||||
| +		error(INFO, "registers not collected for cpu %d\n", cpu);
 |  | ||||||
| +		return;
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	/* Print riscv64 32 regs */
 |  | ||||||
| +	fprintf(ofp,
 |  | ||||||
| +		"epc : " REG_FMT " ra : " REG_FMT " sp : " REG_FMT "\n"
 |  | ||||||
| +		" gp : " REG_FMT " tp : " REG_FMT " t0 : " REG_FMT "\n"
 |  | ||||||
| +		" t1 : " REG_FMT " t2 : " REG_FMT " s0 : " REG_FMT "\n"
 |  | ||||||
| +		" s1 : " REG_FMT " a0 : " REG_FMT " a1 : " REG_FMT "\n"
 |  | ||||||
| +		" a2 : " REG_FMT " a3 : " REG_FMT " a4 : " REG_FMT "\n"
 |  | ||||||
| +		" a5 : " REG_FMT " a6 : " REG_FMT " a7 : " REG_FMT "\n"
 |  | ||||||
| +		" s2 : " REG_FMT " s3 : " REG_FMT " s4 : " REG_FMT "\n"
 |  | ||||||
| +		" s5 : " REG_FMT " s6 : " REG_FMT " s7 : " REG_FMT "\n"
 |  | ||||||
| +		" s8 : " REG_FMT " s9 : " REG_FMT " s10: " REG_FMT "\n"
 |  | ||||||
| +		" s11: " REG_FMT " t3 : " REG_FMT " t4 : " REG_FMT "\n"
 |  | ||||||
| +		" t5 : " REG_FMT " t6 : " REG_FMT "\n",
 |  | ||||||
| +		regs->regs[0],  regs->regs[1],  regs->regs[2],
 |  | ||||||
| +		regs->regs[3],  regs->regs[4],  regs->regs[5],
 |  | ||||||
| +		regs->regs[6],  regs->regs[7],  regs->regs[8],
 |  | ||||||
| +		regs->regs[9],  regs->regs[10], regs->regs[11],
 |  | ||||||
| +		regs->regs[12], regs->regs[13], regs->regs[14],
 |  | ||||||
| +		regs->regs[15], regs->regs[16], regs->regs[17],
 |  | ||||||
| +		regs->regs[18], regs->regs[19], regs->regs[20],
 |  | ||||||
| +		regs->regs[21], regs->regs[22], regs->regs[23],
 |  | ||||||
| +		regs->regs[24], regs->regs[25], regs->regs[26],
 |  | ||||||
| +		regs->regs[27], regs->regs[28], regs->regs[29],
 |  | ||||||
| +		regs->regs[30], regs->regs[31]);
 |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  #else /* !RISCV64 */ |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,141 +0,0 @@ | |||||||
| From 6c281cd355c904ddb82cbb49278b925d2ed13365 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Date: Thu, 20 Oct 2022 09:50:12 +0800 |  | ||||||
| Subject: [PATCH 14/28] RISCV64: Add 'help -m/M' command support |  | ||||||
| 
 |  | ||||||
| Add riscv64_dump_machdep_table() implementation, display machdep_table. |  | ||||||
| 
 |  | ||||||
| crash> help -m |  | ||||||
|               flags: 80 () |  | ||||||
|              kvbase: ff60000000000000 |  | ||||||
|   identity_map_base: ff60000000000000 |  | ||||||
|            pagesize: 4096 |  | ||||||
|           pageshift: 12 |  | ||||||
|            pagemask: fffffffffffff000 |  | ||||||
|          pageoffset: fff |  | ||||||
|         pgdir_shift: 48 |  | ||||||
|        ptrs_per_pgd: 512 |  | ||||||
|        ptrs_per_pte: 512 |  | ||||||
|           stacksize: 16384 |  | ||||||
|                  hz: 250 |  | ||||||
|             memsize: 1071644672 (0x3fe00000) |  | ||||||
|                bits: 64 |  | ||||||
|          back_trace: riscv64_back_trace_cmd() |  | ||||||
|     processor_speed: riscv64_processor_speed() |  | ||||||
|               uvtop: riscv64_uvtop() |  | ||||||
|               kvtop: riscv64_kvtop() |  | ||||||
|     get_stack_frame: riscv64_get_stack_frame() |  | ||||||
|       get_stackbase: generic_get_stackbase() |  | ||||||
|        get_stacktop: generic_get_stacktop() |  | ||||||
|       translate_pte: riscv64_translate_pte() |  | ||||||
|         memory_size: generic_memory_size() |  | ||||||
|       vmalloc_start: riscv64_vmalloc_start() |  | ||||||
|        is_task_addr: riscv64_is_task_addr() |  | ||||||
|       verify_symbol: riscv64_verify_symbol() |  | ||||||
|          dis_filter: generic_dis_filter() |  | ||||||
|            dump_irq: generic_dump_irq() |  | ||||||
|     show_interrupts: generic_show_interrupts() |  | ||||||
|    get_irq_affinity: generic_get_irq_affinity() |  | ||||||
|            cmd_mach: riscv64_cmd_mach() |  | ||||||
|        get_smp_cpus: riscv64_get_smp_cpus() |  | ||||||
|           is_kvaddr: riscv64_is_kvaddr() |  | ||||||
|           is_uvaddr: riscv64_is_uvaddr() |  | ||||||
|        verify_paddr: generic_verify_paddr() |  | ||||||
|     init_kernel_pgd: NULL |  | ||||||
|     value_to_symbol: generic_machdep_value_to_symbol() |  | ||||||
|   line_number_hooks: NULL |  | ||||||
|       last_pgd_read: ffffffff810e9000 |  | ||||||
|       last_p4d_read: 81410000 |  | ||||||
|       last_pud_read: 81411000 |  | ||||||
|       last_pmd_read: 81412000 |  | ||||||
|      last_ptbl_read: 81415000 |  | ||||||
|                 pgd: 560d586f3ab0 |  | ||||||
|                 p4d: 560d586f4ac0 |  | ||||||
|                 pud: 560d586f5ad0 |  | ||||||
|                 pmd: 560d586f6ae0 |  | ||||||
|                ptbl: 560d586f7af0 |  | ||||||
|   section_size_bits: 27 |  | ||||||
|    max_physmem_bits: 56 |  | ||||||
|   sections_per_root: 0 |  | ||||||
|            machspec: 560d57d204a0 |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  riscv64.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- |  | ||||||
|  1 file changed, 59 insertions(+), 1 deletion(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/riscv64.c b/riscv64.c
 |  | ||||||
| index 6d1d3b5f36d1..5e8c7d12227c 100644
 |  | ||||||
| --- a/riscv64.c
 |  | ||||||
| +++ b/riscv64.c
 |  | ||||||
| @@ -132,7 +132,65 @@ riscv64_verify_symbol(const char *name, ulong value, char type)
 |  | ||||||
|  void |  | ||||||
|  riscv64_dump_machdep_table(ulong arg) |  | ||||||
|  { |  | ||||||
| -	/* TODO: */
 |  | ||||||
| +	int others = 0;
 |  | ||||||
| +
 |  | ||||||
| +	fprintf(fp, "              flags: %lx (", machdep->flags);
 |  | ||||||
| +	if (machdep->flags & KSYMS_START)
 |  | ||||||
| +		fprintf(fp, "%sKSYMS_START", others++ ? "|" : "");
 |  | ||||||
| +	fprintf(fp, ")\n");
 |  | ||||||
| +
 |  | ||||||
| +	fprintf(fp, "             kvbase: %lx\n", machdep->kvbase);
 |  | ||||||
| +	fprintf(fp, "  identity_map_base: %lx\n", machdep->identity_map_base);
 |  | ||||||
| +	fprintf(fp, "           pagesize: %d\n", machdep->pagesize);
 |  | ||||||
| +	fprintf(fp, "          pageshift: %d\n", machdep->pageshift);
 |  | ||||||
| +	fprintf(fp, "           pagemask: %llx\n", machdep->pagemask);
 |  | ||||||
| +	fprintf(fp, "         pageoffset: %lx\n", machdep->pageoffset);
 |  | ||||||
| +	fprintf(fp, "        pgdir_shift: %ld\n", machdep->machspec->va_bits - 9);
 |  | ||||||
| +	fprintf(fp, "       ptrs_per_pgd: %u\n", PTRS_PER_PGD);
 |  | ||||||
| +	fprintf(fp, "       ptrs_per_pte: %d\n", PTRS_PER_PTE);
 |  | ||||||
| +	fprintf(fp, "          stacksize: %ld\n", machdep->stacksize);
 |  | ||||||
| +	fprintf(fp, "                 hz: %d\n", machdep->hz);
 |  | ||||||
| +	fprintf(fp, "            memsize: %ld (0x%lx)\n",
 |  | ||||||
| +		machdep->memsize, machdep->memsize);
 |  | ||||||
| +	fprintf(fp, "               bits: %d\n", machdep->bits);
 |  | ||||||
| +	fprintf(fp, "         back_trace: riscv64_back_trace_cmd()\n");
 |  | ||||||
| +	fprintf(fp, "    processor_speed: riscv64_processor_speed()\n");
 |  | ||||||
| +	fprintf(fp, "              uvtop: riscv64_uvtop()\n");
 |  | ||||||
| +	fprintf(fp, "              kvtop: riscv64_kvtop()\n");
 |  | ||||||
| +	fprintf(fp, "    get_stack_frame: riscv64_get_stack_frame()\n");
 |  | ||||||
| +	fprintf(fp, "      get_stackbase: generic_get_stackbase()\n");
 |  | ||||||
| +	fprintf(fp, "       get_stacktop: generic_get_stacktop()\n");
 |  | ||||||
| +	fprintf(fp, "      translate_pte: riscv64_translate_pte()\n");
 |  | ||||||
| +	fprintf(fp, "        memory_size: generic_memory_size()\n");
 |  | ||||||
| +	fprintf(fp, "      vmalloc_start: riscv64_vmalloc_start()\n");
 |  | ||||||
| +	fprintf(fp, "       is_task_addr: riscv64_is_task_addr()\n");
 |  | ||||||
| +	fprintf(fp, "      verify_symbol: riscv64_verify_symbol()\n");
 |  | ||||||
| +	fprintf(fp, "         dis_filter: generic_dis_filter()\n");
 |  | ||||||
| +	fprintf(fp, "           dump_irq: generic_dump_irq()\n");
 |  | ||||||
| +	fprintf(fp, "    show_interrupts: generic_show_interrupts()\n");
 |  | ||||||
| +	fprintf(fp, "   get_irq_affinity: generic_get_irq_affinity()\n");
 |  | ||||||
| +	fprintf(fp, "           cmd_mach: riscv64_cmd_mach()\n");
 |  | ||||||
| +	fprintf(fp, "       get_smp_cpus: riscv64_get_smp_cpus()\n");
 |  | ||||||
| +	fprintf(fp, "          is_kvaddr: riscv64_is_kvaddr()\n");
 |  | ||||||
| +	fprintf(fp, "          is_uvaddr: riscv64_is_uvaddr()\n");
 |  | ||||||
| +	fprintf(fp, "       verify_paddr: generic_verify_paddr()\n");
 |  | ||||||
| +	fprintf(fp, "    init_kernel_pgd: NULL\n");
 |  | ||||||
| +	fprintf(fp, "    value_to_symbol: generic_machdep_value_to_symbol()\n");
 |  | ||||||
| +	fprintf(fp, "  line_number_hooks: NULL\n");
 |  | ||||||
| +	fprintf(fp, "      last_pgd_read: %lx\n", machdep->last_pgd_read);
 |  | ||||||
| +	fprintf(fp, "      last_p4d_read: %lx\n", machdep->machspec->last_p4d_read);
 |  | ||||||
| +	fprintf(fp, "      last_pud_read: %lx\n", machdep->last_pud_read);
 |  | ||||||
| +	fprintf(fp, "      last_pmd_read: %lx\n", machdep->last_pmd_read);
 |  | ||||||
| +	fprintf(fp, "     last_ptbl_read: %lx\n", machdep->last_ptbl_read);
 |  | ||||||
| +	fprintf(fp, "                pgd: %lx\n", (ulong)machdep->pgd);
 |  | ||||||
| +	fprintf(fp, "                p4d: %lx\n", (ulong)machdep->machspec->p4d);
 |  | ||||||
| +	fprintf(fp, "                pud: %lx\n", (ulong)machdep->pud);
 |  | ||||||
| +	fprintf(fp, "                pmd: %lx\n", (ulong)machdep->pmd);
 |  | ||||||
| +	fprintf(fp, "               ptbl: %lx\n", (ulong)machdep->ptbl);
 |  | ||||||
| +	fprintf(fp, "  section_size_bits: %ld\n", machdep->section_size_bits);
 |  | ||||||
| +	fprintf(fp, "   max_physmem_bits: %ld\n", machdep->max_physmem_bits);
 |  | ||||||
| +	fprintf(fp, "  sections_per_root: %ld\n", machdep->sections_per_root);
 |  | ||||||
| +	fprintf(fp, "           machspec: %lx\n", (ulong)machdep->machspec);
 |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  static ulong |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,83 +0,0 @@ | |||||||
| From 3f4714967961c2ca8b70dccb938a5258b6572d2b Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Date: Thu, 20 Oct 2022 09:50:13 +0800 |  | ||||||
| Subject: [PATCH 15/28] RISCV64: Add 'mach' command support |  | ||||||
| 
 |  | ||||||
| With the patch we can get some basic machine state information, |  | ||||||
| crash> mach |  | ||||||
|                 MACHINE TYPE: riscv64 |  | ||||||
|                  MEMORY SIZE: 1 GB |  | ||||||
|                         CPUS: 1 |  | ||||||
|              PROCESSOR SPEED: (unknown) |  | ||||||
|                           HZ: 250 |  | ||||||
|                    PAGE SIZE: 4096 |  | ||||||
|            KERNEL STACK SIZE: 16384 |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  riscv64.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- |  | ||||||
|  1 file changed, 44 insertions(+), 1 deletion(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/riscv64.c b/riscv64.c
 |  | ||||||
| index 5e8c7d12227c..ff77e41b9407 100644
 |  | ||||||
| --- a/riscv64.c
 |  | ||||||
| +++ b/riscv64.c
 |  | ||||||
| @@ -116,10 +116,53 @@ static void riscv64_get_struct_page_size(struct machine_specific *ms)
 |  | ||||||
|  	} |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| +/*
 |  | ||||||
| + * "mach" command output.
 |  | ||||||
| + */
 |  | ||||||
| +static void
 |  | ||||||
| +riscv64_display_machine_stats(void)
 |  | ||||||
| +{
 |  | ||||||
| +	struct new_utsname *uts;
 |  | ||||||
| +	char buf[BUFSIZE];
 |  | ||||||
| +	ulong mhz;
 |  | ||||||
| +
 |  | ||||||
| +	uts = &kt->utsname;
 |  | ||||||
| +
 |  | ||||||
| +	fprintf(fp, "		MACHINE TYPE: %s\n", uts->machine);
 |  | ||||||
| +	fprintf(fp, "		 MEMORY SIZE: %s\n", get_memory_size(buf));
 |  | ||||||
| +	fprintf(fp, "			CPUS: %d\n", get_cpus_to_display());
 |  | ||||||
| +	fprintf(fp, "	     PROCESSOR SPEED: ");
 |  | ||||||
| +	if ((mhz = machdep->processor_speed()))
 |  | ||||||
| +		fprintf(fp, "%ld Mhz\n", mhz);
 |  | ||||||
| +	else
 |  | ||||||
| +		fprintf(fp, "(unknown)\n");
 |  | ||||||
| +	fprintf(fp, "			  HZ: %d\n", machdep->hz);
 |  | ||||||
| +	fprintf(fp, "		   PAGE SIZE: %d\n", PAGESIZE());
 |  | ||||||
| +	fprintf(fp, "	   KERNEL STACK SIZE: %ld\n", STACKSIZE());
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
|  static void |  | ||||||
|  riscv64_cmd_mach(void) |  | ||||||
|  { |  | ||||||
| -	/* TODO: */
 |  | ||||||
| +	int c;
 |  | ||||||
| +
 |  | ||||||
| +	while ((c = getopt(argcnt, args, "cmo")) != EOF) {
 |  | ||||||
| +		switch (c) {
 |  | ||||||
| +		case 'c':
 |  | ||||||
| +		case 'm':
 |  | ||||||
| +		case 'o':
 |  | ||||||
| +			option_not_supported(c);
 |  | ||||||
| +			break;
 |  | ||||||
| +		default:
 |  | ||||||
| +			argerrs++;
 |  | ||||||
| +			break;
 |  | ||||||
| +		}
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	if (argerrs)
 |  | ||||||
| +		cmd_usage(pc->curcmd, SYNOPSIS);
 |  | ||||||
| +
 |  | ||||||
| +	riscv64_display_machine_stats();
 |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  static int |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,45 +0,0 @@ | |||||||
| From 0d5ad129252a18a46d1818a68ed22b35c5234289 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Date: Thu, 20 Oct 2022 09:50:14 +0800 |  | ||||||
| Subject: [PATCH 16/28] RISCV64: Add the implementation of symbol verify |  | ||||||
| 
 |  | ||||||
| Verify the symbol to accept or reject a symbol from the kernel namelist. |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Xianting Tian <xianting.tian@linux.alibaba.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  riscv64.c | 15 ++++++++++++++- |  | ||||||
|  1 file changed, 14 insertions(+), 1 deletion(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/riscv64.c b/riscv64.c
 |  | ||||||
| index ff77e41b9407..6b9a68840d4c 100644
 |  | ||||||
| --- a/riscv64.c
 |  | ||||||
| +++ b/riscv64.c
 |  | ||||||
| @@ -165,10 +165,23 @@ riscv64_cmd_mach(void)
 |  | ||||||
|  	riscv64_display_machine_stats(); |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| +/*
 |  | ||||||
| + * Accept or reject a symbol from the kernel namelist.
 |  | ||||||
| + */
 |  | ||||||
|  static int |  | ||||||
|  riscv64_verify_symbol(const char *name, ulong value, char type) |  | ||||||
|  { |  | ||||||
| -	/* TODO: */
 |  | ||||||
| +	if (CRASHDEBUG(8) && name && strlen(name))
 |  | ||||||
| +		fprintf(fp, "%08lx %s\n", value, name);
 |  | ||||||
| +
 |  | ||||||
| +	if (!(machdep->flags & KSYMS_START)) {
 |  | ||||||
| +		if (STREQ(name, "_text") || STREQ(name, "_stext"))
 |  | ||||||
| +			machdep->flags |= KSYMS_START;
 |  | ||||||
| +
 |  | ||||||
| +		return (name && strlen(name) && !STRNEQ(name, "__func__.") &&
 |  | ||||||
| +			!STRNEQ(name, "__crc_"));
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
|  	return TRUE; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,149 +0,0 @@ | |||||||
| From d83df2fb66cd77877d365fda32cd45c531796599 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Date: Fri, 16 Dec 2022 14:03:46 +0900 |  | ||||||
| Subject: [PATCH 17/28] SLUB: Fix for offset change of struct slab members on |  | ||||||
|  Linux 6.2-rc1 |  | ||||||
| 
 |  | ||||||
| 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.  Luckily, it could work |  | ||||||
| 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@nec.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.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 0cff47e30ae9..d3d837631632 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -2188,6 +2188,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 cb5b508dcc50..33e68d520a72 100644
 |  | ||||||
| --- a/symbols.c
 |  | ||||||
| +++ b/symbols.c
 |  | ||||||
| @@ -9710,6 +9710,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.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,49 +0,0 @@ | |||||||
| From 41d4b85ea50efc733df65ec8421a74be10e47987 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Fri, 23 Dec 2022 18:42:35 +0800 |  | ||||||
| Subject: [PATCH 18/28] Fix for "kmem -i" to display correct SLAB statistics on |  | ||||||
|  Linux 5.9 and later |  | ||||||
| 
 |  | ||||||
| Kernel commit d42f3245c7e2 ("mm: memcg: convert vmstat slab counters to |  | ||||||
| bytes"), which is contained in Linux v5.9-rc1 and later kernels, renamed |  | ||||||
| NR_SLAB_{RECLAIMABLE,UNRECLAIMABLE} to NR_SLAB_{RECLAIMABLE,UNRECLAIMABLE}_B. |  | ||||||
| 
 |  | ||||||
| Without the patch, "kmem -i" command will display incorrect SLAB |  | ||||||
| statistics: |  | ||||||
| 
 |  | ||||||
|   crash> kmem -i | grep -e PAGES -e SLAB |  | ||||||
|                    PAGES        TOTAL      PERCENTAGE |  | ||||||
|            SLAB    89458     349.4 MB    0% of TOTAL MEM |  | ||||||
|                    ^^^^^     ^^^^^ |  | ||||||
| 
 |  | ||||||
| With the patch, the actual result is: |  | ||||||
|   crash> kmem -i | grep -e PAGES -e SLAB |  | ||||||
|                    PAGES        TOTAL      PERCENTAGE |  | ||||||
|            SLAB   261953    1023.3 MB    0% of TOTAL MEM |  | ||||||
| 
 |  | ||||||
| Reported-by: Buland Kumar Singh <bsingh@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| ---
 |  | ||||||
|  memory.c | 5 +++++ |  | ||||||
|  1 file changed, 5 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/memory.c b/memory.c
 |  | ||||||
| index d05737cc1429..625a94b7d7d4 100644
 |  | ||||||
| --- a/memory.c
 |  | ||||||
| +++ b/memory.c
 |  | ||||||
| @@ -8388,6 +8388,11 @@ dump_kmeminfo(void)
 |  | ||||||
|  			get_slabs = nr_slab; |  | ||||||
|  			if (dump_vm_stat("NR_SLAB_UNRECLAIMABLE", &nr_slab, 0)) |  | ||||||
|  				get_slabs += nr_slab; |  | ||||||
| +		} else if (dump_vm_stat("NR_SLAB_RECLAIMABLE_B", &nr_slab, 0)) {
 |  | ||||||
| +			/* 5.9 and later */
 |  | ||||||
| +			get_slabs = nr_slab;
 |  | ||||||
| +			if (dump_vm_stat("NR_SLAB_UNRECLAIMABLE_B", &nr_slab, 0))
 |  | ||||||
| +				get_slabs += nr_slab;
 |  | ||||||
|  		} |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,49 +0,0 @@ | |||||||
| From 4cf7c714e3cc97e6d41a9b1fdd48f5199f632a4d Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Date: Tue, 27 Dec 2022 09:53:46 +0900 |  | ||||||
| Subject: [PATCH 19/28] Fix build failure due to no EM_RISCV with glibc-2.23 |  | ||||||
|  and earlier |  | ||||||
| 
 |  | ||||||
| With glibc-2.23 and earlier (e.g. RHEL7), crash build fails with errors |  | ||||||
| like this due to EM_RISCV undeclared: |  | ||||||
| 
 |  | ||||||
|   $ make -j 24 warn |  | ||||||
|   TARGET: X86_64 |  | ||||||
|   CRASH: 8.0.2++ |  | ||||||
|   GDB: 10.2 |  | ||||||
|   ... |  | ||||||
|   symbols.c: In function 'is_kernel': |  | ||||||
|   symbols.c:3746:8: error: 'EM_RISCV' undeclared (first use in this function) |  | ||||||
|      case EM_RISCV: |  | ||||||
|           ^ |  | ||||||
|   ... |  | ||||||
| 
 |  | ||||||
| Define EM_RISCV as 243 [1][2] if not defined. |  | ||||||
| 
 |  | ||||||
| [1] https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=94e73c95d9b5 |  | ||||||
| [2] http://www.sco.com/developers/gabi/latest/ch4.eheader.html |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  defs.h | 4 ++++ |  | ||||||
|  1 file changed, 4 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index d3d837631632..08ac4dc96a92 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -3493,6 +3493,10 @@ struct arm64_stackframe {
 |  | ||||||
|  #define _MAX_PHYSMEM_BITS       48 |  | ||||||
|  #endif  /* MIPS64 */ |  | ||||||
|   |  | ||||||
| +#ifndef EM_RISCV
 |  | ||||||
| +#define EM_RISCV		243
 |  | ||||||
| +#endif
 |  | ||||||
| +
 |  | ||||||
|  #ifdef RISCV64 |  | ||||||
|  #define _64BIT_ |  | ||||||
|  #define MACHINE_TYPE		"RISCV64" |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,74 +0,0 @@ | |||||||
| From a053a1442dff4eecd17aee089502feac922a7af7 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Mon, 26 Dec 2022 21:03:17 +0800 |  | ||||||
| Subject: [PATCH 20/28] gdb: Fix an assertion failure in the gdb's copy_type() |  | ||||||
| 
 |  | ||||||
| This is a backported patch from gdb. Without the patch, the following |  | ||||||
| crash command may abort due to an assertion failure in the gdb's |  | ||||||
| copy_type(): |  | ||||||
| 
 |  | ||||||
|   crash> px __per_cpu_start:0 |  | ||||||
|   gdbtypes.c:5505: internal-error: type* copy_type(const type*): Assertion `TYPE_OBJFILE_OWNED (type)' failed. |  | ||||||
|   A problem internal to GDB has been detected, |  | ||||||
|   further debugging may prove unreliable. |  | ||||||
|   Quit this debugging session? (y or n) |  | ||||||
| 
 |  | ||||||
| The gdb commit 8e2da1651879 ("Fix assertion failure in copy_type") |  | ||||||
| solved the current issue. |  | ||||||
| 
 |  | ||||||
| Reported-by: Buland Kumar Singh <bsingh@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  gdb-10.2.patch | 39 +++++++++++++++++++++++++++++++++++++++ |  | ||||||
|  1 file changed, 39 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/gdb-10.2.patch b/gdb-10.2.patch
 |  | ||||||
| index 7055f6e0fb0b..aa34743501ad 100644
 |  | ||||||
| --- a/gdb-10.2.patch
 |  | ||||||
| +++ b/gdb-10.2.patch
 |  | ||||||
| @@ -2039,3 +2039,42 @@ exit 0
 |  | ||||||
|                   } |  | ||||||
|                   nextfield++; |  | ||||||
|           } |  | ||||||
| +--- gdb-10.2/gdb/gdbtypes.c.orig
 |  | ||||||
| ++++ gdb-10.2/gdb/gdbtypes.c
 |  | ||||||
| +@@ -5492,27 +5492,25 @@ copy_type_recursive (struct objfile *objfile,
 |  | ||||||
| + }
 |  | ||||||
| + 
 |  | ||||||
| + /* Make a copy of the given TYPE, except that the pointer & reference
 |  | ||||||
| +-   types are not preserved.
 |  | ||||||
| +-   
 |  | ||||||
| +-   This function assumes that the given type has an associated objfile.
 |  | ||||||
| +-   This objfile is used to allocate the new type.  */
 |  | ||||||
| ++   types are not preserved. */
 |  | ||||||
| + 
 |  | ||||||
| + struct type *
 |  | ||||||
| + copy_type (const struct type *type)
 |  | ||||||
| + {
 |  | ||||||
| +-  struct type *new_type;
 |  | ||||||
| +-
 |  | ||||||
| +-  gdb_assert (TYPE_OBJFILE_OWNED (type));
 |  | ||||||
| ++  struct type *new_type = alloc_type_copy (type);
 |  | ||||||
| + 
 |  | ||||||
| +-  new_type = alloc_type_copy (type);
 |  | ||||||
| +   TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type);
 |  | ||||||
| +   TYPE_LENGTH (new_type) = TYPE_LENGTH (type);
 |  | ||||||
| +   memcpy (TYPE_MAIN_TYPE (new_type), TYPE_MAIN_TYPE (type),
 |  | ||||||
| + 	  sizeof (struct main_type));
 |  | ||||||
| +   if (type->main_type->dyn_prop_list != NULL)
 |  | ||||||
| +-    new_type->main_type->dyn_prop_list
 |  | ||||||
| +-      = copy_dynamic_prop_list (&TYPE_OBJFILE (type) -> objfile_obstack,
 |  | ||||||
| +-				type->main_type->dyn_prop_list);
 |  | ||||||
| ++    {
 |  | ||||||
| ++      struct obstack *storage = (TYPE_OBJFILE_OWNED (type)
 |  | ||||||
| ++                                ? &TYPE_OBJFILE (type)->objfile_obstack
 |  | ||||||
| ++                                : gdbarch_obstack (TYPE_OWNER (type).gdbarch));
 |  | ||||||
| ++      new_type->main_type->dyn_prop_list
 |  | ||||||
| ++       = copy_dynamic_prop_list (storage, type->main_type->dyn_prop_list);
 |  | ||||||
| ++    }
 |  | ||||||
| + 
 |  | ||||||
| +   return new_type;
 |  | ||||||
| + }
 |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,46 +0,0 @@ | |||||||
| From 120d6e89fc14eb7f1c9a3106305c7066730f36b8 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Date: Thu, 5 Jan 2023 17:18:51 +0900 |  | ||||||
| Subject: [PATCH 21/28] SLAB: Fix for "kmem -s|-S" options on Linux 6.1 and |  | ||||||
|  later |  | ||||||
| 
 |  | ||||||
| Kernel commit e36ce448a08d ("mm/slab: use kmalloc_node() for off slab |  | ||||||
| freelist_idx_t array allocation"), which is contained in Linux 6.1 and |  | ||||||
| later kernels, removed kmem_cache.freelist_cache member on kernels |  | ||||||
| configured with CONFIG_SLAB=y. |  | ||||||
| 
 |  | ||||||
| Without the patch, crash does not set SLAB_OVERLOAD_PAGE and |  | ||||||
| "kmem -s|-S" options fail with the following error: |  | ||||||
| 
 |  | ||||||
|   kmem: invalid structure member offset: slab_list |  | ||||||
|         FILE: memory.c  LINE: 12156  FUNCTION: verify_slab_v2() |  | ||||||
| 
 |  | ||||||
| Use kmem_cache.freelist_size instead, which was introduced together |  | ||||||
| with kmem_cache.freelist_cache by kernel commit 8456a648cf44. |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  memory.c | 5 ++++- |  | ||||||
|  1 file changed, 4 insertions(+), 1 deletion(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/memory.c b/memory.c
 |  | ||||||
| index 625a94b7d7d4..71ded688206f 100644
 |  | ||||||
| --- a/memory.c
 |  | ||||||
| +++ b/memory.c
 |  | ||||||
| @@ -535,8 +535,11 @@ vm_init(void)
 |  | ||||||
|  	/* |  | ||||||
|  	 * slab: overload struct slab over struct page  |  | ||||||
|           * https://lkml.org/lkml/2013/10/16/155 |  | ||||||
| +	 *
 |  | ||||||
| +	 * commit e36ce448a08d removed kmem_cache.freelist_cache in 6.1,
 |  | ||||||
| +	 * so use freelist_size instead.
 |  | ||||||
|  	 */ |  | ||||||
| -	if (MEMBER_EXISTS("kmem_cache", "freelist_cache")) {
 |  | ||||||
| +	if (MEMBER_EXISTS("kmem_cache", "freelist_size")) {
 |  | ||||||
|  		vt->flags |= SLAB_OVERLOAD_PAGE; |  | ||||||
|  		ANON_MEMBER_OFFSET_INIT(page_s_mem, "page", "s_mem"); |  | ||||||
|  		ANON_MEMBER_OFFSET_INIT(page_freelist, "page", "freelist"); |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,233 +0,0 @@ | |||||||
| From ac96e17d1de51016ee1a983e68c7e840ff55ab8d Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Date: Thu, 5 Jan 2023 17:36:42 +0900 |  | ||||||
| Subject: [PATCH 22/28] SLAB: Fix for "kmem -s|-S" options on Linux 6.2-rc1 and |  | ||||||
|  later |  | ||||||
| 
 |  | ||||||
| Kernel commit 130d4df57390 ("mm/sl[au]b: rearrange struct slab fields to |  | ||||||
| allow larger rcu_head"), which is contained in Linux 6.2-rc1 and later |  | ||||||
| kernels, changed the offset of slab.slab_list and now it's not equal to |  | ||||||
| the offset of page.lru. |  | ||||||
| 
 |  | ||||||
| Without the patch, "kmem -s|-S" options print errors and zeros for slab |  | ||||||
| counters like this for kernels configured with CONFIG_SLAB=y. |  | ||||||
| 
 |  | ||||||
|   crash> kmem -s |  | ||||||
|   CACHE             OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZE  NAME |  | ||||||
|   kmem: rpc_inode_cache: partial list: page/slab: fffff31ac4125190  bad active counter: 99476865 |  | ||||||
|   kmem: rpc_inode_cache: partial list: page/slab: fffff31ac4125190  bad s_mem pointer: 100000003 |  | ||||||
|   kmem: rpc_inode_cache: full list: page/slab: fffff31ac4125150  bad active counter: 99476225 |  | ||||||
|   kmem: rpc_inode_cache: full list: page/slab: fffff31ac4125150  bad active counter: 99476225 |  | ||||||
|   kmem: rpc_inode_cache: full list: page/slab: fffff31ac4125150  bad s_mem pointer: 100000005 |  | ||||||
|   ffff930202adfb40      704          0         0      0     4k rpc_inode_cache |  | ||||||
|   ... |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  memory.c | 45 +++++++++++++++++++++++++-------------------- |  | ||||||
|  1 file changed, 25 insertions(+), 20 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/memory.c b/memory.c
 |  | ||||||
| index 71ded688206f..156de2f7b5a3 100644
 |  | ||||||
| --- a/memory.c
 |  | ||||||
| +++ b/memory.c
 |  | ||||||
| @@ -78,6 +78,7 @@ struct meminfo {           /* general purpose memory information structure */
 |  | ||||||
|  	int *freelist; |  | ||||||
|  	int freelist_index_size; |  | ||||||
|  	ulong random; |  | ||||||
| +	ulong list_offset;
 |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
|  /* |  | ||||||
| @@ -553,6 +554,8 @@ vm_init(void)
 |  | ||||||
|  			MEMBER_OFFSET_INIT(page_freelist, "slab", "freelist"); |  | ||||||
|  		if (INVALID_MEMBER(page_active)) |  | ||||||
|  			MEMBER_OFFSET_INIT(page_active, "slab", "active"); |  | ||||||
| +
 |  | ||||||
| +		MEMBER_OFFSET_INIT(slab_slab_list, "slab", "slab_list");
 |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
|          if (!VALID_STRUCT(kmem_slab_s) && VALID_STRUCT(slab_s)) { |  | ||||||
| @@ -10767,6 +10770,8 @@ dump_kmem_cache_percpu_v2(struct meminfo *si)
 |  | ||||||
|  	if (vt->flags & SLAB_OVERLOAD_PAGE) { |  | ||||||
|  		si->freelist = si->kmem_bufctl; |  | ||||||
|  		si->freelist_index_size = slab_freelist_index_size(); |  | ||||||
| +		si->list_offset = VALID_MEMBER(slab_slab_list) ?
 |  | ||||||
| +					OFFSET(slab_slab_list) : OFFSET(page_lru);
 |  | ||||||
|  	} |  | ||||||
|  	for (i = 0; i < vt->kmem_max_cpus; i++)  |  | ||||||
|  		si->cpudata[i] = (ulong *) |  | ||||||
| @@ -11983,7 +11988,7 @@ do_slab_chain_slab_overload_page(long cmd, struct meminfo *si)
 |  | ||||||
|  					} |  | ||||||
|  					last = si->slab; |  | ||||||
|  		 |  | ||||||
| -					readmem(si->slab - OFFSET(page_lru), KVADDR, page_buf, 
 |  | ||||||
| +					readmem(si->slab - si->list_offset, KVADDR, page_buf,
 |  | ||||||
|  						SIZE(page), "page (slab) buffer",  |  | ||||||
|  						FAULT_ON_ERROR); |  | ||||||
|  		 |  | ||||||
| @@ -11996,8 +12001,7 @@ do_slab_chain_slab_overload_page(long cmd, struct meminfo *si)
 |  | ||||||
|  	 |  | ||||||
|  					si->num_slabs++; |  | ||||||
|  		 |  | ||||||
| -					si->slab = ULONG(page_buf + 
 |  | ||||||
| -						OFFSET(page_lru));
 |  | ||||||
| +					si->slab = ULONG(page_buf + si->list_offset);
 |  | ||||||
|   |  | ||||||
|  					/* |  | ||||||
|  				 	 *  Check for slab transition. (Tony Dziedzic) |  | ||||||
| @@ -12024,11 +12028,11 @@ do_slab_chain_slab_overload_page(long cmd, struct meminfo *si)
 |  | ||||||
|  	case SLAB_WALKTHROUGH: |  | ||||||
|  		if (si->flags & SLAB_OVERLOAD_PAGE_PTR) { |  | ||||||
|  			specified_slab = si->spec_addr; |  | ||||||
| -			si->slab = si->spec_addr + OFFSET(page_lru);
 |  | ||||||
| +			si->slab = si->spec_addr + si->list_offset;
 |  | ||||||
|  		} else {  |  | ||||||
|  			specified_slab = si->slab;     |  | ||||||
|  			if (si->slab) |  | ||||||
| -				si->slab += OFFSET(page_lru);
 |  | ||||||
| +				si->slab += si->list_offset;
 |  | ||||||
|  		} |  | ||||||
|  		si->flags |= (SLAB_WALKTHROUGH|SLAB_FIRST_NODE); |  | ||||||
|  		si->flags &= ~SLAB_GET_COUNTS; |  | ||||||
| @@ -12082,7 +12086,7 @@ do_slab_chain_slab_overload_page(long cmd, struct meminfo *si)
 |  | ||||||
|  				if (si->slab == slab_chains[s]) |  | ||||||
|  					continue; |  | ||||||
|  				 |  | ||||||
| -				readmem(si->slab - OFFSET(page_lru), KVADDR, page_buf, 
 |  | ||||||
| +				readmem(si->slab - si->list_offset, KVADDR, page_buf,
 |  | ||||||
|  						SIZE(page), "page (slab) buffer",  |  | ||||||
|  						FAULT_ON_ERROR); |  | ||||||
|  		 |  | ||||||
| @@ -12242,7 +12246,7 @@ verify_slab_overload_page(struct meminfo *si, ulong last, int s)
 |  | ||||||
|   |  | ||||||
|  	errcnt = 0; |  | ||||||
|   |  | ||||||
| -        if (!readmem(si->slab - OFFSET(page_lru), KVADDR, page_buf,
 |  | ||||||
| +        if (!readmem(si->slab - si->list_offset, KVADDR, page_buf,
 |  | ||||||
|              SIZE(page), "page (slab) buffer", QUIET|RETURN_ON_ERROR)) { |  | ||||||
|                  error(INFO, "%s: %s list: bad slab pointer: %lx\n", |  | ||||||
|                          si->curname, list, si->slab); |  | ||||||
| @@ -12250,7 +12254,7 @@ verify_slab_overload_page(struct meminfo *si, ulong last, int s)
 |  | ||||||
|  		return FALSE; |  | ||||||
|          }                         |  | ||||||
|   |  | ||||||
| -        list_head = (struct kernel_list_head *)(page_buf + OFFSET(page_lru));
 |  | ||||||
| +        list_head = (struct kernel_list_head *)(page_buf + si->list_offset);
 |  | ||||||
|  	if (!IS_KVADDR((ulong)list_head->next) ||  |  | ||||||
|  	    !accessible((ulong)list_head->next)) { |  | ||||||
|                  error(INFO, "%s: %s list: page/slab: %lx  bad next pointer: %lx\n", |  | ||||||
| @@ -12569,7 +12573,7 @@ dump_slab_overload_page(struct meminfo *si)
 |  | ||||||
|  	int tmp; |  | ||||||
|  	ulong slab_overload_page, freelist; |  | ||||||
|   |  | ||||||
| -	slab_overload_page = si->slab - OFFSET(page_lru);
 |  | ||||||
| +	slab_overload_page = si->slab - si->list_offset;
 |  | ||||||
|   |  | ||||||
|          readmem(slab_overload_page + OFFSET(page_s_mem), |  | ||||||
|                  KVADDR, &si->s_mem, sizeof(ulong), |  | ||||||
| @@ -12796,12 +12800,12 @@ gather_slab_free_list_slab_overload_page(struct meminfo *si)
 |  | ||||||
|   |  | ||||||
|  	if (CRASHDEBUG(1)) |  | ||||||
|  		fprintf(fp, "slab page: %lx active: %ld si->c_num: %ld\n",  |  | ||||||
| -			si->slab - OFFSET(page_lru), si->s_inuse, si->c_num);
 |  | ||||||
| +			si->slab - si->list_offset, si->s_inuse, si->c_num);
 |  | ||||||
|   |  | ||||||
|  	if (si->s_inuse == si->c_num ) |  | ||||||
|  		return; |  | ||||||
|   |  | ||||||
| -	slab_overload_page = si->slab - OFFSET(page_lru);
 |  | ||||||
| +	slab_overload_page = si->slab - si->list_offset;
 |  | ||||||
|  	readmem(slab_overload_page + OFFSET(page_freelist), |  | ||||||
|  		KVADDR, &freelist, sizeof(void *), "page freelist", |  | ||||||
|  		FAULT_ON_ERROR); |  | ||||||
| @@ -13099,7 +13103,7 @@ dump_slab_objects_percpu(struct meminfo *si)
 |  | ||||||
|   |  | ||||||
|  	if ((si->flags & ADDRESS_SPECIFIED) &&  |  | ||||||
|  	    (vt->flags & SLAB_OVERLOAD_PAGE)) { |  | ||||||
| -		readmem(si->slab - OFFSET(page_lru) + OFFSET(page_freelist),
 |  | ||||||
| +		readmem(si->slab - si->list_offset + OFFSET(page_freelist),
 |  | ||||||
|  			KVADDR, &freelist, sizeof(ulong), "page.freelist",  |  | ||||||
|  			FAULT_ON_ERROR); |  | ||||||
|   |  | ||||||
| @@ -18713,6 +18717,9 @@ dump_kmem_cache_slub(struct meminfo *si)
 |  | ||||||
|   |  | ||||||
|  	si->cache_buf = GETBUF(SIZE(kmem_cache)); |  | ||||||
|   |  | ||||||
| +	si->list_offset = VALID_MEMBER(slab_slab_list) ?
 |  | ||||||
| +				OFFSET(slab_slab_list) : OFFSET(page_lru);
 |  | ||||||
| +
 |  | ||||||
|  	if (VALID_MEMBER(page_objects) && |  | ||||||
|  	    OFFSET(page_objects) == OFFSET(page_inuse)) |  | ||||||
|  		si->flags |= SLAB_BITFIELD; |  | ||||||
| @@ -19484,7 +19491,6 @@ 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; |  | ||||||
| @@ -19498,7 +19504,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 - list_off;
 |  | ||||||
| +		si->slab = last = next - si->list_offset;
 |  | ||||||
|  		if (first++ == 0) |  | ||||||
|  			fprintf(fp, "  %s", slab_hdr); |  | ||||||
|   |  | ||||||
| @@ -19521,7 +19527,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node)
 |  | ||||||
|   |  | ||||||
|  		if (!IS_KVADDR(next) ||  |  | ||||||
|  		    ((next != list_head) &&  |  | ||||||
| -		     !is_page_ptr(next - list_off, NULL))) {
 |  | ||||||
| +		     !is_page_ptr(next - si->list_offset, NULL))) {
 |  | ||||||
|  			error(INFO,  |  | ||||||
|  			    "%s: partial list slab: %lx invalid page.lru.next: %lx\n",  |  | ||||||
|  				si->curname, last, next); |  | ||||||
| @@ -19548,7 +19554,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 - list_off;
 |  | ||||||
| +		si->slab = next - si->list_offset;
 |  | ||||||
|  		if (first++ == 0) |  | ||||||
|  			fprintf(fp, "  %s", slab_hdr); |  | ||||||
|   |  | ||||||
| @@ -19765,7 +19771,6 @@ 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; |  | ||||||
| @@ -19777,12 +19782,12 @@ count_partial(ulong node, struct meminfo *si, ulong *free)
 |  | ||||||
|  	hq_open(); |  | ||||||
|   |  | ||||||
|  	while (next != list_head) { |  | ||||||
| -		if (!readmem(next - list_off + OFFSET(page_inuse),
 |  | ||||||
| +		if (!readmem(next - si->list_offset + OFFSET(page_inuse),
 |  | ||||||
|  		    KVADDR, &inuse, sizeof(ushort), "page.inuse", RETURN_ON_ERROR)) { |  | ||||||
|  			hq_close(); |  | ||||||
|  			return -1; |  | ||||||
|  		} |  | ||||||
| -		last = next - list_off;
 |  | ||||||
| +		last = next - si->list_offset;
 |  | ||||||
|   |  | ||||||
|  		if (inuse == -1) { |  | ||||||
|  			error(INFO,  |  | ||||||
| @@ -19808,7 +19813,7 @@ count_partial(ulong node, struct meminfo *si, ulong *free)
 |  | ||||||
|  		} |  | ||||||
|  		if (!IS_KVADDR(next) || |  | ||||||
|  		    ((next != list_head) &&  |  | ||||||
| -		     !is_page_ptr(next - list_off, NULL))) {
 |  | ||||||
| +		     !is_page_ptr(next - si->list_offset, NULL))) {
 |  | ||||||
|  			error(INFO, "%s: partial list slab: %lx invalid page.lru.next: %lx\n",  |  | ||||||
|  				si->curname, last, next); |  | ||||||
|  			break; |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,633 +0,0 @@ | |||||||
| From 872cad2d63b3a07f65323fe80a7abb29ea276b44 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Tao Liu <ltao@redhat.com> |  | ||||||
| Date: Tue, 10 Jan 2023 14:56:27 +0800 |  | ||||||
| Subject: [PATCH 23/28] Port the maple tree data structures and functions |  | ||||||
| 
 |  | ||||||
| There have been two ways to iterate vm_area_struct until Linux 6.0: |  | ||||||
|  1) by rbtree, aka vma.vm_rb; |  | ||||||
|  2) by linked list, aka vma.vm_{next,prev}. |  | ||||||
| However with the maple tree patches[1][2] in Linux 6.1, vm_rb and |  | ||||||
| vm_{next,prev} are removed from vm_area_struct. The vm_area_dump() |  | ||||||
| in crash mainly uses the linked list for vma iteration, which will |  | ||||||
| not work for this case. So the maple tree iteration needs to be |  | ||||||
| ported to crash. |  | ||||||
| 
 |  | ||||||
| For crash, currently it only iteratively reads the maple tree, |  | ||||||
| no more rcu safe or maple tree modification features needed. |  | ||||||
| So we only port a subset of kernel maple tree features. |  | ||||||
| In addition, we need to modify the ported kernel source code, |  | ||||||
| making it compatible with crash. |  | ||||||
| 
 |  | ||||||
| This patch deals with the two issues: |  | ||||||
|  1) Poring mt_dump() function and all its dependencies from |  | ||||||
|     kernel source to crash, to enable crash maple tree iteration, |  | ||||||
|  2) adapting the ported code with crash. |  | ||||||
| 
 |  | ||||||
| [1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=524e00b36e8c547f5582eef3fb645a8d9fc5e3df |  | ||||||
| [2]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=763ecb035029f500d7e6dc99acd1ad299b7726a1 |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Tao Liu <ltao@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  Makefile     |  10 +- |  | ||||||
|  defs.h       |  19 +++ |  | ||||||
|  maple_tree.c | 407 +++++++++++++++++++++++++++++++++++++++++++++++++++ |  | ||||||
|  maple_tree.h |  82 +++++++++++ |  | ||||||
|  4 files changed, 515 insertions(+), 3 deletions(-) |  | ||||||
|  create mode 100644 maple_tree.c |  | ||||||
|  create mode 100644 maple_tree.h |  | ||||||
| 
 |  | ||||||
| diff --git a/Makefile b/Makefile
 |  | ||||||
| index 1506dd426bc7..102597f735b2 100644
 |  | ||||||
| --- a/Makefile
 |  | ||||||
| +++ b/Makefile
 |  | ||||||
| @@ -59,6 +59,7 @@ IBM_HFILES=ibm_common.h
 |  | ||||||
|  SADUMP_HFILES=sadump.h |  | ||||||
|  UNWIND_HFILES=unwind.h unwind_i.h rse.h unwind_x86.h unwind_x86_64.h |  | ||||||
|  VMWARE_HFILES=vmware_vmss.h |  | ||||||
| +MAPLE_TREE_HFILES=maple_tree.h
 |  | ||||||
|   |  | ||||||
|  CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \ |  | ||||||
|  	kernel.c test.c gdb_interface.c configure.c net.c dev.c bpf.c \ |  | ||||||
| @@ -73,12 +74,12 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \
 |  | ||||||
|  	xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \ |  | ||||||
|  	xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c \ |  | ||||||
|  	ramdump.c vmware_vmss.c vmware_guestdump.c \ |  | ||||||
| -	xen_dom0.c kaslr_helper.c sbitmap.c
 |  | ||||||
| +	xen_dom0.c kaslr_helper.c sbitmap.c maple_tree.c
 |  | ||||||
|   |  | ||||||
|  SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \ |  | ||||||
|  	${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \ |  | ||||||
|  	${LKCD_DUMP_HFILES} ${LKCD_TRACE_HFILES} ${LKCD_OBSOLETE_HFILES}\ |  | ||||||
| -	${IBM_HFILES} ${SADUMP_HFILES} ${VMWARE_HFILES}
 |  | ||||||
| +	${IBM_HFILES} ${SADUMP_HFILES} ${VMWARE_HFILES} ${MAPLE_TREE_HFILES}
 |  | ||||||
|   |  | ||||||
|  OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \ |  | ||||||
|  	build_data.o kernel.o test.o gdb_interface.o net.o dev.o bpf.o \ |  | ||||||
| @@ -93,7 +94,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \
 |  | ||||||
|  	xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \ |  | ||||||
|  	xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o \ |  | ||||||
|  	ramdump.o vmware_vmss.o vmware_guestdump.o \ |  | ||||||
| -	xen_dom0.o kaslr_helper.o sbitmap.o
 |  | ||||||
| +	xen_dom0.o kaslr_helper.o sbitmap.o maple_tree.o
 |  | ||||||
|   |  | ||||||
|  MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README |  | ||||||
|   |  | ||||||
| @@ -539,6 +540,9 @@ kaslr_helper.o: ${GENERIC_HFILES} kaslr_helper.c
 |  | ||||||
|  bpf.o: ${GENERIC_HFILES} bpf.c |  | ||||||
|  	${CC} -c ${CRASH_CFLAGS} bpf.c ${WARNING_OPTIONS} ${WARNING_ERROR} |  | ||||||
|   |  | ||||||
| +maple_tree.o: ${GENERIC_HFILES} ${MAPLE_TREE_HFILES} maple_tree.c
 |  | ||||||
| +	${CC} -c ${CRASH_CFLAGS} maple_tree.c ${WARNING_OPTIONS} ${WARNING_ERROR}
 |  | ||||||
| +
 |  | ||||||
|  ${PROGRAM}: force |  | ||||||
|  	@$(MAKE) all |  | ||||||
|   |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index 08ac4dc96a92..46bfd4a67e64 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -2189,6 +2189,21 @@ struct offset_table {                    /* stash of commonly-used offsets */
 |  | ||||||
|  	long request_queue_hctx_table; |  | ||||||
|  	long percpu_counter_counters; |  | ||||||
|  	long slab_slab_list; |  | ||||||
| +	long mm_struct_mm_mt;
 |  | ||||||
| +	long maple_tree_ma_root;
 |  | ||||||
| +	long maple_tree_ma_flags;
 |  | ||||||
| +	long maple_node_parent;
 |  | ||||||
| +	long maple_node_ma64;
 |  | ||||||
| +	long maple_node_mr64;
 |  | ||||||
| +	long maple_node_slot;
 |  | ||||||
| +	long maple_arange_64_pivot;
 |  | ||||||
| +	long maple_arange_64_slot;
 |  | ||||||
| +	long maple_arange_64_gap;
 |  | ||||||
| +	long maple_arange_64_meta;
 |  | ||||||
| +	long maple_range_64_pivot;
 |  | ||||||
| +	long maple_range_64_slot;
 |  | ||||||
| +	long maple_metadata_end;
 |  | ||||||
| +	long maple_metadata_gap;
 |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
|  struct size_table {         /* stash of commonly-used sizes */ |  | ||||||
| @@ -2360,6 +2375,8 @@ struct size_table {         /* stash of commonly-used sizes */
 |  | ||||||
|  	long sbq_wait_state; |  | ||||||
|  	long blk_mq_tags; |  | ||||||
|  	long percpu_counter; |  | ||||||
| +	long maple_tree;
 |  | ||||||
| +	long maple_node;
 |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
|  struct array_table { |  | ||||||
| @@ -5742,6 +5759,8 @@ int file_dump(ulong, ulong, ulong, int, int);
 |  | ||||||
|  int same_file(char *, char *); |  | ||||||
|  int cleanup_memory_driver(void); |  | ||||||
|   |  | ||||||
| +void maple_init(void);
 |  | ||||||
| +int do_mptree(struct tree_data *);
 |  | ||||||
|   |  | ||||||
|  /* |  | ||||||
|   *  help.c  |  | ||||||
| diff --git a/maple_tree.c b/maple_tree.c
 |  | ||||||
| new file mode 100644 |  | ||||||
| index 000000000000..474faeda6252
 |  | ||||||
| --- /dev/null
 |  | ||||||
| +++ b/maple_tree.c
 |  | ||||||
| @@ -0,0 +1,407 @@
 |  | ||||||
| +// SPDX-License-Identifier: GPL-2.0+
 |  | ||||||
| +/*
 |  | ||||||
| + * Maple Tree implementation
 |  | ||||||
| + * Copyright (c) 2018-2022 Oracle Corporation
 |  | ||||||
| + * Authors: Liam R. Howlett <Liam.Howlett@oracle.com>
 |  | ||||||
| + * 	    Matthew Wilcox <willy@infradead.org>
 |  | ||||||
| + *
 |  | ||||||
| + * The following are copied and modified from lib/maple_tree.c
 |  | ||||||
| + */
 |  | ||||||
| +
 |  | ||||||
| +#include "maple_tree.h"
 |  | ||||||
| +#include "defs.h"
 |  | ||||||
| +
 |  | ||||||
| +unsigned char *mt_slots = NULL;
 |  | ||||||
| +unsigned char *mt_pivots = NULL;
 |  | ||||||
| +ulong mt_max[4] = {0};
 |  | ||||||
| +
 |  | ||||||
| +#define MAPLE_BUFSIZE			512
 |  | ||||||
| +
 |  | ||||||
| +static inline ulong mte_to_node(ulong maple_enode_entry)
 |  | ||||||
| +{
 |  | ||||||
| +	return maple_enode_entry & ~MAPLE_NODE_MASK;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline enum maple_type mte_node_type(ulong maple_enode_entry)
 |  | ||||||
| +{
 |  | ||||||
| +	return (maple_enode_entry >> MAPLE_NODE_TYPE_SHIFT) &
 |  | ||||||
| +		MAPLE_NODE_TYPE_MASK;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline ulong mt_slot(void **slots, unsigned char offset)
 |  | ||||||
| +{
 |  | ||||||
| +	return (ulong)slots[offset];
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline bool ma_is_leaf(const enum maple_type type)
 |  | ||||||
| +{
 |  | ||||||
| +	return type < maple_range_64;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +/*************** For cmd_tree ********************/
 |  | ||||||
| +
 |  | ||||||
| +struct maple_tree_ops {
 |  | ||||||
| +	void (*entry)(ulong node, ulong slot, const char *path,
 |  | ||||||
| +		      ulong index, void *private);
 |  | ||||||
| +	void *private;
 |  | ||||||
| +	bool is_td;
 |  | ||||||
| +};
 |  | ||||||
| +
 |  | ||||||
| +static const char spaces[] = "                                ";
 |  | ||||||
| +
 |  | ||||||
| +static void do_mt_range64(ulong, ulong, ulong, uint, char *, ulong *,
 |  | ||||||
| +			  struct maple_tree_ops *);
 |  | ||||||
| +static void do_mt_arange64(ulong, ulong, ulong, uint, char *, ulong *,
 |  | ||||||
| +			   struct maple_tree_ops *);
 |  | ||||||
| +static void do_mt_entry(ulong, ulong, ulong, uint, uint, char *, ulong *,
 |  | ||||||
| +			struct maple_tree_ops *);
 |  | ||||||
| +static void do_mt_node(ulong, ulong, ulong, uint, char *, ulong *,
 |  | ||||||
| +		       struct maple_tree_ops *);
 |  | ||||||
| +struct req_entry *fill_member_offsets(char *);
 |  | ||||||
| +void dump_struct_members_fast(struct req_entry *, int, ulong);
 |  | ||||||
| +void dump_struct_members_for_tree(struct tree_data *, int, ulong);
 |  | ||||||
| +
 |  | ||||||
| +static void mt_dump_range(ulong min, ulong max, uint depth)
 |  | ||||||
| +{
 |  | ||||||
| +	if (min == max)
 |  | ||||||
| +		fprintf(fp, "%.*s%lu: ", depth * 2, spaces, min);
 |  | ||||||
| +	else
 |  | ||||||
| +		fprintf(fp, "%.*s%lu-%lu: ", depth * 2, spaces, min, max);
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline bool mt_is_reserved(ulong entry)
 |  | ||||||
| +{
 |  | ||||||
| +       return (entry < MAPLE_RESERVED_RANGE) && xa_is_internal(entry);
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline bool mte_is_leaf(ulong maple_enode_entry)
 |  | ||||||
| +{
 |  | ||||||
| +       return ma_is_leaf(mte_node_type(maple_enode_entry));
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static uint mt_height(char *mt_buf)
 |  | ||||||
| +{
 |  | ||||||
| +	return (UINT(mt_buf + OFFSET(maple_tree_ma_flags)) &
 |  | ||||||
| +		MT_FLAGS_HEIGHT_MASK)
 |  | ||||||
| +	       >> MT_FLAGS_HEIGHT_OFFSET;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void dump_mt_range64(char *mr64_buf)
 |  | ||||||
| +{
 |  | ||||||
| +	int i;
 |  | ||||||
| +
 |  | ||||||
| +	fprintf(fp, " contents: ");
 |  | ||||||
| +	for (i = 0; i < mt_slots[maple_range_64] - 1; i++)
 |  | ||||||
| +		fprintf(fp, "%p %lu ",
 |  | ||||||
| +			VOID_PTR(mr64_buf + OFFSET(maple_range_64_slot)
 |  | ||||||
| +				 + sizeof(void *) * i),
 |  | ||||||
| +			ULONG(mr64_buf + OFFSET(maple_range_64_pivot)
 |  | ||||||
| +			      + sizeof(ulong) * i));
 |  | ||||||
| +	fprintf(fp, "%p\n", VOID_PTR(mr64_buf + OFFSET(maple_range_64_slot)
 |  | ||||||
| +				     + sizeof(void *) * i));
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void dump_mt_arange64(char *ma64_buf)
 |  | ||||||
| +{
 |  | ||||||
| +	int i;
 |  | ||||||
| +
 |  | ||||||
| +	fprintf(fp, " contents: ");
 |  | ||||||
| +	for (i = 0; i < mt_slots[maple_arange_64]; i++)
 |  | ||||||
| +		fprintf(fp, "%lu ", ULONG(ma64_buf + OFFSET(maple_arange_64_gap)
 |  | ||||||
| +					  + sizeof(ulong) * i));
 |  | ||||||
| +
 |  | ||||||
| +	fprintf(fp, "| %02X %02X| ",
 |  | ||||||
| +		UCHAR(ma64_buf + OFFSET(maple_arange_64_meta) +
 |  | ||||||
| +		      OFFSET(maple_metadata_end)),
 |  | ||||||
| +		UCHAR(ma64_buf + OFFSET(maple_arange_64_meta) +
 |  | ||||||
| +		      OFFSET(maple_metadata_gap)));
 |  | ||||||
| +
 |  | ||||||
| +	for (i = 0; i < mt_slots[maple_arange_64] - 1; i++)
 |  | ||||||
| +		fprintf(fp, "%p %lu ",
 |  | ||||||
| +			VOID_PTR(ma64_buf + OFFSET(maple_arange_64_slot) +
 |  | ||||||
| +				 sizeof(void *) * i),
 |  | ||||||
| +			ULONG(ma64_buf + OFFSET(maple_arange_64_pivot) +
 |  | ||||||
| +			      sizeof(ulong) * i));
 |  | ||||||
| +	fprintf(fp, "%p\n", VOID_PTR(ma64_buf + OFFSET(maple_arange_64_slot) +
 |  | ||||||
| +				     sizeof(void *) * i));
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void dump_mt_entry(ulong entry, ulong min, ulong max, uint depth)
 |  | ||||||
| +{
 |  | ||||||
| +	mt_dump_range(min, max, depth);
 |  | ||||||
| +
 |  | ||||||
| +	if (xa_is_value(entry))
 |  | ||||||
| +		fprintf(fp, "value %ld (0x%lx) [0x%lx]\n", xa_to_value(entry),
 |  | ||||||
| +			xa_to_value(entry), entry);
 |  | ||||||
| +	else if (xa_is_zero(entry))
 |  | ||||||
| +		fprintf(fp, "zero (%ld)\n", xa_to_internal(entry));
 |  | ||||||
| +	else if (mt_is_reserved(entry))
 |  | ||||||
| +		fprintf(fp, "UNKNOWN ENTRY (0x%lx)\n", entry);
 |  | ||||||
| +	else
 |  | ||||||
| +		fprintf(fp, "0x%lx\n", entry);
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void dump_mt_node(ulong maple_node, char *node_data, uint type,
 |  | ||||||
| +			 ulong min, ulong max, uint depth)
 |  | ||||||
| +{
 |  | ||||||
| +	mt_dump_range(min, max, depth);
 |  | ||||||
| +
 |  | ||||||
| +	fprintf(fp, "node 0x%lx depth %d type %d parent %p",
 |  | ||||||
| +		maple_node, depth, type,
 |  | ||||||
| +		maple_node ? VOID_PTR(node_data + OFFSET(maple_node_parent)) :
 |  | ||||||
| +			     NULL);
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void do_mt_range64(ulong entry, ulong min, ulong max,
 |  | ||||||
| +			  uint depth, char *path, ulong *global_index,
 |  | ||||||
| +			  struct maple_tree_ops *ops)
 |  | ||||||
| +{
 |  | ||||||
| +	ulong maple_node_m_node = mte_to_node(entry);
 |  | ||||||
| +	char node_buf[MAPLE_BUFSIZE];
 |  | ||||||
| +	bool leaf = mte_is_leaf(entry);
 |  | ||||||
| +	ulong first = min, last;
 |  | ||||||
| +	int i;
 |  | ||||||
| +	int len = strlen(path);
 |  | ||||||
| +	struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
 |  | ||||||
| +	char *mr64_buf;
 |  | ||||||
| +
 |  | ||||||
| +	if (SIZE(maple_node) > MAPLE_BUFSIZE)
 |  | ||||||
| +		error(FATAL, "MAPLE_BUFSIZE should be larger than maple_node struct");
 |  | ||||||
| +
 |  | ||||||
| +	readmem(maple_node_m_node, KVADDR, node_buf, SIZE(maple_node),
 |  | ||||||
| +		"mt_dump_range64 read maple_node", FAULT_ON_ERROR);
 |  | ||||||
| +
 |  | ||||||
| +	mr64_buf = node_buf + OFFSET(maple_node_mr64);
 |  | ||||||
| +
 |  | ||||||
| +	for (i = 0; i < mt_slots[maple_range_64]; i++) {
 |  | ||||||
| +		last = max;
 |  | ||||||
| +
 |  | ||||||
| +		if (i < (mt_slots[maple_range_64] - 1))
 |  | ||||||
| +			last = ULONG(mr64_buf + OFFSET(maple_range_64_pivot) +
 |  | ||||||
| +				     sizeof(ulong) * i);
 |  | ||||||
| +
 |  | ||||||
| +		else if (!VOID_PTR(mr64_buf + OFFSET(maple_range_64_slot) +
 |  | ||||||
| +			  sizeof(void *) * i) &&
 |  | ||||||
| +			 max != mt_max[mte_node_type(entry)])
 |  | ||||||
| +			break;
 |  | ||||||
| +		if (last == 0 && i > 0)
 |  | ||||||
| +			break;
 |  | ||||||
| +		if (leaf)
 |  | ||||||
| +			do_mt_entry(mt_slot((void **)(mr64_buf +
 |  | ||||||
| +						      OFFSET(maple_range_64_slot)), i),
 |  | ||||||
| +				    first, last, depth + 1, i, path, global_index, ops);
 |  | ||||||
| +		else if (VOID_PTR(mr64_buf + OFFSET(maple_range_64_slot) +
 |  | ||||||
| +				  sizeof(void *) * i)) {
 |  | ||||||
| +			sprintf(path + len, "/%d", i);
 |  | ||||||
| +			do_mt_node(mt_slot((void **)(mr64_buf +
 |  | ||||||
| +						     OFFSET(maple_range_64_slot)), i),
 |  | ||||||
| +				   first, last, depth + 1, path, global_index, ops);
 |  | ||||||
| +		}
 |  | ||||||
| +
 |  | ||||||
| +		if (last == max)
 |  | ||||||
| +			break;
 |  | ||||||
| +		if (last > max) {
 |  | ||||||
| +			fprintf(fp, "node %p last (%lu) > max (%lu) at pivot %d!\n",
 |  | ||||||
| +				mr64_buf, last, max, i);
 |  | ||||||
| +			break;
 |  | ||||||
| +		}
 |  | ||||||
| +		first = last + 1;
 |  | ||||||
| +	}
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void do_mt_arange64(ulong entry, ulong min, ulong max,
 |  | ||||||
| +			   uint depth, char *path, ulong *global_index,
 |  | ||||||
| +			   struct maple_tree_ops *ops)
 |  | ||||||
| +{
 |  | ||||||
| +	ulong maple_node_m_node = mte_to_node(entry);
 |  | ||||||
| +	char node_buf[MAPLE_BUFSIZE];
 |  | ||||||
| +	bool leaf = mte_is_leaf(entry);
 |  | ||||||
| +	ulong first = min, last;
 |  | ||||||
| +	int i;
 |  | ||||||
| +	int len = strlen(path);
 |  | ||||||
| +	struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
 |  | ||||||
| +	char *ma64_buf;
 |  | ||||||
| +
 |  | ||||||
| +	if (SIZE(maple_node) > MAPLE_BUFSIZE)
 |  | ||||||
| +		error(FATAL, "MAPLE_BUFSIZE should be larger than maple_node struct");
 |  | ||||||
| +
 |  | ||||||
| +	readmem(maple_node_m_node, KVADDR, node_buf, SIZE(maple_node),
 |  | ||||||
| +		"mt_dump_arange64 read maple_node", FAULT_ON_ERROR);
 |  | ||||||
| +
 |  | ||||||
| +	ma64_buf = node_buf + OFFSET(maple_node_ma64);
 |  | ||||||
| +
 |  | ||||||
| +	for (i = 0; i < mt_slots[maple_arange_64]; i++) {
 |  | ||||||
| +		last = max;
 |  | ||||||
| +
 |  | ||||||
| +		if (i < (mt_slots[maple_arange_64] - 1))
 |  | ||||||
| +			last = ULONG(ma64_buf + OFFSET(maple_arange_64_pivot) +
 |  | ||||||
| +				     sizeof(ulong) * i);
 |  | ||||||
| +		else if (!VOID_PTR(ma64_buf + OFFSET(maple_arange_64_slot) +
 |  | ||||||
| +				   sizeof(void *) * i))
 |  | ||||||
| +			break;
 |  | ||||||
| +		if (last == 0 && i > 0)
 |  | ||||||
| +			break;
 |  | ||||||
| +
 |  | ||||||
| +		if (leaf)
 |  | ||||||
| +			do_mt_entry(mt_slot((void **)(ma64_buf +
 |  | ||||||
| +						      OFFSET(maple_arange_64_slot)), i),
 |  | ||||||
| +				    first, last, depth + 1, i, path, global_index, ops);
 |  | ||||||
| +		else if (VOID_PTR(ma64_buf + OFFSET(maple_arange_64_slot) +
 |  | ||||||
| +				  sizeof(void *) * i)) {
 |  | ||||||
| +			sprintf(path + len, "/%d", i);
 |  | ||||||
| +			do_mt_node(mt_slot((void **)(ma64_buf +
 |  | ||||||
| +						     OFFSET(maple_arange_64_slot)), i),
 |  | ||||||
| +				   first, last, depth + 1, path, global_index, ops);
 |  | ||||||
| +		}
 |  | ||||||
| +
 |  | ||||||
| +		if (last == max)
 |  | ||||||
| +			break;
 |  | ||||||
| +		if (last > max) {
 |  | ||||||
| +			fprintf(fp, "node %p last (%lu) > max (%lu) at pivot %d!\n",
 |  | ||||||
| +				ma64_buf, last, max, i);
 |  | ||||||
| +			break;
 |  | ||||||
| +		}
 |  | ||||||
| +		first = last + 1;
 |  | ||||||
| +	}
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void do_mt_entry(ulong entry, ulong min, ulong max, uint depth,
 |  | ||||||
| +			uint index, char *path, ulong *global_index,
 |  | ||||||
| +			struct maple_tree_ops *ops)
 |  | ||||||
| +{
 |  | ||||||
| +	int print_radix = 0, i;
 |  | ||||||
| +	static struct req_entry **e = NULL;
 |  | ||||||
| +	struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
 |  | ||||||
| +
 |  | ||||||
| +	if (!td)
 |  | ||||||
| +		return;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void do_mt_node(ulong entry, ulong min, ulong max,
 |  | ||||||
| +		       uint depth, char *path, ulong *global_index,
 |  | ||||||
| +		       struct maple_tree_ops *ops)
 |  | ||||||
| +{
 |  | ||||||
| +	ulong maple_node = mte_to_node(entry);
 |  | ||||||
| +	uint type = mte_node_type(entry);
 |  | ||||||
| +	uint i;
 |  | ||||||
| +	char node_buf[MAPLE_BUFSIZE];
 |  | ||||||
| +	struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
 |  | ||||||
| +
 |  | ||||||
| +	if (SIZE(maple_node) > MAPLE_BUFSIZE)
 |  | ||||||
| +		error(FATAL, "MAPLE_BUFSIZE should be larger than maple_node struct");
 |  | ||||||
| +
 |  | ||||||
| +	readmem(maple_node, KVADDR, node_buf, SIZE(maple_node),
 |  | ||||||
| +		"mt_dump_node read maple_node", FAULT_ON_ERROR);
 |  | ||||||
| +
 |  | ||||||
| +	switch (type) {
 |  | ||||||
| +	case maple_dense:
 |  | ||||||
| +		for (i = 0; i < mt_slots[maple_dense]; i++) {
 |  | ||||||
| +			if (min + i > max)
 |  | ||||||
| +				fprintf(fp, "OUT OF RANGE: ");
 |  | ||||||
| +			do_mt_entry(mt_slot((void **)(node_buf + OFFSET(maple_node_slot)), i),
 |  | ||||||
| +				    min + i, min + i, depth, i, path, global_index, ops);
 |  | ||||||
| +		}
 |  | ||||||
| +		break;
 |  | ||||||
| +	case maple_leaf_64:
 |  | ||||||
| +	case maple_range_64:
 |  | ||||||
| +		do_mt_range64(entry, min, max, depth, path, global_index, ops);
 |  | ||||||
| +		break;
 |  | ||||||
| +	case maple_arange_64:
 |  | ||||||
| +		do_mt_arange64(entry, min, max, depth, path, global_index, ops);
 |  | ||||||
| +		break;
 |  | ||||||
| +	default:
 |  | ||||||
| +		fprintf(fp, " UNKNOWN TYPE\n");
 |  | ||||||
| +	}
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static int do_maple_tree_traverse(ulong ptr, int is_root,
 |  | ||||||
| +				  struct maple_tree_ops *ops)
 |  | ||||||
| +{
 |  | ||||||
| +	char path[BUFSIZE] = {0};
 |  | ||||||
| +	char tree_buf[MAPLE_BUFSIZE];
 |  | ||||||
| +	ulong entry;
 |  | ||||||
| +	struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
 |  | ||||||
| +	ulong global_index = 0;
 |  | ||||||
| +
 |  | ||||||
| +	if (SIZE(maple_tree) > MAPLE_BUFSIZE)
 |  | ||||||
| +		error(FATAL, "MAPLE_BUFSIZE should be larger than maple_tree struct");
 |  | ||||||
| +
 |  | ||||||
| +	if (!is_root) {
 |  | ||||||
| +		strcpy(path, "direct");
 |  | ||||||
| +		do_mt_node(ptr, 0, mt_max[mte_node_type(ptr)],
 |  | ||||||
| +			   0, path, &global_index, ops);
 |  | ||||||
| +	} else {
 |  | ||||||
| +		readmem(ptr, KVADDR, tree_buf, SIZE(maple_tree),
 |  | ||||||
| +			"mt_dump read maple_tree", FAULT_ON_ERROR);
 |  | ||||||
| +		entry = ULONG(tree_buf + OFFSET(maple_tree_ma_root));
 |  | ||||||
| +
 |  | ||||||
| +		if (!xa_is_node(entry))
 |  | ||||||
| +			do_mt_entry(entry, 0, 0, 0, 0, path, &global_index, ops);
 |  | ||||||
| +		else if (entry) {
 |  | ||||||
| +			strcpy(path, "root");
 |  | ||||||
| +			do_mt_node(entry, 0, mt_max[mte_node_type(entry)], 0,
 |  | ||||||
| +				   path, &global_index, ops);
 |  | ||||||
| +		}
 |  | ||||||
| +	}
 |  | ||||||
| +	return 0;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +int do_mptree(struct tree_data *td)
 |  | ||||||
| +{
 |  | ||||||
| +	struct maple_tree_ops ops = {
 |  | ||||||
| +		.entry		= NULL,
 |  | ||||||
| +		.private	= td,
 |  | ||||||
| +		.is_td		= true,
 |  | ||||||
| +	};
 |  | ||||||
| +
 |  | ||||||
| +	int is_root = !(td->flags & TREE_NODE_POINTER);
 |  | ||||||
| +
 |  | ||||||
| +	do_maple_tree_traverse(td->start, is_root, &ops);
 |  | ||||||
| +
 |  | ||||||
| +	return 0;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +/***********************************************/
 |  | ||||||
| +void maple_init(void)
 |  | ||||||
| +{
 |  | ||||||
| +	int array_len;
 |  | ||||||
| +
 |  | ||||||
| +	STRUCT_SIZE_INIT(maple_tree, "maple_tree");
 |  | ||||||
| +	STRUCT_SIZE_INIT(maple_node, "maple_node");
 |  | ||||||
| +
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_tree_ma_root, "maple_tree", "ma_root");
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_tree_ma_flags, "maple_tree", "ma_flags");
 |  | ||||||
| +
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_node_parent, "maple_node", "parent");
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_node_ma64, "maple_node", "ma64");
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_node_mr64, "maple_node", "mr64");
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_node_slot, "maple_node", "slot");
 |  | ||||||
| +
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_arange_64_pivot, "maple_arange_64", "pivot");
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_arange_64_slot, "maple_arange_64", "slot");
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_arange_64_gap, "maple_arange_64", "gap");
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_arange_64_meta, "maple_arange_64", "meta");
 |  | ||||||
| +
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_range_64_pivot, "maple_range_64", "pivot");
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_range_64_slot, "maple_range_64", "slot");
 |  | ||||||
| +
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_metadata_end, "maple_metadata", "end");
 |  | ||||||
| +	MEMBER_OFFSET_INIT(maple_metadata_gap, "maple_metadata", "gap");
 |  | ||||||
| +
 |  | ||||||
| +	array_len = get_array_length("mt_slots", NULL, sizeof(char));
 |  | ||||||
| +	mt_slots = calloc(array_len, sizeof(char));
 |  | ||||||
| +	readmem(symbol_value("mt_slots"), KVADDR, mt_slots,
 |  | ||||||
| +		array_len * sizeof(char), "maple_init read mt_slots",
 |  | ||||||
| +		RETURN_ON_ERROR);
 |  | ||||||
| +
 |  | ||||||
| +	array_len = get_array_length("mt_pivots", NULL, sizeof(char));
 |  | ||||||
| +	mt_pivots = calloc(array_len, sizeof(char));
 |  | ||||||
| +	readmem(symbol_value("mt_pivots"), KVADDR, mt_pivots,
 |  | ||||||
| +		array_len * sizeof(char), "maple_init read mt_pivots",
 |  | ||||||
| +		RETURN_ON_ERROR);
 |  | ||||||
| +
 |  | ||||||
| +	mt_max[maple_dense]           = mt_slots[maple_dense];
 |  | ||||||
| +	mt_max[maple_leaf_64]         = ULONG_MAX;
 |  | ||||||
| +	mt_max[maple_range_64]        = ULONG_MAX;
 |  | ||||||
| +	mt_max[maple_arange_64]       = ULONG_MAX;
 |  | ||||||
| +}
 |  | ||||||
| diff --git a/maple_tree.h b/maple_tree.h
 |  | ||||||
| new file mode 100644 |  | ||||||
| index 000000000000..f53d5aaffd2e
 |  | ||||||
| --- /dev/null
 |  | ||||||
| +++ b/maple_tree.h
 |  | ||||||
| @@ -0,0 +1,82 @@
 |  | ||||||
| +/* SPDX-License-Identifier: GPL-2.0+ */
 |  | ||||||
| +#ifndef _MAPLE_TREE_H
 |  | ||||||
| +#define _MAPLE_TREE_H
 |  | ||||||
| +/*
 |  | ||||||
| + * Maple Tree - An RCU-safe adaptive tree for storing ranges
 |  | ||||||
| + * Copyright (c) 2018-2022 Oracle
 |  | ||||||
| + * Authors:     Liam R. Howlett <Liam.Howlett@Oracle.com>
 |  | ||||||
| + *              Matthew Wilcox <willy@infradead.org>
 |  | ||||||
| + *
 |  | ||||||
| + * eXtensible Arrays
 |  | ||||||
| + * Copyright (c) 2017 Microsoft Corporation
 |  | ||||||
| + * Author: Matthew Wilcox <willy@infradead.org>
 |  | ||||||
| + *
 |  | ||||||
| + * See Documentation/core-api/xarray.rst for how to use the XArray.
 |  | ||||||
| + */
 |  | ||||||
| +#include <stdbool.h>
 |  | ||||||
| +#include <limits.h>
 |  | ||||||
| +#include <sys/types.h>
 |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| + * The following are copied and modified from include/linux/maple_tree.h
 |  | ||||||
| + */
 |  | ||||||
| +
 |  | ||||||
| +enum maple_type {
 |  | ||||||
| +	maple_dense,
 |  | ||||||
| +	maple_leaf_64,
 |  | ||||||
| +	maple_range_64,
 |  | ||||||
| +	maple_arange_64,
 |  | ||||||
| +};
 |  | ||||||
| +
 |  | ||||||
| +#define MAPLE_NODE_MASK		255UL
 |  | ||||||
| +
 |  | ||||||
| +#define MT_FLAGS_HEIGHT_OFFSET	0x02
 |  | ||||||
| +#define MT_FLAGS_HEIGHT_MASK	0x7C
 |  | ||||||
| +
 |  | ||||||
| +#define MAPLE_NODE_TYPE_MASK	0x0F
 |  | ||||||
| +#define MAPLE_NODE_TYPE_SHIFT	0x03
 |  | ||||||
| +
 |  | ||||||
| +#define MAPLE_RESERVED_RANGE	4096
 |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| + * The following are copied and modified from include/linux/xarray.h
 |  | ||||||
| + */
 |  | ||||||
| +
 |  | ||||||
| +#define XA_ZERO_ENTRY		xa_mk_internal(257)
 |  | ||||||
| +
 |  | ||||||
| +static inline ulong xa_mk_internal(ulong v)
 |  | ||||||
| +{
 |  | ||||||
| +	return (v << 2) | 2;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline bool xa_is_internal(ulong entry)
 |  | ||||||
| +{
 |  | ||||||
| +	return (entry & 3) == 2;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline bool xa_is_node(ulong entry)
 |  | ||||||
| +{
 |  | ||||||
| +	return xa_is_internal(entry) && entry > 4096;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline bool xa_is_value(ulong entry)
 |  | ||||||
| +{
 |  | ||||||
| +	return entry & 1;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline bool xa_is_zero(ulong entry)
 |  | ||||||
| +{
 |  | ||||||
| +	return entry == XA_ZERO_ENTRY;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline unsigned long xa_to_internal(ulong entry)
 |  | ||||||
| +{
 |  | ||||||
| +	return entry >> 2;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static inline unsigned long xa_to_value(ulong entry)
 |  | ||||||
| +{
 |  | ||||||
| +	return entry >> 1;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +#endif /* _MAPLE_TREE_H */
 |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,335 +0,0 @@ | |||||||
| From 16a696762cbfe6a40312840fee2297f05fdefb21 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Tao Liu <ltao@redhat.com> |  | ||||||
| Date: Tue, 10 Jan 2023 14:56:28 +0800 |  | ||||||
| Subject: [PATCH 24/28] Add maple tree support to "tree" command |  | ||||||
| 
 |  | ||||||
| The maple tree is a new data structure for crash, so "tree" command |  | ||||||
| needs to support it for users to dump and view the content of maple |  | ||||||
| trees.  This patch achieves this by using ported mt_dump() and its |  | ||||||
| related functions from kernel and adapting them with "tree" command. |  | ||||||
| 
 |  | ||||||
| Also introduce a new -v arg specifically for dumping the complete |  | ||||||
| content of a maple tree: |  | ||||||
| 
 |  | ||||||
|     crash> tree -t maple 0xffff9034c006aec0 -v |  | ||||||
| 
 |  | ||||||
|     maple_tree(ffff9034c006aec0) flags 309, height 2 root 0xffff9034de70041e |  | ||||||
| 
 |  | ||||||
|     0-18446744073709551615: node 0xffff9034de700400 depth 0 type 3 parent 0xffff9034c006aec1 contents:... |  | ||||||
|       0-140112331583487: node 0xffff9034c01e8800 depth 1 type 1 parent 0xffff9034de700406 contents:... |  | ||||||
|         0-94643156942847: (nil) |  | ||||||
|         94643156942848-94643158024191: 0xffff9035131754c0 |  | ||||||
|         94643158024192-94643160117247: (nil) |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
| The existing options of "tree" command can work as well: |  | ||||||
| 
 |  | ||||||
|     crash> tree -t maple -r mm_struct.mm_mt 0xffff9034c006aec0 -p |  | ||||||
|     ffff9035131754c0 |  | ||||||
|       index: 1  position: root/0/1 |  | ||||||
|     ffff9035131751c8 |  | ||||||
|       index: 2  position: root/0/3 |  | ||||||
|     ffff9035131757b8 |  | ||||||
|       index: 3  position: root/0/4 |  | ||||||
|     ... |  | ||||||
| 
 |  | ||||||
|     crash> tree -t maple 0xffff9034c006aec0 -p -x -s vm_area_struct.vm_start,vm_end |  | ||||||
|     ffff9035131754c0 |  | ||||||
|       index: 1  position: root/0/1 |  | ||||||
|       vm_start = 0x5613d3c00000, |  | ||||||
|       vm_end = 0x5613d3d08000, |  | ||||||
|     ffff9035131751c8 |  | ||||||
|       index: 2  position: root/0/3 |  | ||||||
|       vm_start = 0x5613d3f07000, |  | ||||||
|       vm_end = 0x5613d3f0b000, |  | ||||||
|     ffff9035131757b8 |  | ||||||
|       index: 3  position: root/0/4 |  | ||||||
|       vm_start = 0x5613d3f0b000, |  | ||||||
|       vm_end = 0x5613d3f14000, |  | ||||||
|     .... |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Tao Liu <ltao@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  defs.h       |  1 + |  | ||||||
|  maple_tree.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ |  | ||||||
|  tools.c      | 67 +++++++++++++++++++++++++++++++++++++++------------- |  | ||||||
|  3 files changed, 114 insertions(+), 17 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index 46bfd4a67e64..f98e18937949 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -2713,6 +2713,7 @@ struct tree_data {
 |  | ||||||
|  #define TREE_PARSE_MEMBER         (VERBOSE << 7) |  | ||||||
|  #define TREE_READ_MEMBER          (VERBOSE << 8) |  | ||||||
|  #define TREE_LINEAR_ORDER         (VERBOSE << 9) |  | ||||||
| +#define TREE_STRUCT_VERBOSE       (VERBOSE << 10)
 |  | ||||||
|   |  | ||||||
|  #define ALIAS_RUNTIME  (1) |  | ||||||
|  #define ALIAS_RCLOCAL  (2) |  | ||||||
| diff --git a/maple_tree.c b/maple_tree.c
 |  | ||||||
| index 474faeda6252..471136f3eb1d 100644
 |  | ||||||
| --- a/maple_tree.c
 |  | ||||||
| +++ b/maple_tree.c
 |  | ||||||
| @@ -173,6 +173,10 @@ static void do_mt_range64(ulong entry, ulong min, ulong max,
 |  | ||||||
|   |  | ||||||
|  	mr64_buf = node_buf + OFFSET(maple_node_mr64); |  | ||||||
|   |  | ||||||
| +	if (td && td->flags & TREE_STRUCT_VERBOSE) {
 |  | ||||||
| +		dump_mt_range64(mr64_buf);
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
|  	for (i = 0; i < mt_slots[maple_range_64]; i++) { |  | ||||||
|  		last = max; |  | ||||||
|   |  | ||||||
| @@ -230,6 +234,10 @@ static void do_mt_arange64(ulong entry, ulong min, ulong max,
 |  | ||||||
|   |  | ||||||
|  	ma64_buf = node_buf + OFFSET(maple_node_ma64); |  | ||||||
|   |  | ||||||
| +	if (td && td->flags & TREE_STRUCT_VERBOSE) {
 |  | ||||||
| +		dump_mt_arange64(ma64_buf);
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
|  	for (i = 0; i < mt_slots[maple_arange_64]; i++) { |  | ||||||
|  		last = max; |  | ||||||
|   |  | ||||||
| @@ -275,6 +283,51 @@ static void do_mt_entry(ulong entry, ulong min, ulong max, uint depth,
 |  | ||||||
|   |  | ||||||
|  	if (!td) |  | ||||||
|  		return; |  | ||||||
| +
 |  | ||||||
| +	if (!td->count && td->structname_args) {
 |  | ||||||
| +		/*
 |  | ||||||
| +		 * Retrieve all members' info only once (count == 0)
 |  | ||||||
| +		 * After last iteration all memory will be freed up
 |  | ||||||
| +		 */
 |  | ||||||
| +		e = (struct req_entry **)GETBUF(sizeof(*e) * td->structname_args);
 |  | ||||||
| +		for (i = 0; i < td->structname_args; i++)
 |  | ||||||
| +			e[i] = fill_member_offsets(td->structname[i]);
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	td->count++;
 |  | ||||||
| +
 |  | ||||||
| +	if (td->flags & TREE_STRUCT_VERBOSE) {
 |  | ||||||
| +		dump_mt_entry(entry, min, max, depth);
 |  | ||||||
| +	} else if (td->flags & VERBOSE && entry)
 |  | ||||||
| +		fprintf(fp, "%lx\n", entry);
 |  | ||||||
| +	if (td->flags & TREE_POSITION_DISPLAY && entry)
 |  | ||||||
| +		fprintf(fp, "  index: %ld  position: %s/%u\n",
 |  | ||||||
| +			++(*global_index), path, index);
 |  | ||||||
| +
 |  | ||||||
| +	if (td->structname) {
 |  | ||||||
| +		if (td->flags & TREE_STRUCT_RADIX_10)
 |  | ||||||
| +			print_radix = 10;
 |  | ||||||
| +		else if (td->flags & TREE_STRUCT_RADIX_16)
 |  | ||||||
| +			print_radix = 16;
 |  | ||||||
| +		else
 |  | ||||||
| +			print_radix = 0;
 |  | ||||||
| +
 |  | ||||||
| +		for (i = 0; i < td->structname_args; i++) {
 |  | ||||||
| +			switch (count_chars(td->structname[i], '.')) {
 |  | ||||||
| +			case 0:
 |  | ||||||
| +				dump_struct(td->structname[i], entry, print_radix);
 |  | ||||||
| +				break;
 |  | ||||||
| +			default:
 |  | ||||||
| +				if (td->flags & TREE_PARSE_MEMBER)
 |  | ||||||
| +					dump_struct_members_for_tree(td, i, entry);
 |  | ||||||
| +				else if (td->flags & TREE_READ_MEMBER)
 |  | ||||||
| +					dump_struct_members_fast(e[i], print_radix, entry);
 |  | ||||||
| +			}
 |  | ||||||
| +		}
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	if (e)
 |  | ||||||
| +		FREEBUF(e);
 |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  static void do_mt_node(ulong entry, ulong min, ulong max, |  | ||||||
| @@ -293,6 +346,10 @@ static void do_mt_node(ulong entry, ulong min, ulong max,
 |  | ||||||
|  	readmem(maple_node, KVADDR, node_buf, SIZE(maple_node), |  | ||||||
|  		"mt_dump_node read maple_node", FAULT_ON_ERROR); |  | ||||||
|   |  | ||||||
| +	if (td && td->flags & TREE_STRUCT_VERBOSE) {
 |  | ||||||
| +		dump_mt_node(maple_node, node_buf, type, min, max, depth);
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
|  	switch (type) { |  | ||||||
|  	case maple_dense: |  | ||||||
|  		for (i = 0; i < mt_slots[maple_dense]; i++) { |  | ||||||
| @@ -335,6 +392,12 @@ static int do_maple_tree_traverse(ulong ptr, int is_root,
 |  | ||||||
|  			"mt_dump read maple_tree", FAULT_ON_ERROR); |  | ||||||
|  		entry = ULONG(tree_buf + OFFSET(maple_tree_ma_root)); |  | ||||||
|   |  | ||||||
| +		if (td && td->flags & TREE_STRUCT_VERBOSE) {
 |  | ||||||
| +			fprintf(fp, "maple_tree(%lx) flags %X, height %u root 0x%lx\n\n",
 |  | ||||||
| +				ptr, UINT(tree_buf + OFFSET(maple_tree_ma_flags)),
 |  | ||||||
| +				mt_height(tree_buf), entry);
 |  | ||||||
| +		}
 |  | ||||||
| +
 |  | ||||||
|  		if (!xa_is_node(entry)) |  | ||||||
|  			do_mt_entry(entry, 0, 0, 0, 0, path, &global_index, ops); |  | ||||||
|  		else if (entry) { |  | ||||||
| diff --git a/tools.c b/tools.c
 |  | ||||||
| index 5f86771f5327..c2cfa7e280bc 100644
 |  | ||||||
| --- a/tools.c
 |  | ||||||
| +++ b/tools.c
 |  | ||||||
| @@ -30,7 +30,7 @@ static void dealloc_hq_entry(struct hq_entry *);
 |  | ||||||
|  static void show_options(void); |  | ||||||
|  static void dump_struct_members(struct list_data *, int, ulong); |  | ||||||
|  static void rbtree_iteration(ulong, struct tree_data *, char *); |  | ||||||
| -static void dump_struct_members_for_tree(struct tree_data *, int, ulong);
 |  | ||||||
| +void dump_struct_members_for_tree(struct tree_data *, int, ulong);
 |  | ||||||
|   |  | ||||||
|  struct req_entry { |  | ||||||
|  	char *arg, *name, **member; |  | ||||||
| @@ -40,8 +40,8 @@ struct req_entry {
 |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
|  static void print_value(struct req_entry *, unsigned int, ulong, unsigned int); |  | ||||||
| -static struct req_entry *fill_member_offsets(char *);
 |  | ||||||
| -static void dump_struct_members_fast(struct req_entry *, int, ulong);
 |  | ||||||
| +struct req_entry *fill_member_offsets(char *);
 |  | ||||||
| +void dump_struct_members_fast(struct req_entry *, int, ulong);
 |  | ||||||
|   |  | ||||||
|  FILE * |  | ||||||
|  set_error(char *target) |  | ||||||
| @@ -3666,7 +3666,7 @@ dump_struct_members_fast(struct req_entry *e, int radix, ulong p)
 |  | ||||||
|  	} |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| -static struct req_entry *
 |  | ||||||
| +struct req_entry *
 |  | ||||||
|  fill_member_offsets(char *arg) |  | ||||||
|  { |  | ||||||
|  	int j; |  | ||||||
| @@ -4307,6 +4307,7 @@ dump_struct_members(struct list_data *ld, int idx, ulong next)
 |  | ||||||
|  #define RADIXTREE_REQUEST (0x1) |  | ||||||
|  #define RBTREE_REQUEST    (0x2) |  | ||||||
|  #define XARRAY_REQUEST    (0x4) |  | ||||||
| +#define MAPLE_REQUEST     (0x8)
 |  | ||||||
|   |  | ||||||
|  void |  | ||||||
|  cmd_tree() |  | ||||||
| @@ -4317,6 +4318,7 @@ cmd_tree()
 |  | ||||||
|  	struct datatype_member struct_member, *sm; |  | ||||||
|  	struct syment *sp; |  | ||||||
|  	ulong value; |  | ||||||
| +	char *type_name = NULL;
 |  | ||||||
|   |  | ||||||
|  	type_flag = 0; |  | ||||||
|  	root_offset = 0; |  | ||||||
| @@ -4324,25 +4326,33 @@ cmd_tree()
 |  | ||||||
|  	td = &tree_data; |  | ||||||
|  	BZERO(td, sizeof(struct tree_data)); |  | ||||||
|   |  | ||||||
| -	while ((c = getopt(argcnt, args, "xdt:r:o:s:S:plN")) != EOF) {
 |  | ||||||
| +	while ((c = getopt(argcnt, args, "xdt:r:o:s:S:plNv")) != EOF) {
 |  | ||||||
|  		switch (c) |  | ||||||
|  		{ |  | ||||||
|  		case 't': |  | ||||||
| -			if (type_flag & (RADIXTREE_REQUEST|RBTREE_REQUEST|XARRAY_REQUEST)) {
 |  | ||||||
| +			if (type_flag & (RADIXTREE_REQUEST|RBTREE_REQUEST|XARRAY_REQUEST|MAPLE_REQUEST)) {
 |  | ||||||
|  				error(INFO, "multiple tree types may not be entered\n"); |  | ||||||
|  				cmd_usage(pc->curcmd, SYNOPSIS); |  | ||||||
|  			} |  | ||||||
|   |  | ||||||
|  			if (STRNEQ(optarg, "ra")) |  | ||||||
| -				if (MEMBER_EXISTS("radix_tree_root", "xa_head"))
 |  | ||||||
| +				if (MEMBER_EXISTS("radix_tree_root", "xa_head")) {
 |  | ||||||
|  					type_flag = XARRAY_REQUEST; |  | ||||||
| -				else
 |  | ||||||
| +					type_name = "Xarrays";
 |  | ||||||
| +				} else {
 |  | ||||||
|  					type_flag = RADIXTREE_REQUEST; |  | ||||||
| -			else if (STRNEQ(optarg, "rb"))
 |  | ||||||
| +					type_name = "radix trees";
 |  | ||||||
| +				}
 |  | ||||||
| +			else if (STRNEQ(optarg, "rb")) {
 |  | ||||||
|  				type_flag = RBTREE_REQUEST; |  | ||||||
| -			else if (STRNEQ(optarg, "x"))
 |  | ||||||
| +				type_name = "rbtrees";
 |  | ||||||
| +			} else if (STRNEQ(optarg, "x")) {
 |  | ||||||
|  				type_flag = XARRAY_REQUEST; |  | ||||||
| -			else {
 |  | ||||||
| +				type_name = "Xarrays";
 |  | ||||||
| +			} else if (STRNEQ(optarg, "m")) {
 |  | ||||||
| +				type_flag = MAPLE_REQUEST;
 |  | ||||||
| +				type_name = "maple trees";
 |  | ||||||
| +			} else {
 |  | ||||||
|  				error(INFO, "invalid tree type: %s\n", optarg); |  | ||||||
|  				cmd_usage(pc->curcmd, SYNOPSIS); |  | ||||||
|  			} |  | ||||||
| @@ -4417,6 +4427,9 @@ cmd_tree()
 |  | ||||||
|  					"-d and -x are mutually exclusive\n"); |  | ||||||
|  			td->flags |= TREE_STRUCT_RADIX_10; |  | ||||||
|  			break; |  | ||||||
| +		case 'v':
 |  | ||||||
| +			td->flags |= TREE_STRUCT_VERBOSE;
 |  | ||||||
| +			break;
 |  | ||||||
|  		default: |  | ||||||
|  			argerrs++; |  | ||||||
|  			break; |  | ||||||
| @@ -4426,13 +4439,17 @@ cmd_tree()
 |  | ||||||
|  	if (argerrs) |  | ||||||
|  		cmd_usage(pc->curcmd, SYNOPSIS); |  | ||||||
|   |  | ||||||
| -	if ((type_flag & (XARRAY_REQUEST|RADIXTREE_REQUEST)) && (td->flags & TREE_LINEAR_ORDER))
 |  | ||||||
| -		error(FATAL, "-l option is not applicable to %s\n", 
 |  | ||||||
| -			type_flag & RADIXTREE_REQUEST ? "radix trees" : "Xarrays");
 |  | ||||||
| +	if ((type_flag & (XARRAY_REQUEST|RADIXTREE_REQUEST|MAPLE_REQUEST)) &&
 |  | ||||||
| +	    (td->flags & TREE_LINEAR_ORDER))
 |  | ||||||
| +		error(FATAL, "-l option is not applicable to %s\n", type_name);
 |  | ||||||
|   |  | ||||||
| -	if ((type_flag & (XARRAY_REQUEST|RADIXTREE_REQUEST)) && (td->flags & TREE_NODE_OFFSET_ENTERED))
 |  | ||||||
| -		error(FATAL, "-o option is not applicable to %s\n",
 |  | ||||||
| -			type_flag & RADIXTREE_REQUEST ? "radix trees" : "Xarrays");
 |  | ||||||
| +	if ((type_flag & (XARRAY_REQUEST|RADIXTREE_REQUEST|MAPLE_REQUEST)) &&
 |  | ||||||
| +	    (td->flags & TREE_NODE_OFFSET_ENTERED))
 |  | ||||||
| +		error(FATAL, "-o option is not applicable to %s\n", type_name);
 |  | ||||||
| +
 |  | ||||||
| +	if ((type_flag & (RBTREE_REQUEST|XARRAY_REQUEST|RADIXTREE_REQUEST)) &&
 |  | ||||||
| +	    (td->flags & TREE_STRUCT_VERBOSE))
 |  | ||||||
| +		error(FATAL, "-v option is not applicable to %s\n", type_name);
 |  | ||||||
|   |  | ||||||
|  	if ((td->flags & TREE_ROOT_OFFSET_ENTERED) &&  |  | ||||||
|  	    (td->flags & TREE_NODE_POINTER)) |  | ||||||
| @@ -4506,12 +4523,26 @@ next_arg:
 |  | ||||||
|  		if (td->flags & TREE_STRUCT_RADIX_16) |  | ||||||
|  			fprintf(fp, "%sTREE_STRUCT_RADIX_16", |  | ||||||
|  				others++ ? "|" : ""); |  | ||||||
| +		if (td->flags & TREE_PARSE_MEMBER)
 |  | ||||||
| +			fprintf(fp, "%sTREE_PARSE_MEMBER",
 |  | ||||||
| +				others++ ? "|" : "");
 |  | ||||||
| +		if (td->flags & TREE_READ_MEMBER)
 |  | ||||||
| +			fprintf(fp, "%sTREE_READ_MEMBER",
 |  | ||||||
| +				others++ ? "|" : "");
 |  | ||||||
| +		if (td->flags & TREE_LINEAR_ORDER)
 |  | ||||||
| +			fprintf(fp, "%sTREE_LINEAR_ORDER",
 |  | ||||||
| +				others++ ? "|" : "");
 |  | ||||||
| +		if (td->flags & TREE_STRUCT_VERBOSE)
 |  | ||||||
| +			fprintf(fp, "%sTREE_STRUCT_VERBOSE",
 |  | ||||||
| +				others++ ? "|" : "");
 |  | ||||||
|  		fprintf(fp, ")\n"); |  | ||||||
|  		fprintf(fp, "              type: "); |  | ||||||
|  			if (type_flag & RADIXTREE_REQUEST) |  | ||||||
|  				fprintf(fp, "radix\n"); |  | ||||||
|  			else if (type_flag & XARRAY_REQUEST) |  | ||||||
|  				fprintf(fp, "xarray\n"); |  | ||||||
| +			else if (type_flag & MAPLE_REQUEST)
 |  | ||||||
| +				fprintf(fp, "maple\n");
 |  | ||||||
|  			else |  | ||||||
|  				fprintf(fp, "red-black%s",  |  | ||||||
|  					type_flag & RBTREE_REQUEST ?  |  | ||||||
| @@ -4532,6 +4563,8 @@ next_arg:
 |  | ||||||
|  		do_rdtree(td); |  | ||||||
|  	else if (type_flag & XARRAY_REQUEST) |  | ||||||
|  		do_xatree(td); |  | ||||||
| +	else if (type_flag & MAPLE_REQUEST)
 |  | ||||||
| +		do_mptree(td);
 |  | ||||||
|  	else |  | ||||||
|  		do_rbtree(td); |  | ||||||
|  	hq_close(); |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,205 +0,0 @@ | |||||||
| From 222176a0a6c14b6a1cdcebb8dda020ccb17b90f8 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Tao Liu <ltao@redhat.com> |  | ||||||
| Date: Tue, 10 Jan 2023 14:56:29 +0800 |  | ||||||
| Subject: [PATCH 25/28] Add do_maple_tree() for maple tree operations |  | ||||||
| 
 |  | ||||||
| do_maple_tree() is similar to do_radix_tree() and do_xarray(), which |  | ||||||
| takes the same do_maple_tree_traverse entry as tree command. |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Tao Liu <ltao@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  defs.h       |   6 +++ |  | ||||||
|  maple_tree.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++ |  | ||||||
|  2 files changed, 151 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index f98e18937949..33a823b7b67c 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -5762,6 +5762,12 @@ int cleanup_memory_driver(void);
 |  | ||||||
|   |  | ||||||
|  void maple_init(void); |  | ||||||
|  int do_mptree(struct tree_data *); |  | ||||||
| +ulong do_maple_tree(ulong, int, struct list_pair *);
 |  | ||||||
| +#define MAPLE_TREE_COUNT   (1)
 |  | ||||||
| +#define MAPLE_TREE_SEARCH  (2)
 |  | ||||||
| +#define MAPLE_TREE_DUMP    (3)
 |  | ||||||
| +#define MAPLE_TREE_GATHER  (4)
 |  | ||||||
| +#define MAPLE_TREE_DUMP_CB (5)
 |  | ||||||
|   |  | ||||||
|  /* |  | ||||||
|   *  help.c  |  | ||||||
| diff --git a/maple_tree.c b/maple_tree.c
 |  | ||||||
| index 471136f3eb1d..807c17f7dfa0 100644
 |  | ||||||
| --- a/maple_tree.c
 |  | ||||||
| +++ b/maple_tree.c
 |  | ||||||
| @@ -40,6 +40,12 @@ static inline bool ma_is_leaf(const enum maple_type type)
 |  | ||||||
|   |  | ||||||
|  /*************** For cmd_tree ********************/ |  | ||||||
|   |  | ||||||
| +struct do_maple_tree_info {
 |  | ||||||
| +	ulong maxcount;
 |  | ||||||
| +	ulong count;
 |  | ||||||
| +	void *data;
 |  | ||||||
| +};
 |  | ||||||
| +
 |  | ||||||
|  struct maple_tree_ops { |  | ||||||
|  	void (*entry)(ulong node, ulong slot, const char *path, |  | ||||||
|  		      ulong index, void *private); |  | ||||||
| @@ -281,6 +287,9 @@ static void do_mt_entry(ulong entry, ulong min, ulong max, uint depth,
 |  | ||||||
|  	static struct req_entry **e = NULL; |  | ||||||
|  	struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL; |  | ||||||
|   |  | ||||||
| +	if (ops->entry)
 |  | ||||||
| +		ops->entry(entry, entry, path, max, ops->private);
 |  | ||||||
| +
 |  | ||||||
|  	if (!td) |  | ||||||
|  		return; |  | ||||||
|   |  | ||||||
| @@ -424,6 +433,142 @@ int do_mptree(struct tree_data *td)
 |  | ||||||
|  	return 0; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| +/************* For do_maple_tree *****************/
 |  | ||||||
| +static void do_maple_tree_count(ulong node, ulong slot, const char *path,
 |  | ||||||
| +				ulong index, void *private)
 |  | ||||||
| +{
 |  | ||||||
| +	struct do_maple_tree_info *info = private;
 |  | ||||||
| +	info->count++;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void do_maple_tree_search(ulong node, ulong slot, const char *path,
 |  | ||||||
| +				 ulong index, void *private)
 |  | ||||||
| +{
 |  | ||||||
| +	struct do_maple_tree_info *info = private;
 |  | ||||||
| +	struct list_pair *lp = info->data;
 |  | ||||||
| +
 |  | ||||||
| +	if (lp->index == index) {
 |  | ||||||
| +		lp->value = (void *)slot;
 |  | ||||||
| +		info->count = 1;
 |  | ||||||
| +	}
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void do_maple_tree_dump(ulong node, ulong slot, const char *path,
 |  | ||||||
| +			       ulong index, void *private)
 |  | ||||||
| +{
 |  | ||||||
| +	struct do_maple_tree_info *info = private;
 |  | ||||||
| +	fprintf(fp, "[%lu] %lx\n", index, slot);
 |  | ||||||
| +	info->count++;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void do_maple_tree_gather(ulong node, ulong slot, const char *path,
 |  | ||||||
| +				 ulong index, void *private)
 |  | ||||||
| +{
 |  | ||||||
| +	struct do_maple_tree_info *info = private;
 |  | ||||||
| +	struct list_pair *lp = info->data;
 |  | ||||||
| +
 |  | ||||||
| +	if (info->maxcount) {
 |  | ||||||
| +		lp[info->count].index = index;
 |  | ||||||
| +		lp[info->count].value = (void *)slot;
 |  | ||||||
| +
 |  | ||||||
| +		info->count++;
 |  | ||||||
| +		info->maxcount--;
 |  | ||||||
| +	}
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void do_maple_tree_dump_cb(ulong node, ulong slot, const char *path,
 |  | ||||||
| +				  ulong index, void *private)
 |  | ||||||
| +{
 |  | ||||||
| +	struct do_maple_tree_info *info = private;
 |  | ||||||
| +	struct list_pair *lp = info->data;
 |  | ||||||
| +	int (*cb)(ulong) = lp->value;
 |  | ||||||
| +
 |  | ||||||
| +	/* Caller defined operation */
 |  | ||||||
| +	if (!cb(slot)) {
 |  | ||||||
| +		error(FATAL, "do_maple_tree: callback "
 |  | ||||||
| +		      "operation failed: entry: %ld  item: %lx\n",
 |  | ||||||
| +		      info->count, slot);
 |  | ||||||
| +	}
 |  | ||||||
| +	info->count++;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +/*
 |  | ||||||
| + *  do_maple_tree argument usage:
 |  | ||||||
| + *
 |  | ||||||
| + *    root: Address of a maple_tree_root structure
 |  | ||||||
| + *
 |  | ||||||
| + *    flag: MAPLE_TREE_COUNT - Return the number of entries in the tree.
 |  | ||||||
| + *          MAPLE_TREE_SEARCH - Search for an entry at lp->index; if found,
 |  | ||||||
| + *            store the entry in lp->value and return a count of 1; otherwise
 |  | ||||||
| + *            return a count of 0.
 |  | ||||||
| + *          MAPLE_TREE_DUMP - Dump all existing index/value pairs.
 |  | ||||||
| + *          MAPLE_TREE_GATHER - Store all existing index/value pairs in the
 |  | ||||||
| + *            passed-in array of list_pair structs starting at lp,
 |  | ||||||
| + *            returning the count of entries stored; the caller can/should
 |  | ||||||
| + *            limit the number of returned entries by putting the array size
 |  | ||||||
| + *            (max count) in the lp->index field of the first structure
 |  | ||||||
| + *            in the passed-in array.
 |  | ||||||
| + *          MAPLE_TREE_DUMP_CB - Similar with MAPLE_TREE_DUMP, but for each
 |  | ||||||
| + *            maple tree entry, a user defined callback at lp->value will
 |  | ||||||
| + *            be invoked.
 |  | ||||||
| + *
 |  | ||||||
| + *     lp: Unused by MAPLE_TREE_COUNT and MAPLE_TREE_DUMP.
 |  | ||||||
| + *          A pointer to a list_pair structure for MAPLE_TREE_SEARCH.
 |  | ||||||
| + *          A pointer to an array of list_pair structures for
 |  | ||||||
| + *          MAPLE_TREE_GATHER; the dimension (max count) of the array may
 |  | ||||||
| + *          be stored in the index field of the first structure to avoid
 |  | ||||||
| + *          any chance of an overrun.
 |  | ||||||
| + *          For MAPLE_TREE_DUMP_CB, the lp->value must be initialized as a
 |  | ||||||
| + *          callback function.  The callback prototype must be: int (*)(ulong);
 |  | ||||||
| + */
 |  | ||||||
| +ulong
 |  | ||||||
| +do_maple_tree(ulong root, int flag, struct list_pair *lp)
 |  | ||||||
| +{
 |  | ||||||
| +	struct do_maple_tree_info info = {
 |  | ||||||
| +		.count		= 0,
 |  | ||||||
| +		.data		= lp,
 |  | ||||||
| +	};
 |  | ||||||
| +	struct maple_tree_ops ops = {
 |  | ||||||
| +		.private	= &info,
 |  | ||||||
| +		.is_td		= false,
 |  | ||||||
| +	};
 |  | ||||||
| +
 |  | ||||||
| +	switch (flag)
 |  | ||||||
| +	{
 |  | ||||||
| +	case MAPLE_TREE_COUNT:
 |  | ||||||
| +		ops.entry = do_maple_tree_count;
 |  | ||||||
| +		break;
 |  | ||||||
| +
 |  | ||||||
| +	case MAPLE_TREE_SEARCH:
 |  | ||||||
| +		ops.entry = do_maple_tree_search;
 |  | ||||||
| +		break;
 |  | ||||||
| +
 |  | ||||||
| +	case MAPLE_TREE_DUMP:
 |  | ||||||
| +		ops.entry = do_maple_tree_dump;
 |  | ||||||
| +		break;
 |  | ||||||
| +
 |  | ||||||
| +	case MAPLE_TREE_GATHER:
 |  | ||||||
| +		if (!(info.maxcount = lp->index))
 |  | ||||||
| +			info.maxcount = (ulong)(-1);   /* caller beware */
 |  | ||||||
| +
 |  | ||||||
| +		ops.entry = do_maple_tree_gather;
 |  | ||||||
| +		break;
 |  | ||||||
| +
 |  | ||||||
| +	case MAPLE_TREE_DUMP_CB:
 |  | ||||||
| +		if (lp->value == NULL) {
 |  | ||||||
| +			error(FATAL, "do_maple_tree: need set callback function");
 |  | ||||||
| +		}
 |  | ||||||
| +		ops.entry = do_maple_tree_dump_cb;
 |  | ||||||
| +		break;
 |  | ||||||
| +
 |  | ||||||
| +	default:
 |  | ||||||
| +		error(FATAL, "do_maple_tree: invalid flag: %lx\n", flag);
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	do_maple_tree_traverse(root, true, &ops);
 |  | ||||||
| +	return info.count;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
|  /***********************************************/ |  | ||||||
|  void maple_init(void) |  | ||||||
|  { |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,455 +0,0 @@ | |||||||
| From 9efc1f68a44f6fe521e64efe4a3dc36e9ba0bbc1 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Tao Liu <ltao@redhat.com> |  | ||||||
| Date: Tue, 10 Jan 2023 14:56:30 +0800 |  | ||||||
| Subject: [PATCH 26/28] Introduce maple tree vma iteration to vm_area_dump() |  | ||||||
| 
 |  | ||||||
| Since memory.c:vm_area_dump() will iterate all vma, this patch mainly |  | ||||||
| introduces maple tree vma iteration to it. |  | ||||||
| 
 |  | ||||||
| We extract the code which handles each vma into a function. If |  | ||||||
| mm_struct_mmap exist, aka the linked list of vma iteration available, |  | ||||||
| we goto the original way; if not and mm_struct_mm_mt exist, aka |  | ||||||
| maple tree is available, then we goto the maple tree vma iteration. |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Tao Liu <ltao@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  Makefile |   2 +- |  | ||||||
|  memory.c | 321 +++++++++++++++++++++++++++++++++---------------------- |  | ||||||
|  2 files changed, 193 insertions(+), 130 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/Makefile b/Makefile
 |  | ||||||
| index 102597f735b2..a94a243c243e 100644
 |  | ||||||
| --- a/Makefile
 |  | ||||||
| +++ b/Makefile
 |  | ||||||
| @@ -355,7 +355,7 @@ filesys.o: ${GENERIC_HFILES} filesys.c
 |  | ||||||
|  help.o: ${GENERIC_HFILES} help.c |  | ||||||
|  	${CC} -c ${CRASH_CFLAGS} help.c ${WARNING_OPTIONS} ${WARNING_ERROR} |  | ||||||
|   |  | ||||||
| -memory.o: ${GENERIC_HFILES} memory.c
 |  | ||||||
| +memory.o: ${GENERIC_HFILES} ${MAPLE_TREE_HFILES} memory.c
 |  | ||||||
|  	${CC} -c ${CRASH_CFLAGS} memory.c ${WARNING_OPTIONS} ${WARNING_ERROR} |  | ||||||
|   |  | ||||||
|  test.o: ${GENERIC_HFILES} test.c |  | ||||||
| diff --git a/memory.c b/memory.c
 |  | ||||||
| index 156de2f7b5a3..5141fbea4b40 100644
 |  | ||||||
| --- a/memory.c
 |  | ||||||
| +++ b/memory.c
 |  | ||||||
| @@ -21,6 +21,7 @@
 |  | ||||||
|  #include <ctype.h> |  | ||||||
|  #include <netinet/in.h> |  | ||||||
|  #include <byteswap.h> |  | ||||||
| +#include "maple_tree.h"
 |  | ||||||
|   |  | ||||||
|  struct meminfo {           /* general purpose memory information structure */ |  | ||||||
|          ulong cache;       /* used by the various memory searching/dumping */ |  | ||||||
| @@ -137,6 +138,27 @@ struct searchinfo {
 |  | ||||||
|  	char buf[BUFSIZE]; |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
| +struct handle_each_vm_area_args {
 |  | ||||||
| +	ulong task;
 |  | ||||||
| +	ulong flag;
 |  | ||||||
| +	ulong vaddr;
 |  | ||||||
| +	struct reference *ref;
 |  | ||||||
| +	char *vma_header;
 |  | ||||||
| +	char *buf1;
 |  | ||||||
| +	char *buf2;
 |  | ||||||
| +	char *buf3;
 |  | ||||||
| +	char *buf4;
 |  | ||||||
| +	char *buf5;
 |  | ||||||
| +	ulong vma;
 |  | ||||||
| +	char **vma_buf;
 |  | ||||||
| +	struct task_mem_usage *tm;
 |  | ||||||
| +	int *found;
 |  | ||||||
| +	int *single_vma_found;
 |  | ||||||
| +	unsigned int radix;
 |  | ||||||
| +	struct task_context *tc;
 |  | ||||||
| +	ulong *single_vma;
 |  | ||||||
| +};
 |  | ||||||
| +
 |  | ||||||
|  static char *memtype_string(int, int); |  | ||||||
|  static char *error_handle_string(ulong); |  | ||||||
|  static void collect_page_member_data(char *, struct meminfo *); |  | ||||||
| @@ -299,6 +321,7 @@ static void dump_page_flags(ulonglong);
 |  | ||||||
|  static ulong kmem_cache_nodelists(ulong); |  | ||||||
|  static void dump_hstates(void); |  | ||||||
|  static ulong freelist_ptr(struct meminfo *, ulong, ulong); |  | ||||||
| +static ulong handle_each_vm_area(struct handle_each_vm_area_args *);
 |  | ||||||
|   |  | ||||||
|  /* |  | ||||||
|   *  Memory display modes specific to this file. |  | ||||||
| @@ -363,6 +386,10 @@ vm_init(void)
 |  | ||||||
|   |  | ||||||
|          MEMBER_OFFSET_INIT(task_struct_mm, "task_struct", "mm"); |  | ||||||
|          MEMBER_OFFSET_INIT(mm_struct_mmap, "mm_struct", "mmap"); |  | ||||||
| +	MEMBER_OFFSET_INIT(mm_struct_mm_mt, "mm_struct", "mm_mt");
 |  | ||||||
| +	if (VALID_MEMBER(mm_struct_mm_mt)) {
 |  | ||||||
| +		maple_init();
 |  | ||||||
| +	}
 |  | ||||||
|          MEMBER_OFFSET_INIT(mm_struct_pgd, "mm_struct", "pgd"); |  | ||||||
|  	MEMBER_OFFSET_INIT(mm_struct_rss, "mm_struct", "rss"); |  | ||||||
|  	if (!VALID_MEMBER(mm_struct_rss)) |  | ||||||
| @@ -3874,7 +3901,7 @@ bailout:
 |  | ||||||
|   *                        for references -- and only then does a display       |  | ||||||
|   */ |  | ||||||
|   |  | ||||||
| -#define PRINT_VM_DATA()                                                  \
 |  | ||||||
| +#define PRINT_VM_DATA(buf4, buf5, tm)                                    \
 |  | ||||||
|                  {                                                        \ |  | ||||||
|                  fprintf(fp, "%s  %s  ",                                  \ |  | ||||||
|                      mkstring(buf4, VADDR_PRLEN, CENTER|LJUST, "MM"),     \ |  | ||||||
| @@ -3896,9 +3923,9 @@ bailout:
 |  | ||||||
|                      mkstring(buf5, 8, CENTER|LJUST, NULL));              \ |  | ||||||
|  	        } |  | ||||||
|   |  | ||||||
| -#define PRINT_VMA_DATA()                                                       \
 |  | ||||||
| +#define PRINT_VMA_DATA(buf1, buf2, buf3, buf4, vma)                            \
 |  | ||||||
|  	fprintf(fp, "%s%s%s%s%s %6llx%s%s\n",                                  \ |  | ||||||
| -                mkstring(buf4, VADDR_PRLEN, CENTER|LJUST|LONG_HEX, MKSTR(vma)),       \
 |  | ||||||
| +                mkstring(buf4, VADDR_PRLEN, CENTER|LJUST|LONG_HEX, MKSTR(vma)),\
 |  | ||||||
|  	        space(MINSPACE),                                               \ |  | ||||||
|                  mkstring(buf2, UVADDR_PRLEN, RJUST|LONG_HEX, MKSTR(vm_start)), \ |  | ||||||
|                  space(MINSPACE),                                               \ |  | ||||||
| @@ -3925,18 +3952,137 @@ bailout:
 |  | ||||||
|     (DO_REF_SEARCH(X) && (string_exists(S)) && FILENAME_COMPONENT((S),(X)->str)) |  | ||||||
|  #define VM_REF_FOUND(X)    ((X) && ((X)->cmdflags & VM_REF_HEADER)) |  | ||||||
|   |  | ||||||
| -ulong
 |  | ||||||
| -vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
 |  | ||||||
| +static ulong handle_each_vm_area(struct handle_each_vm_area_args *args)
 |  | ||||||
|  { |  | ||||||
| -        struct task_context *tc;
 |  | ||||||
| -	ulong vma;
 |  | ||||||
| +	char *dentry_buf, *file_buf;
 |  | ||||||
|  	ulong vm_start; |  | ||||||
|  	ulong vm_end; |  | ||||||
| -	ulong vm_next, vm_mm;
 |  | ||||||
| -	char *dentry_buf, *vma_buf, *file_buf;
 |  | ||||||
| +	ulong vm_mm;
 |  | ||||||
|  	ulonglong vm_flags; |  | ||||||
|  	ulong vm_file, inode; |  | ||||||
|  	ulong dentry, vfsmnt; |  | ||||||
| +
 |  | ||||||
| +	if ((args->flag & PHYSADDR) && !DO_REF_SEARCH(args->ref))
 |  | ||||||
| +		fprintf(fp, "%s", args->vma_header);
 |  | ||||||
| +
 |  | ||||||
| +	inode = 0;
 |  | ||||||
| +	BZERO(args->buf1, BUFSIZE);
 |  | ||||||
| +	*(args->vma_buf) = fill_vma_cache(args->vma);
 |  | ||||||
| +
 |  | ||||||
| +	vm_mm = ULONG(*(args->vma_buf) + OFFSET(vm_area_struct_vm_mm));
 |  | ||||||
| +	vm_end = ULONG(*(args->vma_buf) + OFFSET(vm_area_struct_vm_end));
 |  | ||||||
| +	vm_start = ULONG(*(args->vma_buf) + OFFSET(vm_area_struct_vm_start));
 |  | ||||||
| +	vm_flags = get_vm_flags(*(args->vma_buf));
 |  | ||||||
| +	vm_file = ULONG(*(args->vma_buf) + OFFSET(vm_area_struct_vm_file));
 |  | ||||||
| +
 |  | ||||||
| +	if (args->flag & PRINT_SINGLE_VMA) {
 |  | ||||||
| +		if (args->vma != *(args->single_vma))
 |  | ||||||
| +			return 0;
 |  | ||||||
| +		fprintf(fp, "%s", args->vma_header);
 |  | ||||||
| +		*(args->single_vma_found) = TRUE;
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	if (args->flag & PRINT_VMA_STRUCTS) {
 |  | ||||||
| +		dump_struct("vm_area_struct", args->vma, args->radix);
 |  | ||||||
| +		return 0;
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	if (vm_file && !(args->flag & VERIFY_ADDR)) {
 |  | ||||||
| +		file_buf = fill_file_cache(vm_file);
 |  | ||||||
| +		dentry = ULONG(file_buf + OFFSET(file_f_dentry));
 |  | ||||||
| +		dentry_buf = NULL;
 |  | ||||||
| +		if (dentry) {
 |  | ||||||
| +			dentry_buf = fill_dentry_cache(dentry);
 |  | ||||||
| +			if (VALID_MEMBER(file_f_vfsmnt)) {
 |  | ||||||
| +				vfsmnt = ULONG(file_buf + OFFSET(file_f_vfsmnt));
 |  | ||||||
| +				get_pathname(dentry, args->buf1, BUFSIZE, 1, vfsmnt);
 |  | ||||||
| +			} else
 |  | ||||||
| +				get_pathname(dentry, args->buf1, BUFSIZE, 1, 0);
 |  | ||||||
| +		}
 |  | ||||||
| +		if ((args->flag & PRINT_INODES) && dentry)
 |  | ||||||
| +			inode = ULONG(dentry_buf + OFFSET(dentry_d_inode));
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	if (!(args->flag & UVADDR) || ((args->flag & UVADDR) &&
 |  | ||||||
| +	    ((args->vaddr >= vm_start) && (args->vaddr < vm_end)))) {
 |  | ||||||
| +		*(args->found) = TRUE;
 |  | ||||||
| +
 |  | ||||||
| +		if (args->flag & VERIFY_ADDR)
 |  | ||||||
| +			return args->vma;
 |  | ||||||
| +
 |  | ||||||
| +		if (DO_REF_SEARCH(args->ref)) {
 |  | ||||||
| +			if (VM_REF_CHECK_HEXVAL(args->ref, args->vma) ||
 |  | ||||||
| +			    VM_REF_CHECK_HEXVAL(args->ref, (ulong)vm_flags) ||
 |  | ||||||
| +			    VM_REF_CHECK_STRING(args->ref, args->buf1)) {
 |  | ||||||
| +				if (!(args->ref->cmdflags & VM_REF_HEADER)) {
 |  | ||||||
| +					print_task_header(fp, args->tc, 0);
 |  | ||||||
| +					PRINT_VM_DATA(args->buf4, args->buf5, args->tm);
 |  | ||||||
| +					args->ref->cmdflags |= VM_REF_HEADER;
 |  | ||||||
| +				}
 |  | ||||||
| +				if (!(args->ref->cmdflags & VM_REF_VMA) ||
 |  | ||||||
| +				    (args->ref->cmdflags & VM_REF_PAGE)) {
 |  | ||||||
| +					fprintf(fp, "%s", args->vma_header);
 |  | ||||||
| +					args->ref->cmdflags |= VM_REF_VMA;
 |  | ||||||
| +					args->ref->cmdflags &= ~VM_REF_PAGE;
 |  | ||||||
| +					args->ref->ref1 = args->vma;
 |  | ||||||
| +				}
 |  | ||||||
| +				PRINT_VMA_DATA(args->buf1, args->buf2,
 |  | ||||||
| +						args->buf3, args->buf4, args->vma);
 |  | ||||||
| +			}
 |  | ||||||
| +
 |  | ||||||
| +			if (vm_area_page_dump(args->vma, args->task,
 |  | ||||||
| +			    vm_start, vm_end, vm_mm, args->ref)) {
 |  | ||||||
| +				if (!(args->ref->cmdflags & VM_REF_HEADER)) {
 |  | ||||||
| +					print_task_header(fp, args->tc, 0);
 |  | ||||||
| +					PRINT_VM_DATA(args->buf4, args->buf5, args->tm);
 |  | ||||||
| +					args->ref->cmdflags |= VM_REF_HEADER;
 |  | ||||||
| +				}
 |  | ||||||
| +				if (!(args->ref->cmdflags & VM_REF_VMA) ||
 |  | ||||||
| +				    (args->ref->ref1 != args->vma)) {
 |  | ||||||
| +					fprintf(fp, "%s", args->vma_header);
 |  | ||||||
| +					PRINT_VMA_DATA(args->buf1, args->buf2,
 |  | ||||||
| +							args->buf3, args->buf4, args->vma);
 |  | ||||||
| +					args->ref->cmdflags |= VM_REF_VMA;
 |  | ||||||
| +					args->ref->ref1 = args->vma;
 |  | ||||||
| +				}
 |  | ||||||
| +
 |  | ||||||
| +				args->ref->cmdflags |= VM_REF_DISPLAY;
 |  | ||||||
| +				vm_area_page_dump(args->vma, args->task,
 |  | ||||||
| +					vm_start, vm_end, vm_mm, args->ref);
 |  | ||||||
| +				args->ref->cmdflags &= ~VM_REF_DISPLAY;
 |  | ||||||
| +			}
 |  | ||||||
| +
 |  | ||||||
| +			return 0;
 |  | ||||||
| +		}
 |  | ||||||
| +
 |  | ||||||
| +		if (inode) {
 |  | ||||||
| +			fprintf(fp, "%lx%s%s%s%s%s%6llx%s%lx %s\n",
 |  | ||||||
| +				args->vma, space(MINSPACE),
 |  | ||||||
| +				mkstring(args->buf2, UVADDR_PRLEN, RJUST|LONG_HEX,
 |  | ||||||
| +				MKSTR(vm_start)), space(MINSPACE),
 |  | ||||||
| +				mkstring(args->buf3, UVADDR_PRLEN, RJUST|LONG_HEX,
 |  | ||||||
| +				MKSTR(vm_end)), space(MINSPACE),
 |  | ||||||
| +				vm_flags, space(MINSPACE), inode, args->buf1);
 |  | ||||||
| +		} else {
 |  | ||||||
| +			PRINT_VMA_DATA(args->buf1, args->buf2,
 |  | ||||||
| +					args->buf3, args->buf4, args->vma);
 |  | ||||||
| +
 |  | ||||||
| +			if (args->flag & (PHYSADDR|PRINT_SINGLE_VMA))
 |  | ||||||
| +				vm_area_page_dump(args->vma, args->task,
 |  | ||||||
| +				    vm_start, vm_end, vm_mm, args->ref);
 |  | ||||||
| +		}
 |  | ||||||
| +
 |  | ||||||
| +		if (args->flag & UVADDR)
 |  | ||||||
| +			return args->vma;
 |  | ||||||
| +	}
 |  | ||||||
| +	return 0;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +ulong
 |  | ||||||
| +vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
 |  | ||||||
| +{
 |  | ||||||
| +	struct task_context *tc;
 |  | ||||||
| +	ulong vma;
 |  | ||||||
|  	ulong single_vma; |  | ||||||
|  	unsigned int radix; |  | ||||||
|  	int single_vma_found; |  | ||||||
| @@ -3948,6 +4094,10 @@ vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
 |  | ||||||
|  	char buf4[BUFSIZE]; |  | ||||||
|  	char buf5[BUFSIZE]; |  | ||||||
|  	char vma_header[BUFSIZE]; |  | ||||||
| +	char *vma_buf;
 |  | ||||||
| +	int i;
 |  | ||||||
| +	ulong mm_mt, entry_num;
 |  | ||||||
| +	struct list_pair *entry_list;
 |  | ||||||
|   |  | ||||||
|          tc = task_to_context(task); |  | ||||||
|  	tm = &task_mem_usage; |  | ||||||
| @@ -3981,14 +4131,14 @@ vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
 |  | ||||||
|          if (VM_REF_CHECK_HEXVAL(ref, tm->mm_struct_addr) || |  | ||||||
|              VM_REF_CHECK_HEXVAL(ref, tm->pgd_addr)) { |  | ||||||
|          	print_task_header(fp, tc, 0); |  | ||||||
| -		PRINT_VM_DATA();
 |  | ||||||
| +		PRINT_VM_DATA(buf4, buf5, tm);
 |  | ||||||
|  		fprintf(fp, "\n"); |  | ||||||
|                  return (ulong)NULL; |  | ||||||
|          } |  | ||||||
|   |  | ||||||
|          if (!(flag & (UVADDR|PRINT_MM_STRUCT|PRINT_VMA_STRUCTS|PRINT_SINGLE_VMA)) && |  | ||||||
|  	    !DO_REF_SEARCH(ref))  |  | ||||||
| -		PRINT_VM_DATA();
 |  | ||||||
| +		PRINT_VM_DATA(buf4, buf5, tm);
 |  | ||||||
|   |  | ||||||
|          if (!tm->mm_struct_addr) { |  | ||||||
|  		if (pc->curcmd_flags & MM_STRUCT_FORCE) { |  | ||||||
| @@ -4012,9 +4162,6 @@ vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
 |  | ||||||
|                  return (ulong)NULL; |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| -	readmem(tm->mm_struct_addr + OFFSET(mm_struct_mmap), KVADDR, 
 |  | ||||||
| -		&vma, sizeof(void *), "mm_struct mmap", FAULT_ON_ERROR);
 |  | ||||||
| -
 |  | ||||||
|         	sprintf(vma_header, "%s%s%s%s%s  FLAGS%sFILE\n", |  | ||||||
|                  mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "VMA"), |  | ||||||
|                  space(MINSPACE),               |  | ||||||
| @@ -4027,125 +4174,41 @@ vm_area_dump(ulong task, ulong flag, ulong vaddr, struct reference *ref)
 |  | ||||||
|  	    !DO_REF_SEARCH(ref))  |  | ||||||
|  		fprintf(fp, "%s", vma_header); |  | ||||||
|   |  | ||||||
| -	for (found = FALSE; vma; vma = vm_next) {
 |  | ||||||
| -
 |  | ||||||
| -		if ((flag & PHYSADDR) && !DO_REF_SEARCH(ref))
 |  | ||||||
| -			fprintf(fp, "%s", vma_header);
 |  | ||||||
| -
 |  | ||||||
| -		inode = 0;
 |  | ||||||
| -		BZERO(buf1, BUFSIZE);
 |  | ||||||
| -		vma_buf = fill_vma_cache(vma);
 |  | ||||||
| -
 |  | ||||||
| -		vm_mm = ULONG(vma_buf + OFFSET(vm_area_struct_vm_mm));
 |  | ||||||
| -		vm_end = ULONG(vma_buf + OFFSET(vm_area_struct_vm_end));
 |  | ||||||
| -		vm_next = ULONG(vma_buf + OFFSET(vm_area_struct_vm_next));
 |  | ||||||
| -		vm_start = ULONG(vma_buf + OFFSET(vm_area_struct_vm_start));
 |  | ||||||
| -		vm_flags = get_vm_flags(vma_buf);
 |  | ||||||
| -		vm_file = ULONG(vma_buf + OFFSET(vm_area_struct_vm_file));
 |  | ||||||
| -		
 |  | ||||||
| -		if (flag & PRINT_SINGLE_VMA) {
 |  | ||||||
| -			if (vma != single_vma)
 |  | ||||||
| -				continue;
 |  | ||||||
| -			fprintf(fp, "%s", vma_header);
 |  | ||||||
| -			single_vma_found = TRUE;
 |  | ||||||
| -		}
 |  | ||||||
| -
 |  | ||||||
| -		if (flag & PRINT_VMA_STRUCTS) {
 |  | ||||||
| -			dump_struct("vm_area_struct", vma, radix);
 |  | ||||||
| -			continue;
 |  | ||||||
| -		}
 |  | ||||||
| +	found = FALSE;
 |  | ||||||
|   |  | ||||||
| -		if (vm_file && !(flag & VERIFY_ADDR)) {
 |  | ||||||
| -			file_buf = fill_file_cache(vm_file);
 |  | ||||||
| -			dentry = ULONG(file_buf + OFFSET(file_f_dentry));
 |  | ||||||
| -			dentry_buf = NULL;
 |  | ||||||
| -			if (dentry) {
 |  | ||||||
| -				dentry_buf = fill_dentry_cache(dentry);
 |  | ||||||
| -				if (VALID_MEMBER(file_f_vfsmnt)) {
 |  | ||||||
| -					vfsmnt = ULONG(file_buf +
 |  | ||||||
| -                                		OFFSET(file_f_vfsmnt));
 |  | ||||||
| -					get_pathname(dentry, buf1, BUFSIZE,
 |  | ||||||
| -						1, vfsmnt);
 |  | ||||||
| -				} else {
 |  | ||||||
| -					get_pathname(dentry, buf1, BUFSIZE, 
 |  | ||||||
| -						1, 0);
 |  | ||||||
| -				}
 |  | ||||||
| -			}
 |  | ||||||
| -			if ((flag & PRINT_INODES) && dentry) {
 |  | ||||||
| -				inode = ULONG(dentry_buf + 
 |  | ||||||
| -					OFFSET(dentry_d_inode));
 |  | ||||||
| +	struct handle_each_vm_area_args args = {
 |  | ||||||
| +		.task = task,		.flag = flag,	.vaddr = vaddr,
 |  | ||||||
| +		.ref = ref,		.tc = tc,	.radix = radix,
 |  | ||||||
| +		.tm = tm,		.buf1 = buf1,	.buf2 = buf2,
 |  | ||||||
| +		.buf3 = buf3,		.buf4 = buf4,	.buf5 = buf5,
 |  | ||||||
| +		.vma_header = vma_header,		.single_vma = &single_vma,
 |  | ||||||
| +		.single_vma_found = &single_vma_found,	.found = &found,
 |  | ||||||
| +		.vma_buf = &vma_buf,
 |  | ||||||
| +	};
 |  | ||||||
| +
 |  | ||||||
| +	if (INVALID_MEMBER(mm_struct_mmap) && VALID_MEMBER(mm_struct_mm_mt)) {
 |  | ||||||
| +		mm_mt = tm->mm_struct_addr + OFFSET(mm_struct_mm_mt);
 |  | ||||||
| +		entry_num = do_maple_tree(mm_mt, MAPLE_TREE_COUNT, NULL);
 |  | ||||||
| +		entry_list = (struct list_pair *)GETBUF(entry_num * sizeof(struct list_pair));
 |  | ||||||
| +		do_maple_tree(mm_mt, MAPLE_TREE_GATHER, entry_list);
 |  | ||||||
| +
 |  | ||||||
| +		for (i = 0; i < entry_num; i++) {
 |  | ||||||
| +			if (!!(args.vma = (ulong)entry_list[i].value) &&
 |  | ||||||
| +			    handle_each_vm_area(&args)) {
 |  | ||||||
| +				FREEBUF(entry_list);
 |  | ||||||
| +				return args.vma;
 |  | ||||||
|  			} |  | ||||||
|  		} |  | ||||||
| -
 |  | ||||||
| -		if (!(flag & UVADDR) || ((flag & UVADDR) && 
 |  | ||||||
| -		    ((vaddr >= vm_start) && (vaddr < vm_end)))) {
 |  | ||||||
| -			found = TRUE;
 |  | ||||||
| -
 |  | ||||||
| -			if (flag & VERIFY_ADDR)
 |  | ||||||
| -				return vma;
 |  | ||||||
| -
 |  | ||||||
| -			if (DO_REF_SEARCH(ref)) {
 |  | ||||||
| -				if (VM_REF_CHECK_HEXVAL(ref, vma) ||
 |  | ||||||
| -				    VM_REF_CHECK_HEXVAL(ref, (ulong)vm_flags) ||
 |  | ||||||
| -				    VM_REF_CHECK_STRING(ref, buf1)) {
 |  | ||||||
| -					if (!(ref->cmdflags & VM_REF_HEADER)) {
 |  | ||||||
| -						print_task_header(fp, tc, 0);
 |  | ||||||
| -                				PRINT_VM_DATA();
 |  | ||||||
| -						ref->cmdflags |= VM_REF_HEADER;
 |  | ||||||
| -					}
 |  | ||||||
| -					if (!(ref->cmdflags & VM_REF_VMA) ||
 |  | ||||||
| -					    (ref->cmdflags & VM_REF_PAGE)) { 
 |  | ||||||
| -						fprintf(fp, "%s", vma_header);
 |  | ||||||
| -						ref->cmdflags |= VM_REF_VMA;
 |  | ||||||
| -						ref->cmdflags &= ~VM_REF_PAGE;
 |  | ||||||
| -						ref->ref1 = vma;
 |  | ||||||
| -					}
 |  | ||||||
| -					PRINT_VMA_DATA();
 |  | ||||||
| -				}
 |  | ||||||
| -
 |  | ||||||
| -				if (vm_area_page_dump(vma, task, 
 |  | ||||||
| -				    vm_start, vm_end, vm_mm, ref)) {
 |  | ||||||
| -					if (!(ref->cmdflags & VM_REF_HEADER)) {
 |  | ||||||
| -					        print_task_header(fp, tc, 0);
 |  | ||||||
| -                			        PRINT_VM_DATA();
 |  | ||||||
| -						ref->cmdflags |= VM_REF_HEADER;
 |  | ||||||
| -					}
 |  | ||||||
| -                                        if (!(ref->cmdflags & VM_REF_VMA) ||
 |  | ||||||
| -                                            (ref->ref1 != vma)) {
 |  | ||||||
| -                                                fprintf(fp, "%s", vma_header);
 |  | ||||||
| -						PRINT_VMA_DATA();
 |  | ||||||
| -                                                ref->cmdflags |= VM_REF_VMA;
 |  | ||||||
| -                                                ref->ref1 = vma;
 |  | ||||||
| -					}
 |  | ||||||
| -
 |  | ||||||
| -					ref->cmdflags |= VM_REF_DISPLAY;
 |  | ||||||
| -					vm_area_page_dump(vma, task,
 |  | ||||||
| -						vm_start, vm_end, vm_mm, ref); 
 |  | ||||||
| -					ref->cmdflags &= ~VM_REF_DISPLAY;
 |  | ||||||
| -				}
 |  | ||||||
| -
 |  | ||||||
| -				continue;
 |  | ||||||
| -			}
 |  | ||||||
| -
 |  | ||||||
| -			if (inode) {
 |  | ||||||
| -                                fprintf(fp, "%lx%s%s%s%s%s%6llx%s%lx %s\n",
 |  | ||||||
| -                                    vma, space(MINSPACE),               
 |  | ||||||
| -                                    mkstring(buf2, UVADDR_PRLEN, RJUST|LONG_HEX,
 |  | ||||||
| -                                        MKSTR(vm_start)), space(MINSPACE),      
 |  | ||||||
| -                                    mkstring(buf3, UVADDR_PRLEN, RJUST|LONG_HEX,
 |  | ||||||
| -                                        MKSTR(vm_end)), space(MINSPACE), 
 |  | ||||||
| -				    vm_flags, space(MINSPACE), inode, buf1);
 |  | ||||||
| -			} else {
 |  | ||||||
| -				PRINT_VMA_DATA();
 |  | ||||||
| -				     
 |  | ||||||
| -				if (flag & (PHYSADDR|PRINT_SINGLE_VMA)) 
 |  | ||||||
| -					vm_area_page_dump(vma, task,
 |  | ||||||
| -						vm_start, vm_end, vm_mm, ref);
 |  | ||||||
| -			}
 |  | ||||||
| -
 |  | ||||||
| -			if (flag & UVADDR)
 |  | ||||||
| +		FREEBUF(entry_list);
 |  | ||||||
| +	} else {
 |  | ||||||
| +		readmem(tm->mm_struct_addr + OFFSET(mm_struct_mmap), KVADDR,
 |  | ||||||
| +			&vma, sizeof(void *), "mm_struct mmap", FAULT_ON_ERROR);
 |  | ||||||
| +		while (vma) {
 |  | ||||||
| +			args.vma = vma;
 |  | ||||||
| +			if (handle_each_vm_area(&args))
 |  | ||||||
|  				return vma; |  | ||||||
| -		} 
 |  | ||||||
| +			vma = ULONG(vma_buf + OFFSET(vm_area_struct_vm_next));
 |  | ||||||
| +		}
 |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
|  	if (flag & VERIFY_ADDR) |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,135 +0,0 @@ | |||||||
| From 49f6c2095d82700b7845ad9a09cb6942cc114b52 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Tao Liu <ltao@redhat.com> |  | ||||||
| Date: Tue, 10 Jan 2023 14:56:31 +0800 |  | ||||||
| Subject: [PATCH 27/28] Update the help text of "tree" command for maple tree |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Tao Liu <ltao@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  help.c | 86 +++++++++++++++++++++++++++++++++++++++++++--------------- |  | ||||||
|  1 file changed, 64 insertions(+), 22 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/help.c b/help.c
 |  | ||||||
| index 367500fc280d..56a9d8274525 100644
 |  | ||||||
| --- a/help.c
 |  | ||||||
| +++ b/help.c
 |  | ||||||
| @@ -6307,19 +6307,20 @@ NULL
 |  | ||||||
|   |  | ||||||
|  char *help_tree[] = { |  | ||||||
|  "tree", |  | ||||||
| -"display radix tree, XArray or red-black tree",
 |  | ||||||
| -"[-t [radix|xarray|rbtree]] [-r offset] [-[s|S] struct[.member[,member]]]\n       -[x|d] [-o offset] [-l] [-p] [-N] start",
 |  | ||||||
| -"  This command dumps the contents of a radix tree, an XAarray, or a red-black",
 |  | ||||||
| -"  tree.  The arguments are as follows:\n",
 |  | ||||||
| +"display radix tree, XArray, red-black tree or maple tree",
 |  | ||||||
| +"[-t [radix|xarray|rbtree|maple]] [-r offset] [-[s|S] struct[.member[,member]]]\n"
 |  | ||||||
| +"       -[x|d] [-o offset] [-l] [-p] [-v] [-N] start",
 |  | ||||||
| +"  This command dumps the contents of a radix tree, an XAarray, a red-black",
 |  | ||||||
| +"  tree, or a maple tree.  The arguments are as follows:\n",
 |  | ||||||
|  "    -t type  The type of tree to dump; the type string can be one of ", |  | ||||||
| -"             \"radix\", \"rbtree\", or \"xarray\", or alternatively, \"ra\",",
 |  | ||||||
| -"             \"rb\" or \"x\" are acceptable.  If not specified, rbtree is the",
 |  | ||||||
| -"             default type.",
 |  | ||||||
| +"             \"radix\", \"rbtree\", \"xarray\", or \"maple\", or alternatively,",
 |  | ||||||
| +"             \"ra\", \"rb\", \"x\" or \"m\" are acceptable. If not specified,",
 |  | ||||||
| +"             rbtree is the default type.",
 |  | ||||||
|  "  -r offset  If the \"start\" argument is the address of a data structure that", |  | ||||||
| -"             contains an radix_tree_root, xarray or rb_root structure, then this", 
 |  | ||||||
| -"             is the offset to that structure member.  If the offset is non-zero,",
 |  | ||||||
| -"             then this option is required.  The offset may be entered in either",
 |  | ||||||
| -"             of two manners:",
 |  | ||||||
| +"             contains an radix_tree_root, maple_tree, xarray or rb_root",
 |  | ||||||
| +"             structure, then this is the offset to that structure member. If",
 |  | ||||||
| +"             the offset is non-zero, then this option is required.  The offset",
 |  | ||||||
| +"             may be entered in either of two manners:",
 |  | ||||||
|  "               1. In \"structure.member\" format.", |  | ||||||
|  "               2. A number of bytes.", |  | ||||||
|  "  -o offset  For red-black trees only, the offset of the rb_node within its ", |  | ||||||
| @@ -6348,25 +6349,26 @@ char *help_tree[] = {
 |  | ||||||
|  "         -p  Display the node's position information, showing the relationship", |  | ||||||
|  "             between it and the root.  For red-black trees, a position that", |  | ||||||
|  "             indicates \"root/l/r\" means that the node is the right child", |  | ||||||
| -"             of the left child of the root node.  For radix trees and xarrays,",
 |  | ||||||
| -"             the index, the height, and the slot index values are shown with",
 |  | ||||||
| -"             respect to the root.",
 |  | ||||||
| +"             of the left child of the root node.  For radix trees, xarrays and",
 |  | ||||||
| +"             maple trees, the index, the height, and the slot index values are",
 |  | ||||||
| +"             shown with respect to the root.",
 |  | ||||||
|  "         -x  Override default output format with hexadecimal format.", |  | ||||||
|  "         -d  Override default output format with decimal format.", |  | ||||||
| +"         -v  For maple trees only, dump the contents of each maple tree node.",
 |  | ||||||
|  " ", |  | ||||||
|  "  The meaning of the \"start\" argument, which can be expressed either in", |  | ||||||
|  "  hexadecimal format or symbolically, depends upon whether the -N option", |  | ||||||
|  "  is prepended:", |  | ||||||
|  " ", |  | ||||||
| -"      start  The address of a radix_tree_root, xarray or rb_root structure, or",
 |  | ||||||
| -"             the address of a structure containing the radix_tree_root, xarray",
 |  | ||||||
| -"             or rb_root structure; if the latter, then the \"-r offset\" option",
 |  | ||||||
| -"             must be used if the member offset of the root structure is ",
 |  | ||||||
| -"             non-zero.",
 |  | ||||||
| +"      start  The address of a radix_tree_root, maple_tree, xarray or rb_root",
 |  | ||||||
| +"             structure, or the address of a structure containing the",
 |  | ||||||
| +"             radix_tree_root, maple_tree, xarray or rb_root structure; if the",
 |  | ||||||
| +"             latter, then the \"-r offset\" option must be used if the member",
 |  | ||||||
| +"             offset of the root structure is non-zero.",
 |  | ||||||
|  "               ", |  | ||||||
| -"   -N start  The address of a radix_tree_node, xa_node or rb_node structure,",
 |  | ||||||
| -"             bypassing the radix_tree_root, xarray, or rb_root that points",
 |  | ||||||
| -"             to it.",
 |  | ||||||
| +"   -N start  The address of a radix_tree_node, maple_node, xa_node or rb_node",
 |  | ||||||
| +"             structure, bypassing the radix_tree_root, maple_tree, xarray, or",
 |  | ||||||
| +"             rb_root that points to it.",
 |  | ||||||
|  "", |  | ||||||
|  "\nEXAMPLES", |  | ||||||
|  "  The vmap_area_root is a standalone rb_root structure.  Display the ", |  | ||||||
| @@ -6703,6 +6705,46 @@ char *help_tree[] = {
 |  | ||||||
|  "      _refcount = {", |  | ||||||
|  "        counter = 0x1", |  | ||||||
|  "      }", |  | ||||||
| +"",
 |  | ||||||
| +"  The -v option is introduced specifically for dumping the complete content of",
 |  | ||||||
| +"  maple tree:",
 |  | ||||||
| +"",
 |  | ||||||
| +"    %s> tree -t maple 0xffff9034c006aec0 -v",
 |  | ||||||
| +"",
 |  | ||||||
| +"    maple_tree(ffff9034c006aec0) flags 309, height 2 root 0xffff9034de70041e",
 |  | ||||||
| +"",
 |  | ||||||
| +"    0-18446744073709551615: node 0xffff9034de700400 depth 0 type 3 parent ...",
 |  | ||||||
| +"      0-140112331583487: node 0xffff9034c01e8800 depth 1 type 1 parent ...",
 |  | ||||||
| +"        0-94643156942847: 0x0",
 |  | ||||||
| +"        94643156942848-94643158024191: 0xffff9035131754c0",
 |  | ||||||
| +"        94643158024192-94643160117247: 0x0",
 |  | ||||||
| +"        ...",
 |  | ||||||
| +"",
 |  | ||||||
| +"  The existing options can work as well for maple tree:",
 |  | ||||||
| +"",
 |  | ||||||
| +"    %s> tree -t maple -r mm_struct.mm_mt 0xffff9034c006aec0 -p",
 |  | ||||||
| +"    ffff9035131754c0",
 |  | ||||||
| +"      index: 1  position: root/0/1",
 |  | ||||||
| +"    ffff9035131751c8",
 |  | ||||||
| +"      index: 2  position: root/0/3",
 |  | ||||||
| +"    ffff9035131757b8",
 |  | ||||||
| +"      index: 3  position: root/0/4",
 |  | ||||||
| +"    ...",
 |  | ||||||
| +"",
 |  | ||||||
| +"    %s> tree -t maple 0xffff9034c006aec0 -p -x -s vm_area_struct.vm_start,vm_end",
 |  | ||||||
| +"    ffff9035131754c0",
 |  | ||||||
| +"      index: 1  position: root/0/1",
 |  | ||||||
| +"      vm_start = 0x5613d3c00000,",
 |  | ||||||
| +"      vm_end = 0x5613d3d08000,",
 |  | ||||||
| +"    ffff9035131751c8",
 |  | ||||||
| +"      index: 2  position: root/0/3",
 |  | ||||||
| +"      vm_start = 0x5613d3f07000,",
 |  | ||||||
| +"      vm_end = 0x5613d3f0b000,",
 |  | ||||||
| +"    ffff9035131757b8",
 |  | ||||||
| +"      index: 3  position: root/0/4",
 |  | ||||||
| +"      vm_start = 0x5613d3f0b000,",
 |  | ||||||
| +"      vm_end = 0x5613d3f14000,",
 |  | ||||||
| +"    ....",
 |  | ||||||
|  NULL |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,52 +0,0 @@ | |||||||
| From 46344aa2f92b07ded52cf9841f8db24dd7fe67d7 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Tao Liu <ltao@redhat.com> |  | ||||||
| Date: Tue, 10 Jan 2023 14:56:32 +0800 |  | ||||||
| Subject: [PATCH 28/28] Dump maple tree offset variables by "help -o" |  | ||||||
| 
 |  | ||||||
| In the previous patches, some variables are added to offset_table and |  | ||||||
| size_table, print them out with "help -o" command. |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Tao Liu <ltao@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  symbols.c | 17 +++++++++++++++++ |  | ||||||
|  1 file changed, 17 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/symbols.c b/symbols.c
 |  | ||||||
| index 33e68d520a72..e38df8aad0f5 100644
 |  | ||||||
| --- a/symbols.c
 |  | ||||||
| +++ b/symbols.c
 |  | ||||||
| @@ -10766,6 +10766,21 @@ dump_offset_table(char *spec, ulong makestruct)
 |  | ||||||
|  		OFFSET(sbq_wait_state_wait_cnt)); |  | ||||||
|  	fprintf(fp, "           sbq_wait_state_wait: %ld\n", |  | ||||||
|  		OFFSET(sbq_wait_state_wait)); |  | ||||||
| +	fprintf(fp, "               mm_struct_mm_mt: %ld\n", OFFSET(mm_struct_mm_mt));
 |  | ||||||
| +	fprintf(fp, "            maple_tree_ma_root: %ld\n", OFFSET(maple_tree_ma_root));
 |  | ||||||
| +	fprintf(fp, "           maple_tree_ma_flags: %ld\n", OFFSET(maple_tree_ma_flags));
 |  | ||||||
| +	fprintf(fp, "             maple_node_parent: %ld\n", OFFSET(maple_node_parent));
 |  | ||||||
| +	fprintf(fp, "               maple_node_ma64: %ld\n", OFFSET(maple_node_ma64));
 |  | ||||||
| +	fprintf(fp, "               maple_node_mr64: %ld\n", OFFSET(maple_node_mr64));
 |  | ||||||
| +	fprintf(fp, "               maple_node_slot: %ld\n", OFFSET(maple_node_slot));
 |  | ||||||
| +	fprintf(fp, "         maple_arange_64_pivot: %ld\n", OFFSET(maple_arange_64_pivot));
 |  | ||||||
| +	fprintf(fp, "          maple_arange_64_slot: %ld\n", OFFSET(maple_arange_64_slot));
 |  | ||||||
| +	fprintf(fp, "           maple_arange_64_gap: %ld\n", OFFSET(maple_arange_64_gap));
 |  | ||||||
| +	fprintf(fp, "          maple_arange_64_meta: %ld\n", OFFSET(maple_arange_64_meta));
 |  | ||||||
| +	fprintf(fp, "          maple_range_64_pivot: %ld\n", OFFSET(maple_range_64_pivot));
 |  | ||||||
| +	fprintf(fp, "           maple_range_64_slot: %ld\n", OFFSET(maple_range_64_slot));
 |  | ||||||
| +	fprintf(fp, "            maple_metadata_end: %ld\n", OFFSET(maple_metadata_end));
 |  | ||||||
| +	fprintf(fp, "            maple_metadata_gap: %ld\n", OFFSET(maple_metadata_gap));
 |  | ||||||
|   |  | ||||||
|  	fprintf(fp, "\n                    size_table:\n"); |  | ||||||
|  	fprintf(fp, "                          page: %ld\n", SIZE(page)); |  | ||||||
| @@ -11038,6 +11053,8 @@ dump_offset_table(char *spec, ulong makestruct)
 |  | ||||||
|  	fprintf(fp, "                 sbitmap_queue: %ld\n", SIZE(sbitmap_queue)); |  | ||||||
|  	fprintf(fp, "                sbq_wait_state: %ld\n", SIZE(sbq_wait_state)); |  | ||||||
|  	fprintf(fp, "                   blk_mq_tags: %ld\n", SIZE(blk_mq_tags)); |  | ||||||
| +	fprintf(fp, "                    maple_tree: %ld\n", SIZE(maple_tree));
 |  | ||||||
| +	fprintf(fp, "                    maple_node: %ld\n", SIZE(maple_node));
 |  | ||||||
|   |  | ||||||
|  	fprintf(fp, "                percpu_counter: %ld\n", SIZE(percpu_counter)); |  | ||||||
|   |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,80 +0,0 @@ | |||||||
| From 92de7c34b1f910abff4d77522f74454ea0263a90 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Mon, 13 Feb 2023 11:12:12 +0800 |  | ||||||
| Subject: [PATCH 01/12] Fix for "bt" command printing "bogus exception frame" |  | ||||||
|  warning |  | ||||||
| 
 |  | ||||||
| Currently, the "bt" command may print a bogus exception frame |  | ||||||
| and the remaining frame will be truncated on x86_64 when using the |  | ||||||
| "virsh send-key <kvm guest> KEY_LEFTALT KEY_SYSRQ KEY_C" command |  | ||||||
| to trigger a panic from the KVM host. For example: |  | ||||||
| 
 |  | ||||||
|   crash> bt |  | ||||||
|   PID: 0        TASK: ffff9e7a47e32f00  CPU: 3    COMMAND: "swapper/3" |  | ||||||
|    #0 [ffffba7900118bb8] machine_kexec at ffffffff87e5c2c7 |  | ||||||
|    #1 [ffffba7900118c08] __crash_kexec at ffffffff87f9500d |  | ||||||
|    #2 [ffffba7900118cd0] panic at ffffffff87edfff9 |  | ||||||
|    #3 [ffffba7900118d50] sysrq_handle_crash at ffffffff883ce2c1 |  | ||||||
|    ... |  | ||||||
|    #16 [ffffba7900118fd8] handle_edge_irq at ffffffff87f559f2 |  | ||||||
|    #17 [ffffba7900118ff0] asm_call_on_stack at ffffffff88800fa2 |  | ||||||
|    --- <IRQ stack> --- |  | ||||||
|    #18 [ffffba790008bda0] asm_call_on_stack at ffffffff88800fa2 |  | ||||||
|        RIP: ffffffffffffffff  RSP: 0000000000000124  RFLAGS: 00000003 |  | ||||||
|        RAX: 0000000000000000  RBX: 0000000000000001  RCX: 0000000000000000 |  | ||||||
|        RDX: ffffffff88800c1e  RSI: 0000000000000000  RDI: 0000000000000000 |  | ||||||
|        RBP: 0000000000000001   R8: 0000000000000000   R9: 0000000000000000 |  | ||||||
|        R10: 0000000000000000  R11: ffffffff88760555  R12: ffffba790008be08 |  | ||||||
|        R13: ffffffff87f18002  R14: ffff9e7a47e32f00  R15: ffff9e7bb6198e00 |  | ||||||
|        ORIG_RAX: 0000000000000000  CS: 0003  SS: 0000 |  | ||||||
|   bt: WARNING: possibly bogus exception frame |  | ||||||
|   crash> |  | ||||||
| 
 |  | ||||||
| The following related kernel commits cause the current issue, crash |  | ||||||
| needs to adjust the value of irq_eframe_link. |  | ||||||
| 
 |  | ||||||
| Related kernel commits: |  | ||||||
| [1] v5.8: 931b94145981 ("x86/entry: Provide helpers for executing on the irqstack") |  | ||||||
| [2] v5.8: fa5e5c409213 ("x86/entry: Use idtentry for interrupts") |  | ||||||
| [3] v5.12: 52d743f3b712 ("x86/softirq: Remove indirection in do_softirq_own_stack()") |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| ---
 |  | ||||||
|  x86_64.c | 13 +++++++++++++ |  | ||||||
|  1 file changed, 13 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/x86_64.c b/x86_64.c
 |  | ||||||
| index 7a5d6f050c89..5b671bd97775 100644
 |  | ||||||
| --- a/x86_64.c
 |  | ||||||
| +++ b/x86_64.c
 |  | ||||||
| @@ -3938,6 +3938,11 @@ in_exception_stack:
 |  | ||||||
|          if (irq_eframe) { |  | ||||||
|                  bt->flags |= BT_EXCEPTION_FRAME; |  | ||||||
|                  i = (irq_eframe - bt->stackbase)/sizeof(ulong); |  | ||||||
| +                if (symbol_exists("asm_common_interrupt")) {
 |  | ||||||
| +			i -= 1;
 |  | ||||||
| +			up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]);
 |  | ||||||
| +			bt->instptr = *up;
 |  | ||||||
| +                }
 |  | ||||||
|                  x86_64_print_stack_entry(bt, ofp, level, i, bt->instptr); |  | ||||||
|                  bt->flags &= ~(ulonglong)BT_EXCEPTION_FRAME; |  | ||||||
|                  cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0,  |  | ||||||
| @@ -6521,6 +6526,14 @@ x86_64_irq_eframe_link_init(void)
 |  | ||||||
|  	else |  | ||||||
|  		return;  |  | ||||||
|   |  | ||||||
| +	if (symbol_exists("asm_common_interrupt")) {
 |  | ||||||
| +		if (symbol_exists("asm_call_on_stack"))
 |  | ||||||
| +			machdep->machspec->irq_eframe_link = -64;
 |  | ||||||
| +		else
 |  | ||||||
| +			machdep->machspec->irq_eframe_link = -32;
 |  | ||||||
| +		return;
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
|  	if (THIS_KERNEL_VERSION < LINUX(2,6,9))  |  | ||||||
|  		return; |  | ||||||
|   |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,143 +0,0 @@ | |||||||
| From 9253b40a0ecb2d365f89f0a5ebc28a01735c1d24 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: "Aureau, Georges (Kernel Tools ERT)" <georges.aureau@hpe.com> |  | ||||||
| Date: Wed, 8 Feb 2023 12:09:03 +0000 |  | ||||||
| Subject: [PATCH 02/12] Fix "kmem -s|-S" not working properly on RHEL8.6 and |  | ||||||
|  later |  | ||||||
| 
 |  | ||||||
| For CONFIG_SLAB_FREELIST_HARDENED, the crash memory.c:freelist_ptr() |  | ||||||
| code is checking for an additional bswap using a simple release test eg. |  | ||||||
| THIS_KERNEL_VERSION >= LINUX(5,7,0), basically checking for RHEL9 and |  | ||||||
| beyond. |  | ||||||
| 
 |  | ||||||
| However, for RHEL8.6 and later, we have CONFIG_SLAB_FREELIST_HARDENED=y, |  | ||||||
| and we also have the additional bswap, but the current crash is not |  | ||||||
| handling this case, hence "kmem -s|-S" will not work properly, and free |  | ||||||
| objects will not be counted nor reported properly. |  | ||||||
| 
 |  | ||||||
| An example from a RHEL8.6 x86_64 kdump, a kmem cache with a single slab |  | ||||||
| having 42 objects, only the freelist head is seen as free as crash can't |  | ||||||
| walk freelist next pointers, and crash is wrongly reporting 41 allocated |  | ||||||
| objects: |  | ||||||
| 
 |  | ||||||
|   crash> sys | grep RELEASE |  | ||||||
|        RELEASE: 4.18.0-372.9.1.el8.x86_64 |  | ||||||
|   crash> kmem -s nfs_commit_data |  | ||||||
|   CACHE             OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZE  NAME |  | ||||||
|   ffff9ad40c7cb2c0      728         41        42      1    32k  nfs_commit_data |  | ||||||
| 
 |  | ||||||
| When properly accounting for the additional bswap, we can walk the |  | ||||||
| freelist and find 38 free objects, and crash is now reporting only 4 |  | ||||||
| allocated objects: |  | ||||||
| 
 |  | ||||||
|   crash> kmem -s nfs_commit_data |  | ||||||
|   CACHE             OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZE  NAME |  | ||||||
|   ffff9ad40c7cb2c0      728          4        42      1    32k  nfs_commit_data |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Georges Aureau <georges.aureau@hpe.com> |  | ||||||
| ---
 |  | ||||||
|  defs.h   |  1 + |  | ||||||
|  memory.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- |  | ||||||
|  2 files changed, 49 insertions(+), 1 deletion(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index 33a823b7b67c..56d6cf4489c9 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -2638,6 +2638,7 @@ struct vm_table {                /* kernel VM-related data */
 |  | ||||||
|  #define SLAB_OVERLOAD_PAGE    (0x8000000) |  | ||||||
|  #define SLAB_CPU_CACHE       (0x10000000) |  | ||||||
|  #define SLAB_ROOT_CACHES     (0x20000000) |  | ||||||
| +#define FREELIST_PTR_BSWAP   (0x40000000)
 |  | ||||||
|   |  | ||||||
|  #define IS_FLATMEM()		(vt->flags & FLATMEM) |  | ||||||
|  #define IS_DISCONTIGMEM()	(vt->flags & DISCONTIGMEM) |  | ||||||
| diff --git a/memory.c b/memory.c
 |  | ||||||
| index 5141fbea4b40..e0742c1bd3a4 100644
 |  | ||||||
| --- a/memory.c
 |  | ||||||
| +++ b/memory.c
 |  | ||||||
| @@ -320,6 +320,7 @@ static void dump_per_cpu_offsets(void);
 |  | ||||||
|  static void dump_page_flags(ulonglong); |  | ||||||
|  static ulong kmem_cache_nodelists(ulong); |  | ||||||
|  static void dump_hstates(void); |  | ||||||
| +static void freelist_ptr_init(void);
 |  | ||||||
|  static ulong freelist_ptr(struct meminfo *, ulong, ulong); |  | ||||||
|  static ulong handle_each_vm_area(struct handle_each_vm_area_args *); |  | ||||||
|   |  | ||||||
| @@ -789,6 +790,8 @@ vm_init(void)
 |  | ||||||
|  		MEMBER_OFFSET_INIT(kmem_cache_name, "kmem_cache", "name"); |  | ||||||
|  		MEMBER_OFFSET_INIT(kmem_cache_flags, "kmem_cache", "flags"); |  | ||||||
|  		MEMBER_OFFSET_INIT(kmem_cache_random, "kmem_cache", "random"); |  | ||||||
| +		if (VALID_MEMBER(kmem_cache_random))
 |  | ||||||
| +			freelist_ptr_init();
 |  | ||||||
|  		MEMBER_OFFSET_INIT(kmem_cache_cpu_freelist, "kmem_cache_cpu", "freelist"); |  | ||||||
|  		MEMBER_OFFSET_INIT(kmem_cache_cpu_page, "kmem_cache_cpu", "page"); |  | ||||||
|  		if (INVALID_MEMBER(kmem_cache_cpu_page)) |  | ||||||
| @@ -13932,6 +13935,8 @@ dump_vm_table(int verbose)
 |  | ||||||
|  		fprintf(fp, "%sSLAB_CPU_CACHE", others++ ? "|" : "");\ |  | ||||||
|  	if (vt->flags & SLAB_ROOT_CACHES) |  | ||||||
|  		fprintf(fp, "%sSLAB_ROOT_CACHES", others++ ? "|" : "");\ |  | ||||||
| +	if (vt->flags & FREELIST_PTR_BSWAP)
 |  | ||||||
| +		fprintf(fp, "%sFREELIST_PTR_BSWAP", others++ ? "|" : "");\
 |  | ||||||
|  	if (vt->flags & USE_VMAP_AREA) |  | ||||||
|  		fprintf(fp, "%sUSE_VMAP_AREA", others++ ? "|" : "");\ |  | ||||||
|  	if (vt->flags & CONFIG_NUMA) |  | ||||||
| @@ -19519,13 +19524,55 @@ count_free_objects(struct meminfo *si, ulong freelist)
 |  | ||||||
|  	return c; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| +/*
 |  | ||||||
| + * With CONFIG_SLAB_FREELIST_HARDENED, freelist_ptr's are crypted with xor's,
 |  | ||||||
| + * and for recent release with an additionnal bswap. Some releases prio to 5.7.0
 |  | ||||||
| + * may be using the additionnal bswap. The only easy and reliable way to tell is
 |  | ||||||
| + * to inspect assembly code (eg. "__slab_free") for a bswap instruction.
 |  | ||||||
| + */
 |  | ||||||
| +static int
 |  | ||||||
| +freelist_ptr_bswap_x86(void)
 |  | ||||||
| +{
 |  | ||||||
| +	char buf1[BUFSIZE];
 |  | ||||||
| +	char buf2[BUFSIZE];
 |  | ||||||
| +	char *arglist[MAXARGS];
 |  | ||||||
| +	int found;
 |  | ||||||
| +
 |  | ||||||
| +	sprintf(buf1, "disassemble __slab_free");
 |  | ||||||
| +	open_tmpfile();
 |  | ||||||
| +	if (!gdb_pass_through(buf1, pc->tmpfile, GNU_RETURN_ON_ERROR)) {
 |  | ||||||
| +		close_tmpfile();
 |  | ||||||
| +		return FALSE;
 |  | ||||||
| +	}
 |  | ||||||
| +	rewind(pc->tmpfile);
 |  | ||||||
| +	found = FALSE;
 |  | ||||||
| +	while (fgets(buf2, BUFSIZE, pc->tmpfile)) {
 |  | ||||||
| +		if (parse_line(buf2, arglist) < 3)
 |  | ||||||
| +			continue;
 |  | ||||||
| +		if (STREQ(arglist[2], "bswap")) {
 |  | ||||||
| +			found = TRUE;
 |  | ||||||
| +			break;
 |  | ||||||
| +		}
 |  | ||||||
| +	}
 |  | ||||||
| +	close_tmpfile();
 |  | ||||||
| +	return found;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
| +static void
 |  | ||||||
| +freelist_ptr_init(void)
 |  | ||||||
| +{
 |  | ||||||
| +	if (THIS_KERNEL_VERSION >= LINUX(5,7,0) ||
 |  | ||||||
| +	    ((machine_type("X86_64") || machine_type("X86")) && freelist_ptr_bswap_x86()))
 |  | ||||||
| +		vt->flags |= FREELIST_PTR_BSWAP;
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
|  static ulong |  | ||||||
|  freelist_ptr(struct meminfo *si, ulong ptr, ulong ptr_addr) |  | ||||||
|  { |  | ||||||
|  	if (VALID_MEMBER(kmem_cache_random)) { |  | ||||||
|  		/* CONFIG_SLAB_FREELIST_HARDENED */ |  | ||||||
|   |  | ||||||
| -		if (THIS_KERNEL_VERSION >= LINUX(5,7,0))
 |  | ||||||
| +		if (vt->flags & FREELIST_PTR_BSWAP)
 |  | ||||||
|  			ptr_addr = (sizeof(long) == 8) ? bswap_64(ptr_addr) |  | ||||||
|  						       : bswap_32(ptr_addr); |  | ||||||
|  		return (ptr ^ si->random ^ ptr_addr); |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,106 +0,0 @@ | |||||||
| From c64a827e0bcab15e86f8fbacec141c2bf4b776ea Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Thu, 9 Feb 2023 20:15:46 +0800 |  | ||||||
| Subject: [PATCH 03/12] Fix for "net -s" option to show IPv6 addresses on Linux |  | ||||||
|  3.13 and later |  | ||||||
| 
 |  | ||||||
| Currently, the "net -s" option fails to show IPv6 addresses and ports |  | ||||||
| for the SOURCE-PORT and DESTINATION-PORT columns on Linux 3.13 and later |  | ||||||
| kernels, which have kernel commit efe4208f47f907 ("ipv6: make lookups |  | ||||||
| simpler and faster").  For example: |  | ||||||
| 
 |  | ||||||
|   crash> net -s |  | ||||||
|   PID: 305524   TASK: ffff9bc449895580  CPU: 6    COMMAND: "sshd" |  | ||||||
|   FD      SOCKET            SOCK       FAMILY:TYPE SOURCE-PORT DESTINATION-PORT |  | ||||||
|    3 ffff9bc446e9a680 ffff9bc4455b5940 UNIX:DGRAM |  | ||||||
|    4 ffff9bc446e9c600 ffff9bc3b2b24e00 INET6:STREAM |  | ||||||
| 
 |  | ||||||
| With the patch: |  | ||||||
| 
 |  | ||||||
|   crash> net -s |  | ||||||
|   PID: 305524   TASK: ffff9bc449895580  CPU: 6    COMMAND: "sshd" |  | ||||||
|   FD      SOCKET            SOCK       FAMILY:TYPE SOURCE-PORT DESTINATION-PORT |  | ||||||
|    3 ffff9bc446e9a680 ffff9bc4455b5940 UNIX:DGRAM |  | ||||||
|    4 ffff9bc446e9c600 ffff9bc3b2b24e00 INET6:STREAM xxxx:xx:x:xxxx:xxxx:xxxx:xxxx:xxxx-22 yyyy:yy:y:yyyy:yyyy:yyyy:yyyy:yyyy-44870 |  | ||||||
| 
 |  | ||||||
| Reported-by: Buland Kumar Singh <bsingh@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| ---
 |  | ||||||
|  defs.h    |  3 +++ |  | ||||||
|  net.c     | 20 +++++++++++++++----- |  | ||||||
|  symbols.c |  3 +++ |  | ||||||
|  3 files changed, 21 insertions(+), 5 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index 56d6cf4489c9..ab4f02cc65cf 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -2204,6 +2204,9 @@ struct offset_table {                    /* stash of commonly-used offsets */
 |  | ||||||
|  	long maple_range_64_slot; |  | ||||||
|  	long maple_metadata_end; |  | ||||||
|  	long maple_metadata_gap; |  | ||||||
| +	long sock_sk_common;
 |  | ||||||
| +	long sock_common_skc_v6_daddr;
 |  | ||||||
| +	long sock_common_skc_v6_rcv_saddr;
 |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
|  struct size_table {         /* stash of commonly-used sizes */ |  | ||||||
| diff --git a/net.c b/net.c
 |  | ||||||
| index 7c9c8bd9c98d..aa445ab7ee13 100644
 |  | ||||||
| --- a/net.c
 |  | ||||||
| +++ b/net.c
 |  | ||||||
| @@ -199,6 +199,9 @@ net_init(void)
 |  | ||||||
|  			MEMBER_OFFSET_INIT(sock_common_skc_family, |  | ||||||
|  				"sock_common", "skc_family"); |  | ||||||
|  			MEMBER_OFFSET_INIT(sock_sk_type, "sock", "sk_type"); |  | ||||||
| +			MEMBER_OFFSET_INIT(sock_sk_common, "sock", "__sk_common");
 |  | ||||||
| +			MEMBER_OFFSET_INIT(sock_common_skc_v6_daddr, "sock_common", "skc_v6_daddr");
 |  | ||||||
| +			MEMBER_OFFSET_INIT(sock_common_skc_v6_rcv_saddr, "sock_common", "skc_v6_rcv_saddr");
 |  | ||||||
|  			/* |  | ||||||
|  			 *  struct inet_sock { |  | ||||||
|          		 *	struct sock       sk; |  | ||||||
| @@ -1104,12 +1107,19 @@ get_sock_info(ulong sock, char *buf)
 |  | ||||||
|  		break; |  | ||||||
|   |  | ||||||
|  	case SOCK_V2: |  | ||||||
| -		if (INVALID_MEMBER(ipv6_pinfo_rcv_saddr) ||
 |  | ||||||
| -		    INVALID_MEMBER(ipv6_pinfo_daddr))
 |  | ||||||
| +		if (VALID_MEMBER(ipv6_pinfo_rcv_saddr) &&
 |  | ||||||
| +		    VALID_MEMBER(ipv6_pinfo_daddr)) {
 |  | ||||||
| +			ipv6_rcv_saddr = ipv6_pinfo + OFFSET(ipv6_pinfo_rcv_saddr);
 |  | ||||||
| +			ipv6_daddr = ipv6_pinfo + OFFSET(ipv6_pinfo_daddr);
 |  | ||||||
| +		} else if (VALID_MEMBER(sock_sk_common) &&
 |  | ||||||
| +			   VALID_MEMBER(sock_common_skc_v6_daddr) &&
 |  | ||||||
| +			   VALID_MEMBER(sock_common_skc_v6_rcv_saddr)) {
 |  | ||||||
| +			ipv6_rcv_saddr = sock + OFFSET(sock_sk_common) + OFFSET(sock_common_skc_v6_rcv_saddr);
 |  | ||||||
| +			ipv6_daddr = sock + OFFSET(sock_sk_common) + OFFSET(sock_common_skc_v6_daddr);
 |  | ||||||
| +		} else {
 |  | ||||||
| +			sprintf(&buf[strlen(buf)], "%s", "(cannot get IPv6 addresses)");
 |  | ||||||
|  			break; |  | ||||||
| -
 |  | ||||||
| -        	ipv6_rcv_saddr = ipv6_pinfo + OFFSET(ipv6_pinfo_rcv_saddr);
 |  | ||||||
| -		ipv6_daddr = ipv6_pinfo + OFFSET(ipv6_pinfo_daddr);
 |  | ||||||
| +		}
 |  | ||||||
|   |  | ||||||
|  		if (!readmem(ipv6_rcv_saddr, KVADDR, u6_addr16_src, SIZE(in6_addr), |  | ||||||
|                      "ipv6_rcv_saddr buffer", QUIET|RETURN_ON_ERROR)) |  | ||||||
| diff --git a/symbols.c b/symbols.c
 |  | ||||||
| index e38df8aad0f5..b702b9665ec1 100644
 |  | ||||||
| --- a/symbols.c
 |  | ||||||
| +++ b/symbols.c
 |  | ||||||
| @@ -9818,8 +9818,11 @@ dump_offset_table(char *spec, ulong makestruct)
 |  | ||||||
|   |  | ||||||
|          fprintf(fp, "                  sock_sk_type: %ld\n",  |  | ||||||
|  		OFFSET(sock_sk_type)); |  | ||||||
| +	fprintf(fp, "                sock_sk_common: %ld\n", OFFSET(sock_sk_common));
 |  | ||||||
|          fprintf(fp, "        sock_common_skc_family: %ld\n",  |  | ||||||
|  		OFFSET(sock_common_skc_family)); |  | ||||||
| +	fprintf(fp, "      sock_common_skc_v6_daddr: %ld\n", OFFSET(sock_common_skc_v6_daddr));
 |  | ||||||
| +	fprintf(fp, "  sock_common_skc_v6_rcv_saddr: %ld\n", OFFSET(sock_common_skc_v6_rcv_saddr));
 |  | ||||||
|  	fprintf(fp, "        socket_alloc_vfs_inode: %ld\n", |  | ||||||
|  		OFFSET(socket_alloc_vfs_inode)); |  | ||||||
|          fprintf(fp, "                inet_sock_inet: %ld\n",  |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,56 +0,0 @@ | |||||||
| From 277da34dd5da8c1280d0d0fd7ce50499b31c3a58 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Tue, 14 Feb 2023 22:37:08 +0800 |  | ||||||
| Subject: [PATCH 04/12] Fix for "kmem -i" option to not print invalid values |  | ||||||
|  for CACHED |  | ||||||
| 
 |  | ||||||
| The "kmem -i" option may output a bogus statistics for CACHED, which |  | ||||||
| might be observed when some extreme situations occur in kernel, such as |  | ||||||
| OOM, disk IO errors, etc. |  | ||||||
| 
 |  | ||||||
| The following result of calculation may be a negative value, refer to |  | ||||||
| the dump_kmeminfo(): |  | ||||||
|   page_cache_size = nr_file_pages - swapper_space_nrpages - buffer_pages; |  | ||||||
| 
 |  | ||||||
| As a result, the negative value will be converted to unsigned long |  | ||||||
| integer, eventually it overflows and is printed as big integers. |  | ||||||
| 
 |  | ||||||
|   crash> kmem -i |  | ||||||
|                    PAGES        TOTAL      PERCENTAGE |  | ||||||
|       TOTAL MEM  255314511     973.9 GB         ---- |  | ||||||
|            FREE   533574         2 GB    0% of TOTAL MEM |  | ||||||
|            USED  254780937     971.9 GB   99% of TOTAL MEM |  | ||||||
|          SHARED     1713       6.7 MB    0% of TOTAL MEM |  | ||||||
|         BUFFERS      374       1.5 MB    0% of TOTAL MEM |  | ||||||
|          CACHED     -114  70368744177664 GB  72251060080% of TOTAL MEM |  | ||||||
|                     ^^^^  ^^^^^^^^^^^^^^     ^^^^^^^^^^^^ |  | ||||||
|          ... |  | ||||||
| 
 |  | ||||||
| Let's normalize it to zero with an info message to fix such cornor cases. |  | ||||||
| 
 |  | ||||||
| Reported-by: Buland Kumar Singh <bsingh@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| ---
 |  | ||||||
|  memory.c | 5 +++++ |  | ||||||
|  1 file changed, 5 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/memory.c b/memory.c
 |  | ||||||
| index e0742c1bd3a4..d9cd616f19de 100644
 |  | ||||||
| --- a/memory.c
 |  | ||||||
| +++ b/memory.c
 |  | ||||||
| @@ -8615,6 +8615,11 @@ dump_kmeminfo(void)
 |  | ||||||
|  		page_cache_size = 0; |  | ||||||
|   |  | ||||||
|   |  | ||||||
| +	if (page_cache_size < 0) {
 |  | ||||||
| +		error(INFO, "page_cache_size went negative (%ld), setting to 0\n",
 |  | ||||||
| +			page_cache_size);
 |  | ||||||
| +		page_cache_size = 0;
 |  | ||||||
| +	}
 |  | ||||||
|          pct = (page_cache_size * 100)/totalram_pages; |  | ||||||
|          fprintf(fp, "%13s  %7ld  %11s  %3ld%% of TOTAL MEM\n",  |  | ||||||
|  		"CACHED", page_cache_size,  |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,77 +0,0 @@ | |||||||
| From e0e6e4a7ee03b3d00b50a9e4db2f2ea6f7da0da3 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Wed, 15 Feb 2023 16:24:57 +0800 |  | ||||||
| Subject: [PATCH 05/12] Fix for "bt" command unnecessarily printing an |  | ||||||
|  exception frame |  | ||||||
| 
 |  | ||||||
| Kernel commit 7d65f4a65532 ("irq: Consolidate do_softirq() arch overriden |  | ||||||
| implementations") renamed the call_softirq to do_softirq_own_stack, and |  | ||||||
| there is no exception frame also when coming from do_softirq_own_stack. |  | ||||||
| Without the patch, crash may unnecessarily output an exception frame with |  | ||||||
| a warning as below: |  | ||||||
| 
 |  | ||||||
|   crash> foreach bt |  | ||||||
|   ... |  | ||||||
|   PID: 0        TASK: ffff914f820a8000  CPU: 25   COMMAND: "swapper/25" |  | ||||||
|    #0 [fffffe0000504e48] crash_nmi_callback at ffffffffa665d763 |  | ||||||
|    #1 [fffffe0000504e50] nmi_handle at ffffffffa662a423 |  | ||||||
|    #2 [fffffe0000504ea8] default_do_nmi at ffffffffa6fe7dc9 |  | ||||||
|    #3 [fffffe0000504ec8] do_nmi at ffffffffa662a97f |  | ||||||
|    #4 [fffffe0000504ef0] end_repeat_nmi at ffffffffa70015e8 |  | ||||||
|       [exception RIP: clone_endio+172] |  | ||||||
|       RIP: ffffffffc005c1ec  RSP: ffffa1d403d08e98  RFLAGS: 00000246 |  | ||||||
|       RAX: 0000000000000000  RBX: ffff915326fba230  RCX: 0000000000000018 |  | ||||||
|       RDX: ffffffffc0075400  RSI: 0000000000000000  RDI: ffff915326fba230 |  | ||||||
|       RBP: ffff915326fba1c0   R8: 0000000000001000   R9: ffff915308d6d2a0 |  | ||||||
|       R10: 000000a97dfe5e10  R11: ffffa1d40038fe98  R12: ffff915302babc40 |  | ||||||
|       R13: ffff914f94360000  R14: 0000000000000000  R15: 0000000000000000 |  | ||||||
|       ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018 |  | ||||||
|   --- <NMI exception stack> --- |  | ||||||
|    #5 [ffffa1d403d08e98] clone_endio at ffffffffc005c1ec [dm_mod] |  | ||||||
|    #6 [ffffa1d403d08ed0] blk_update_request at ffffffffa6a96954 |  | ||||||
|    #7 [ffffa1d403d08f10] scsi_end_request at ffffffffa6c9b968 |  | ||||||
|    #8 [ffffa1d403d08f48] scsi_io_completion at ffffffffa6c9bb3e |  | ||||||
|    #9 [ffffa1d403d08f90] blk_complete_reqs at ffffffffa6aa0e95 |  | ||||||
|    #10 [ffffa1d403d08fa0] __softirqentry_text_start at ffffffffa72000dc |  | ||||||
|    #11 [ffffa1d403d08ff0] do_softirq_own_stack at ffffffffa7000f9a |  | ||||||
|   --- <IRQ stack> --- |  | ||||||
|    #12 [ffffa1d40038fe70] do_softirq_own_stack at ffffffffa7000f9a |  | ||||||
|       [exception RIP: unknown or invalid address] |  | ||||||
|       RIP: 0000000000000000  RSP: 0000000000000000  RFLAGS: 00000000 |  | ||||||
|       RAX: ffffffffa672eae5  RBX: ffffffffa83b34e0  RCX: ffffffffa672eb12 |  | ||||||
|       RDX: 0000000000000010  RSI: 8b7d6c8869010c00  RDI: 0000000000000085 |  | ||||||
|       RBP: 0000000000000286   R8: ffff914f820a8000   R9: ffffffffa67a94e0 |  | ||||||
|       R10: 0000000000000286  R11: ffffffffa66fb4c5  R12: ffffffffa67a898b |  | ||||||
|       R13: 0000000000000000  R14: fffffffffffffff8  R15: ffffffffa67a1e68 |  | ||||||
|       ORIG_RAX: 0000000000000000  CS: 0000  SS: ffffffffa672edff |  | ||||||
|    bt: WARNING: possibly bogus exception frame |  | ||||||
|    #13 [ffffa1d40038ff30] start_secondary at ffffffffa665fa2c |  | ||||||
|    #14 [ffffa1d40038ff50] secondary_startup_64_no_verify at ffffffffa6600116 |  | ||||||
|    ... |  | ||||||
| 
 |  | ||||||
| Reported-by: Marco Patalano <mpatalan@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  x86_64.c | 5 +++-- |  | ||||||
|  1 file changed, 3 insertions(+), 2 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/x86_64.c b/x86_64.c
 |  | ||||||
| index 5b671bd97775..6cac3936b33d 100644
 |  | ||||||
| --- a/x86_64.c
 |  | ||||||
| +++ b/x86_64.c
 |  | ||||||
| @@ -3825,10 +3825,11 @@ in_exception_stack:
 |  | ||||||
|  		up -= 1; |  | ||||||
|                  bt->instptr = *up; |  | ||||||
|  		/* |  | ||||||
| -		 *  No exception frame when coming from call_softirq.
 |  | ||||||
| +		 *  No exception frame when coming from do_softirq_own_stack
 |  | ||||||
| +		 *  or call_softirq.
 |  | ||||||
|  		 */ |  | ||||||
|  		if ((sp = value_search(bt->instptr, &offset)) &&  |  | ||||||
| -		    STREQ(sp->name, "call_softirq"))
 |  | ||||||
| +		    (STREQ(sp->name, "do_softirq_own_stack") || STREQ(sp->name, "call_softirq")))
 |  | ||||||
|  			irq_eframe = 0; |  | ||||||
|                  bt->frameptr = 0; |  | ||||||
|                  done = FALSE; |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,62 +0,0 @@ | |||||||
| From 59c19818190dd4b7ae0dc2221586a4ad6f4fe905 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Tue, 21 Feb 2023 11:03:26 +0800 |  | ||||||
| Subject: [PATCH 06/12] Fix for "dis" command to correctly display the offset |  | ||||||
|  of disassembly code |  | ||||||
| 
 |  | ||||||
| For gdb-10.2, the disassembly code may start with "=>", which needs to |  | ||||||
| be stripped when calculating the address. Otherwise, parsing the address |  | ||||||
| will fail because the current code always assumes that it starts with the |  | ||||||
| "0x". For example: |  | ||||||
| 
 |  | ||||||
|   crash> gdb disassemble 0xffffffffa2317add |  | ||||||
|   Dump of assembler code for function native_queued_spin_lock_slowpath: |  | ||||||
|      ... |  | ||||||
|      0xffffffffa2317ad3 <+35>:    mov    %edx,%eax |  | ||||||
|      0xffffffffa2317ad5 <+37>:    lock cmpxchg %ecx,(%rdi) |  | ||||||
|   => 0xffffffffa2317ad9 <+41>:    cmp    %eax,%edx |  | ||||||
|      0xffffffffa2317adb <+43>:    jne    0xffffffffa2317ac0 ... |  | ||||||
|      0xffffffffa2317add <+45>:    pop    %rbp |  | ||||||
|      ... |  | ||||||
| 
 |  | ||||||
| Without the patch: |  | ||||||
|   crash> dis 0xffffffffa2317add -r | tail -5 |  | ||||||
|   0xffffffffa2317ad3 <native_queued_spin_lock_slowpath+35>:	mov    %edx,%eax |  | ||||||
|   0xffffffffa2317ad5 <native_queued_spin_lock_slowpath+37>:	lock cmpxchg %ecx,(%rdi) |  | ||||||
|   0xffffffffa2317ad5 <native_queued_spin_lock_slowpath+37>:	cmp    %eax,%edx |  | ||||||
|                                                        ^^ |  | ||||||
|   0xffffffffa2317adb <native_queued_spin_lock_slowpath+43>:	jne    0xffffffffa2317ac0 ... |  | ||||||
|   0xffffffffa2317add <native_queued_spin_lock_slowpath+45>:	pop    %rbp |  | ||||||
| 
 |  | ||||||
| With the patch: |  | ||||||
| 
 |  | ||||||
|   crash> dis 0xffffffffa2317add -r | tail -5 |  | ||||||
|   0xffffffffa2317ad3 <native_queued_spin_lock_slowpath+35>:	mov    %edx,%eax |  | ||||||
|   0xffffffffa2317ad5 <native_queued_spin_lock_slowpath+37>:	lock cmpxchg %ecx,(%rdi) |  | ||||||
|   0xffffffffa2317ad9 <native_queued_spin_lock_slowpath+41>:	cmp    %eax,%edx |  | ||||||
|   0xffffffffa2317adb <native_queued_spin_lock_slowpath+43>:	jne    0xffffffffa2317ac0 ... |  | ||||||
|   0xffffffffa2317add <native_queued_spin_lock_slowpath+45>:	pop    %rbp |  | ||||||
| 
 |  | ||||||
| Reported-by: Vernon Lovejoy <vlovejoy@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  kernel.c | 4 ++++ |  | ||||||
|  1 file changed, 4 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/kernel.c b/kernel.c
 |  | ||||||
| index a42e6ad7d78c..6e98f5f6f6b1 100644
 |  | ||||||
| --- a/kernel.c
 |  | ||||||
| +++ b/kernel.c
 |  | ||||||
| @@ -2112,6 +2112,10 @@ cmd_dis(void)
 |  | ||||||
|  			rewind(pc->tmpfile); |  | ||||||
|   |  | ||||||
|  		while (fgets(buf2, BUFSIZE, pc->tmpfile)) { |  | ||||||
| +
 |  | ||||||
| +			if (STRNEQ(buf2, "=>"))
 |  | ||||||
| +				shift_string_left(buf2, 2);
 |  | ||||||
| +
 |  | ||||||
|  			strip_beginning_whitespace(buf2); |  | ||||||
|   |  | ||||||
|  			if (do_load_module_filter) |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,299 +0,0 @@ | |||||||
| From daa43fa5324f2dd232ad72df2c6554646868f3b2 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Date: Mon, 20 Feb 2023 10:28:53 +0900 |  | ||||||
| Subject: [PATCH 07/12] x86_64: Fix "bt" command on kernels with |  | ||||||
|  random_kstack_offset=on |  | ||||||
| 
 |  | ||||||
| On kernels configured with CONFIG_RANDOMIZE_KSTACK_OFFSET=y and |  | ||||||
| random_kstack_offset=on, a random offset is added to task stacks with |  | ||||||
| __kstack_alloca() at the beginning of do_syscall_64() and other syscall |  | ||||||
| entry functions.  This eventually does the following instruction. |  | ||||||
| 
 |  | ||||||
|   <do_syscall_64+32>:  sub    %rax,%rsp |  | ||||||
| 
 |  | ||||||
| On the other hand, crash uses only a part of data for ORC unwinder to |  | ||||||
| unwind stacks and if an ip value doesn't have a usable ORC data, it |  | ||||||
| caluculates the frame size with parsing the assembly of the function. |  | ||||||
| 
 |  | ||||||
| However, crash cannot calculate the frame size correctly with the |  | ||||||
| instruction above, and prints stale return addresses like this: |  | ||||||
| 
 |  | ||||||
|   crash> bt 1 |  | ||||||
|   PID: 1        TASK: ffff9c250023b880  CPU: 0    COMMAND: "systemd" |  | ||||||
|     #0 [ffffb7e5c001fc80] __schedule at ffffffff91ae2b16 |  | ||||||
|     #1 [ffffb7e5c001fd00] schedule at ffffffff91ae2ed3 |  | ||||||
|     #2 [ffffb7e5c001fd18] schedule_hrtimeout_range_clock at ffffffff91ae7ed8 |  | ||||||
|     #3 [ffffb7e5c001fda8] ep_poll at ffffffff913ef828 |  | ||||||
|     #4 [ffffb7e5c001fe48] do_epoll_wait at ffffffff913ef943 |  | ||||||
|     #5 [ffffb7e5c001fe80] __x64_sys_epoll_wait at ffffffff913f0130 |  | ||||||
|     #6 [ffffb7e5c001fed0] do_syscall_64 at ffffffff91ad7169 |  | ||||||
|     #7 [ffffb7e5c001fef0] do_syscall_64 at ffffffff91ad7179             << |  | ||||||
|     #8 [ffffb7e5c001ff10] syscall_exit_to_user_mode at ffffffff91adaab2 << stale entries |  | ||||||
|     #9 [ffffb7e5c001ff20] do_syscall_64 at ffffffff91ad7179             << |  | ||||||
|    #10 [ffffb7e5c001ff50] entry_SYSCALL_64_after_hwframe at ffffffff91c0009b |  | ||||||
|        RIP: 00007f258d9427ae  RSP: 00007fffda631d60  RFLAGS: 00000293 |  | ||||||
|        ... |  | ||||||
| 
 |  | ||||||
| To fix this, enhance the use of ORC data.  The ORC unwinder often uses |  | ||||||
| %rbp value, so keep it from exception frames and inactive task stacks. |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| ---
 |  | ||||||
|  defs.h    |   1 + |  | ||||||
|  symbols.c |   1 + |  | ||||||
|  x86_64.c  | 118 ++++++++++++++++++++++++++++++++++++++---------------- |  | ||||||
|  3 files changed, 85 insertions(+), 35 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index ab4f02cc65cf..e76af3c78b69 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -2207,6 +2207,7 @@ struct offset_table {                    /* stash of commonly-used offsets */
 |  | ||||||
|  	long sock_sk_common; |  | ||||||
|  	long sock_common_skc_v6_daddr; |  | ||||||
|  	long sock_common_skc_v6_rcv_saddr; |  | ||||||
| +	long inactive_task_frame_bp;
 |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
|  struct size_table {         /* stash of commonly-used sizes */ |  | ||||||
| diff --git a/symbols.c b/symbols.c
 |  | ||||||
| index b702b9665ec1..a974fc9141a0 100644
 |  | ||||||
| --- a/symbols.c
 |  | ||||||
| +++ b/symbols.c
 |  | ||||||
| @@ -8822,6 +8822,7 @@ dump_offset_table(char *spec, ulong makestruct)
 |  | ||||||
|  		OFFSET(task_struct_tss_ksp)); |  | ||||||
|          fprintf(fp, "        task_struct_thread_eip: %ld\n", |  | ||||||
|                  OFFSET(task_struct_thread_eip)); |  | ||||||
| +	fprintf(fp, "        inactive_task_frame_bp: %ld\n", OFFSET(inactive_task_frame_bp));
 |  | ||||||
|  	fprintf(fp, "  inactive_task_frame_ret_addr: %ld\n", |  | ||||||
|  		OFFSET(inactive_task_frame_ret_addr)); |  | ||||||
|          fprintf(fp, "        task_struct_thread_esp: %ld\n", |  | ||||||
| diff --git a/x86_64.c b/x86_64.c
 |  | ||||||
| index 6cac3936b33d..8e3eb8957af1 100644
 |  | ||||||
| --- a/x86_64.c
 |  | ||||||
| +++ b/x86_64.c
 |  | ||||||
| @@ -122,7 +122,7 @@ static int x86_64_do_not_cache_framesize(struct syment *, ulong);
 |  | ||||||
|  static int x86_64_framesize_cache_func(int, ulong, int *, int, struct syment *); |  | ||||||
|  static ulong x86_64_get_framepointer(struct bt_info *, ulong); |  | ||||||
|  int search_for_eframe_target_caller(struct bt_info *, ulong, int *); |  | ||||||
| -static int x86_64_get_framesize(struct bt_info *, ulong, ulong);
 |  | ||||||
| +static int x86_64_get_framesize(struct bt_info *, ulong, ulong, char *);
 |  | ||||||
|  static void x86_64_framesize_debug(struct bt_info *); |  | ||||||
|  static void x86_64_get_active_set(void); |  | ||||||
|  static int x86_64_get_kvaddr_ranges(struct vaddr_range *); |  | ||||||
| @@ -3642,7 +3642,7 @@ in_exception_stack:
 |  | ||||||
|  				bt, ofp); |  | ||||||
|                          rsp += SIZE(pt_regs);  /* guaranteed kernel mode */ |  | ||||||
|  			if (bt->eframe_ip && ((framesize = x86_64_get_framesize(bt,  |  | ||||||
| -			    bt->eframe_ip, rsp)) >= 0))
 |  | ||||||
| +			    bt->eframe_ip, rsp, NULL)) >= 0))
 |  | ||||||
|  				rsp += framesize; |  | ||||||
|                          level++; |  | ||||||
|                          irq_eframe = 0; |  | ||||||
| @@ -3674,7 +3674,7 @@ in_exception_stack:
 |  | ||||||
|  	                case BACKTRACE_ENTRY_DISPLAYED: |  | ||||||
|  	                        level++; |  | ||||||
|  				if ((framesize = x86_64_get_framesize(bt,  |  | ||||||
| -				    bt->eframe_ip ?  bt->eframe_ip : *up, rsp)) >= 0) {
 |  | ||||||
| +				    bt->eframe_ip ?  bt->eframe_ip : *up, rsp, NULL)) >= 0) {
 |  | ||||||
|  					rsp += framesize; |  | ||||||
|  					i += framesize/sizeof(ulong); |  | ||||||
|  				} |  | ||||||
| @@ -3747,7 +3747,7 @@ in_exception_stack:
 |  | ||||||
|  			} |  | ||||||
|   |  | ||||||
|  			level++; |  | ||||||
| -			if ((framesize = x86_64_get_framesize(bt, bt->instptr, rsp)) >= 0)
 |  | ||||||
| +			if ((framesize = x86_64_get_framesize(bt, bt->instptr, rsp, NULL)) >= 0)
 |  | ||||||
|  				rsp += framesize; |  | ||||||
|  		} |  | ||||||
|  	} |  | ||||||
| @@ -3799,7 +3799,7 @@ in_exception_stack:
 |  | ||||||
|                          case BACKTRACE_ENTRY_DISPLAYED: |  | ||||||
|                                  level++; |  | ||||||
|  				if ((framesize = x86_64_get_framesize(bt,  |  | ||||||
| -				    bt->eframe_ip ? bt->eframe_ip : *up, rsp)) >= 0) {
 |  | ||||||
| +				    bt->eframe_ip ? bt->eframe_ip : *up, rsp, NULL)) >= 0) {
 |  | ||||||
|  					rsp += framesize; |  | ||||||
|  					i += framesize/sizeof(ulong); |  | ||||||
|  				} |  | ||||||
| @@ -3909,24 +3909,34 @@ in_exception_stack:
 |  | ||||||
|  	    (STREQ(rip_symbol, "thread_return") ||  |  | ||||||
|  	     STREQ(rip_symbol, "schedule") ||  |  | ||||||
|  	     STREQ(rip_symbol, "__schedule"))) { |  | ||||||
| -		if (STREQ(rip_symbol, "__schedule")) {
 |  | ||||||
| -			i = (rsp - bt->stackbase)/sizeof(ulong);
 |  | ||||||
| -			x86_64_print_stack_entry(bt, ofp, level, 
 |  | ||||||
| -				i, bt->instptr);
 |  | ||||||
| -			level++;
 |  | ||||||
| -			rsp = __schedule_frame_adjust(rsp, bt);
 |  | ||||||
| -			if (STREQ(closest_symbol(bt->instptr), "schedule"))
 |  | ||||||
| +		if ((machdep->flags & ORC) && VALID_MEMBER(inactive_task_frame_ret_addr)) {
 |  | ||||||
| +			/*
 |  | ||||||
| +			 * %rsp should have the address of inactive_task_frame, so
 |  | ||||||
| +			 * skip the registers before ret_addr to adjust rsp.
 |  | ||||||
| +			 */
 |  | ||||||
| +			if (CRASHDEBUG(1))
 |  | ||||||
| +				fprintf(fp, "rsp: %lx rbp: %lx\n", rsp, bt->bptr);
 |  | ||||||
| +			rsp += OFFSET(inactive_task_frame_ret_addr);
 |  | ||||||
| +		} else {
 |  | ||||||
| +			if (STREQ(rip_symbol, "__schedule")) {
 |  | ||||||
| +				i = (rsp - bt->stackbase)/sizeof(ulong);
 |  | ||||||
| +				x86_64_print_stack_entry(bt, ofp, level,
 |  | ||||||
| +					i, bt->instptr);
 |  | ||||||
| +				level++;
 |  | ||||||
| +				rsp = __schedule_frame_adjust(rsp, bt);
 |  | ||||||
| +				if (STREQ(closest_symbol(bt->instptr), "schedule"))
 |  | ||||||
| +					bt->flags |= BT_SCHEDULE;
 |  | ||||||
| +			} else
 |  | ||||||
|  				bt->flags |= BT_SCHEDULE; |  | ||||||
| -		} else
 |  | ||||||
| -			bt->flags |= BT_SCHEDULE;
 |  | ||||||
| -
 |  | ||||||
| -		if (bt->flags & BT_SCHEDULE) {
 |  | ||||||
| -			i = (rsp - bt->stackbase)/sizeof(ulong);
 |  | ||||||
| -			x86_64_print_stack_entry(bt, ofp, level, 
 |  | ||||||
| -				i, bt->instptr);
 |  | ||||||
| -			bt->flags &= ~(ulonglong)BT_SCHEDULE;
 |  | ||||||
| -			rsp += sizeof(ulong);
 |  | ||||||
| -			level++;
 |  | ||||||
| +
 |  | ||||||
| +			if (bt->flags & BT_SCHEDULE) {
 |  | ||||||
| +				i = (rsp - bt->stackbase)/sizeof(ulong);
 |  | ||||||
| +				x86_64_print_stack_entry(bt, ofp, level,
 |  | ||||||
| +					i, bt->instptr);
 |  | ||||||
| +				bt->flags &= ~(ulonglong)BT_SCHEDULE;
 |  | ||||||
| +				rsp += sizeof(ulong);
 |  | ||||||
| +				level++;
 |  | ||||||
| +			}
 |  | ||||||
|  		} |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| @@ -3957,7 +3967,7 @@ in_exception_stack:
 |  | ||||||
|  			irq_eframe = 0; |  | ||||||
|  			bt->flags |= BT_EFRAME_TARGET; |  | ||||||
|  			if (bt->eframe_ip && ((framesize = x86_64_get_framesize(bt,  |  | ||||||
| -			    bt->eframe_ip, rsp)) >= 0))
 |  | ||||||
| +			    bt->eframe_ip, rsp, NULL)) >= 0))
 |  | ||||||
|  				rsp += framesize; |  | ||||||
|  			bt->flags &= ~BT_EFRAME_TARGET; |  | ||||||
|  		} |  | ||||||
| @@ -4044,7 +4054,7 @@ in_exception_stack:
 |  | ||||||
|  		case BACKTRACE_ENTRY_DISPLAYED: |  | ||||||
|  			level++; |  | ||||||
|  			if ((framesize = x86_64_get_framesize(bt,  |  | ||||||
| -			    bt->eframe_ip ? bt->eframe_ip : *up, rsp)) >= 0) {
 |  | ||||||
| +			    bt->eframe_ip ? bt->eframe_ip : *up, rsp, (char *)up)) >= 0) {
 |  | ||||||
|  				rsp += framesize; |  | ||||||
|  				i += framesize/sizeof(ulong); |  | ||||||
|  			} |  | ||||||
| @@ -4755,7 +4765,8 @@ x86_64_exception_frame(ulong flags, ulong kvaddr, char *local,
 |  | ||||||
|  		bt->instptr = rip; |  | ||||||
|  		bt->stkptr = rsp; |  | ||||||
|  		bt->bptr = rbp; |  | ||||||
| -	}
 |  | ||||||
| +	} else if (machdep->flags & ORC)
 |  | ||||||
| +		bt->bptr = rbp;
 |  | ||||||
|   |  | ||||||
|  	if (kvaddr) |  | ||||||
|  		FREEBUF(pt_regs_buf); |  | ||||||
| @@ -5315,6 +5326,10 @@ x86_64_get_sp(struct bt_info *bt)
 |  | ||||||
|  			OFFSET(thread_struct_rsp), KVADDR, |  | ||||||
|                          &rsp, sizeof(void *), |  | ||||||
|                          "thread_struct rsp", FAULT_ON_ERROR); |  | ||||||
| +		if ((machdep->flags & ORC) && VALID_MEMBER(inactive_task_frame_bp)) {
 |  | ||||||
| +			readmem(rsp + OFFSET(inactive_task_frame_bp), KVADDR, &bt->bptr,
 |  | ||||||
| +				sizeof(void *), "inactive_task_frame.bp", FAULT_ON_ERROR);
 |  | ||||||
| +		}
 |  | ||||||
|                  return rsp; |  | ||||||
|          } |  | ||||||
|   |  | ||||||
| @@ -6421,6 +6436,9 @@ x86_64_ORC_init(void)
 |  | ||||||
|  	orc->__stop_orc_unwind = symbol_value("__stop_orc_unwind"); |  | ||||||
|  	orc->orc_lookup = symbol_value("orc_lookup"); |  | ||||||
|   |  | ||||||
| +	MEMBER_OFFSET_INIT(inactive_task_frame_bp, "inactive_task_frame", "bp");
 |  | ||||||
| +	MEMBER_OFFSET_INIT(inactive_task_frame_ret_addr, "inactive_task_frame", "ret_addr");
 |  | ||||||
| +
 |  | ||||||
|  	machdep->flags |= ORC; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| @@ -8489,7 +8507,7 @@ search_for_eframe_target_caller(struct bt_info *bt, ulong stkptr, int *framesize
 |  | ||||||
|  	(BT_OLD_BACK_TRACE|BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_ALL|BT_FRAMESIZE_DISABLE) |  | ||||||
|    |  | ||||||
|  static int |  | ||||||
| -x86_64_get_framesize(struct bt_info *bt, ulong textaddr, ulong rsp)
 |  | ||||||
| +x86_64_get_framesize(struct bt_info *bt, ulong textaddr, ulong rsp, char *stack_ptr)
 |  | ||||||
|  { |  | ||||||
|  	int c, framesize, instr, arg, max; |  | ||||||
|  	struct syment *sp; |  | ||||||
| @@ -8590,19 +8608,49 @@ x86_64_get_framesize(struct bt_info *bt, ulong textaddr, ulong rsp)
 |  | ||||||
|  	if ((machdep->flags & ORC) && (korc = orc_find(textaddr))) { |  | ||||||
|  		if (CRASHDEBUG(1)) { |  | ||||||
|  			fprintf(fp,  |  | ||||||
| -			    "rsp: %lx textaddr: %lx framesize: %d -> spo: %d bpo: %d spr: %d bpr: %d type: %d %s", 
 |  | ||||||
| -				rsp, textaddr, framesize, korc->sp_offset, korc->bp_offset, 
 |  | ||||||
| -				korc->sp_reg, korc->bp_reg, korc->type,
 |  | ||||||
| -				(korc->type == ORC_TYPE_CALL) && (korc->sp_reg == ORC_REG_SP) ? "" : "(UNUSED)");
 |  | ||||||
| +			    "rsp: %lx textaddr: %lx -> spo: %d bpo: %d spr: %d bpr: %d type: %d",
 |  | ||||||
| +				rsp, textaddr, korc->sp_offset, korc->bp_offset,
 |  | ||||||
| +				korc->sp_reg, korc->bp_reg, korc->type);
 |  | ||||||
|  			if (MEMBER_EXISTS("orc_entry", "end")) |  | ||||||
|  				fprintf(fp, " end: %d", korc->end); |  | ||||||
|  			fprintf(fp, "\n"); |  | ||||||
|  		} |  | ||||||
|   |  | ||||||
| -		if ((korc->type == ORC_TYPE_CALL) && (korc->sp_reg == ORC_REG_SP)) {
 |  | ||||||
| -			framesize = (korc->sp_offset - 8);
 |  | ||||||
| -			return (x86_64_framesize_cache_func(FRAMESIZE_ENTER, textaddr, 
 |  | ||||||
| -				&framesize, exception, NULL));
 |  | ||||||
| +		if (korc->type == ORC_TYPE_CALL) {
 |  | ||||||
| +			ulong prev_sp = 0, prev_bp = 0;
 |  | ||||||
| +			framesize = -1;
 |  | ||||||
| +
 |  | ||||||
| +			if (korc->sp_reg == ORC_REG_SP) {
 |  | ||||||
| +				framesize = (korc->sp_offset - 8);
 |  | ||||||
| +
 |  | ||||||
| +				/* rsp points to a return address, so +8 to use sp_offset */
 |  | ||||||
| +				prev_sp = (rsp + 8) + korc->sp_offset;
 |  | ||||||
| +				if (CRASHDEBUG(1))
 |  | ||||||
| +					fprintf(fp, "rsp: %lx prev_sp: %lx framesize: %d\n",
 |  | ||||||
| +							rsp, prev_sp, framesize);
 |  | ||||||
| +			} else if ((korc->sp_reg == ORC_REG_BP) && bt->bptr) {
 |  | ||||||
| +				prev_sp = bt->bptr + korc->sp_offset;
 |  | ||||||
| +				framesize = (prev_sp - (rsp + 8) - 8);
 |  | ||||||
| +				if (CRASHDEBUG(1))
 |  | ||||||
| +					fprintf(fp, "rsp: %lx rbp: %lx prev_sp: %lx framesize: %d\n",
 |  | ||||||
| +							rsp, bt->bptr, prev_sp, framesize);
 |  | ||||||
| +			}
 |  | ||||||
| +
 |  | ||||||
| +			if ((korc->bp_reg == ORC_REG_PREV_SP) && prev_sp) {
 |  | ||||||
| +				prev_bp = prev_sp + korc->bp_offset;
 |  | ||||||
| +				if (stack_ptr && INSTACK(prev_bp, bt)) {
 |  | ||||||
| +					bt->bptr = ULONG(stack_ptr + (prev_bp - rsp));
 |  | ||||||
| +					if (CRASHDEBUG(1))
 |  | ||||||
| +						fprintf(fp, "rsp: %lx prev_sp: %lx prev_bp: %lx -> %lx\n",
 |  | ||||||
| +								rsp, prev_sp, prev_bp, bt->bptr);
 |  | ||||||
| +				} else
 |  | ||||||
| +					bt->bptr = 0;
 |  | ||||||
| +			} else if ((korc->bp_reg != ORC_REG_UNDEFINED))
 |  | ||||||
| +				bt->bptr = 0;
 |  | ||||||
| +
 |  | ||||||
| +			if (framesize >= 0)
 |  | ||||||
| +				/* Do not cache this, possibly it may be variable. */
 |  | ||||||
| +				return framesize;
 |  | ||||||
|  		} |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| @@ -8758,7 +8806,7 @@ x86_64_framesize_debug(struct bt_info *bt)
 |  | ||||||
|  		if (!bt->hp->eip) |  | ||||||
|  			error(INFO, "x86_64_framesize_debug: ignoring command\n"); |  | ||||||
|  		else |  | ||||||
| -			x86_64_get_framesize(bt, bt->hp->eip, 0);
 |  | ||||||
| +			x86_64_get_framesize(bt, bt->hp->eip, 0, NULL);
 |  | ||||||
|  		break; |  | ||||||
|   |  | ||||||
|  	case -3: |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,168 +0,0 @@ | |||||||
| From d0d6cf868577fdca81c40633fa082dae1794294f Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Tao Liu <ltao@redhat.com> |  | ||||||
| Date: Wed, 22 Feb 2023 14:32:09 +0800 |  | ||||||
| Subject: [PATCH 08/12] Fix for "search -u" option failing in maple tree kernel |  | ||||||
| 
 |  | ||||||
| Kernel with maple tree enabled doesn't have mmap as a member of mm_struct[1], |  | ||||||
| so OFFSET(mm_struct_mmap) case needed to be handled differently for |  | ||||||
| maple tree kernel. |  | ||||||
| 
 |  | ||||||
| Before: |  | ||||||
| crash> search -u a |  | ||||||
| 
 |  | ||||||
| search: invalid structure member offset: mm_struct_mmap |  | ||||||
|         FILE: memory.c  LINE: 14255  FUNCTION: address_space_start() |  | ||||||
| 
 |  | ||||||
| [crash] error trace: 549500 => 548fff => 5f1c91 => 5f1c13 |  | ||||||
| 
 |  | ||||||
|   5f1c13: OFFSET_verify.part.36+51 |  | ||||||
|   5f1c91: OFFSET_verify+49 |  | ||||||
|   548fff: address_space_start+106 |  | ||||||
|   549500: cmd_search+855 |  | ||||||
| 
 |  | ||||||
| search: invalid structure member offset: mm_struct_mmap |  | ||||||
|         FILE: memory.c  LINE: 14255  FUNCTION: address_space_start() |  | ||||||
| 
 |  | ||||||
| After: |  | ||||||
| crash> search -u a |  | ||||||
| 7ffea63e6440: a |  | ||||||
| 
 |  | ||||||
| [1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=763ecb035029f500d7e6dc99acd1ad299b7726a1 |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Tao Liu <ltao@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  memory.c | 89 +++++++++++++++++++++++++++++++++++++++++--------------- |  | ||||||
|  1 file changed, 65 insertions(+), 24 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/memory.c b/memory.c
 |  | ||||||
| index d9cd616f19de..c4a6ecd18004 100644
 |  | ||||||
| --- a/memory.c
 |  | ||||||
| +++ b/memory.c
 |  | ||||||
| @@ -14245,14 +14245,28 @@ vaddr_type(ulong vaddr, struct task_context *tc)
 |  | ||||||
|  static int |  | ||||||
|  address_space_start(struct task_context *tc, ulong *addr) |  | ||||||
|  { |  | ||||||
| -        ulong vma;
 |  | ||||||
| +	ulong mm_mt, entry_num, i, vma = 0;
 |  | ||||||
|          char *vma_buf; |  | ||||||
| +	struct list_pair *entry_list;
 |  | ||||||
|   |  | ||||||
|          if (!tc->mm_struct) |  | ||||||
|                  return FALSE; |  | ||||||
|   |  | ||||||
| -        fill_mm_struct(tc->mm_struct);
 |  | ||||||
| -        vma = ULONG(tt->mm_struct + OFFSET(mm_struct_mmap));
 |  | ||||||
| +	if (INVALID_MEMBER(mm_struct_mmap) && VALID_MEMBER(mm_struct_mm_mt)) {
 |  | ||||||
| +		mm_mt = tc->mm_struct + OFFSET(mm_struct_mm_mt);
 |  | ||||||
| +		entry_num = do_maple_tree(mm_mt, MAPLE_TREE_COUNT, NULL);
 |  | ||||||
| +		entry_list = (struct list_pair *)GETBUF(entry_num * sizeof(struct list_pair));
 |  | ||||||
| +		do_maple_tree(mm_mt, MAPLE_TREE_GATHER, entry_list);
 |  | ||||||
| +		for (i = 0; i < entry_num; i++) {
 |  | ||||||
| +			if (!!(vma = (ulong)entry_list[i].value))
 |  | ||||||
| +				break;
 |  | ||||||
| +		}
 |  | ||||||
| +		FREEBUF(entry_list);
 |  | ||||||
| +	} else {
 |  | ||||||
| +		fill_mm_struct(tc->mm_struct);
 |  | ||||||
| +		vma = ULONG(tt->mm_struct + OFFSET(mm_struct_mmap));
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
|          if (!vma) |  | ||||||
|                  return FALSE; |  | ||||||
|  	vma_buf = fill_vma_cache(vma); |  | ||||||
| @@ -15491,6 +15505,30 @@ search_physical(struct searchinfo *si)
 |  | ||||||
|  	FREEBUF(pagebuf); |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| +static bool
 |  | ||||||
| +check_vma(ulong vma, ulong vaddr, ulong *vm_next, ulong *nextvaddr)
 |  | ||||||
| +{
 |  | ||||||
| +	char *vma_buf;
 |  | ||||||
| +	ulong vm_start, vm_end;
 |  | ||||||
| +
 |  | ||||||
| +	vma_buf = fill_vma_cache(vma);
 |  | ||||||
| +
 |  | ||||||
| +	vm_start = ULONG(vma_buf + OFFSET(vm_area_struct_vm_start));
 |  | ||||||
| +	vm_end = ULONG(vma_buf + OFFSET(vm_area_struct_vm_end));
 |  | ||||||
| +	if (vm_next)
 |  | ||||||
| +		*vm_next = ULONG(vma_buf + OFFSET(vm_area_struct_vm_next));
 |  | ||||||
| +
 |  | ||||||
| +	if (vaddr <= vm_start) {
 |  | ||||||
| +		*nextvaddr = vm_start;
 |  | ||||||
| +		return TRUE;
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	if ((vaddr > vm_start) && (vaddr < vm_end)) {
 |  | ||||||
| +		*nextvaddr = vaddr;
 |  | ||||||
| +		return TRUE;
 |  | ||||||
| +	}
 |  | ||||||
| +	return FALSE;
 |  | ||||||
| +}
 |  | ||||||
|   |  | ||||||
|  /* |  | ||||||
|   *  Return the next mapped user virtual address page that comes after  |  | ||||||
| @@ -15500,37 +15538,40 @@ static int
 |  | ||||||
|  next_upage(struct task_context *tc, ulong vaddr, ulong *nextvaddr) |  | ||||||
|  { |  | ||||||
|  	ulong vma, total_vm; |  | ||||||
| -	char *vma_buf;
 |  | ||||||
| -        ulong vm_start, vm_end;
 |  | ||||||
|  	ulong vm_next; |  | ||||||
| +	ulong mm_mt, entry_num, i;
 |  | ||||||
| +	struct list_pair *entry_list;
 |  | ||||||
|   |  | ||||||
|          if (!tc->mm_struct) |  | ||||||
|                  return FALSE; |  | ||||||
|   |  | ||||||
| -        fill_mm_struct(tc->mm_struct);
 |  | ||||||
| -	vma = ULONG(tt->mm_struct + OFFSET(mm_struct_mmap));
 |  | ||||||
| +	fill_mm_struct(tc->mm_struct);
 |  | ||||||
| +	vaddr = VIRTPAGEBASE(vaddr) + PAGESIZE();  /* first possible page */
 |  | ||||||
|  	total_vm = ULONG(tt->mm_struct + OFFSET(mm_struct_total_vm)); |  | ||||||
| -
 |  | ||||||
| -	if (!vma || (total_vm == 0))
 |  | ||||||
| +	if (!total_vm)
 |  | ||||||
|  		return FALSE; |  | ||||||
|   |  | ||||||
| -	vaddr = VIRTPAGEBASE(vaddr) + PAGESIZE();  /* first possible page */
 |  | ||||||
| -
 |  | ||||||
| -        for ( ; vma; vma = vm_next) {
 |  | ||||||
| -                vma_buf = fill_vma_cache(vma);
 |  | ||||||
| -
 |  | ||||||
| -                vm_start = ULONG(vma_buf + OFFSET(vm_area_struct_vm_start));
 |  | ||||||
| -                vm_end = ULONG(vma_buf + OFFSET(vm_area_struct_vm_end));
 |  | ||||||
| -                vm_next = ULONG(vma_buf + OFFSET(vm_area_struct_vm_next));
 |  | ||||||
| -
 |  | ||||||
| -		if (vaddr <= vm_start) {
 |  | ||||||
| -			*nextvaddr = vm_start;
 |  | ||||||
| -			return TRUE;
 |  | ||||||
| +	if (INVALID_MEMBER(mm_struct_mmap) && VALID_MEMBER(mm_struct_mm_mt)) {
 |  | ||||||
| +		mm_mt = tc->mm_struct + OFFSET(mm_struct_mm_mt);
 |  | ||||||
| +		entry_num = do_maple_tree(mm_mt, MAPLE_TREE_COUNT, NULL);
 |  | ||||||
| +		entry_list = (struct list_pair *)GETBUF(entry_num * sizeof(struct list_pair));
 |  | ||||||
| +		do_maple_tree(mm_mt, MAPLE_TREE_GATHER, entry_list);
 |  | ||||||
| +		for (i = 0; i < entry_num; i++) {
 |  | ||||||
| +			if (!!(vma = (ulong)entry_list[i].value) &&
 |  | ||||||
| +			    check_vma(vma, vaddr, NULL, nextvaddr)) {
 |  | ||||||
| +				FREEBUF(entry_list);
 |  | ||||||
| +				return TRUE;
 |  | ||||||
| +			}
 |  | ||||||
|  		} |  | ||||||
| +		FREEBUF(entry_list);
 |  | ||||||
| +	} else {
 |  | ||||||
| +		vma = ULONG(tt->mm_struct + OFFSET(mm_struct_mmap));
 |  | ||||||
|   |  | ||||||
| -		if ((vaddr > vm_start) && (vaddr < vm_end)) {
 |  | ||||||
| -			*nextvaddr = vaddr;
 |  | ||||||
| -			return TRUE;
 |  | ||||||
| +		if (!vma)
 |  | ||||||
| +			return FALSE;
 |  | ||||||
| +		for ( ; vma; vma = vm_next) {
 |  | ||||||
| +			if (check_vma(vma, vaddr, &vm_next, nextvaddr))
 |  | ||||||
| +				return TRUE;
 |  | ||||||
|  		} |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,258 +0,0 @@ | |||||||
| From 38325fab533751a001b80481cec149213d125abb Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Tue, 7 Mar 2023 17:14:25 +0800 |  | ||||||
| Subject: [PATCH 09/12] Enhance "net" command to display IPv6 address of |  | ||||||
|  network interface |  | ||||||
| 
 |  | ||||||
| Currently, the "net" command displays only the IPv4 address of a network |  | ||||||
| interface.  Support outputting IPv6 addresses.  For example: |  | ||||||
| 
 |  | ||||||
| Without the patch: |  | ||||||
|   crash> net |  | ||||||
|      NET_DEVICE     NAME   IP ADDRESS(ES) |  | ||||||
|   ffff8d01b1205000  lo     127.0.0.1 |  | ||||||
|   ffff8d0087e40000  eno1   192.168.122.2 |  | ||||||
| 
 |  | ||||||
| With the patch: |  | ||||||
|   crash> net |  | ||||||
|      NET_DEVICE     NAME       IP ADDRESS(ES) |  | ||||||
|   ffff8d01b1205000  lo         127.0.0.1, ::1 |  | ||||||
|   ffff8d0087e40000  eno1       192.168.122.2, xxxx:xx:x:xxxx:xxxx:xxx:xxxx:xxxx, yyyy::yyyy:yyy:yyyy:yyyy |  | ||||||
| 
 |  | ||||||
| Also align with longer device names. |  | ||||||
| 
 |  | ||||||
| Related kernel commit: |  | ||||||
| 502a2ffd7376 ("ipv6: convert idev_list to list macros") |  | ||||||
| 
 |  | ||||||
| Reported-by: Buland Kumar Singh <bsingh@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| ---
 |  | ||||||
|  defs.h    |   6 +++ |  | ||||||
|  net.c     | 109 +++++++++++++++++++++++++++++++++++++++++++++++++----- |  | ||||||
|  symbols.c |   6 +++ |  | ||||||
|  3 files changed, 112 insertions(+), 9 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index e76af3c78b69..1f2cf6e0ce01 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -2208,6 +2208,12 @@ struct offset_table {                    /* stash of commonly-used offsets */
 |  | ||||||
|  	long sock_common_skc_v6_daddr; |  | ||||||
|  	long sock_common_skc_v6_rcv_saddr; |  | ||||||
|  	long inactive_task_frame_bp; |  | ||||||
| +	long net_device_ip6_ptr;
 |  | ||||||
| +	long inet6_dev_addr_list;
 |  | ||||||
| +	long inet6_ifaddr_addr;
 |  | ||||||
| +	long inet6_ifaddr_if_list;
 |  | ||||||
| +	long inet6_ifaddr_if_next;
 |  | ||||||
| +	long in6_addr_in6_u;
 |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
|  struct size_table {         /* stash of commonly-used sizes */ |  | ||||||
| diff --git a/net.c b/net.c
 |  | ||||||
| index aa445ab7ee13..987dc8934942 100644
 |  | ||||||
| --- a/net.c
 |  | ||||||
| +++ b/net.c
 |  | ||||||
| @@ -71,6 +71,7 @@ static void print_neighbour_q(ulong, int);
 |  | ||||||
|  static void get_netdev_info(ulong, struct devinfo *); |  | ||||||
|  static void get_device_name(ulong, char *); |  | ||||||
|  static long get_device_address(ulong, char **, long); |  | ||||||
| +static void get_device_ip6_address(ulong, char **, long);
 |  | ||||||
|  static void get_sock_info(ulong, char *); |  | ||||||
|  static void dump_arp(void); |  | ||||||
|  static void arp_state_to_flags(unsigned char); |  | ||||||
| @@ -114,6 +115,13 @@ net_init(void)
 |  | ||||||
|  		net->dev_ip_ptr = MEMBER_OFFSET_INIT(net_device_ip_ptr, |  | ||||||
|  			"net_device", "ip_ptr"); |  | ||||||
|  		MEMBER_OFFSET_INIT(net_device_dev_list, "net_device", "dev_list"); |  | ||||||
| +		MEMBER_OFFSET_INIT(net_device_ip6_ptr, "net_device", "ip6_ptr");
 |  | ||||||
| +		MEMBER_OFFSET_INIT(inet6_dev_addr_list, "inet6_dev", "addr_list");
 |  | ||||||
| +		MEMBER_OFFSET_INIT(inet6_ifaddr_addr, "inet6_ifaddr", "addr");
 |  | ||||||
| +		MEMBER_OFFSET_INIT(inet6_ifaddr_if_list, "inet6_ifaddr", "if_list");
 |  | ||||||
| +		MEMBER_OFFSET_INIT(inet6_ifaddr_if_next, "inet6_ifaddr", "if_next");
 |  | ||||||
| +		MEMBER_OFFSET_INIT(in6_addr_in6_u, "in6_addr", "in6_u");
 |  | ||||||
| +
 |  | ||||||
|  		MEMBER_OFFSET_INIT(net_dev_base_head, "net", "dev_base_head"); |  | ||||||
|  		ARRAY_LENGTH_INIT(net->net_device_name_index, |  | ||||||
|  			net_device_name, "net_device.name", NULL, sizeof(char)); |  | ||||||
| @@ -466,7 +474,7 @@ show_net_devices(ulong task)
 |  | ||||||
|  	buf = GETBUF(buflen); |  | ||||||
|  	flen = MAX(VADDR_PRLEN, strlen(net->netdevice)); |  | ||||||
|   |  | ||||||
| -	fprintf(fp, "%s  NAME   IP ADDRESS(ES)\n",
 |  | ||||||
| +	fprintf(fp, "%s  NAME       IP ADDRESS(ES)\n",
 |  | ||||||
|  		mkstring(upper_case(net->netdevice, buf),  |  | ||||||
|  			flen, CENTER|LJUST, NULL)); |  | ||||||
|   |  | ||||||
| @@ -475,9 +483,10 @@ show_net_devices(ulong task)
 |  | ||||||
|                      mkstring(buf, flen, CENTER|RJUST|LONG_HEX, MKSTR(next))); |  | ||||||
|   |  | ||||||
|  		get_device_name(next, buf); |  | ||||||
| -		fprintf(fp, "%-6s ", buf);
 |  | ||||||
| +		fprintf(fp, "%-10s ", buf);
 |  | ||||||
|   |  | ||||||
| -		buflen = get_device_address(next, &buf, buflen);
 |  | ||||||
| +		get_device_address(next, &buf, buflen);
 |  | ||||||
| +		get_device_ip6_address(next, &buf, buflen);
 |  | ||||||
|  		fprintf(fp, "%s\n", buf); |  | ||||||
|   |  | ||||||
|          	readmem(next+net->dev_next, KVADDR, &next,  |  | ||||||
| @@ -503,7 +512,7 @@ show_net_devices_v2(ulong task)
 |  | ||||||
|  	buf = GETBUF(buflen); |  | ||||||
|  	flen = MAX(VADDR_PRLEN, strlen(net->netdevice)); |  | ||||||
|   |  | ||||||
| -	fprintf(fp, "%s  NAME   IP ADDRESS(ES)\n",
 |  | ||||||
| +	fprintf(fp, "%s  NAME       IP ADDRESS(ES)\n",
 |  | ||||||
|  		mkstring(upper_case(net->netdevice, buf),  |  | ||||||
|  			flen, CENTER|LJUST, NULL)); |  | ||||||
|   |  | ||||||
| @@ -528,9 +537,10 @@ show_net_devices_v2(ulong task)
 |  | ||||||
|  			MKSTR(ld->list_ptr[i]))); |  | ||||||
|   |  | ||||||
|  		get_device_name(ld->list_ptr[i], buf); |  | ||||||
| -		fprintf(fp, "%-6s ", buf);
 |  | ||||||
| +		fprintf(fp, "%-10s ", buf);
 |  | ||||||
|   |  | ||||||
| -		buflen = get_device_address(ld->list_ptr[i], &buf, buflen);
 |  | ||||||
| +		get_device_address(ld->list_ptr[i], &buf, buflen);
 |  | ||||||
| +		get_device_ip6_address(ld->list_ptr[i], &buf, buflen);
 |  | ||||||
|  		fprintf(fp, "%s\n", buf); |  | ||||||
|  	} |  | ||||||
|  	 |  | ||||||
| @@ -556,7 +566,7 @@ show_net_devices_v3(ulong task)
 |  | ||||||
|  	buf = GETBUF(buflen); |  | ||||||
|  	flen = MAX(VADDR_PRLEN, strlen(net->netdevice)); |  | ||||||
|   |  | ||||||
| -	fprintf(fp, "%s  NAME   IP ADDRESS(ES)\n",
 |  | ||||||
| +	fprintf(fp, "%s  NAME       IP ADDRESS(ES)\n",
 |  | ||||||
|  		mkstring(upper_case(net->netdevice, buf),  |  | ||||||
|  			flen, CENTER|LJUST, NULL)); |  | ||||||
|   |  | ||||||
| @@ -591,9 +601,10 @@ show_net_devices_v3(ulong task)
 |  | ||||||
|  			MKSTR(ld->list_ptr[i]))); |  | ||||||
|   |  | ||||||
|  		get_device_name(ld->list_ptr[i], buf); |  | ||||||
| -		fprintf(fp, "%-6s ", buf);
 |  | ||||||
| +		fprintf(fp, "%-10s ", buf);
 |  | ||||||
|   |  | ||||||
| -		buflen = get_device_address(ld->list_ptr[i], &buf, buflen);
 |  | ||||||
| +		get_device_address(ld->list_ptr[i], &buf, buflen);
 |  | ||||||
| +		get_device_ip6_address(ld->list_ptr[i], &buf, buflen);
 |  | ||||||
|  		fprintf(fp, "%s\n", buf); |  | ||||||
|  	} |  | ||||||
|  	 |  | ||||||
| @@ -925,6 +936,86 @@ get_device_address(ulong devaddr, char **bufp, long buflen)
 |  | ||||||
|  	return buflen; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| +static void
 |  | ||||||
| +get_device_ip6_address(ulong devaddr, char **bufp, long buflen)
 |  | ||||||
| +{
 |  | ||||||
| +	ulong ip6_ptr = 0, pos = 0, bufsize = buflen, addr = 0;
 |  | ||||||
| +	struct in6_addr ip6_addr;
 |  | ||||||
| +	char *buf;
 |  | ||||||
| +	char str[INET6_ADDRSTRLEN] = {0};
 |  | ||||||
| +	char buffer[INET6_ADDRSTRLEN + 2] = {0};
 |  | ||||||
| +	uint len = 0;
 |  | ||||||
| +
 |  | ||||||
| +	buf = *bufp;
 |  | ||||||
| +	pos = strlen(buf);
 |  | ||||||
| +
 |  | ||||||
| +	readmem(devaddr + OFFSET(net_device_ip6_ptr), KVADDR,
 |  | ||||||
| +		&ip6_ptr, sizeof(ulong), "ip6_ptr", FAULT_ON_ERROR);
 |  | ||||||
| +
 |  | ||||||
| +	if (!ip6_ptr)
 |  | ||||||
| +		return;
 |  | ||||||
| +
 |  | ||||||
| +	/*
 |  | ||||||
| +	 * 502a2ffd7376 ("ipv6: convert idev_list to list macros")
 |  | ||||||
| +	 * v2.6.35-rc1~473^2~733
 |  | ||||||
| +	 */
 |  | ||||||
| +	if (VALID_MEMBER(inet6_ifaddr_if_list)) {
 |  | ||||||
| +		struct list_data list_data, *ld;
 |  | ||||||
| +		ulong cnt = 0, i;
 |  | ||||||
| +
 |  | ||||||
| +		ld = &list_data;
 |  | ||||||
| +		BZERO(ld, sizeof(struct list_data));
 |  | ||||||
| +		ld->flags |= LIST_ALLOCATE;
 |  | ||||||
| +		ld->start = ip6_ptr + OFFSET(inet6_dev_addr_list);
 |  | ||||||
| +		ld->list_head_offset = OFFSET(inet6_ifaddr_if_list);
 |  | ||||||
| +		cnt = do_list(ld);
 |  | ||||||
| +
 |  | ||||||
| +		for (i = 1; i < cnt; i++) {
 |  | ||||||
| +
 |  | ||||||
| +			addr = ld->list_ptr[i] + OFFSET(inet6_ifaddr_addr);
 |  | ||||||
| +			readmem(addr + OFFSET(in6_addr_in6_u), KVADDR, &ip6_addr,
 |  | ||||||
| +				sizeof(struct in6_addr), "in6_addr.in6_u", FAULT_ON_ERROR);
 |  | ||||||
| +
 |  | ||||||
| +			inet_ntop(AF_INET6, (void*)&ip6_addr, str, INET6_ADDRSTRLEN);
 |  | ||||||
| +			sprintf(buffer, "%s%s", pos ? ", " : "", str);
 |  | ||||||
| +			len = strlen(buffer);
 |  | ||||||
| +			if (pos + len >= bufsize) {
 |  | ||||||
| +				RESIZEBUF(*bufp, bufsize, bufsize + buflen);
 |  | ||||||
| +				buf = *bufp;
 |  | ||||||
| +				BZERO(buf + bufsize, buflen);
 |  | ||||||
| +				bufsize += buflen;
 |  | ||||||
| +			}
 |  | ||||||
| +			BCOPY(buffer, &buf[pos], len);
 |  | ||||||
| +			pos += len;
 |  | ||||||
| +		}
 |  | ||||||
| +
 |  | ||||||
| +		FREEBUF(ld->list_ptr);
 |  | ||||||
| +		return;
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	readmem(ip6_ptr + OFFSET(inet6_dev_addr_list), KVADDR,
 |  | ||||||
| +		&addr, sizeof(void *), "inet6_dev.addr_list", FAULT_ON_ERROR);
 |  | ||||||
| +
 |  | ||||||
| +	while (addr) {
 |  | ||||||
| +		readmem(addr + OFFSET(in6_addr_in6_u), KVADDR, &ip6_addr,
 |  | ||||||
| +			sizeof(struct in6_addr), "in6_addr.in6_u", FAULT_ON_ERROR);
 |  | ||||||
| +		inet_ntop(AF_INET6, (void*)&ip6_addr, str, INET6_ADDRSTRLEN);
 |  | ||||||
| +		sprintf(buffer, "%s%s", pos ? ", " : "", str);
 |  | ||||||
| +		len = strlen(buffer);
 |  | ||||||
| +
 |  | ||||||
| +		if (pos + len >= bufsize) {
 |  | ||||||
| +			RESIZEBUF(*bufp, bufsize, bufsize + buflen);
 |  | ||||||
| +			buf = *bufp;
 |  | ||||||
| +			BZERO(buf + bufsize, buflen);
 |  | ||||||
| +			bufsize += buflen;
 |  | ||||||
| +		}
 |  | ||||||
| +		BCOPY(buffer, &buf[pos], len);
 |  | ||||||
| +		pos += len;
 |  | ||||||
| +		readmem(addr + OFFSET(inet6_ifaddr_if_next), KVADDR, &addr,
 |  | ||||||
| +			sizeof(void *), "inet6_ifaddr.if_next", FAULT_ON_ERROR);
 |  | ||||||
| +	}
 |  | ||||||
| +}
 |  | ||||||
| +
 |  | ||||||
|  /* |  | ||||||
|   *  Get the family, type, local and destination address/port pairs. |  | ||||||
|   */ |  | ||||||
| diff --git a/symbols.c b/symbols.c
 |  | ||||||
| index a974fc9141a0..28846d06273c 100644
 |  | ||||||
| --- a/symbols.c
 |  | ||||||
| +++ b/symbols.c
 |  | ||||||
| @@ -9787,6 +9787,7 @@ dump_offset_table(char *spec, ulong makestruct)
 |  | ||||||
|          	OFFSET(net_device_addr_len)); |  | ||||||
|  	fprintf(fp, "             net_device_ip_ptr: %ld\n", |  | ||||||
|          	OFFSET(net_device_ip_ptr)); |  | ||||||
| +	fprintf(fp, "            net_device_ip6_ptr: %ld\n", OFFSET(net_device_ip6_ptr));
 |  | ||||||
|  	fprintf(fp, "           net_device_dev_list: %ld\n", |  | ||||||
|  		OFFSET(net_device_dev_list)); |  | ||||||
|  	fprintf(fp, "             net_dev_base_head: %ld\n", |  | ||||||
| @@ -9839,6 +9840,11 @@ dump_offset_table(char *spec, ulong makestruct)
 |  | ||||||
|          fprintf(fp, "                  inet_opt_num: %ld\n",  |  | ||||||
|  		OFFSET(inet_opt_num)); |  | ||||||
|   |  | ||||||
| +	fprintf(fp, "           inet6_dev_addr_list: %ld\n", OFFSET(inet6_dev_addr_list));
 |  | ||||||
| +	fprintf(fp, "             inet6_ifaddr_addr: %ld\n", OFFSET(inet6_ifaddr_addr));
 |  | ||||||
| +	fprintf(fp, "          inet6_ifaddr_if_list: %ld\n", OFFSET(inet6_ifaddr_if_list));
 |  | ||||||
| +	fprintf(fp, "          inet6_ifaddr_if_next: %ld\n", OFFSET(inet6_ifaddr_if_next));
 |  | ||||||
| +	fprintf(fp, "                in6_addr_in6_u: %ld\n", OFFSET(in6_addr_in6_u));
 |  | ||||||
|          fprintf(fp, "          ipv6_pinfo_rcv_saddr: %ld\n",  |  | ||||||
|  		OFFSET(ipv6_pinfo_rcv_saddr)); |  | ||||||
|          fprintf(fp, "              ipv6_pinfo_daddr: %ld\n",  |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,44 +0,0 @@ | |||||||
| From 5a652ed0c8db8d4c5891091b747470431054c717 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Wed, 8 Mar 2023 20:22:02 +0800 |  | ||||||
| Subject: [PATCH 11/12] Fix for "net -n" option to properly deal with an |  | ||||||
|  invalid argument |  | ||||||
| 
 |  | ||||||
| The help/man page of the "net" command suggests that "-n" option can |  | ||||||
| accept two kinds of argument: PID or task_struct pointer.  However, |  | ||||||
| the "net -n" command accepts an invalid argument and shows the |  | ||||||
| namespace of the current context silently.  For example: |  | ||||||
| 
 |  | ||||||
|   crash> net -n 1000000000 |  | ||||||
|      NET_DEVICE     NAME   IP ADDRESS(ES) |  | ||||||
|   ffff949dc11d7000  lo     127.0.0.1 |  | ||||||
|   ffff949dcc01c000  eno49  192.168.122.17 |  | ||||||
| 
 |  | ||||||
| With the patch, emit an error expectedly. |  | ||||||
| 
 |  | ||||||
|   crash> net -n 1000000000 |  | ||||||
|   net: invalid task or pid value: 1000000000 |  | ||||||
| 
 |  | ||||||
| Reported-by: Buland Kumar Singh <bsingh@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  net.c | 3 +++ |  | ||||||
|  1 file changed, 3 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/net.c b/net.c
 |  | ||||||
| index 987dc8934942..18c238be346d 100644
 |  | ||||||
| --- a/net.c
 |  | ||||||
| +++ b/net.c
 |  | ||||||
| @@ -420,6 +420,9 @@ cmd_net(void)
 |  | ||||||
|  				case STR_PID: |  | ||||||
|  				case STR_TASK: |  | ||||||
|  					task = tc->task; |  | ||||||
| +					break;
 |  | ||||||
| +				case STR_INVALID:
 |  | ||||||
| +					error(FATAL, "invalid task or pid value: %s\n", args[optind]);
 |  | ||||||
|  				} |  | ||||||
|  			} |  | ||||||
|  			break; |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,71 +0,0 @@ | |||||||
| From ade71c3ec1d28751c3d6ba1eec71781bdff093d3 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| Date: Tue, 7 Mar 2023 19:04:08 +0800 |  | ||||||
| Subject: [PATCH 12/12] gdb: Fix an assertion failure in |  | ||||||
|  dw2_find_pc_sect_compunit_symtab() |  | ||||||
| 
 |  | ||||||
| This is a partial backport patch from gdb commit 834eaf9201c1 ("Fix |  | ||||||
| crash in new DWARF indexer"). |  | ||||||
| 
 |  | ||||||
| Without the patch, the "dis -rl" option may abort due to an assertion |  | ||||||
| failure in gdb's dw2_find_pc_sect_compunit_symtab(): |  | ||||||
| 
 |  | ||||||
|   crash> dis -rl ffffffff96ad716c |  | ||||||
|   dwarf2/read.c:4928: internal-error: compunit_symtab* dw2_find_pc_sect_compunit_symtab(objfile*, bound_minimal_symbol, CORE_ADDR, obj_section*, int): Assertion `result != NULL' failed. |  | ||||||
|   A problem internal to GDB has been detected, |  | ||||||
|   further debugging may prove unreliable. |  | ||||||
|   Quit this debugging session? (y or n) dwarf2/read.c:4928: internal-error: compunit_symtab* dw2_find_pc_sect_compunit_symtab(objfile*, bound_minimal_symbol, CORE_ADDR, obj_section*, int): Assertion `result != NULL' failed. |  | ||||||
|   A problem internal to GDB has been detected, |  | ||||||
|   further debugging may prove unreliable. |  | ||||||
|   Aborted (core dumped) |  | ||||||
| 
 |  | ||||||
| Reported-by: Buland Kumar Singh <bsingh@redhat.com> |  | ||||||
| Signed-off-by: Lianbo Jiang <lijiang@redhat.com> |  | ||||||
| ---
 |  | ||||||
|  gdb-10.2.patch | 19 +++++++++++++++++-- |  | ||||||
|  1 file changed, 17 insertions(+), 2 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/gdb-10.2.patch b/gdb-10.2.patch
 |  | ||||||
| index 5089df9e72e1..835aae9859be 100644
 |  | ||||||
| --- a/gdb-10.2.patch
 |  | ||||||
| +++ b/gdb-10.2.patch
 |  | ||||||
| @@ -4,7 +4,7 @@
 |  | ||||||
|  # that have already been applied.  However, if a gdb file has been modified |  | ||||||
|  # multiple times, the subsequent patching may fail to recognize that a |  | ||||||
|  # given patch has been previously applied, and will attempt to re-apply it. |  | ||||||
| -# To prevent any uninintended consequences, this file also acts as a
 |  | ||||||
| +# To prevent any unintended consequences, this file also acts as a
 |  | ||||||
|  # shell script that can restore any gdb file to its original state prior |  | ||||||
|  # to all subsequent patch applications. |  | ||||||
|   |  | ||||||
| @@ -12,7 +12,8 @@ tar xvzmf gdb-10.2.tar.gz \
 |  | ||||||
|  	gdb-10.2/gdb/symtab.c \ |  | ||||||
|  	gdb-10.2/gdb/printcmd.c \ |  | ||||||
|  	gdb-10.2/gdb/symfile.c \ |  | ||||||
| -	gdb-10.2/gdb/Makefile.in
 |  | ||||||
| +	gdb-10.2/gdb/Makefile.in \
 |  | ||||||
| +	gdb-10.2/gdb/dwarf2/read.c
 |  | ||||||
|   |  | ||||||
|  exit 0 |  | ||||||
|   |  | ||||||
| @@ -3105,3 +3106,17 @@ exit 0
 |  | ||||||
|    |  | ||||||
|   m4_include([../../config/override.m4]) |  | ||||||
|    |  | ||||||
| +--- gdb-10.2/gdb/dwarf2/read.c.orig
 |  | ||||||
| ++++ gdb-10.2/gdb/dwarf2/read.c
 |  | ||||||
| +@@ -4925,7 +4925,10 @@ dw2_find_pc_sect_compunit_symtab (struct objfile *objfile,
 |  | ||||||
| +   result = recursively_find_pc_sect_compunit_symtab
 |  | ||||||
| +     (dw2_instantiate_symtab (data, per_objfile, false), pc);
 |  | ||||||
| + 
 |  | ||||||
| +-  gdb_assert (result != NULL);
 |  | ||||||
| ++  if (warn_if_readin && result == nullptr)
 |  | ||||||
| ++    warning (_("(Error: pc %s in address map, but not in symtab.)"),
 |  | ||||||
| ++            paddress (objfile->arch (), pc));
 |  | ||||||
| ++
 |  | ||||||
| +   return result;
 |  | ||||||
| + }
 |  | ||||||
| + 
 |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,159 +0,0 @@ | |||||||
| From 489093c2183f4f0365d8957e7275cd88225942ce Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| Date: Fri, 10 Mar 2023 02:38:26 +0000 |  | ||||||
| Subject: [PATCH] Fix "kmem -n" option to display memory blocks on Linux |  | ||||||
|  6.3-rc1 and later |  | ||||||
| 
 |  | ||||||
| Kernel commit d2bf38c088e0 ("driver core: remove private pointer from |  | ||||||
| struct bus_type") removed the bus_type.p member, and the "kmem -n" |  | ||||||
| option fails with the following error before displaying memory block |  | ||||||
| information on Linux 6.3-rc1 and later kernels. |  | ||||||
| 
 |  | ||||||
|   kmem: invalid structure member offset: bus_type_p |  | ||||||
|         FILE: memory.c  LINE: 17852  FUNCTION: init_memory_block() |  | ||||||
| 
 |  | ||||||
| Search bus_kset.list instead for subsys_private of memory subsys. |  | ||||||
| 
 |  | ||||||
| Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com> |  | ||||||
| ---
 |  | ||||||
|  defs.h    |  2 ++ |  | ||||||
|  memory.c  | 63 +++++++++++++++++++++++++++++++++++++++++++++++++------ |  | ||||||
|  symbols.c |  2 ++ |  | ||||||
|  3 files changed, 61 insertions(+), 6 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/defs.h b/defs.h
 |  | ||||||
| index 1f2cf6e0ce01..12ad6aaa0998 100644
 |  | ||||||
| --- a/defs.h
 |  | ||||||
| +++ b/defs.h
 |  | ||||||
| @@ -2214,6 +2214,8 @@ struct offset_table {                    /* stash of commonly-used offsets */
 |  | ||||||
|  	long inet6_ifaddr_if_list; |  | ||||||
|  	long inet6_ifaddr_if_next; |  | ||||||
|  	long in6_addr_in6_u; |  | ||||||
| +	long kset_kobj;
 |  | ||||||
| +	long subsys_private_subsys;
 |  | ||||||
|  }; |  | ||||||
|   |  | ||||||
|  struct size_table {         /* stash of commonly-used sizes */ |  | ||||||
| diff --git a/memory.c b/memory.c
 |  | ||||||
| index c4a6ecd18004..592a5ef49d50 100644
 |  | ||||||
| --- a/memory.c
 |  | ||||||
| +++ b/memory.c
 |  | ||||||
| @@ -17822,6 +17822,13 @@ static void
 |  | ||||||
|  init_memory_block_offset(void) |  | ||||||
|  { |  | ||||||
|  	MEMBER_OFFSET_INIT(bus_type_p, "bus_type", "p"); |  | ||||||
| +	if (INVALID_MEMBER(bus_type_p)) {
 |  | ||||||
| +		MEMBER_OFFSET_INIT(kset_list, "kset", "list");
 |  | ||||||
| +		MEMBER_OFFSET_INIT(kset_kobj, "kset", "kobj");
 |  | ||||||
| +		MEMBER_OFFSET_INIT(kobject_name, "kobject", "name");
 |  | ||||||
| +		MEMBER_OFFSET_INIT(kobject_entry, "kobject", "entry");
 |  | ||||||
| +		MEMBER_OFFSET_INIT(subsys_private_subsys, "subsys_private", "subsys");
 |  | ||||||
| +	}
 |  | ||||||
|  	MEMBER_OFFSET_INIT(subsys_private_klist_devices, |  | ||||||
|  				"subsys_private", "klist_devices"); |  | ||||||
|  	MEMBER_OFFSET_INIT(klist_k_list, "klist", "k_list"); |  | ||||||
| @@ -17842,15 +17849,60 @@ init_memory_block_offset(void)
 |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  static void |  | ||||||
| -init_memory_block(struct list_data *ld, int *klistcnt, ulong **klistbuf)
 |  | ||||||
| +init_memory_block(int *klistcnt, ulong **klistbuf)
 |  | ||||||
|  { |  | ||||||
| -	ulong memory_subsys = symbol_value("memory_subsys");
 |  | ||||||
|  	ulong private, klist, start; |  | ||||||
| +	struct list_data list_data, *ld;
 |  | ||||||
| +
 |  | ||||||
| +	ld = &list_data;
 |  | ||||||
| +	private = 0;
 |  | ||||||
|   |  | ||||||
|  	init_memory_block_offset(); |  | ||||||
|   |  | ||||||
| -	readmem(memory_subsys + OFFSET(bus_type_p), KVADDR, &private,
 |  | ||||||
| -		sizeof(void *), "memory_subsys.private", FAULT_ON_ERROR);
 |  | ||||||
| +	/*
 |  | ||||||
| +	 * v6.3-rc1
 |  | ||||||
| +	 * d2bf38c088e0 driver core: remove private pointer from struct bus_type
 |  | ||||||
| +	 */
 |  | ||||||
| +	if (INVALID_MEMBER(bus_type_p)) {
 |  | ||||||
| +		int i, cnt;
 |  | ||||||
| +		char buf[32];
 |  | ||||||
| +		ulong bus_kset, list, name;
 |  | ||||||
| +
 |  | ||||||
| +		BZERO(ld, sizeof(struct list_data));
 |  | ||||||
| +
 |  | ||||||
| +		get_symbol_data("bus_kset", sizeof(ulong), &bus_kset);
 |  | ||||||
| +		readmem(bus_kset + OFFSET(kset_list), KVADDR, &list,
 |  | ||||||
| +			sizeof(ulong), "bus_kset.list", FAULT_ON_ERROR);
 |  | ||||||
| +
 |  | ||||||
| +		ld->flags |= LIST_ALLOCATE;
 |  | ||||||
| +		ld->start = list;
 |  | ||||||
| +		ld->end = bus_kset + OFFSET(kset_list);
 |  | ||||||
| +		ld->list_head_offset = OFFSET(kobject_entry);
 |  | ||||||
| +
 |  | ||||||
| +		cnt = do_list(ld);
 |  | ||||||
| +		for (i = 0; i < cnt; i++) {
 |  | ||||||
| +			readmem(ld->list_ptr[i] + OFFSET(kobject_name), KVADDR, &name,
 |  | ||||||
| +				sizeof(ulong), "kobject.name", FAULT_ON_ERROR);
 |  | ||||||
| +			read_string(name, buf, sizeof(buf)-1);
 |  | ||||||
| +			if (CRASHDEBUG(1))
 |  | ||||||
| +				fprintf(fp, "kobject: %lx name: %s\n", ld->list_ptr[i], buf);
 |  | ||||||
| +			if (STREQ(buf, "memory")) {
 |  | ||||||
| +				/* entry is subsys_private.subsys.kobj. See bus_to_subsys(). */
 |  | ||||||
| +				private = ld->list_ptr[i] - OFFSET(kset_kobj)
 |  | ||||||
| +						- OFFSET(subsys_private_subsys);
 |  | ||||||
| +				break;
 |  | ||||||
| +			}
 |  | ||||||
| +		}
 |  | ||||||
| +		FREEBUF(ld->list_ptr);
 |  | ||||||
| +	} else {
 |  | ||||||
| +		ulong memory_subsys = symbol_value("memory_subsys");
 |  | ||||||
| +		readmem(memory_subsys + OFFSET(bus_type_p), KVADDR, &private,
 |  | ||||||
| +			sizeof(void *), "memory_subsys.private", FAULT_ON_ERROR);
 |  | ||||||
| +	}
 |  | ||||||
| +
 |  | ||||||
| +	if (!private)
 |  | ||||||
| +		error(FATAL, "cannot determine subsys_private for memory.\n");
 |  | ||||||
| +
 |  | ||||||
|  	klist = private + OFFSET(subsys_private_klist_devices) + |  | ||||||
|  					OFFSET(klist_k_list); |  | ||||||
|  	BZERO(ld, sizeof(struct list_data)); |  | ||||||
| @@ -17875,7 +17927,6 @@ dump_memory_blocks(int initialize)
 |  | ||||||
|  	ulong memory_block, device; |  | ||||||
|  	ulong *klistbuf; |  | ||||||
|  	int klistcnt, i; |  | ||||||
| -	struct list_data list_data;
 |  | ||||||
|  	char mb_hdr[BUFSIZE]; |  | ||||||
|  	char paddr_hdr[BUFSIZE]; |  | ||||||
|  	char buf1[BUFSIZE]; |  | ||||||
| @@ -17892,7 +17943,7 @@ dump_memory_blocks(int initialize)
 |  | ||||||
|  	if (initialize) |  | ||||||
|  		return; |  | ||||||
|   |  | ||||||
| -	init_memory_block(&list_data, &klistcnt, &klistbuf);
 |  | ||||||
| +	init_memory_block(&klistcnt, &klistbuf);
 |  | ||||||
|   |  | ||||||
|  	if ((symbol_exists("memory_block_size_probed")) || |  | ||||||
|  	    (MEMBER_EXISTS("memory_block", "end_section_nr"))) |  | ||||||
| diff --git a/symbols.c b/symbols.c
 |  | ||||||
| index 28846d06273c..f0721023816d 100644
 |  | ||||||
| --- a/symbols.c
 |  | ||||||
| +++ b/symbols.c
 |  | ||||||
| @@ -10404,6 +10404,7 @@ dump_offset_table(char *spec, ulong makestruct)
 |  | ||||||
|  		OFFSET(kobject_entry)); |  | ||||||
|  	fprintf(fp, "                     kset_list: %ld\n", |  | ||||||
|  		OFFSET(kset_list)); |  | ||||||
| +	fprintf(fp, "                     kset_kobj: %ld\n", OFFSET(kset_kobj));
 |  | ||||||
|  	fprintf(fp, "            request_list_count: %ld\n", |  | ||||||
|  		OFFSET(request_list_count)); |  | ||||||
|  	fprintf(fp, "             request_cmd_flags: %ld\n", |  | ||||||
| @@ -10441,6 +10442,7 @@ dump_offset_table(char *spec, ulong makestruct)
 |  | ||||||
|  	fprintf(fp, "               blk_mq_tags_rqs: %ld\n", |  | ||||||
|  		OFFSET(blk_mq_tags_rqs)); |  | ||||||
|   |  | ||||||
| +	fprintf(fp, "         subsys_private_subsys: %ld\n", OFFSET(subsys_private_subsys));
 |  | ||||||
|  	fprintf(fp, "  subsys_private_klist_devices: %ld\n", |  | ||||||
|  		OFFSET(subsys_private_klist_devices)); |  | ||||||
|  	fprintf(fp, "                subsystem_kset: %ld\n", |  | ||||||
| -- 
 |  | ||||||
| 2.37.1 |  | ||||||
| 
 |  | ||||||
| @ -1,5 +1,5 @@ | |||||||
| --- crash-8.0.2/Makefile.orig
 | --- crash-8.0.3/Makefile.orig
 | ||||||
| +++ crash-8.0.2/Makefile
 | +++ crash-8.0.3/Makefile
 | ||||||
| @@ -204,7 +204,7 @@ GDB_FLAGS=
 | @@ -204,7 +204,7 @@ GDB_FLAGS=
 | ||||||
|  # TARGET_CFLAGS will be configured automatically by configure |  # TARGET_CFLAGS will be configured automatically by configure | ||||||
|  TARGET_CFLAGS= |  TARGET_CFLAGS= | ||||||
| @ -18,8 +18,8 @@ | |||||||
|  	@echo "../../${PROGRAM} ../../${PROGRAM}lib.a" > ${GDB}/gdb/mergeobj |  	@echo "../../${PROGRAM} ../../${PROGRAM}lib.a" > ${GDB}/gdb/mergeobj | ||||||
|  	@rm -f ${PROGRAM} |  	@rm -f ${PROGRAM} | ||||||
|  	@if [ ! -f ${GDB}/config.status ]; then \ |  	@if [ ! -f ${GDB}/config.status ]; then \ | ||||||
| --- crash-8.0.2/configure.c.orig
 | --- crash-8.0.3/configure.c.orig
 | ||||||
| +++ crash-8.0.2/configure.c
 | +++ crash-8.0.3/configure.c
 | ||||||
| @@ -810,7 +810,8 @@ build_configure(struct supported_gdb_version *sp)
 | @@ -810,7 +810,8 @@ build_configure(struct supported_gdb_version *sp)
 | ||||||
|                          fprintf(fp2, "%s\n", sp->GDB); |                          fprintf(fp2, "%s\n", sp->GDB); | ||||||
|                          sprintf(target_data.gdb_version, "%s", &sp->GDB[4]); |                          sprintf(target_data.gdb_version, "%s", &sp->GDB[4]); | ||||||
							
								
								
									
										91
									
								
								crash.spec
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								crash.spec
									
									
									
									
									
								
							| @ -3,8 +3,8 @@ | |||||||
| # | # | ||||||
| Summary: Kernel analysis utility for live systems, netdump, diskdump, kdump, LKCD or mcore dumpfiles | Summary: Kernel analysis utility for live systems, netdump, diskdump, kdump, LKCD or mcore dumpfiles | ||||||
| Name: crash | Name: crash | ||||||
| Version: 8.0.2 | Version: 8.0.3 | ||||||
| Release: 4%{?dist} | Release: 1%{?dist} | ||||||
| License: GPLv3 | License: GPLv3 | ||||||
| Source0: https://github.com/crash-utility/crash/archive/crash-%{version}.tar.gz | Source0: https://github.com/crash-utility/crash/archive/crash-%{version}.tar.gz | ||||||
| Source1: http://ftp.gnu.org/gnu/gdb/gdb-10.2.tar.gz | Source1: http://ftp.gnu.org/gnu/gdb/gdb-10.2.tar.gz | ||||||
| @ -18,48 +18,7 @@ Requires: binutils | |||||||
| Provides: bundled(libiberty) | Provides: bundled(libiberty) | ||||||
| Provides: bundled(gdb) = 10.2 | Provides: bundled(gdb) = 10.2 | ||||||
| Patch0: lzo_snappy_zstd.patch | Patch0: lzo_snappy_zstd.patch | ||||||
| Patch1: 0001-ps-Provide-an-option-to-display-no-header-line.patch | Patch1: crash-8.0.3_build.patch | ||||||
| Patch2: 0002-arm64-fix-backtraces-of-KASAN-kernel-dumpfile-trunca.patch |  | ||||||
| Patch3: 0003-arm64-handle-vabits_actual-symbol-missing-case.patch |  | ||||||
| Patch4: 0004-EPPIC-extension-support-for-crash-8.x-gdb-10.x.patch |  | ||||||
| Patch5: 0005-x86_64-Fix-for-move-of-per-cpu-variables-into-struct.patch |  | ||||||
| Patch6: 0006-Fix-for-mm_struct.rss_stat-conversion-into-percpu_co.patch |  | ||||||
| Patch7: 0007-Fix-mount-command-to-appropriately-display-the-mount.patch |  | ||||||
| Patch8: 0008-Add-RISCV64-framework-code-support.patch |  | ||||||
| Patch9: 0009-RISCV64-Make-crash-tool-enter-command-line-and-suppo.patch |  | ||||||
| Patch10: 0010-RISCV64-Add-dis-command-support.patch |  | ||||||
| Patch11: 0011-RISCV64-Add-irq-command-support.patch |  | ||||||
| Patch12: 0012-RISCV64-Add-bt-command-support.patch |  | ||||||
| Patch13: 0013-RISCV64-Add-help-r-command-support.patch |  | ||||||
| Patch14: 0014-RISCV64-Add-help-m-M-command-support.patch |  | ||||||
| Patch15: 0015-RISCV64-Add-mach-command-support.patch |  | ||||||
| Patch16: 0016-RISCV64-Add-the-implementation-of-symbol-verify.patch |  | ||||||
| Patch17: 0017-SLUB-Fix-for-offset-change-of-struct-slab-members-on.patch |  | ||||||
| Patch18: 0018-Fix-for-kmem-i-to-display-correct-SLAB-statistics-on.patch |  | ||||||
| Patch19: 0019-Fix-build-failure-due-to-no-EM_RISCV-with-glibc-2.23.patch |  | ||||||
| Patch20: 0020-gdb-Fix-an-assertion-failure-in-the-gdb-s-copy_type.patch |  | ||||||
| Patch21: 0021-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.1-and-later.patch |  | ||||||
| Patch22: 0022-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.2-rc1-and-l.patch |  | ||||||
| Patch23: 0023-Port-the-maple-tree-data-structures-and-functions.patch |  | ||||||
| Patch24: 0024-Add-maple-tree-support-to-tree-command.patch |  | ||||||
| Patch25: 0025-Add-do_maple_tree-for-maple-tree-operations.patch |  | ||||||
| Patch26: 0026-Introduce-maple-tree-vma-iteration-to-vm_area_dump.patch |  | ||||||
| Patch27: 0027-Update-the-help-text-of-tree-command-for-maple-tree.patch |  | ||||||
| Patch28: 0028-Dump-maple-tree-offset-variables-by-help-o.patch |  | ||||||
| Patch29: 0029-Fix-for-bt-command-printing-bogus-exception-frame-wa.patch |  | ||||||
| Patch30: 0030-Fix-kmem-s-S-not-working-properly-on-RHEL8.6-and-lat.patch |  | ||||||
| Patch31: 0031-Fix-for-net-s-option-to-show-IPv6-addresses-on-Linux.patch |  | ||||||
| Patch32: 0032-Fix-for-kmem-i-option-to-not-print-invalid-values-fo.patch |  | ||||||
| Patch33: 0033-Fix-for-bt-command-unnecessarily-printing-an-excepti.patch |  | ||||||
| Patch34: 0034-Fix-for-dis-command-to-correctly-display-the-offset-.patch |  | ||||||
| Patch35: 0035-x86_64-Fix-bt-command-on-kernels-with-random_kstack_.patch |  | ||||||
| Patch36: 0036-Fix-for-search-u-option-failing-in-maple-tree-kernel.patch |  | ||||||
| Patch37: 0037-Enhance-net-command-to-display-IPv6-address-of-netwo.patch |  | ||||||
| Patch38: 0038-Fix-C99-compatibility-issues-in-embedded-copy-of-GDB.patch |  | ||||||
| Patch39: 0039-Fix-for-net-n-option-to-properly-deal-with-an-invali.patch |  | ||||||
| Patch40: 0040-gdb-Fix-an-assertion-failure-in-dw2_find_pc_sect_com.patch |  | ||||||
| Patch41: 0041-Fix-kmem-n-option-to-display-memory-blocks-on-Linux-.patch |  | ||||||
| Patch42: crash-8.0.2_build.patch |  | ||||||
| 
 | 
 | ||||||
| %description | %description | ||||||
| The core analysis suite is a self-contained tool that can be used to | The core analysis suite is a self-contained tool that can be used to | ||||||
| @ -81,47 +40,6 @@ offered by Mission Critical Linux, or the LKCD kernel patch. | |||||||
| %setup -n %{name}-%{version} -q | %setup -n %{name}-%{version} -q | ||||||
| %patch0 -p1 -b lzo_snappy_zstd.patch | %patch0 -p1 -b lzo_snappy_zstd.patch | ||||||
| %patch1 -p1 | %patch1 -p1 | ||||||
| %patch2 -p1 |  | ||||||
| %patch3 -p1 |  | ||||||
| %patch4 -p1 |  | ||||||
| %patch5 -p1 |  | ||||||
| %patch6 -p1 |  | ||||||
| %patch7 -p1 |  | ||||||
| %patch8 -p1 |  | ||||||
| %patch9 -p1 |  | ||||||
| %patch10 -p1 |  | ||||||
| %patch11 -p1 |  | ||||||
| %patch12 -p1 |  | ||||||
| %patch13 -p1 |  | ||||||
| %patch14 -p1 |  | ||||||
| %patch15 -p1 |  | ||||||
| %patch16 -p1 |  | ||||||
| %patch17 -p1 |  | ||||||
| %patch18 -p1 |  | ||||||
| %patch19 -p1 |  | ||||||
| %patch20 -p1 |  | ||||||
| %patch21 -p1 |  | ||||||
| %patch22 -p1 |  | ||||||
| %patch23 -p1 |  | ||||||
| %patch24 -p1 |  | ||||||
| %patch25 -p1 |  | ||||||
| %patch26 -p1 |  | ||||||
| %patch27 -p1 |  | ||||||
| %patch28 -p1 |  | ||||||
| %patch29 -p1 |  | ||||||
| %patch30 -p1 |  | ||||||
| %patch31 -p1 |  | ||||||
| %patch32 -p1 |  | ||||||
| %patch33 -p1 |  | ||||||
| %patch34 -p1 |  | ||||||
| %patch35 -p1 |  | ||||||
| %patch36 -p1 |  | ||||||
| %patch37 -p1 |  | ||||||
| %patch38 -p1 |  | ||||||
| %patch39 -p1 |  | ||||||
| %patch40 -p1 |  | ||||||
| %patch41 -p1 |  | ||||||
| %patch42 -p1 |  | ||||||
| 
 | 
 | ||||||
| %build | %build | ||||||
| 
 | 
 | ||||||
| @ -147,6 +65,9 @@ cp -p defs.h %{buildroot}%{_includedir}/crash | |||||||
| %{_includedir}/* | %{_includedir}/* | ||||||
| 
 | 
 | ||||||
| %changelog | %changelog | ||||||
|  | * Fri Apr 28 2023 Lianbo Jiang <lijiang@redhat.com> - 8.0.3-1 | ||||||
|  | - Rebase to upstream crash 8.0.3 | ||||||
|  | 
 | ||||||
| * Fri Mar 10 2023 Lianbo Jiang <lijiang@redhat.com> - 8.0.2-4 | * Fri Mar 10 2023 Lianbo Jiang <lijiang@redhat.com> - 8.0.2-4 | ||||||
| - Fix "kmem -n" option to display memory blocks on Linux 6.3-rc1 and later | - Fix "kmem -n" option to display memory blocks on Linux 6.3-rc1 and later | ||||||
| - gdb: Fix an assertion failure in dw2_find_pc_sect_compunit_symtab() | - gdb: Fix an assertion failure in dw2_find_pc_sect_compunit_symtab() | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								sources
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								sources
									
									
									
									
									
								
							| @ -1,2 +1,2 @@ | |||||||
| SHA512 (crash-8.0.2.tar.gz) = 9ff24d1206e9376e83690f76c817a48a68ff6adce677fad70335a73550a59c9af6e4753c1199f22eafa60c137156313244bbf98ed01bc2b066f41d324738ef6b | SHA512 (crash-8.0.3.tar.gz) = 1ce7fda89274051cea02a049a674f2ca43fc02e00121f951af0d4c23c7b74cc79949ec376bb6737f82b95fec0cbe495b53a09df7e5f1f31ee5a829c1d53d0ba0 | ||||||
| SHA512 (gdb-10.2.tar.gz) = aa89caf47c1c84366020377d47e7c51ddbc48e5b7686f244e38797c8eb88411cf57fcdc37eb669961efb41ceeac4181747f429625fd1acce7712cb9a1fea9c41 | SHA512 (gdb-10.2.tar.gz) = aa89caf47c1c84366020377d47e7c51ddbc48e5b7686f244e38797c8eb88411cf57fcdc37eb669961efb41ceeac4181747f429625fd1acce7712cb9a1fea9c41 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user