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:
Lianbo Jiang 2023-04-28 13:26:04 +08:00
parent f24b8df61c
commit 922cb60578
45 changed files with 12 additions and 9013 deletions

1
.gitignore vendored
View File

@ -47,5 +47,6 @@ crash-5.0.6.tar.gz
/crash-8.0.0.tar.gz
/crash-8.0.1.tar.gz
/crash-8.0.2.tar.gz
/crash-8.0.3.tar.gz
/gdb-7.6.tar.gz
/gdb-10.2.tar.gz

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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, &current, &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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
--- crash-8.0.2/Makefile.orig
+++ crash-8.0.2/Makefile
--- crash-8.0.3/Makefile.orig
+++ crash-8.0.3/Makefile
@@ -204,7 +204,7 @@ GDB_FLAGS=
# TARGET_CFLAGS will be configured automatically by configure
TARGET_CFLAGS=
@ -18,8 +18,8 @@
@echo "../../${PROGRAM} ../../${PROGRAM}lib.a" > ${GDB}/gdb/mergeobj
@rm -f ${PROGRAM}
@if [ ! -f ${GDB}/config.status ]; then \
--- crash-8.0.2/configure.c.orig
+++ crash-8.0.2/configure.c
--- crash-8.0.3/configure.c.orig
+++ crash-8.0.3/configure.c
@@ -810,7 +810,8 @@ build_configure(struct supported_gdb_version *sp)
fprintf(fp2, "%s\n", sp->GDB);
sprintf(target_data.gdb_version, "%s", &sp->GDB[4]);

View File

@ -3,8 +3,8 @@
#
Summary: Kernel analysis utility for live systems, netdump, diskdump, kdump, LKCD or mcore dumpfiles
Name: crash
Version: 8.0.2
Release: 4%{?dist}
Version: 8.0.3
Release: 1%{?dist}
License: GPLv3
Source0: https://github.com/crash-utility/crash/archive/crash-%{version}.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(gdb) = 10.2
Patch0: lzo_snappy_zstd.patch
Patch1: 0001-ps-Provide-an-option-to-display-no-header-line.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
Patch1: crash-8.0.3_build.patch
%description
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
%patch0 -p1 -b lzo_snappy_zstd.patch
%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
@ -147,6 +65,9 @@ cp -p defs.h %{buildroot}%{_includedir}/crash
%{_includedir}/*
%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
- 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()

View File

@ -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