[PATCH v1 0/3] Add valgrind support for the crash's custom memory
by HATAYAMA Daisuke
This patch set adds valgrind support for the crash's custom memory
allocator. The motivation comes from investigation at
https://github.com/crash-utility/crash-extensions/issues/1.
The 1st patch implements the valgrind support, while 2nd and 3rd fixes
the actual issues on the crash's custom memory allocator detected by
valgrind.
HATAYAMA Daisuke (3):
Add valgrind support for the crash's custom memory allocator
symbols: Fix potential read to already freed object
tools: Fix potential write to object of 0 size
Makefile | 4 ++++
configure.c | 15 ++++++++++++-
symbols.c | 10 +++------
tools.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 91 insertions(+), 10 deletions(-)
--
1.8.3.1
3 years, 9 months
Re: [Crash-utility] increase __PHYSICAL_MASK_SHIFT_XEN
by lijiang
Hi, Jiri
Thank you for the update.
在 2021年01月26日 09:46, crash-utility-request(a)redhat.com 写道:
> Date: Mon, 25 Jan 2021 22:44:50 +0100
> From: Jiri Bohac <jbohac(a)suse.cz>
> To: lijiang <lijiang(a)redhat.com>
> Cc: crash-utility(a)redhat.com
> Subject: [Crash-utility] [PATCH] increase __PHYSICAL_MASK_SHIFT_XEN
> Message-ID: <20210125214450.n5qvx6pjg2otslrm(a)dwarf.suse.cz>
> Content-Type: text/plain; charset=us-ascii
>
> The current value of __PHYSICAL_MASK_SHIFT_XEN in crash (40) is
> smaller than the kernel (52) since kernel commit 6f0e8bf167 (xen:
> support 52 bit physical addresses in pv guests).
>
> This can cause x86_64_pud_offset() to lose the most significant
> bits of pgd_pte, leading to a failed xen_m2p() translation,
> resulting in crash failing with an error message like this:
> crash: read error: physical address: ffffffffffffffff type: "pud page"
>
> Both Intel and AMD documentation mandate that unused physical
> address bits must be 0, so there is no need to explicitly mask them
> out with a mask narrower than the architecture limit of 52. This
> is also confirmed by this kernel commit: b83ce5ee91.
>
> Increase the value of __PHYSICAL_MASK_SHIFT_XEN to 52.
>
> Signed-off-by: Jiri Bohac <jbohac(a)suse.cz>
>
> diff --git a/defs.h b/defs.h
> index e468b1d..848c1f6 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -3583,7 +3583,7 @@ struct arm64_stackframe {
> * PHYSICAL_PAGE_MASK changed (enlarged) between 2.4 and 2.6, so
> * for safety, use the 2.6 values to generate it.
> */
> -#define __PHYSICAL_MASK_SHIFT_XEN 40
> +#define __PHYSICAL_MASK_SHIFT_XEN 52
> #define __PHYSICAL_MASK_SHIFT_2_6 46
> #define __PHYSICAL_MASK_SHIFT_5LEVEL 52
> #define __PHYSICAL_MASK_SHIFT (machdep->machspec->physical_mask_shift)
>
Acked-by: Lianbo Jiang <lijiang(a)redhat.com>
>
> -- Jiri Bohac <jbohac(a)suse.cz> SUSE Labs, Prague, Czechia
3 years, 10 months
Re: [Crash-utility] [PATCH v3 1/2] Update gdb to 10.1
by lijiang
Hi, Kazu, Alexey
在 2021年01月16日 01:00, crash-utility-request(a)redhat.com 写道:
> Date: Fri, 15 Jan 2021 17:35:32 +0800
> From: lijiang <lijiang(a)redhat.com>
> To: crash-utility(a)redhat.com, crash-utility-request(a)redhat.com
> Subject: Re: [Crash-utility] [PATCH v3 1/2] Update gdb to 10.1
> Message-ID: <d3eaaa31-4a70-cc25-12e6-9e08181b93a3(a)redhat.com>
> Content-Type: text/plain; charset=utf-8
>
> Hi, Alexey
>
> Sorry for the late reply. And also thank you for the update.
>
> At present, I'm looking at this patchset, but I have to say that this is a big one,
> I will take some time to understand these changes and think more about this.
>
> And I will provide feedback ASAP.
>
After applied the v3 series based on the latest crash, I got the following error:
# crash vmlinux vmcore
crash 7.2.9++
Copyright (C) 2002-2020 Red Hat, Inc.
Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation
Copyright (C) 1999-2006 Hewlett-Packard Co
Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited
Copyright (C) 2006, 2007 VA Linux Systems Japan K.K.
Copyright (C) 2005, 2011 NEC Corporation
Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc.
Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
Copyright (C) 2015, 2020 VMware, Inc.
This program is free software, covered by the GNU General Public License,
and you are welcome to change it and/or distribute copies of it under
certain conditions. Enter "help copying" to see the conditions.
This program has absolutely no warranty. Enter "help warranty" for details.
GNU gdb (GDB) 10.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from 3.10.0-957.el7.x86_64/vmlinux...
thread.c:95: internal-error: thread_info* inferior_thread(): Assertion `current_thread_ != nullptr' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) n
This is a bug, please report it.
thread.c:95: internal-error: thread_info* inferior_thread(): Assertion `current_thread_ != nullptr' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Create a core file of GDB? (y or n) y
Command aborted.
#
We would make sure that the crash has good backward compatibility.
I didn't test the functions yet, there may be another issues. In view of this, I would suggest temporarily
putting the patch series in our reviewing queue, because this is a big change and need to handle it carefully.
Currently, I'm planning to improve the test cases. Once the test is ready, which can help us find out more
potential issues. And we can improve it based on this series. What do you think? Kazu, Bhupesh and Alexey.
Thanks.
Lianbo
> Thanks.
> Lianbo
> ? 2020?12?29? 18:06, crash-utility-request(a)redhat.com ??:
>> Date: Tue, 29 Dec 2020 02:06:08 -0800
>> From: Alexey Makhalov <amakhalov(a)vmware.com>
>> To: <crash-utility(a)redhat.com>, <k-hagio-ab(a)nec.com>
>> Subject: [Crash-utility] [PATCH v3 1/2] Update gdb to 10.1
>> Message-ID: <20201229100609.83147-2-amakhalov(a)vmware.com>
>> Content-Type: text/plain
>>
>> Fully redone gdb-7.6.patch to gdb-10.1.patch to keep all
>> functionality. Changes which were dropped are saved in
>> dropped-gdb-7.6-to-10.1.patch
>>
>> Main difference between gdb-7.6 and gdb-10.1 is the last
>> one was rewritten in C++.
>> I continue to keep crash code in C. Mark transition
>> functions as extern "C" to resolve linking issues.
>>
>> Eliminated error_hook() and SJLJ while running in C++ code
>> (after gdb_command_funnel()) use try-catch mechanism instead.
>>
>> request_types() was redone to do not call
>> GNU_GET_NEXT_DATATYPE multiple times but single usage of
>> GNU_ITERATE_DATATYPES with proper callback instead.
>> Complete iteration happens on C++ side now.
>> Removed "struct global_iterator" from request structure,
>> but added several fields (including callback pointer) to
>> be able to perform iteration on C++ side.
>>
>> Type of "linux_banner" symbol is reported as 'D' by new
>> gdb as its section ".rodata" marked as writable in vmlinux.
>>
>> BFD API has changed.
>>
>> deprecated_command_loop_hook got deprecated. So, call crash
>> main_loop() directly from gdb captured_main().
>>
>> Added symbol file (vmlinux) rebase in gdb by kaslr_offset.
>> by using new function: objfile_rebase().
>> As result, we do not need kernel symbol patching as well as
>> bait_and_switch hook anymore.
>>
>> Added crash_target for gdb to provide target operations
>> such as xfer_partial to read and write crash dump memory.
>> Removed previously used hooks for that in target.c.
>> Keep crash_target.c as a file in crash folder instead of
>> in gdb-10.1.patch for easier development and history
>> tracking.
>> crash_target can be enhanced in future to provide access
>> to CPU registers, so backtrace and frame related commands
>> from gdb can be used.
>>
>> Removed gdb-7.6-proc_service.h.patch is not required as
>> gdb-10.1 already has this change.
>>
>> Extra: add VMware copyright to the version info.
>>
>> TODO:
>> 1) gdb-10.1-ppc64le-support.patch has to be updated with
>> following commits.
>> 2) deprecate #if defined(GDB_X_Y) code as crash really
>> supports only the latest gdb (only one patch).
>> 3) move gdb_funnel_command() and subfunctions to separate
>> file, similar to crash_target.c
>> 4) remove legacy kernel patching and bait_and_switch hook.
>>
>> Signed-off-by: Alexey Makhalov <amakhalov(a)vmware.com>
>> ---
>> Makefile | 11 +-
>> configure.c | 20 +-
>> crash_target.c | 104 +
>> defs.h | 35 +-
>> dropped-gdb-7.6-to-10.1.patch | 303 +++
>> ...support.patch => gdb-10.1-ppc64le-support.patch | 0
>> gdb-10.1.patch | 1577 ++++++++++++
>> gdb-7.6-proc_service.h.patch | 67 -
>> gdb-7.6.patch | 2503 --------------------
>> gdb_interface.c | 85 +-
>> help.c | 1 +
>> kernel.c | 2 +-
>> main.c | 1 -
>> symbols.c | 125 +-
>> x86_64.c | 14 +-
>> 15 files changed, 2141 insertions(+), 2707 deletions(-)
>> create mode 100644 crash_target.c
>> create mode 100644 dropped-gdb-7.6-to-10.1.patch
>> rename gdb-7.6-ppc64le-support.patch => gdb-10.1-ppc64le-support.patch (100%)
>> create mode 100644 gdb-10.1.patch
>> delete mode 100644 gdb-7.6-proc_service.h.patch
>> delete mode 100644 gdb-7.6.patch
3 years, 10 months
[PATCH 16/16] MIPS64: Add 'help -r' command support
by Youling Tang
Add support form printing out the registers from the dump file. We don't
take the registers directly from the ELF notes but instead use the version
we've saved into the machine_specific structure. If we don't do this,
we'd get misleading output when the number of ELF notes don't match the
number of online CPUs.
E.g. Without this patch:
crash> help -r
help: -r option not supported for this dumpfile
E.g. With this patch:
crash> help -r
...
CPU 3:
R0: 0000000000000000 R1: 0000000000000001 R2: 9800000254f3c400
R3: 0000000000000000 R4: ffffffff8123b6b0 R5: 0000000000000000
R6: 9800000243bcf200 R7: fffffffffffffff8 R8: fffffffffffffffd
R9: 00180000000000ff R10: ffffffff810e29a8 R11: ffffffff80e84190
R12: 000000005400cce0 R13: 0000000000000000 R14: 0000000000000040
R15: 6e69636e79732074 R16: ffffffff81200000 R17: ffffffff81240000
R18: 0000000000000000 R19: ffffffff81430000 R20: 980000024291f938
R21: 0000000000000001 R22: 980000024aef7320 R23: ffffffff81430000
R24: 0000000000000002 R25: ffffffff80878b58 R26: 0000000000000000
R27: 0000000000000000 R28: 980000024291c000 R29: 980000024291f930
R30: 9800000243bcf200 R31: ffffffff802fff00
LO: ffffffff81210000 HI: ffffffff81210000
EPC: ffffffff802fff84 BADVADDR: ffffffff802bbe9c
STATUS: ffffffff81430000 CAUSE: 9800000243bcf200
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
diskdump.c | 13 ++++++++++--
mips64.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
netdump.c | 4 ++++
3 files changed, 85 insertions(+), 2 deletions(-)
diff --git a/diskdump.c b/diskdump.c
index b5e77da..43400b7 100644
--- a/diskdump.c
+++ b/diskdump.c
@@ -2486,6 +2486,14 @@ diskdump_display_regs(int cpu, FILE *ofp)
UINT(user_regs + OFFSET(user_regs_struct_eflags))
);
}
+
+ if (machine_type("MIPS")) {
+#ifdef MIPS
+ mips_display_regs_from_elf_notes(cpu, ofp);
+#else
+ mips64_display_regs_from_elf_notes(cpu, ofp);
+#endif
+ }
}
void
@@ -2494,8 +2502,9 @@ dump_registers_for_compressed_kdump(void)
int c;
if (!KDUMP_CMPRS_VALID() || (dd->header->header_version < 4) ||
- !(machine_type("X86") || machine_type("X86_64") ||
- machine_type("ARM64") || machine_type("PPC64")))
+ !(machine_type("X86") || machine_type("X86_64") ||
+ machine_type("ARM64") || machine_type("PPC64") ||
+ machine_type("MIPS")))
error(FATAL, "-r option not supported for this dumpfile\n");
if (machine_type("ARM64") && (kt->cpus != dd->num_prstatus_notes))
diff --git a/mips64.c b/mips64.c
index 843983a..22cac3d 100644
--- a/mips64.c
+++ b/mips64.c
@@ -1290,9 +1290,79 @@ mips64_init(int when)
}
}
+/*
+ * 'help -r' command output
+ */
void
mips64_display_regs_from_elf_notes(int cpu, FILE *ofp)
{
+ const struct machine_specific *ms = machdep->machspec;
+ struct mips64_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[MIPS64_EF_R29] && !regs->regs[MIPS64_EF_CP0_EPC]) {
+ error(INFO, "registers not collected for cpu %d\n", cpu);
+ return;
+ }
+
+ fprintf(ofp,
+ " R0: %016lx R1: %016lx R2: %016lx\n"
+ " R3: %016lx R4: %016lx R5: %016lx\n"
+ " R6: %016lx R7: %016lx R8: %016lx\n"
+ " R9: %016lx R10: %016lx R11: %016lx\n"
+ " R12: %016lx R13: %016lx R14: %016lx\n"
+ " R15: %016lx R16: %016lx R17: %016lx\n"
+ " R18: %016lx R19: %016lx R20: %016lx\n"
+ " R21: %016lx R22: %016lx R23: %016lx\n"
+ " R24: %016lx R25: %016lx R26: %016lx\n"
+ " R27: %016lx R28: %016lx R29: %016lx\n"
+ " R30: %016lx R31: %016lx\n"
+ " LO: %016lx HI: %016lx\n"
+ " EPC: %016lx BADVADDR: %016lx\n"
+ " STATUS: %016lx CAUSE: %016lx\n",
+ regs->regs[MIPS64_EF_R0],
+ regs->regs[MIPS64_EF_R0 + 1],
+ regs->regs[MIPS64_EF_R0 + 2],
+ regs->regs[MIPS64_EF_R0 + 3],
+ regs->regs[MIPS64_EF_R0 + 4],
+ regs->regs[MIPS64_EF_R0 + 5],
+ regs->regs[MIPS64_EF_R0 + 6],
+ regs->regs[MIPS64_EF_R0 + 7],
+ regs->regs[MIPS64_EF_R0 + 8],
+ regs->regs[MIPS64_EF_R0 + 9],
+ regs->regs[MIPS64_EF_R0 + 10],
+ regs->regs[MIPS64_EF_R0 + 11],
+ regs->regs[MIPS64_EF_R0 + 12],
+ regs->regs[MIPS64_EF_R0 + 13],
+ regs->regs[MIPS64_EF_R0 + 14],
+ regs->regs[MIPS64_EF_R0 + 15],
+ regs->regs[MIPS64_EF_R0 + 16],
+ regs->regs[MIPS64_EF_R0 + 17],
+ regs->regs[MIPS64_EF_R0 + 18],
+ regs->regs[MIPS64_EF_R0 + 19],
+ regs->regs[MIPS64_EF_R0 + 20],
+ regs->regs[MIPS64_EF_R0 + 21],
+ regs->regs[MIPS64_EF_R0 + 22],
+ regs->regs[MIPS64_EF_R0 + 23],
+ regs->regs[MIPS64_EF_R0 + 24],
+ regs->regs[MIPS64_EF_R0 + 25],
+ regs->regs[MIPS64_EF_R0 + 26],
+ regs->regs[MIPS64_EF_R0 + 27],
+ regs->regs[MIPS64_EF_R0 + 28],
+ regs->regs[MIPS64_EF_R0 + 29],
+ regs->regs[MIPS64_EF_R0 + 30],
+ regs->regs[MIPS64_EF_R0 + 31],
+ regs->regs[MIPS64_EF_LO],
+ regs->regs[MIPS64_EF_HI],
+ regs->regs[MIPS64_EF_CP0_EPC],
+ regs->regs[MIPS64_EF_CP0_BADVADDR],
+ regs->regs[MIPS64_EF_CP0_STATUS],
+ regs->regs[MIPS64_EF_CP0_CAUSE]);
}
#else /* !MIPS64 */
diff --git a/netdump.c b/netdump.c
index f2b3363..c9ce83b 100644
--- a/netdump.c
+++ b/netdump.c
@@ -2922,7 +2922,11 @@ display_regs_from_elf_notes(int cpu, FILE *ofp)
ULONG(user_regs + sizeof(ulong) * 33),
UINT(user_regs + sizeof(ulong) * 34));
} else if (machine_type("MIPS")) {
+#ifdef MIPS
mips_display_regs_from_elf_notes(cpu, ofp);
+#else
+ mips64_display_regs_from_elf_notes(cpu, ofp);
+#endif
}
}
--
2.1.0
3 years, 10 months
[PATCH 13/16] MIPS64: Add 'bt -l' command support
by Youling Tang
Add 'bt -l' command support, get a line number associated with a
current pc address.
E.g. With this patch:
crash> bt -l
PID: 4768 TASK: 9800000243bcf200 CPU: 3 COMMAND: "bash"
#0 [980000024291f930] __crash_kexec at ffffffff802fff84
/home/tang/loongson-419/linux-4.19.152kexec/./arch/mips/include/asm/stacktrace.h: 43
#1 [980000024291faa0] panic at ffffffff80248cac
/home/tang/loongson-419/linux-4.19.152kexec/kernel/panic.c: 206
...
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/mips64.c b/mips64.c
index 2708f5d..6e8e922 100644
--- a/mips64.c
+++ b/mips64.c
@@ -647,6 +647,15 @@ mips64_dump_backtrace_entry(struct bt_info *bt, struct syment *sym,
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);
+ }
+
if (sym && mips64_is_exception_entry(sym)) {
GET_STACK_DATA(current->sp, &pt_regs, SIZE(pt_regs));
mips64_dump_exception_stack(bt, pt_regs);
--
2.1.0
3 years, 10 months
[PATCH 12/16] MIPS64: Add 'bt -f' command support
by Youling Tang
Add 'bt -f' command support, display all stack data contained in a frame.
E.g. With this patch:
crash> bt -f
PID: 4768 TASK: 9800000243bcf200 CPU: 3 COMMAND: "bash"
#0 [980000024291f930] __crash_kexec at ffffffff802fff84
[PC: ffffffff802fff84 RA: ffffffff80248cac SP: 980000024291f930 SIZE: 368]
980000024291f930: ffffffff81239060 ffffffff802a9944
980000024291f940: 0000000000000001 9800000254f3c400
...
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/mips64.c b/mips64.c
index d949af4..2708f5d 100644
--- a/mips64.c
+++ b/mips64.c
@@ -37,6 +37,9 @@ static void mips64_dump_backtrace_entry(struct bt_info *bt,
struct mips64_unwind_frame *previous, int level);
static void mips64_dump_exception_stack(struct bt_info *bt, char *pt_regs);
static int mips64_is_exception_entry(struct syment *sym);
+static void mips64_display_full_frame(struct bt_info *bt,
+ struct mips64_unwind_frame *current,
+ struct mips64_unwind_frame *previous);
static void mips64_stackframe_init(void);
static void mips64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp);
static int mips64_get_dumpfile_stack_frame(struct bt_info *bt,
@@ -648,6 +651,15 @@ mips64_dump_backtrace_entry(struct bt_info *bt, struct syment *sym,
GET_STACK_DATA(current->sp, &pt_regs, SIZE(pt_regs));
mips64_dump_exception_stack(bt, pt_regs);
}
+
+ /* bt -f */
+ if (bt->flags & BT_FULL) {
+ fprintf(fp, " "
+ "[PC: %016lx RA: %016lx SP: %016lx SIZE: %ld]\n",
+ current->pc, current->ra, current->sp,
+ previous->sp - current->sp);
+ mips64_display_full_frame(bt, current, previous);
+ }
}
static void
@@ -692,6 +704,40 @@ mips64_is_exception_entry(struct syment *sym)
STREQ(sym->name, "handle_sys64");
}
+/*
+ * 'bt -f' commend output
+ * Display all stack data contained in a frame
+ */
+static void
+mips64_display_full_frame(struct bt_info *bt, struct mips64_unwind_frame *current,
+ struct mips64_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
mips64_stackframe_init(void)
{
--
2.1.0
3 years, 10 months
[PATCH 10/16] MIPS64: Add basic support for the 'bt' command
by Youling Tang
Add basic support for the 'bt' command, refer to the implementation
of mips.c.
E.g. With this patch:
crash> bt
PID: 4768 TASK: 9800000243bcf200 CPU: 3 COMMAND: "bash"
bt: WARNING: cannot determine starting stack frame for task 9800000243bcf200
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 427 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 426 insertions(+), 1 deletion(-)
diff --git a/mips64.c b/mips64.c
index 18e763d..57a7f41 100644
--- a/mips64.c
+++ b/mips64.c
@@ -28,6 +28,21 @@ static int mips64_kvtop(struct task_context *tc, ulong kvaddr,
physaddr_t *paddr, int verbose);
static void mips64_cmd_mach(void);
static void mips64_display_machine_stats(void);
+static void mips64_back_trace_cmd(struct bt_info *bt);
+static void mips64_analyze_function(ulong start, ulong offset,
+ struct mips64_unwind_frame *current,
+ struct mips64_unwind_frame *previous);
+static void mips64_dump_backtrace_entry(struct bt_info *bt,
+ struct syment *sym, struct mips64_unwind_frame *current,
+ struct mips64_unwind_frame *previous, int level);
+static void mips64_dump_exception_stack(struct bt_info *bt, char *pt_regs);
+static int mips64_is_exception_entry(struct syment *sym);
+static void mips64_stackframe_init(void);
+static void mips64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp);
+static int mips64_get_dumpfile_stack_frame(struct bt_info *bt,
+ ulong *nip, ulong *ksp);
+static int mips64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp);
+
/*
* 3 Levels paging PAGE_SIZE=16KB
@@ -385,6 +400,413 @@ mips64_display_machine_stats(void)
}
/*
+ * Unroll a kernel stack.
+ */
+static void
+mips64_back_trace_cmd(struct bt_info *bt)
+{
+ struct mips64_unwind_frame current, previous;
+ struct mips64_register *regs;
+ struct mips64_pt_regs_main *mains;
+ struct mips64_pt_regs_cp0 *cp0;
+ char pt_regs[SIZE(pt_regs)];
+ int level = 0;
+ int invalid_ok = 1;
+
+ if (bt->flags & BT_REGS_NOT_FOUND)
+ return;
+
+ previous.sp = previous.pc = previous.ra = 0;
+
+ current.pc = bt->instptr;
+ current.sp = bt->stkptr;
+ current.ra = 0;
+
+ if (!INSTACK(current.sp, bt))
+ return;
+
+ if (bt->machdep) {
+ regs = bt->machdep;
+ previous.pc = current.ra = regs->regs[MIPS64_EF_R31];
+ }
+
+ while (current.sp <= bt->stacktop - 32 - SIZE(pt_regs)) {
+ struct syment *symbol = NULL;
+ ulong offset;
+
+ if (CRASHDEBUG(8))
+ fprintf(fp, "level %d pc %#lx ra %#lx sp %lx\n",
+ level, current.pc, current.ra, current.sp);
+
+ if (!IS_KVADDR(current.pc) && !invalid_ok)
+ return;
+
+ symbol = value_search(current.pc, &offset);
+ if (!symbol && !invalid_ok) {
+ error(FATAL, "PC is unknown symbol (%lx)", current.pc);
+ return;
+ }
+ invalid_ok = 0;
+
+ /*
+ * If we get an address which points to the start of a
+ * function, then it could one of the following:
+ *
+ * - we are dealing with a noreturn function. The last call
+ * from a noreturn function has an ra which points to the
+ * start of the function after it. This is common in the
+ * oops callchain because of die() which is annotated as
+ * noreturn.
+ *
+ * - we have taken an exception at the start of this function.
+ * In this case we already have the RA in current.ra.
+ *
+ * - we are in one of these routines which appear with zero
+ * offset in manually-constructed stack frames:
+ *
+ * * ret_from_exception
+ * * ret_from_irq
+ * * ret_from_fork
+ * * ret_from_kernel_thread
+ */
+ if (symbol && !STRNEQ(symbol->name, "ret_from") && !offset &&
+ !current.ra && current.sp < bt->stacktop - 32 - SIZE(pt_regs)) {
+ if (CRASHDEBUG(8))
+ fprintf(fp, "zero offset at %s, try previous symbol\n",
+ symbol->name);
+
+ symbol = value_search(current.pc - 4, &offset);
+ if (!symbol) {
+ error(FATAL, "PC is unknown symbol (%lx)", current.pc);
+ return;
+ }
+ }
+
+ if (symbol && mips64_is_exception_entry(symbol)) {
+
+ mains = (struct mips64_pt_regs_main *) \
+ (pt_regs + OFFSET(pt_regs_regs));
+ cp0 = (struct mips64_pt_regs_cp0 *) \
+ (pt_regs + OFFSET(pt_regs_cp0_badvaddr));
+
+ GET_STACK_DATA(current.sp, pt_regs, sizeof(pt_regs));
+
+ previous.ra = mains->regs[31];
+ previous.sp = mains->regs[29];
+ current.ra = cp0->cp0_epc;
+
+ if (CRASHDEBUG(8))
+ fprintf(fp, "exception pc %#lx ra %#lx sp %lx\n",
+ previous.pc, previous.ra, previous.sp);
+
+ /* The PC causing the exception may have been invalid */
+ invalid_ok = 1;
+ } else if (symbol) {
+ mips64_analyze_function(symbol->value, offset, ¤t, &previous);
+ } else {
+ /*
+ * The current PC is invalid. Assume that the code
+ * jumped through a invalid pointer and that the SP has
+ * not been adjusted.
+ */
+ previous.sp = current.sp;
+ }
+
+ mips64_dump_backtrace_entry(bt, symbol, ¤t, &previous, level++);
+
+ current.pc = current.ra;
+ current.sp = previous.sp;
+ current.ra = previous.ra;
+
+ if (CRASHDEBUG(8))
+ fprintf(fp, "next %d pc %#lx ra %#lx sp %lx\n",
+ level, current.pc, current.ra, current.sp);
+
+ previous.sp = previous.pc = previous.ra = 0;
+ }
+}
+
+static void
+mips64_analyze_function(ulong start, ulong offset,
+ struct mips64_unwind_frame *current,
+ struct mips64_unwind_frame *previous)
+{
+ ulong i, reg;
+ ulong rapos = 0;
+ ulong spadjust = 0;
+ uint32_t *funcbuf, *ip;
+
+ if (CRASHDEBUG(8))
+ fprintf(fp, "%s: start %#lx offset %#lx\n",
+ __func__, start, offset);
+
+ if (!offset) {
+ previous->sp = current->sp;
+ return;
+ }
+
+ ip = funcbuf = (uint32_t *)GETBUF(offset);
+ if (!readmem(start, KVADDR, funcbuf, offset,
+ "mips64_analyze_function", RETURN_ON_ERROR)) {
+ FREEBUF(funcbuf);
+ error(WARNING, "Cannot read function at %16lx\n", start);
+ return;
+ }
+
+ for (i = 0; i < offset; i += 4) {
+ ulong insn = *ip & 0xffffffff;
+ ulong high = (insn >> 16) & 0xffff;
+ ulong low = insn & 0xffff;
+
+ if (CRASHDEBUG(8))
+ fprintf(fp, "insn @ %#lx = %#lx\n", start + i, insn);
+
+ if (high == 0x27bd || high == 0x67bd) { /* ADDIU/DADDIU sp, sp, imm */
+ if (!(low & 0x8000))
+ break;
+
+ spadjust += 0x10000 - low;
+ if (CRASHDEBUG(8))
+ fprintf(fp, "spadjust = %lu\n", spadjust);
+ } else if (high == 0xafbf) { /* SW RA, imm(SP) */
+ rapos = current->sp + low;
+ if (CRASHDEBUG(8))
+ fprintf(fp, "rapos %lx\n", rapos);
+ break;
+ } else if (high == 0xffbf) { /* SD RA, imm(SP) */
+ rapos = current->sp + low;
+ if (CRASHDEBUG(8))
+ fprintf(fp, "rapos %lx\n", rapos);
+ break;
+ } else if ((insn & 0xffe08020) == 0xeba00020) { /* GSSQ reg, reg, offset(SP) */
+ reg = (insn >> 16) & 0x1f;
+ if (reg == 31) {
+ low = ((((insn >> 6) & 0x1ff) ^ 0x100) - 0x100) << 4;
+ rapos = current->sp + low;
+ if (CRASHDEBUG(8))
+ fprintf(fp, "rapos %lx\n", rapos);
+ break;
+ }
+ reg = insn & 0x1f;
+ if (reg == 31) {
+ low = (((((insn >> 6) & 0x1ff) ^ 0x100) - 0x100) << 4) + 8;
+ rapos = current->sp + low;
+ if (CRASHDEBUG(8))
+ fprintf(fp, "rapos %lx\n", rapos);
+ break;
+ }
+ }
+
+ ip++;
+ }
+
+ FREEBUF(funcbuf);
+
+ previous->sp = current->sp + spadjust;
+
+ if (rapos && !readmem(rapos, KVADDR, ¤t->ra,
+ sizeof(current->ra), "RA from stack",
+ RETURN_ON_ERROR)) {
+ error(FATAL, "Cannot read RA from stack %lx", rapos);
+ return;
+ }
+}
+
+static void
+mips64_dump_backtrace_entry(struct bt_info *bt, struct syment *sym,
+ struct mips64_unwind_frame *current,
+ struct mips64_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];
+ char pt_regs[SIZE(pt_regs)];
+
+ 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");
+
+ if (sym && mips64_is_exception_entry(sym)) {
+ GET_STACK_DATA(current->sp, &pt_regs, SIZE(pt_regs));
+ mips64_dump_exception_stack(bt, pt_regs);
+ }
+}
+
+static void
+mips64_dump_exception_stack(struct bt_info *bt, char *pt_regs)
+{
+ struct mips64_pt_regs_main *mains;
+ struct mips64_pt_regs_cp0 *cp0;
+ int i;
+ char buf[BUFSIZE];
+
+ mains = (struct mips64_pt_regs_main *) (pt_regs + OFFSET(pt_regs_regs));
+ cp0 = (struct mips64_pt_regs_cp0 *) \
+ (pt_regs + OFFSET(pt_regs_cp0_badvaddr));
+
+ for (i = 0; i < 32; i += 4) {
+ fprintf(fp, " $%2d : %016lx %016lx %016lx %016lx\n",
+ i, mains->regs[i], mains->regs[i+1],
+ mains->regs[i+2], mains->regs[i+3]);
+ }
+ fprintf(fp, " Hi : %016lx\n", mains->hi);
+ fprintf(fp, " Lo : %016lx\n", mains->lo);
+
+ value_to_symstr(cp0->cp0_epc, buf, 16);
+ fprintf(fp, " epc : %016lx %s\n", cp0->cp0_epc, buf);
+
+ value_to_symstr(mains->regs[31], buf, 16);
+ fprintf(fp, " ra : %016lx %s\n", mains->regs[31], buf);
+
+ fprintf(fp, " Status: %016lx\n", mains->cp0_status);
+ fprintf(fp, " Cause : %016lx\n", cp0->cp0_cause);
+ fprintf(fp, " BadVA : %016lx\n", cp0->cp0_badvaddr);
+}
+
+static int
+mips64_is_exception_entry(struct syment *sym)
+{
+ return STREQ(sym->name, "ret_from_exception") ||
+ STREQ(sym->name, "ret_from_irq") ||
+ STREQ(sym->name, "work_resched") ||
+ STREQ(sym->name, "handle_sys") ||
+ STREQ(sym->name, "handle_sysn32") ||
+ STREQ(sym->name, "handle_sys64");
+}
+
+static void
+mips64_stackframe_init(void)
+{
+ long task_struct_thread = MEMBER_OFFSET("task_struct", "thread");
+ long thread_reg29 = MEMBER_OFFSET("thread_struct", "reg29");
+ long thread_reg31 = MEMBER_OFFSET("thread_struct", "reg31");
+
+ if ((task_struct_thread == INVALID_OFFSET) ||
+ (thread_reg29 == INVALID_OFFSET) ||
+ (thread_reg31 == INVALID_OFFSET)) {
+ error(FATAL,
+ "cannot determine thread_struct offsets\n");
+ return;
+ }
+
+ ASSIGN_OFFSET(task_struct_thread_reg29) =
+ task_struct_thread + thread_reg29;
+ ASSIGN_OFFSET(task_struct_thread_reg31) =
+ task_struct_thread + thread_reg31;
+
+ STRUCT_SIZE_INIT(pt_regs, "pt_regs");
+ MEMBER_OFFSET_INIT(pt_regs_regs, "pt_regs", "regs");
+ MEMBER_OFFSET_INIT(pt_regs_cp0_badvaddr, "pt_regs", "cp0_badvaddr");
+}
+
+/*
+ * Get a stack frame combination of pc and ra from the most relevant spot.
+ */
+static void
+mips64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
+{
+ ulong ksp, nip;
+ int ret = 0;
+
+ nip = ksp = 0;
+ bt->machdep = NULL;
+
+ if (DUMPFILE() && is_task_active(bt->task))
+ ret = mips64_get_dumpfile_stack_frame(bt, &nip, &ksp);
+ else
+ ret = mips64_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
+mips64_get_dumpfile_stack_frame(struct bt_info *bt, ulong *nip, ulong *ksp)
+{
+ const struct machine_specific *ms = machdep->machspec;
+ struct mips64_register *regs;
+ ulong epc, r29;
+
+ 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[MIPS64_EF_CP0_EPC];
+ r29 = regs->regs[MIPS64_EF_R29];
+
+ if (!epc && !r29) {
+ bt->flags |= BT_REGS_NOT_FOUND;
+ return FALSE;
+ }
+
+ if (nip)
+ *nip = epc;
+ if (ksp)
+ *ksp = r29;
+
+ bt->machdep = regs;
+
+ return TRUE;
+}
+
+/*
+ * Do the work for mips64_get_stack_frame() for non-active tasks.
+ * Get SP and PC values for idle tasks.
+ */
+static int
+mips64_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_reg31),
+ KVADDR, pcp, sizeof(*pcp),
+ "thread_struct.regs31",
+ RETURN_ON_ERROR)) {
+ return FALSE;
+ }
+
+ if (!readmem(bt->task + OFFSET(task_struct_thread_reg29),
+ KVADDR, spp, sizeof(*spp),
+ "thread_struct.regs29",
+ RETURN_ON_ERROR)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
* Accept or reject a symbol from the kernel namelist.
*/
static int
@@ -414,7 +836,7 @@ mips64_get_page_size(void)
static ulong
mips64_vmalloc_start(void)
{
- return 0;
+ return first_vmalloc_address();
}
/*
@@ -515,6 +937,8 @@ mips64_init(int when)
machdep->uvtop = mips64_uvtop;
machdep->kvtop = mips64_kvtop;
machdep->cmd_mach = mips64_cmd_mach;
+ machdep->back_trace = mips64_back_trace_cmd;
+ machdep->get_stack_frame = mips64_get_stack_frame;
machdep->vmalloc_start = mips64_vmalloc_start;
machdep->processor_speed = mips64_processor_speed;
machdep->get_stackbase = generic_get_stackbase;
@@ -532,6 +956,7 @@ mips64_init(int when)
mips64_init_page_flags();
machdep->section_size_bits = _SECTION_SIZE_BITS;
machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
+ mips64_stackframe_init();
if (!machdep->hz)
machdep->hz = 250;
break;
--
2.1.0
3 years, 10 months
[PATCH 09/16] MIPS64: Add 'mach' command support
by Youling Tang
The 'mach' command can only get some basic machine state information, such
as machine type, processor speed, etc.
E.g. With this patch:
crash> mach
MACHINE TYPE: mips64
MEMORY SIZE: 7.5 GB
CPUS: 4
PROCESSOR SPEED: 1800 Mhz
HZ: 250
PAGE SIZE: 16384
KERNEL STACK SIZE: 16384
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 61 insertions(+), 3 deletions(-)
diff --git a/mips64.c b/mips64.c
index a0d7220..18e763d 100644
--- a/mips64.c
+++ b/mips64.c
@@ -17,15 +17,17 @@
#include <elf.h>
#include "defs.h"
+static void mips64_init_page_flags(void);
+static int mips64_translate_pte(ulong pte, void *physaddr,
+ ulonglong pte64);
static int mips64_pgd_vtop(ulong *pgd, ulong vaddr,
physaddr_t *paddr, int verbose);
static int mips64_uvtop(struct task_context *tc, ulong vaddr,
physaddr_t *paddr, int verbose);
static int mips64_kvtop(struct task_context *tc, ulong kvaddr,
physaddr_t *paddr, int verbose);
-static void mips64_init_page_flags(void);
-static int mips64_translate_pte(ulong pte, void *physaddr,
- ulonglong pte64);
+static void mips64_cmd_mach(void);
+static void mips64_display_machine_stats(void);
/*
* 3 Levels paging PAGE_SIZE=16KB
@@ -330,6 +332,59 @@ mips64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbo
}
/*
+ * Machine dependent command.
+ */
+static void
+mips64_cmd_mach(void)
+{
+ 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);
+
+ mips64_display_machine_stats();
+}
+
+/*
+ * "mach" command output.
+ */
+static void
+mips64_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());
+
+}
+
+/*
* Accept or reject a symbol from the kernel namelist.
*/
static int
@@ -459,6 +514,7 @@ mips64_init(int when)
machdep->is_uvaddr = generic_is_uvaddr;
machdep->uvtop = mips64_uvtop;
machdep->kvtop = mips64_kvtop;
+ machdep->cmd_mach = mips64_cmd_mach;
machdep->vmalloc_start = mips64_vmalloc_start;
machdep->processor_speed = mips64_processor_speed;
machdep->get_stackbase = generic_get_stackbase;
@@ -476,6 +532,8 @@ mips64_init(int when)
mips64_init_page_flags();
machdep->section_size_bits = _SECTION_SIZE_BITS;
machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
+ if (!machdep->hz)
+ machdep->hz = 250;
break;
case POST_VM:
--
2.1.0
3 years, 10 months
[PATCH 08/16] MIPS64: Add to get processor speed
by Youling Tang
Obtain the processor speed from the kernel symbol "mips_cpu_frequency" or
"cpu_clock_freq".
E.g. With this patch:
...
MACHINE: mips64 (1800 Mhz)
...
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/mips64.c b/mips64.c
index 1d1297f..a0d7220 100644
--- a/mips64.c
+++ b/mips64.c
@@ -362,9 +362,29 @@ mips64_vmalloc_start(void)
return 0;
}
+/*
+ * Calculate and return the speed of the processor.
+ */
static ulong
mips64_processor_speed(void)
{
+ unsigned long cpu_hz1 = 0, cpu_hz2 = 0;
+
+ if (machdep->mhz)
+ return (machdep->mhz);
+
+ if (symbol_exists("mips_cpu_frequency")) {
+ get_symbol_data("mips_cpu_frequency", sizeof(int), &cpu_hz1);
+ if (cpu_hz1)
+ return(machdep->mhz = cpu_hz1/1000000);
+ }
+
+ if (symbol_exists("cpu_clock_freq")) {
+ get_symbol_data("cpu_clock_freq", sizeof(int), &cpu_hz2);
+ if (cpu_hz2)
+ return(machdep->mhz = cpu_hz2/1000000);
+ }
+
return 0;
}
--
2.1.0
3 years, 10 months
[PATCH 06/16] MIPS64: Add 'dis' command support
by Youling Tang
Use generic_dis_filter() function to support dis command implementation.
E.g. With this patch:
crash> dis machine_kexec
0xffffffff8022dfd0 <machine_kexec>: daddiu sp,sp,-48
0xffffffff8022dfd4 <machine_kexec+4>: sd s2,24(sp)
0xffffffff8022dfd8 <machine_kexec+8>: sd s1,16(sp)
...
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/mips64.c b/mips64.c
index 74f0492..1d1297f 100644
--- a/mips64.c
+++ b/mips64.c
@@ -447,6 +447,7 @@ mips64_init(int when)
machdep->memory_size = generic_memory_size;
machdep->is_task_addr = mips64_is_task_addr;
machdep->get_smp_cpus = mips64_get_smp_cpus;
+ machdep->dis_filter = generic_dis_filter;
machdep->value_to_symbol = generic_machdep_value_to_symbol;
machdep->init_kernel_pgd = NULL;
break;
--
2.1.0
3 years, 10 months