[PATCH] Fix machdep->HZ calculation for kernel versions > 2.6.0
by Bhupesh Sharma
We have hard-coded the HZ value for some ARCHs to either 1000 or 100
(mainly for kernel versions > 2.6.0), which causes 'help -m' to show
an incorrect hz value for various architectures.
I tested this on ppc64le and x86_64 and the hz value reported is 1000,
whereas the kernel CONFIG_HZ_100 is set to Y. See some logs below:
crash> help -m
flags: 124000f5 (KSYMS_START|MACHDEP_BT_TEXT|VM_4_LEVEL|VMEMMAP|VMEMMAP_AWARE|PHYS_ENTRY_L4|SWAP_ENTRY_L4|RADIX_MMU|OPAL_FW)
kvbase: c000000000000000
identity_map_base: c000000000000000
pagesize: 65536
pageshift: 16
pagemask: ffffffffffff0000
pageoffset: ffff
stacksize: 16384
hz: 1000
mhz: 2800
[host@rhel7]$ grep CONFIG_HZ_100= redhat/configs/kernel-3.10.0-ppc64le.config
CONFIG_HZ_100=y
Fix the same by using the sysconf(_SC_CLK_TCK) value instead of the
hardcoded HZ values depending on kernel versions.
Cc: k-hagio-ab(a)nec.com
Cc: lijiang(a)redhat.com
Cc: bhupesh.linux(a)gmail.com
Signed-off-by: Bhupesh Sharma <bhsharma(a)redhat.com>
---
arm.c | 2 +-
arm64.c | 2 +-
ppc.c | 5 +----
ppc64.c | 6 ++----
x86.c | 5 +----
x86_64.c | 5 +----
6 files changed, 7 insertions(+), 18 deletions(-)
diff --git a/arm.c b/arm.c
index e52d29f04015..234feca7d1df 100644
--- a/arm.c
+++ b/arm.c
@@ -326,7 +326,7 @@ arm_init(int when)
"pr_reg");
if (!machdep->hz)
- machdep->hz = 100;
+ machdep->hz = HZ;
break;
case POST_VM:
diff --git a/arm64.c b/arm64.c
index 37aed07edf1d..8226a8ed7929 100644
--- a/arm64.c
+++ b/arm64.c
@@ -457,7 +457,7 @@ arm64_init(int when)
&machdep->nr_irqs);
if (!machdep->hz)
- machdep->hz = 100;
+ machdep->hz = HZ;
arm64_irq_stack_init();
arm64_stackframe_init();
diff --git a/ppc.c b/ppc.c
index cf5bf5688227..1c1c15a1fab3 100644
--- a/ppc.c
+++ b/ppc.c
@@ -401,11 +401,8 @@ ppc_init(int when)
&machdep->nr_irqs);
else
machdep->nr_irqs = 512; /* NR_IRQS (at least) */
- if (!machdep->hz) {
+ if (!machdep->hz)
machdep->hz = HZ;
- if (THIS_KERNEL_VERSION >= LINUX(2,6,0))
- machdep->hz = 1000;
- }
if (symbol_exists("cur_cpu_spec")) {
get_symbol_data("cur_cpu_spec", sizeof(void *), &cur_cpu_spec);
readmem(cur_cpu_spec + MEMBER_OFFSET("cpu_spec", "cpu_user_features"),
diff --git a/ppc64.c b/ppc64.c
index f368bf8e1a08..0cc82ffbba0e 100644
--- a/ppc64.c
+++ b/ppc64.c
@@ -694,11 +694,9 @@ ppc64_init(int when)
*/
BZERO(&machdep->machspec->hwintrstack,
NR_CPUS*sizeof(ulong));
- if (!machdep->hz) {
+ if (!machdep->hz)
machdep->hz = HZ;
- if (THIS_KERNEL_VERSION >= LINUX(2,6,0))
- machdep->hz = 1000;
- }
+
/*
* IRQ stacks are introduced in 2.6 and also configurable.
*/
diff --git a/x86.c b/x86.c
index de0d3d3114d0..ab34052da7af 100644
--- a/x86.c
+++ b/x86.c
@@ -1998,11 +1998,8 @@ x86_init(int when)
&machdep->nr_irqs);
else
machdep->nr_irqs = 224; /* NR_IRQS */
- if (!machdep->hz) {
+ if (!machdep->hz)
machdep->hz = HZ;
- if (THIS_KERNEL_VERSION >= LINUX(2,6,0))
- machdep->hz = 1000;
- }
if (machdep->flags & PAE) {
if (THIS_KERNEL_VERSION < LINUX(2,6,26))
diff --git a/x86_64.c b/x86_64.c
index 23a40a04bbc4..3e6750708659 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -660,11 +660,8 @@ x86_64_init(int when)
machdep->show_interrupts = x86_64_show_interrupts;
if (THIS_KERNEL_VERSION < LINUX(2,6,24))
machdep->line_number_hooks = x86_64_line_number_hooks;
- if (!machdep->hz) {
+ if (!machdep->hz)
machdep->hz = HZ;
- if (THIS_KERNEL_VERSION >= LINUX(2,6,0))
- machdep->hz = 1000;
- }
machdep->section_size_bits = _SECTION_SIZE_BITS;
if (!machdep->max_physmem_bits) {
if ((string = pc->read_vmcoreinfo("NUMBER(MAX_PHYSMEM_BITS)"))) {
--
2.26.2
3 years, 8 months
[PATCH 07/16] MIPS: Fix display memory size issue
by Youling Tang
"__node_data" instead of "node_data" is used in the MIPS architecture,
so "__node_data" is used to replace "node_data" to improve the use of
next_online_pgdat() functions in the MIPS architecture.
E.g. Without this patch:
...
MEMORY: 0
...
With this patch:
...
MEMORY: 7.5 GB
...
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
memory.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/memory.c b/memory.c
index 33b0ca7..5347958 100644
--- a/memory.c
+++ b/memory.c
@@ -17820,22 +17820,28 @@ next_online_pgdat(int node)
char buf[BUFSIZE];
ulong pgdat;
+#ifndef __mips__
+#define NODE_DATA_VAR "node_data"
+#else
+#define NODE_DATA_VAR "__node_data"
+#endif
+
/*
- * Default -- look for type: struct pglist_data node_data[]
+ * Default -- look for type: node_data[]/__node_data[]
*/
if (LKCD_KERNTYPES()) {
- if (!kernel_symbol_exists("node_data"))
+ if (!kernel_symbol_exists(NODE_DATA_VAR))
goto pgdat2;
/*
- * Just index into node_data[] without checking that it is
- * an array; kerntypes have no such symbol information.
+ * Just index into node_data[]/__node_data[] without checking that
+ * it is an array; kerntypes have no such symbol information.
*/
} else {
- if (get_symbol_type("node_data", NULL, NULL) != TYPE_CODE_ARRAY)
+ if (get_symbol_type(NODE_DATA_VAR, NULL, NULL) != TYPE_CODE_ARRAY)
goto pgdat2;
open_tmpfile();
- sprintf(buf, "whatis node_data");
+ sprintf(buf, "whatis " NODE_DATA_VAR);
if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) {
close_tmpfile();
goto pgdat2;
@@ -17848,14 +17854,15 @@ next_online_pgdat(int node)
close_tmpfile();
if ((!strstr(buf, "struct pglist_data *") &&
- !strstr(buf, "pg_data_t *")) ||
+ !strstr(buf, "pg_data_t *") &&
+ !strstr(buf, "struct node_data *")) ||
(count_chars(buf, '[') != 1) ||
(count_chars(buf, ']') != 1))
goto pgdat2;
}
- if (!readmem(symbol_value("node_data") + (node * sizeof(void *)),
- KVADDR, &pgdat, sizeof(void *), "node_data", RETURN_ON_ERROR) ||
+ if (!readmem(symbol_value(NODE_DATA_VAR) + (node * sizeof(void *)),
+ KVADDR, &pgdat, sizeof(void *), NODE_DATA_VAR, RETURN_ON_ERROR) ||
!IS_KVADDR(pgdat))
goto pgdat2;
@@ -17883,7 +17890,8 @@ pgdat2:
close_tmpfile();
if ((!strstr(buf, "struct pglist_data *") &&
- !strstr(buf, "pg_data_t *")) ||
+ !strstr(buf, "pg_data_t *") &&
+ !strstr(buf, "struct node_data *")) ||
(count_chars(buf, '[') != 1) ||
(count_chars(buf, ']') != 1))
goto pgdat3;
--
2.1.0
3 years, 9 months
[PATCH 01/16] Add MIPS64 framework code support
by Youling Tang
Mainly added some environment configurations, macro definitions, specific
architecture structures and some function declarations supported by the
MIPS64 architecture.
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
Makefile | 7 ++-
configure.c | 33 ++++++++++--
defs.h | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++-
diskdump.c | 3 ++
lkcd_vmdump_v2_v3.h | 3 +-
mips64.c | 45 +++++++++++++++++
symbols.c | 10 ++++
7 files changed, 236 insertions(+), 8 deletions(-)
create mode 100644 mips64.c
diff --git a/Makefile b/Makefile
index f66eba7..eb1e018 100644
--- a/Makefile
+++ b/Makefile
@@ -63,7 +63,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 sparc64.c \
+ arm.c arm64.c mips.c mips64.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 \
@@ -83,7 +83,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 sparc64.o \
+ arm.o arm64.o mips.o mips64.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 \
@@ -434,6 +434,9 @@ arm64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} arm64.c
mips.o: ${GENERIC_HFILES} ${REDHAT_HFILES} mips.c
${CC} -c ${CRASH_CFLAGS} mips.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+mips64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} mips64.c
+ ${CC} -c ${CRASH_CFLAGS} mips64.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/configure.c b/configure.c
index 7f6d19e..e2df6f0 100644
--- a/configure.c
+++ b/configure.c
@@ -104,7 +104,9 @@ void add_extra_lib(char *);
#undef X86_64
#undef ARM
#undef ARM64
+#undef MIPS
#undef SPARC64
+#undef MIPS64
#define UNKNOWN 0
#define X86 1
@@ -119,6 +121,7 @@ void add_extra_lib(char *);
#define ARM64 10
#define MIPS 11
#define SPARC64 12
+#define MIPS64 13
#define TARGET_X86 "TARGET=X86"
#define TARGET_ALPHA "TARGET=ALPHA"
@@ -131,6 +134,7 @@ void add_extra_lib(char *);
#define TARGET_ARM "TARGET=ARM"
#define TARGET_ARM64 "TARGET=ARM64"
#define TARGET_MIPS "TARGET=MIPS"
+#define TARGET_MIPS64 "TARGET=MIPS64"
#define TARGET_SPARC64 "TARGET=SPARC64"
#define TARGET_CFLAGS_X86 "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64"
@@ -152,6 +156,7 @@ void add_extra_lib(char *);
#define TARGET_CFLAGS_MIPS "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64"
#define TARGET_CFLAGS_MIPS_ON_X86 "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64"
#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 GDB_TARGET_DEFAULT "GDB_CONF_FLAGS="
@@ -380,7 +385,11 @@ get_current_configuration(struct supported_gdb_version *sp)
target_data.target = ARM64;
#endif
#ifdef __mips__
- target_data.target = MIPS;
+#ifndef __mips64
+ target_data.target = MIPS;
+#else
+ target_data.target = MIPS64;
+#endif
#endif
#ifdef __sparc_v9__
target_data.target = SPARC64;
@@ -474,6 +483,10 @@ get_current_configuration(struct supported_gdb_version *sp)
arch_mismatch(sp);
}
+ if ((target_data.initial_gdb_target == MIPS64) &&
+ (target_data.target != MIPS64))
+ arch_mismatch(sp);
+
if ((target_data.initial_gdb_target == X86) &&
(target_data.target != X86)) {
if (target_data.target == X86_64)
@@ -631,6 +644,9 @@ show_configuration(void)
case MIPS:
printf("TARGET: MIPS\n");
break;
+ case MIPS64:
+ printf("TARGET: MIPS64\n");
+ break;
case SPARC64:
printf("TARGET: SPARC64\n");
break;
@@ -742,7 +758,11 @@ build_configure(struct supported_gdb_version *sp)
gdb_conf_flags = GDB_TARGET_MIPS_ON_X86_64;
} else
target_CFLAGS = TARGET_CFLAGS_MIPS;
- break;
+ break;
+ case MIPS64:
+ target = TARGET_MIPS64;
+ target_CFLAGS = TARGET_CFLAGS_MIPS64;
+ break;
case SPARC64:
target = TARGET_SPARC64;
target_CFLAGS = TARGET_CFLAGS_SPARC64;
@@ -1344,7 +1364,7 @@ make_spec_file(struct supported_gdb_version *sp)
printf("Vendor: Red Hat, Inc.\n");
printf("Packager: Dave Anderson <anderson(a)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 sparc64\n");
+ printf("ExclusiveArch: %%{ix86} alpha ia64 ppc ppc64 ppc64pseries ppc64iseries x86_64 s390 s390x arm aarch64 ppc64le mips mipsel mips64el sparc64\n");
printf("Buildroot: %%{_tmppath}/%%{name}-root\n");
printf("BuildRequires: ncurses-devel zlib-devel bison\n");
printf("Requires: binutils\n");
@@ -1571,6 +1591,8 @@ set_initial_target(struct supported_gdb_version *sp)
target_data.initial_gdb_target = ARM64;
else if (strncmp(buf, "ARM", strlen("ARM")) == 0)
target_data.initial_gdb_target = ARM;
+ else if (strncmp(buf, "MIPS64", strlen("MIPS64")) == 0)
+ target_data.initial_gdb_target = MIPS64;
else if (strncmp(buf, "MIPS", strlen("MIPS")) == 0)
target_data.initial_gdb_target = MIPS;
else if (strncmp(buf, "SPARC64", strlen("SPARC64")) == 0)
@@ -1593,6 +1615,7 @@ target_to_name(int target)
case ARM: return("ARM");
case ARM64: return("ARM64");
case MIPS: return("MIPS");
+ case MIPS64: return("MIPS64");
case SPARC64: return("SPARC64");
}
@@ -1652,6 +1675,10 @@ name_to_target(char *name)
return MIPS;
else if (strncmp(name, "MIPS", strlen("MIPS")) == 0)
return MIPS;
+ else if (strncmp(name, "mips64", strlen("mips64")) == 0)
+ return MIPS64;
+ else if (strncmp(name, "MIPS64", strlen("MIPS64")) == 0)
+ return MIPS64;
else if (strncmp(name, "sparc64", strlen("sparc64")) == 0)
return SPARC64;
diff --git a/defs.h b/defs.h
index ffbe73b..21cd904 100644
--- a/defs.h
+++ b/defs.h
@@ -71,7 +71,8 @@
#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(SPARC64)
+ !defined(ARM) && !defined(ARM64) && !defined(MIPS) && !defined(MIPS64) && \
+ !defined(SPARC64)
#ifdef __alpha__
#define ALPHA
#endif
@@ -104,7 +105,11 @@
#define ARM64
#endif
#ifdef __mipsel__
+#ifndef __mips64
#define MIPS
+#else
+#define MIPS64
+#endif
#endif
#ifdef __sparc_v9__
#define SPARC64
@@ -144,6 +149,9 @@
#ifdef MIPS
#define NR_CPUS (32)
#endif
+#ifdef MIPS64
+#define NR_CPUS (256)
+#endif
#ifdef SPARC64
#define NR_CPUS (4096)
#endif
@@ -3343,7 +3351,6 @@ struct arm64_stackframe {
#ifdef MIPS
#define _32BIT_
-#define MACHINE_TYPE "MIPS"
#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask)
@@ -3375,6 +3382,44 @@ struct arm64_stackframe {
#define _MAX_PHYSMEM_BITS 32
#endif /* MIPS */
+#ifdef MIPS64
+#define _64BIT_
+
+#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask)
+#define IS_CKPHYS(X) (((X) >= 0xffffffff80000000lu) && \
+ ((X) < 0xffffffffc0000000lu))
+#define IS_XKPHYS(X) (((X) >= 0x8000000000000000lu) && \
+ ((X) < 0xc000000000000000lu))
+
+#define PTOV(X) ((ulong)(X) + 0x9800000000000000lu)
+#define VTOP(X) (IS_CKPHYS(X) ? ((ulong)(X) & 0x000000001ffffffflu) \
+ : ((ulong)(X) & 0x0000fffffffffffflu))
+
+#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start && !IS_CKPHYS(X))
+
+#define DEFAULT_MODULES_VADDR 0xffffffffc0000000lu
+#define MODULES_VADDR (machdep->machspec->modules_vaddr)
+#define MODULES_END (machdep->machspec->modules_end)
+#define VMALLOC_START (machdep->machspec->vmalloc_start_addr)
+#define VMALLOC_END (machdep->machspec->vmalloc_end)
+
+#define __SWP_TYPE_SHIFT 16
+#define __SWP_TYPE_BITS 8
+#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1)
+#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
+
+#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 (2)
+
+#define _SECTION_SIZE_BITS 28
+#define _MAX_PHYSMEM_BITS 48
+#endif /* MIPS64 */
+
#ifdef X86
#define _32BIT_
#define MACHINE_TYPE "X86"
@@ -4415,6 +4460,10 @@ struct machine_specific {
#define MAX_HEXADDR_STRLEN (8)
#define UVADDR_PRLEN (8)
#endif
+#ifdef MIPS64
+#define MAX_HEXADDR_STRLEN (16)
+#define UVADDR_PRLEN (16)
+#endif
#ifdef SPARC64
#define MAX_HEXADDR_STRLEN (16)
#define UVADDR_PRLEN (16)
@@ -4991,6 +5040,9 @@ void dump_build_data(void);
#ifdef MIPS
#define machdep_init(X) mips_init(X)
#endif
+#ifdef MIPS64
+#define machdep_init(X) mips64_init(X)
+#endif
#ifdef SPARC64
#define machdep_init(X) sparc64_init(X)
#endif
@@ -5471,6 +5523,9 @@ void display_help_screen(char *);
#ifdef MIPS
#define dump_machdep_table(X) mips_dump_machdep_table(X)
#endif
+#ifdef MIPS64
+#define dump_machdep_table(X) mips64_dump_machdep_table(X)
+#endif
#ifdef SPARC64
#define dump_machdep_table(X) sparc64_dump_machdep_table(X)
#endif
@@ -6348,6 +6403,10 @@ void s390x_dump_machdep_table(ulong);
#define KSYMS_START (0x1)
#endif
+#ifdef __mips__ /* MIPS & MIPS64 */
+#define MACHINE_TYPE "MIPS"
+#endif
+
/*
* mips.c
*/
@@ -6418,6 +6477,86 @@ struct machine_specific {
#endif /* MIPS */
/*
+ * mips64.c
+ */
+void mips64_display_regs_from_elf_notes(int, FILE *);
+
+#ifdef MIPS64
+void mips64_init(int);
+void mips64_dump_machdep_table(ulong);
+
+#define display_idt_table() \
+ error(FATAL, "-d option is not applicable to MIPS64 architecture\n")
+
+/* from arch/mips/include/uapi/asm/ptrace.h */
+struct mips64_register {
+ ulong regs[45];
+};
+
+struct mips64_pt_regs_main {
+ ulong regs[32];
+ ulong cp0_status;
+ ulong hi;
+ ulong lo;
+};
+
+struct mips64_pt_regs_cp0 {
+ ulong cp0_badvaddr;
+ ulong cp0_cause;
+ ulong cp0_epc;
+};
+
+struct mips64_unwind_frame {
+ unsigned long sp;
+ unsigned long pc;
+ unsigned long ra;
+};
+
+#define KSYMS_START (0x1)
+
+struct machine_specific {
+ ulong phys_base;
+ ulong vmalloc_start_addr;
+ ulong modules_vaddr;
+ ulong modules_end;
+
+ ulong _page_present;
+ ulong _page_read;
+ ulong _page_write;
+ ulong _page_accessed;
+ ulong _page_modified;
+ ulong _page_huge;
+ ulong _page_special;
+ ulong _page_protnone;
+ ulong _page_global;
+ ulong _page_valid;
+ ulong _page_no_read;
+ ulong _page_no_exec;
+ ulong _page_dirty;
+
+ ulong _pfn_shift;
+
+ struct mips64_register *crash_task_regs;
+};
+/* from arch/mips/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_ACCESSED (machdep->machspec->_page_accessed)
+#define _PAGE_MODIFIED (machdep->machspec->_page_modified)
+#define _PAGE_HUGE (machdep->machspec->_page_huge)
+#define _PAGE_SPECIAL (machdep->machspec->_page_special)
+#define _PAGE_PROTNONE (machdep->machspec->_page_protnone)
+#define _PAGE_GLOBAL (machdep->machspec->_page_global)
+#define _PAGE_VALID (machdep->machspec->_page_valid)
+#define _PAGE_NO_READ (machdep->machspec->_page_no_read)
+#define _PAGE_NO_EXEC (machdep->machspec->_page_no_exec)
+#define _PAGE_DIRTY (machdep->machspec->_page_dirty)
+#define _PFN_SHIFT (machdep->machspec->_pfn_shift)
+
+#endif /* MIPS64 */
+
+/*
* sparc64.c
*/
#ifdef SPARC64
diff --git a/diskdump.c b/diskdump.c
index 4f14596..4ad2c50 100644
--- a/diskdump.c
+++ b/diskdump.c
@@ -594,6 +594,9 @@ restart:
else if (STRNEQ(header->utsname.machine, "mips") &&
machine_type_mismatch(file, "MIPS", NULL, 0))
goto err;
+ else if (STRNEQ(header->utsname.machine, "mips64") &&
+ machine_type_mismatch(file, "MIPS", NULL, 0))
+ goto err;
else if (STRNEQ(header->utsname.machine, "s390x") &&
machine_type_mismatch(file, "S390X", NULL, 0))
goto err;
diff --git a/lkcd_vmdump_v2_v3.h b/lkcd_vmdump_v2_v3.h
index 8d5eae4..984c2c2 100644
--- a/lkcd_vmdump_v2_v3.h
+++ b/lkcd_vmdump_v2_v3.h
@@ -36,7 +36,8 @@
#endif
#if defined(ARM) || defined(X86) || defined(PPC) || defined(S390) || \
- defined(S390X) || defined(ARM64) || defined(MIPS) || defined(SPARC64)
+ defined(S390X) || defined(ARM64) || defined(MIPS) || \
+ defined(MIPS64) || defined(SPARC64)
/*
* Kernel header file for Linux crash dumps.
diff --git a/mips64.c b/mips64.c
new file mode 100644
index 0000000..5ebe61d
--- /dev/null
+++ b/mips64.c
@@ -0,0 +1,45 @@
+/* mips64.c - core analysis suite
+ *
+ * Copyright (C) 2021 Loongson Technology Co., Ltd.
+ *
+ * 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.
+ */
+#ifdef MIPS64
+
+#include <elf.h>
+#include "defs.h"
+
+void
+mips64_dump_machdep_table(ulong arg)
+{
+}
+
+void
+mips64_init(int when)
+{
+}
+
+void
+mips64_display_regs_from_elf_notes(int cpu, FILE *ofp)
+{
+}
+
+#else /* !MIPS64 */
+
+#include "defs.h"
+
+void
+mips64_display_regs_from_elf_notes(int cpu, FILE *ofp)
+{
+ return;
+}
+
+#endif /* !MIPS64 */
diff --git a/symbols.c b/symbols.c
index ed5f731..57cb177 100644
--- a/symbols.c
+++ b/symbols.c
@@ -3636,6 +3636,11 @@ is_kernel(char *file)
goto bailout;
break;
+ case EM_MIPS:
+ if (machine_type_mismatch(file, "MIPS", NULL, 0))
+ goto bailout;
+ break;
+
default:
if (machine_type_mismatch(file, "(unknown)", NULL, 0))
goto bailout;
@@ -3890,6 +3895,11 @@ is_shared_object(char *file)
if (machine_type("SPARC64"))
return TRUE;
break;
+
+ case EM_MIPS:
+ if (machine_type("MIPS"))
+ return TRUE;
+ break;
}
if (CRASHDEBUG(1))
--
2.1.0
3 years, 9 months
[PATCH 03/16] MIPS64: Add gdb patch for Loongson machine
by Youling Tang
The gssq instruction is a Loongson extended instruction, so the gssq patch
is applied to gdb.
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
Makefile | 3 +++
configure.c | 2 +-
gdb-7.6-loongson.patch | 19 +++++++++++++++++++
3 files changed, 23 insertions(+), 1 deletion(-)
create mode 100644 gdb-7.6-loongson.patch
diff --git a/Makefile b/Makefile
index eb1e018..c629d17 100644
--- a/Makefile
+++ b/Makefile
@@ -277,6 +277,9 @@ gdb_patch:
patch -p0 < ${GDB}-proc_service.h.patch; \
fi; \
fi
+ if [ "${ARCH}" = "mips64" ] && [ -f ${GDB}-loongson.patch ]; then \
+ patch -d ${GDB} -p1 -F0 < ${GDB}-loongson.patch ; \
+ fi
library: make_build_data ${OBJECT_FILES}
ar -rs ${PROGRAM}lib.a ${OBJECT_FILES}
diff --git a/configure.c b/configure.c
index e2df6f0..40351c3 100644
--- a/configure.c
+++ b/configure.c
@@ -245,7 +245,7 @@ struct supported_gdb_version {
"7.6",
"GDB_FILES=${GDB_7.6_FILES}",
"GDB_OFILES=${GDB_7.6_OFILES}",
- "GDB_PATCH_FILES=gdb-7.6.patch gdb-7.6-ppc64le-support.patch gdb-7.6-proc_service.h.patch",
+ "GDB_PATCH_FILES=gdb-7.6.patch gdb-7.6-ppc64le-support.patch gdb-7.6-proc_service.h.patch gdb-7.6-loongson.patch",
"GDB_FLAGS=-DGDB_7_6",
"GPLv3"
},
diff --git a/gdb-7.6-loongson.patch b/gdb-7.6-loongson.patch
new file mode 100644
index 0000000..556163f
--- /dev/null
+++ b/gdb-7.6-loongson.patch
@@ -0,0 +1,19 @@
+--- gdb-7.6/gdb/mips-tdep.c.orig 2018-08-28 11:20:32.653771170 +0800
++++ gdb-7.6/gdb/mips-tdep.c 2018-08-28 11:25:53.129043377 +0800
+@@ -3261,6 +3261,16 @@ restart:
+ /* Irix 6.2 N32 ABI uses sd instructions for saving $gp and $ra. */
+ set_reg_offset (gdbarch, this_cache, reg, sp + low_word);
+ }
++ else if (((inst & 0xFFE08020) == 0xeba00020) /* gssq reg,reg,offset($sp) */
++ && regsize_is_64_bits)
++ {
++ reg = (inst >> 16) & 0x1F;
++ low_word = ((((inst >> 6) & 0x1FF) ^ 0x100) - 0x100) << 4;
++ set_reg_offset (gdbarch, this_cache, reg, sp + low_word);
++ reg = inst & 0x1F;
++ low_word = (((((inst >> 6) & 0x1FF) ^ 0x100) - 0x100) << 4) + 8;
++ set_reg_offset (gdbarch, this_cache, reg, sp + low_word);
++ }
+ else if (high_word == 0x27be) /* addiu $30,$sp,size */
+ {
+ /* Old gcc frame, r30 is virtual frame pointer. */
--
2.1.0
3 years, 9 months
Corrupted tee in crash gdb
by Andi Kleen
Hi,
I have several crash dump files that reliably crash gdb inside crash.
This is with compressed dumps and recent kernels
It appears there is an error during the symbol processing (usually
when looking up runqueue, but even if you disable that it fails on
something else) and then gdb crashes because the tee
structure it uses to print error messages is corrupted. The tee fputs
vector is NULL and gdb jumps to zero while trying to print the
error message. So somehow crash doesn't set this up properly.
Using -minimal works, but that's too limiting.
I'm using this gdb patch to work around it by disabling the gdb errors.
That makes crash work well enough to look at most things.
It's probably not the correct fix, but at least it works for me.
diff -urp gdb-7.6-orig/gdb/ui-file.c gdb-7.6/gdb/ui-file.c
--- gdb-7.6-orig/gdb/ui-file.c 2020-12-22 09:48:27.532409801 -0800
+++ gdb-7.6/gdb/ui-file.c 2020-12-17 13:10:07.806799729 -0800
@@ -740,6 +740,8 @@ tee_file_flush (struct ui_file *file)
{
struct tee_file *tee = ui_file_data (file);
+ return;
+
if (tee->magic != &tee_file_magic)
internal_error (__FILE__, __LINE__,
_("tee_file_flush: bad magic number"));
@@ -752,6 +754,8 @@ tee_file_write (struct ui_file *file, co
{
struct tee_file *tee = ui_file_data (file);
+ return;
+
if (tee->magic != &tee_file_magic)
internal_error (__FILE__, __LINE__,
_("tee_file_write: bad magic number"));
@@ -764,9 +768,16 @@ tee_file_fputs (const char *linebuffer,
{
struct tee_file *tee = ui_file_data (file);
+ return;
+
if (tee->magic != &tee_file_magic)
internal_error (__FILE__, __LINE__,
_("tee_file_fputs: bad magic number"));
+ if (!tee->one->to_fputs) {
+ fputs(linebuffer, stdout);
+ return;
+ }
+
tee->one->to_fputs (linebuffer, tee->one);
tee->two->to_fputs (linebuffer, tee->two);
}
WARNING: kernel relocated [336MB]: patching 167186 gdb minimal_symbol
values
please wait... (patching 167186 gdb minimal_symbol values) [Detaching
after vfork from child process 1824671]
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
... up
#10 0x000000000066e75a in c_parse_internal () at c-exp.y:442
442 error (_("%s is not an ObjC Class"),
(gdb) p *tee
$2 = {ssize_t (int, int, size_t, unsigned int)} 0x7ffff7cc4a30 <tee>
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x00000000007b3f09 in tee_file_fputs (
linebuffer=0x23425f0 "No symbol \"runqueue\" in current context.\n",
file=<optimized out>)
at ui-file.c:770
#2 0x00000000007b071b in fputs_maybe_filtered (
linebuffer=linebuffer@entry=0x23425f0 "No symbol
\"runqueue\" in current context.\n",
stream=stream@entry=0x16c3ff0, filter=1) at utils.c:2091
#3 0x00000000007b08c1 in vfprintf_maybe_filtered
(stream=0x16c3ff0,
format=format@entry=0xa8f375 "%s\n",
args=args@entry=0x7ffffffe8828, filter=1, filter=1)
at utils.c:2332
#4 0x00000000007b0a2c in vfprintf_filtered
(args=0x7ffffffe8828, format=0xa8f375 "%s\n",
stream=<optimized out>) at utils.c:2392
#5 fprintf_filtered (stream=<optimized
out>, format=format@entry=0xa8f375 "%s\n")
at utils.c:2392
#6 0x00000000006f84f8 in throw_exception
(exception=...) at exceptions.c:234
#7 0x00000000006f874b in throw_it
(reason=reason@entry=RETURN_ERROR,
error=error@entry=GENERIC_ERROR,
fmt=<optimized out>,
ap=ap@entry=0x7ffffffe8978)
at exceptions.c:434
#8 0x00000000006f8956 in
throw_verror
(error=error@entry=GENERIC_ERROR,
fmt=<optimized out>,
ap=ap@entry=0x7ffffffe8978) at
exceptions.c:440
#9 0x00000000007af3e7 in error
(string=<optimized out>) at
utils.c:717
#10 0x000000000066e75a in
c_parse_internal () at
c-exp.y:442
#11 0x000000000066eab7 in
c_parse () at c-exp.y:3064
#12 0x0000000000723091 in
parse_exp_in_context
(stringptr=stringptr@entry=0x7ffffffea708,
#13 0x00000000007232b8 in parse_exp_1
(stringptr=stringptr@entry=0x7ffffffea758, pc=pc@entry=0,
block=block@entry=0x0, comma=comma@entry=0) at parse.c:1136
#14 0x00000000007232f9 in parse_expression (string=<optimized out>)
at parse.c:1279
#15 0x00000000006cf083 in gdb_get_datatype (req=0xdf8b20
<shared_bufs>) at symtab.c:5361
#16 gdb_command_funnel (req=0xdf8b20 <shared_bufs>) at symtab.c:5210
#17 0x0000000000518d4f in gdb_interface (req=0xdf8b20 <shared_bufs>)
at gdb_interface.c:397
#18 0x00000000005676dc in datatype_info (name=0x7ffffffec200
"runqueue", member=0x0,
dm=0x7ffffffeb000) at symbols.c:5635
#19 0x000000000056abe5 in arg_to_datatype (s=0x7ffffffec200
"runqueue", dm=0x7ffffffeb000,
flags=2) at symbols.c:6872
#20 0x000000000056f928 in get_array_length (s=0x90dcd6
"runqueue.cpu", two_dim=0x0, entry_size=0)
at symbols.c:8481
#21 0x00000000004f1092 in kernel_init () at kernel.c:338
#22 0x00000000004658a8 in main_loop () at main.c:781
#23 0x00000000006fa433 in captured_command_loop
(data=data@entry=0x0) at main.c:258
#24 0x00000000006f8c4a in catch_errors
(func=func@entry=0x6fa420 <captured_command_loop>,
func_args=func_args@entry=0x0,
errstring=errstring@entry=0x9617cf "",
mask=mask@entry=6)
at exceptions.c:557
#25 0x00000000006fb406 in captured_main
(data=data@entry=0x7fffffffd180) at main.c:1064
3 years, 9 months
[PATCH 15/16] MIPS64: Add 'help -m/M' command support
by Youling Tang
Add mips64_dump_machdep_table() implementation, display machdep_table.
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/mips64.c b/mips64.c
index d8a5a0a..843983a 100644
--- a/mips64.c
+++ b/mips64.c
@@ -1127,9 +1127,70 @@ mips64_is_task_addr(ulong task)
return (IS_KVADDR(task) && ALIGNED_STACK_OFFSET(task) == 0);
}
+/*
+ * "help -m/M" command output
+ */
void
mips64_dump_machdep_table(ulong arg)
{
+ 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: %d\n", PGDIR_SHIFT);
+ fprintf(fp, " ptrs_per_pgd: %lu\n", PTRS_PER_PGD);
+ fprintf(fp, " ptrs_per_pte: %ld\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, " nr_irqs: %d\n", machdep->nr_irqs);
+ fprintf(fp, " eframe_search: mips64_eframe_search()\n");
+ fprintf(fp, " back_trace: mips64_back_trace_cmd()\n");
+ fprintf(fp, " processor_speed: mips64_processor_speed()\n");
+ fprintf(fp, " uvtop: mips64_uvtop()\n");
+ fprintf(fp, " kvtop: mips64_kvtop()\n");
+ fprintf(fp, " get_task_pgd: mips64_get_task_pgd()\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, " get_stack_frame: mips64_get_stack_frame()\n");
+ fprintf(fp, " get_stackbase: generic_get_stackbase()\n");
+ fprintf(fp, " get_stacktop: generic_get_stacktop()\n");
+ fprintf(fp, " translate_pte: mips64_translate_pte()\n");
+ fprintf(fp, " memory_size: generic_memory_size()\n");
+ fprintf(fp, " vmalloc_start: mips64_vmalloc_start()\n");
+ fprintf(fp, " is_task_addr: mips64_is_task_addr()\n");
+ fprintf(fp, " verify_symbol: mips64_verify_symbol()\n");
+ fprintf(fp, " dis_filter: generic_dis_filter()\n");
+ fprintf(fp, " cmd_mach: mips64_cmd_mach()\n");
+ fprintf(fp, " get_smp_cpus: mips64_get_smp_cpus()\n");
+ fprintf(fp, " is_kvaddr: generic_is_kvaddr()\n");
+ fprintf(fp, " is_uvaddr: generic_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_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, " 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 void
--
2.1.0
3 years, 9 months
[PATCH 14/16] MIPS64: Add the relization of verify symbol
by Youling Tang
Add mips64_verify_symbol() implementation, accept or reject a
symbol from the kernel namelist.
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/mips64.c b/mips64.c
index 6e8e922..d8a5a0a 100644
--- a/mips64.c
+++ b/mips64.c
@@ -1055,7 +1055,14 @@ mips64_get_elf_notes(void)
static int
mips64_verify_symbol(const char *name, ulong value, char type)
{
- return TRUE;
+ if (CRASHDEBUG(8) && name && strlen(name))
+ fprintf(fp, "%08lx %s\n", value, name);
+
+ if (STREQ(name, "_text") || STREQ(name, "_stext"))
+ machdep->flags |= KSYMS_START;
+
+ return (name && strlen(name) && (machdep->flags & KSYMS_START) &&
+ !STRNEQ(name, "__func__.") && !STRNEQ(name, "__crc_"));
}
/*
--
2.1.0
3 years, 9 months
[PATCH 11/16] MIPS64: Fixes for the gathering of the active task registers for the 'bt' command
by Youling Tang
dumpfiles:
(1) If ELF notes are not available, read them from the kernel's
crash_notes.
(2) If an online CPUs did not save its ELF notes, then adjust
the mapping of each ELF note to its CPU accordingly.
E.g. With this patch:
crash> bt
PID: 4768 TASK: 9800000243bcf200 CPU: 3 COMMAND: "bash"
#0 [980000024291f930] __crash_kexec at ffffffff802fff84
#1 [980000024291faa0] panic at ffffffff80248cac
#2 [980000024291fb40] die at ffffffff8021b338
#3 [980000024291fb70] do_page_fault at ffffffff802315e0
#4 [980000024291fbd0] tlb_do_page_fault_1 at ffffffff80239388
#5 [980000024291fd00] sysrq_handle_crash at ffffffff8085d308
#6 [980000024291fd10] __handle_sysrq at ffffffff8085d9e0
#7 [980000024291fd60] write_sysrq_trigger at ffffffff8085e020
#8 [980000024291fd80] proc_reg_write at ffffffff804762f0
#9 [980000024291fda0] __vfs_write at ffffffff803f3138
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 202 insertions(+), 1 deletion(-)
diff --git a/mips64.c b/mips64.c
index 57a7f41..d949af4 100644
--- a/mips64.c
+++ b/mips64.c
@@ -42,7 +42,9 @@ 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);
-
+static int mips64_init_active_task_regs(void);
+static int mips64_get_crash_notes(void);
+static int mips64_get_elf_notes(void);
/*
* 3 Levels paging PAGE_SIZE=16KB
@@ -806,6 +808,192 @@ mips64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
return TRUE;
}
+static int
+mips64_init_active_task_regs(void)
+{
+ int retval;
+
+ retval = mips64_get_crash_notes();
+ if (retval == TRUE)
+ return retval;
+
+ return mips64_get_elf_notes();
+}
+
+/*
+ * Retrieve task registers for the time of the crash.
+ */
+static int
+mips64_get_crash_notes(void)
+{
+ struct machine_specific *ms = machdep->machspec;
+ ulong crash_notes;
+ Elf64_Nhdr *note;
+ ulong offset;
+ char *buf, *p;
+ ulong *notes_ptrs;
+ ulong i;
+
+ /*
+ * crash_notes contains per cpu memory for storing cpu states
+ * in case of system crash.
+ */
+ if (!symbol_exists("crash_notes"))
+ return FALSE;
+
+ crash_notes = symbol_value("crash_notes");
+
+ notes_ptrs = (ulong *)GETBUF(kt->cpus*sizeof(notes_ptrs[0]));
+
+ /*
+ * Read crash_notes for the first CPU. crash_notes are in standard ELF
+ * note format.
+ */
+ if (!readmem(crash_notes, KVADDR, ¬es_ptrs[kt->cpus-1],
+ sizeof(notes_ptrs[kt->cpus-1]), "crash_notes",
+ RETURN_ON_ERROR)) {
+ error(WARNING, "cannot read crash_notes\n");
+ FREEBUF(notes_ptrs);
+ return FALSE;
+ }
+
+ if (symbol_exists("__per_cpu_offset")) {
+
+ /*
+ * Add __per_cpu_offset for each cpu to form the pointer to the notes
+ */
+ for (i = 0; i < kt->cpus; i++)
+ notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i];
+ }
+
+ buf = GETBUF(SIZE(note_buf));
+
+ if (!(panic_task_regs = calloc((size_t)kt->cpus, sizeof(*panic_task_regs))))
+ error(FATAL, "cannot calloc panic_task_regs space\n");
+
+ for (i = 0; i < kt->cpus; i++) {
+
+ if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf), "note_buf_t",
+ RETURN_ON_ERROR)) {
+ error(WARNING,
+ "cannot find NT_PRSTATUS note for cpu: %d\n", i);
+ goto fail;
+ }
+
+ /*
+ * Do some sanity checks for this note before reading registers from it.
+ */
+ note = (Elf64_Nhdr *)buf;
+ p = buf + sizeof(Elf64_Nhdr);
+
+ /*
+ * dumpfiles created with qemu won't have crash_notes, but there will
+ * be elf notes; dumpfiles created by kdump do not create notes for
+ * offline cpus.
+ */
+ if (note->n_namesz == 0 && (DISKDUMP_DUMPFILE() || KDUMP_DUMPFILE())) {
+ if (DISKDUMP_DUMPFILE())
+ note = diskdump_get_prstatus_percpu(i);
+ else if (KDUMP_DUMPFILE())
+ note = netdump_get_prstatus_percpu(i);
+ if (note) {
+ /*
+ * SIZE(note_buf) accounts for a "final note", which is a
+ * trailing empty elf note header.
+ */
+ long notesz = SIZE(note_buf) - sizeof(Elf64_Nhdr);
+
+ if (sizeof(Elf64_Nhdr) + roundup(note->n_namesz, 4) +
+ note->n_descsz == notesz)
+ BCOPY((char *)note, buf, notesz);
+ } else {
+ error(WARNING,
+ "cannot find NT_PRSTATUS note for cpu: %d\n", i);
+ continue;
+ }
+ }
+
+ /*
+ * Check the sanity of NT_PRSTATUS note only for each online cpu.
+ */
+ if (note->n_type != NT_PRSTATUS) {
+ error(WARNING, "invalid NT_PRSTATUS note (n_type != NT_PRSTATUS)\n");
+ goto fail;
+ }
+ if (!STRNEQ(p, "CORE")) {
+ error(WARNING, "invalid NT_PRSTATUS note (name != \"CORE\"\n");
+ goto fail;
+ }
+
+ /*
+ * Find correct location of note data. This contains elf_prstatus
+ * structure which has registers etc. for the crashed task.
+ */
+ offset = sizeof(Elf64_Nhdr);
+ offset = roundup(offset + note->n_namesz, 4);
+ p = buf + offset; /* start of elf_prstatus */
+
+ BCOPY(p + OFFSET(elf_prstatus_pr_reg), &panic_task_regs[i],
+ sizeof(panic_task_regs[i]));
+ }
+
+ /*
+ * And finally we have the registers for the crashed task. This is
+ * used later on when dumping backtrace.
+ */
+ ms->crash_task_regs = panic_task_regs;
+
+ FREEBUF(buf);
+ FREEBUF(notes_ptrs);
+ return TRUE;
+
+fail:
+ FREEBUF(buf);
+ FREEBUF(notes_ptrs);
+ free(panic_task_regs);
+ return FALSE;
+}
+
+static int
+mips64_get_elf_notes(void)
+{
+ struct machine_specific *ms = machdep->machspec;
+ int i;
+
+ if (!DISKDUMP_DUMPFILE() && !KDUMP_DUMPFILE())
+ return FALSE;
+
+ panic_task_regs = calloc(kt->cpus, sizeof(*panic_task_regs));
+ if (!panic_task_regs)
+ error(FATAL, "cannot calloc panic_task_regs space\n");
+
+ for (i = 0; i < kt->cpus; i++) {
+ Elf64_Nhdr *note = NULL;
+ size_t len;
+
+ if (DISKDUMP_DUMPFILE())
+ note = diskdump_get_prstatus_percpu(i);
+ else if (KDUMP_DUMPFILE())
+ note = netdump_get_prstatus_percpu(i);
+
+ if (!note) {
+ error(WARNING,
+ "cannot find NT_PRSTATUS note for cpu: %d\n", i);
+ continue;
+ }
+
+ len = sizeof(Elf64_Nhdr);
+ len = roundup(len + note->n_namesz, 4);
+
+ BCOPY((char *)note + len + OFFSET(elf_prstatus_pr_reg),
+ &panic_task_regs[i], sizeof(panic_task_regs[i]));
+ }
+
+ ms->crash_task_regs = panic_task_regs;
+
+ return TRUE;
+}
+
/*
* Accept or reject a symbol from the kernel namelist.
*/
@@ -959,9 +1147,22 @@ mips64_init(int when)
mips64_stackframe_init();
if (!machdep->hz)
machdep->hz = 250;
+ MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus",
+ "pr_reg");
+ STRUCT_SIZE_INIT(note_buf, "note_buf_t");
break;
case POST_VM:
+ /*
+ * crash_notes contains machine specific information about the
+ * crash. In particular, it contains CPU registers at the time
+ * of the crash. We need this information to extract correct
+ * backtraces from the panic task.
+ */
+ if (!ACTIVE() && !mips64_init_active_task_regs())
+ error(WARNING,
+ "cannot retrieve registers for active task%s\n\n",
+ kt->cpus > 1 ? "s" : "");
break;
}
}
--
2.1.0
3 years, 9 months
[PATCH 04/16] MIPS64: Make the crash tool successfully enter the crash command line
by Youling Tang
1. Add mips64_init() implementation, do all necessary machine-specific setup,
which will be called multiple times during initialization.
2. Add the implementation of the vtop command, which is used to convert a
virtual address to a physical address. When entering the crash command line,
the corresponding symbols in the kernel will be read, and at the same time,
the conversion of virtual and real addresses will also be used, so the vtop
command is a prerequisite for entering the crash command line.
3. Add mips64_get_smp_cpus() implementation, get the number of online cpus.
4. Add mips64_get_page_size() implementation, get page size.
The results after applying patch 01~04 are as follows:
...
KERNEL: /boot/vmlinux-4.19.161kexec+
DUMPFILE: /home/tang/vmcore_4.19.161
CPUS: 4
DATE: Mon Jan 25 18:54:14 HKT 2021
UPTIME: (cannot calculate: unknown HZ value)
LOAD AVERAGE: 0.24, 0.21, 0.09
TASKS: 348
NODENAME: bogon
RELEASE: 4.19.161kexec+
VERSION: #15 SMP PREEMPT Mon Jan 25 17:56:16 HKT 2021
MACHINE: mips64 (unknown Mhz)
MEMORY: 0
PANIC: "CPU 3 Unable to handle kernel paging request at virtual address 0000000000000000, epc == ffffffff8085d318, ra == ffffffff8085d308"
PID: 4768
COMMAND: "bash"
TASK: 9800000243bcf200 [THREAD_INFO: 980000024291c000]
CPU: 3
STATE: TASK_RUNNING (PANIC)
crash>
Signed-off-by: Huacai Chen <chenhuacai(a)loongson.cn>
Signed-off-by: Youling Tang <tangyouling(a)loongson.cn>
---
mips64.c | 308 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 308 insertions(+)
diff --git a/mips64.c b/mips64.c
index c3eb03c..21a8206 100644
--- a/mips64.c
+++ b/mips64.c
@@ -17,11 +17,269 @@
#include <elf.h>
#include "defs.h"
+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);
+
+/*
+ * 3 Levels paging PAGE_SIZE=16KB
+ * PGD | PMD | PTE | OFFSET |
+ * 11 | 11 | 11 | 14 |
+ */
+/* From arch/mips/include/asm/pgtable{,-64}.h */
+typedef struct { ulong pgd; } pgd_t;
+typedef struct { ulong pmd; } pmd_t;
+typedef struct { ulong pte; } pte_t;
+
+#define PMD_ORDER 0
+#define PTE_ORDER 0
+
+#define PMD_SHIFT (PAGESHIFT() + (PAGESHIFT() + PTE_ORDER - 3))
+#define PMD_SIZE (1UL << PMD_SHIFT)
+#define PMD_MASK (~(PMD_SIZE - 1))
+
+#define PGDIR_SHIFT (PMD_SHIFT + (PAGESHIFT() + PMD_ORDER - 3))
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE - 1))
+
+#define PTRS_PER_PTE (1UL << (PAGESHIFT() - 3))
+#define PTRS_PER_PMD PTRS_PER_PTE
+#define PTRS_PER_PGD PTRS_PER_PTE
+#define USER_PTRS_PER_PGD (0x80000000UL/PGDIR_SIZE)
+
+#define pte_index(addr) (((addr) >> PAGESHIFT()) & (PTRS_PER_PTE - 1))
+#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
+#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
+
+#define MIPS64_CPU_RIXI (1UL << 23) /* CPU has TLB Read/eXec Inhibit */
+
+/* From arch/mips/include/uapi/asm/reg.h */
+#define MIPS64_EF_R0 0
+#define MIPS64_EF_R29 29
+#define MIPS64_EF_R31 31
+#define MIPS64_EF_LO 32
+#define MIPS64_EF_HI 33
+#define MIPS64_EF_CP0_EPC 34
+#define MIPS64_EF_CP0_BADVADDR 35
+#define MIPS64_EF_CP0_STATUS 36
+#define MIPS64_EF_CP0_CAUSE 37
+
+static struct machine_specific mips64_machine_specific = { 0 };
+
+/*
+ * Holds registers during the crash.
+ */
+static struct mips64_register *panic_task_regs;
+
+/*
+ * Virtual to physical memory translation. This function will be called
+ * by both mips64_kvtop and mips64_uvtop.
+ */
+static int
+mips64_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
+{
+ ulong *pgd_ptr, pgd_val;
+ ulong *pmd_ptr, pmd_val;
+ ulong *pte_ptr, pte_val;
+
+ if (verbose) {
+ const char *segment;
+
+ if (vaddr < 0x4000000000000000lu)
+ segment = "xuseg";
+ else if (vaddr < 0x8000000000000000lu)
+ segment = "xsseg";
+ else if (vaddr < 0xc000000000000000lu)
+ segment = "xkphys";
+ else if (vaddr < 0xffffffff80000000lu)
+ segment = "xkseg";
+ else if (vaddr < 0xffffffffa0000000lu)
+ segment = "kseg0";
+ else if (vaddr < 0xffffffffc0000000lu)
+ segment = "kseg1";
+ else if (vaddr < 0xffffffffe0000000lu)
+ segment = "sseg";
+ else
+ segment = "kseg3";
+
+ fprintf(fp, "SEGMENT: %s\n", segment);
+ }
+
+ if (IS_CKPHYS(vaddr) || IS_XKPHYS(vaddr)) {
+ *paddr = VTOP(vaddr);
+ return TRUE;
+ }
+
+ if (verbose)
+ fprintf(fp, "PAGE DIRECTORY: %016lx\n", (ulong)pgd);
+
+ pgd_ptr = pgd + pgd_index(vaddr);
+ FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
+ pgd_val = ULONG(machdep->pgd + PAGEOFFSET(pgd_ptr));
+ if (verbose)
+ fprintf(fp, " PGD: %16lx => %16lx\n", (ulong)pgd_ptr, pgd_val);
+ if (!pgd_val)
+ goto no_page;
+
+ pmd_ptr = (ulong *)(VTOP(pgd_val) + sizeof(pmd_t) * pmd_index(vaddr));
+ FILL_PMD(PAGEBASE(pmd_ptr), PHYSADDR, PAGESIZE());
+ pmd_val = ULONG(machdep->pmd + PAGEOFFSET(pmd_ptr));
+ if (verbose)
+ fprintf(fp, " PMD: %016lx => %016lx\n", (ulong)pmd_ptr, pmd_val);
+ if (!pmd_val)
+ goto no_page;
+
+ pte_ptr = (ulong *)(VTOP(pmd_val) + sizeof(pte_t) * pte_index(vaddr));
+ FILL_PTBL(PAGEBASE(pte_ptr), PHYSADDR, PAGESIZE());
+ pte_val = ULONG(machdep->ptbl + PAGEOFFSET(pte_ptr));
+ if (verbose)
+ fprintf(fp, " PTE: %016lx => %016lx\n", (ulong)pte_ptr, pte_val);
+ if (!pte_val)
+ goto no_page;
+
+ return TRUE;
+no_page:
+ fprintf(fp, "invalid\n");
+ return FALSE;
+}
+
+/* Translates a user virtual address to its physical address. cmd_vtop() sets
+ * the verbose flag so that the pte translation gets displayed; all other
+ * callers quietly accept the translation.
+ */
+static int
+mips64_uvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
+{
+ ulong mm, active_mm;
+ ulong *pgd;
+
+ if (!tc)
+ error(FATAL, "current context invalid\n");
+
+ *paddr = 0;
+
+ if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) {
+ if (VALID_MEMBER(thread_struct_pg_tables))
+ pgd = (ulong *)machdep->get_task_pgd(tc->task);
+ else {
+ if (INVALID_MEMBER(task_struct_active_mm))
+ error(FATAL, "no pg_tables or active_mm?\n");
+
+ readmem(tc->task + OFFSET(task_struct_active_mm),
+ KVADDR, &active_mm, sizeof(void *),
+ "task active_mm contents", FAULT_ON_ERROR);
+
+ if (!active_mm)
+ error(FATAL,
+ "no active_mm for this kernel thread\n");
+
+ readmem(active_mm + OFFSET(mm_struct_pgd),
+ KVADDR, &pgd, sizeof(long),
+ "mm_struct pgd", FAULT_ON_ERROR);
+ }
+ } else {
+ if ((mm = task_mm(tc->task, TRUE)))
+ pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd));
+ else
+ readmem(tc->mm_struct + OFFSET(mm_struct_pgd),
+ KVADDR, &pgd, sizeof(long), "mm_struct pgd",
+ FAULT_ON_ERROR);
+ }
+
+ return mips64_pgd_vtop(pgd, vaddr, paddr, verbose);;
+}
+
+/* Translates a user virtual address to its physical address. cmd_vtop() sets
+ * the verbose flag so that the pte translation gets displayed; all other
+ * callers quietly accept the translation.
+ */
+static int
+mips64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
+{
+ if (!IS_KVADDR(kvaddr))
+ return FALSE;
+
+ if (!verbose) {
+ if (IS_CKPHYS(kvaddr) || IS_XKPHYS(kvaddr)) {
+ *paddr = VTOP(kvaddr);
+ return TRUE;
+ }
+ }
+
+ return mips64_pgd_vtop((ulong *)vt->kernel_pgd[0], kvaddr, paddr,
+ verbose);
+}
+
+/*
+ * Accept or reject a symbol from the kernel namelist.
+ */
+static int
+mips64_verify_symbol(const char *name, ulong value, char type)
+{
+ return TRUE;
+}
+
+/*
+ * Override smp_num_cpus if possible and necessary.
+ */
+static int
+mips64_get_smp_cpus(void)
+{
+ return (get_cpus_online() > 0) ? get_cpus_online() : kt->cpus;
+}
+
+static ulong
+mips64_get_page_size(void)
+{
+ return memory_page_size();
+}
+
+/*
+ * Determine where vmalloc'd memory starts.
+ */
+static ulong
+mips64_vmalloc_start(void)
+{
+ return 0;
+}
+
+static ulong
+mips64_processor_speed(void)
+{
+ return 0;
+}
+
+/*
+ * Checks whether given task is valid task address.
+ */
+static int
+mips64_is_task_addr(ulong task)
+{
+ if (tt->flags & THREAD_INFO)
+ return IS_KVADDR(task);
+
+ return (IS_KVADDR(task) && ALIGNED_STACK_OFFSET(task) == 0);
+}
+
void
mips64_dump_machdep_table(ulong arg)
{
}
+static void
+pt_level_alloc(char **lvl, char *name)
+{
+ size_t sz = PAGESIZE();
+ void *pointer = malloc(sz);
+
+ if (!pointer)
+ error(FATAL, name);
+ *lvl = pointer;
+}
+
/*
* Do all necessary machine-specific setup here. This is called several
* times during initialization.
@@ -33,6 +291,56 @@ mips64_init(int when)
case SETUP_ENV:
machdep->process_elf_notes = process_elf64_notes;
break;
+
+ case PRE_SYMTAB:
+ machdep->verify_symbol = mips64_verify_symbol;
+ machdep->machspec = &mips64_machine_specific;
+ if (pc->flags & KERNEL_DEBUG_QUERY)
+ return;
+ machdep->last_pgd_read = 0;
+ machdep->last_pmd_read = 0;
+ machdep->last_ptbl_read = 0;
+ machdep->verify_paddr = generic_verify_paddr;
+ machdep->ptrs_per_pgd = PTRS_PER_PGD;
+ break;
+
+ case PRE_GDB:
+ machdep->pagesize = mips64_get_page_size();
+ machdep->pageshift = ffs(machdep->pagesize) - 1;
+ machdep->pageoffset = machdep->pagesize - 1;
+ machdep->pagemask = ~((ulonglong)machdep->pageoffset);
+ if (machdep->pagesize >= 16384)
+ machdep->stacksize = machdep->pagesize;
+ else
+ machdep->stacksize = machdep->pagesize * 2;
+
+ pt_level_alloc(&machdep->pgd, "cannot malloc pgd space.");
+ pt_level_alloc(&machdep->pmd, "cannot malloc pmd space.");
+ pt_level_alloc(&machdep->ptbl, "cannot malloc ptbl space.");
+ machdep->kvbase = 0x8000000000000000lu;
+ machdep->identity_map_base = machdep->kvbase;
+ machdep->is_kvaddr = generic_is_kvaddr;
+ machdep->is_uvaddr = generic_is_uvaddr;
+ machdep->uvtop = mips64_uvtop;
+ machdep->kvtop = mips64_kvtop;
+ machdep->vmalloc_start = mips64_vmalloc_start;
+ machdep->processor_speed = mips64_processor_speed;
+ machdep->get_stackbase = generic_get_stackbase;
+ machdep->get_stacktop = generic_get_stacktop;
+ machdep->memory_size = generic_memory_size;
+ machdep->is_task_addr = mips64_is_task_addr;
+ machdep->get_smp_cpus = mips64_get_smp_cpus;
+ machdep->value_to_symbol = generic_machdep_value_to_symbol;
+ machdep->init_kernel_pgd = NULL;
+ break;
+
+ case POST_GDB:
+ machdep->section_size_bits = _SECTION_SIZE_BITS;
+ machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
+ break;
+
+ case POST_VM:
+ break;
}
}
--
2.1.0
3 years, 9 months
Re: [Crash-utility] [PATCH v1 0/3] Add valgrind support for the crash's custom memory
by lijiang
在 2021年02月22日 09:12, crash-utility-request(a)redhat.com 写道:
> Date: Mon, 22 Feb 2021 00:37:36 +0000
> From: HAGIO KAZUHITO(?????) <k-hagio-ab(a)nec.com>
> To: "Discussion list for crash utility usage, maintenance and
> development" <crash-utility(a)redhat.com>
> Cc: "d.hatayama(a)fujitsu.com" <d.hatayama(a)fujitsu.com>
> Subject: Re: [Crash-utility] [PATCH v1 0/3] Add valgrind support for
> the crash's custom memory
> Message-ID:
> <OSBPR01MB1991940E91708000BFEDE9D3DD819(a)OSBPR01MB1991.jpnprd01.prod.outlook.com>
>
> Content-Type: text/plain; charset="utf-8"
>
> Hi Lianbo, Hatayama-san,
>
> -----Original Message-----
>> Hi, HATAYAMA
>>
>> ? 2021?01?21? 12:47, crash-utility-request(a)redhat.com ??:
>>> From: HATAYAMA Daisuke <d.hatayama(a)fujitsu.com>
>>> Sent: Monday, January 4, 2021 14:28
>>> To: crash-utility(a)redhat.com
>>> Cc: Hatayama, Daisuke/?? ??
>>> Subject: [PATCH v1 0/3] Add valgrind support for the crash's custom memory
>>>
>>> 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
>>>
>> Thank you for the patchset.
>>
>> This changes are fine to me, but I have some other concerns as below:
>>
>> [1] add a simple description for supporting 'make valgrind' in README?
> Good catch, thanks Lianbo.
>
> FYI, note that the README data is also in help.c and needs to be updated.
>
Sure.
>> [2] only pass the '-DVALGRIND' when using 'make valgrind' explicitly?
>>
>> For example:
>>
>> Step1: [root@dell-pet620-01 crash]# make valgrind
>> TARGET: X86_64
>> CRASH: 7.2.9++
>> GDB: 7.6
>>
>> cc -c -g -DX86_64 -DVALGRIND -DGDB_7_6 build_data.c -Wall -O2 -Wstrict-prototypes -Wmissing-prototypes
>> -fstack-protector -Wformat-security
>> cc -c -g -DX86_64 -DVALGRIND -DGDB_7_6 tools.c -Wall -O2 -Wstrict-prototypes -Wmissing-prototypes
>> -fstack-protector -Wformat-security
>> cc -c -g -DX86_64 -DVALGRIND -DGDB_7_6 global_data.c -Wall -O2 -Wstrict-prototypes -Wmissing-prototypes
>> -fstack-protector -Wformat-security
>> ^^^^^^^^^
>> ...
>>
>> Step2: [root@dell-pet620-01 crash]# make lzo
>> TARGET: X86_64
>> CRASH: 7.2.9++
>> GDB: 7.6
>>
>> cc -c -g -DX86_64 -DVALGRIND -DLZO -DGDB_7_6 build_data.c -Wall -O2 -Wstrict-prototypes
>> -Wmissing-prototypes -fstack-protector -Wformat-security
>> cc -c -g -DX86_64 -DVALGRIND -DLZO -DGDB_7_6 main.c -Wall -O2 -Wstrict-prototypes -Wmissing-prototypes
>> -fstack-protector -Wformat-security
>> cc -c -g -DX86_64 -DVALGRIND -DLZO -DGDB_7_6 tools.c -Wall -O2 -Wstrict-prototypes -Wmissing-prototypes
>> -fstack-protector -Wformat-security
>> ^^^^^^^^^^^^^^^
>> ...
>>
>> For the 'make lzo', the cflag '-DVALGRIND' is also added here after the step1, is that expected?
> As written in the README, these targets are sticky, so it's expected:
>
> All of the alternate build commands above are "sticky" in that the
> special "make" targets only have to be entered one time; all subsequent
> builds will follow suit.
>
> AFAIK, the only command that can drop a target is "make nowarn", otherwise
> we can drop "lzo" and so on by removing CFLAGS.extra and LDFLAGS.extra for
> the present.
>
Seems yes. Is it possible to separate these CFLAGS? And we may put them together when
it is needed, For example:
make lzo (-DLZO)
make valgrind (-DVALGRIND)
make lzo_valgrind (-DVALGRIND -DLZO)
But I'm not sure if it looks more reasonable. Anyway, this is another issue.
Thanks.
Lianbo
> Thanks,
> Kazu
>
>>
>> BTW: this change could make the distribution add a new dependency of valgrind-devel package(A warm reminder).
>>
>> Thanks.
>> Lianbo
>>
>>> Makefile | 4 ++++
>>> configure.c | 15 ++++++++++++-
>>> symbols.c | 10 +++------
>>> tools.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>>> 4 files changed, 91 insertions(+), 10 deletions(-)
>>>
>>> --
>>> 1.8.3.1
3 years, 10 months