Update to the latest commit <46344aa2f92b>

Release: crash-8.0.2-3

Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
This commit is contained in:
Lianbo Jiang 2023-02-07 10:51:06 +08:00
parent 80a83f7af4
commit 22c47c372b
30 changed files with 6397 additions and 9 deletions

View File

@ -0,0 +1,72 @@
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

@ -0,0 +1,150 @@
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

@ -0,0 +1,37 @@
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

@ -0,0 +1,479 @@
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

@ -0,0 +1,144 @@
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

@ -0,0 +1,163 @@
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

@ -0,0 +1,48 @@
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

@ -0,0 +1,692 @@
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

@ -0,0 +1,44 @@
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

@ -0,0 +1,36 @@
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

@ -0,0 +1,413 @@
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

@ -0,0 +1,80 @@
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

@ -0,0 +1,141 @@
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

@ -0,0 +1,83 @@
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

@ -0,0 +1,45 @@
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

@ -0,0 +1,149 @@
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

@ -0,0 +1,49 @@
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

@ -0,0 +1,49 @@
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

@ -0,0 +1,74 @@
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

@ -0,0 +1,46 @@
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

@ -0,0 +1,233 @@
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

@ -0,0 +1,633 @@
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

@ -0,0 +1,335 @@
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

@ -0,0 +1,205 @@
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

@ -0,0 +1,455 @@
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

@ -0,0 +1,135 @@
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

@ -0,0 +1,52 @@
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,9 +1,9 @@
--- a/gdb-10.2.patch
+++ b/gdb-10.2.patch
@@ -1737,3 +1737,14 @@ exit 0
struct field *nextfield;
short nfields;
struct type *typedef_type, *target_type;
@@ -2078,3 +2078,14 @@ exit 0
return new_type;
}
+--- gdb-10.2/gnulib/import/libc-config.h.orig
++++ gdb-10.2/gnulib/import/libc-config.h
+@@ -156,7 +156,7 @@

View File

@ -4,7 +4,7 @@
Summary: Kernel analysis utility for live systems, netdump, diskdump, kdump, LKCD or mcore dumpfiles
Name: crash
Version: 8.0.2
Release: 2%{?dist}
Release: 3%{?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,8 +18,36 @@ Requires: binutils
Provides: bundled(libiberty)
Provides: bundled(gdb) = 10.2
Patch0: lzo_snappy_zstd.patch
Patch1: crash-8.0.2_build.patch
Patch2: crash-8.0.0-5-gdb-cdefs.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: crash-8.0.2_build.patch
Patch30: crash-8.0.0-5-gdb-cdefs.patch
%description
The core analysis suite is a self-contained tool that can be used to
@ -40,9 +68,37 @@ offered by Mission Critical Linux, or the LKCD kernel patch.
%prep
%setup -n %{name}-%{version} -q
%patch0 -p1 -b lzo_snappy_zstd.patch
%patch1 -p1 -b crash-8.0.2_build.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 -b crash-8.0.2_build.patch
%ifarch ppc64le
%patch2 -p1 -b crash-8.0.0-5-gdb-cdefs.patch
%patch30 -p1 -b crash-8.0.0-5-gdb-cdefs.patch
%endif
@ -70,6 +126,9 @@ cp -p defs.h %{buildroot}%{_includedir}/crash
%{_includedir}/*
%changelog
* Tue Feb 07 2023 Lianbo Jiang <lijiang@redhat.com> - 8.0.2-3
- Update to the latest upstream commit <46344aa2f92b>
* Thu Jan 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 8.0.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild