Question regarding crash usage on Xen Dom0 Kernel
by yang oliver
All,
Could latest crash version (b349598) could work on Linux 4.6.4 Xen Dom0?
It seemed that crash only could support open dump files, instead of running directly without a kernel core.
Please let me know whether my understanding is correct or not.
Daniel,
If my understanding is correct, I’m wondering do you have the plan to support this crash use case on Xen Dom0?
Here are detailed information, just FYI,
On Linux kernel 4.6.4 based Xen Dom0, I ran crash directly with kernel debug info installed,
# crash
crash 7.1.5++
Copyright (C) 2002-2016 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.
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) 7.6
Copyright (C) 2013 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-unknown-linux-gnu"...
crash: p2m array in new format is unreadable.
The error message was from below patch, which indicated that it only works for dump file case,
https://github.com/crash-utility/crash/commit/c3413456599161cabc4e910a0ae...
In the patch, the XEN_CORE_DUMPFILE check excluded the case running crash without a kernel file,
} else if (symbol_exists("xen_p2m_addr")) {
if (!XEN_CORE_DUMPFILE()) >>>>>>>>>>>>> hit the condition here
error(FATAL, "p2m array in new format is unreadable.");
8 years, 5 months
[PATCH 1/1] Speed up list/tree '-s' output.
by Alexandr Terekhov
Hi Dave,
here is the patch which introduces new key of `list` and `tree` commands.
If new key is used, crash reads fields by means of 'readmem' function
instead of parsing the gdb output. Therefore works much faster:
% echo "tree -t radix -r address_space.page_tree -s page.flags,index,private ffff880456375220 | wc -l" | time ./crash -s ../crash_images/504.23.4.el6_x86-64-vm*
crash: invalid task address: ffffffff81a01ea8
scroll: off (/usr/bin/less)
extend: r.so: No such device or address
16652
./crash -s ../crash_images/504.23.4.el6_x86-64-vm* 226.63s user 2.90s system 99% cpu 3:51.42 total
% echo "tree -t radix -r address_space.page_tree -S page.flags,index,private ffff880456375220 | wc -l" | time ./crash -s ../crash_images/504.23.4.el6_x86-64-vm*
crash: invalid task address: ffffffff81a01ea8
scroll: off (/usr/bin/less)
extend: r.so: No such device or address
16652
./crash -s ../crash_images/504.23.4.el6_x86-64-vm* 5.30s user 0.14s system 99% cpu 5.460 total
11,000,000 records might be dealt with within several minutes.
Looking forward to your comments.
Best,
Alexandr
--- crash-7.1.5.orig/tools.c 2016-04-27 21:46:50.000000000 +0300
+++ crash-7.1.5/tools.c 2016-07-26 13:56:27.192042851 +0300
@@ -23,10 +23,11 @@
struct hq_entry;
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 dump_struct_members(struct struct_req_entry *, int, ulong);
static void rbtree_iteration(ulong, struct tree_data *, char *);
static void rdtree_iteration(ulong, struct tree_data *, char *, ulong, uint);
-static void dump_struct_members_for_tree(struct tree_data *, int, ulong);
+static struct struct_req_entry *fill_member_offsets(char *);
+static void print_value(char *, ulong, short, unsigned int);
/*
* General purpose error reporting routine. Type INFO prints the message
@@ -3229,7 +3230,7 @@
BZERO(ld, sizeof(struct list_data));
struct_list_offset = 0;
- while ((c = getopt(argcnt, args, "Hhrs:e:o:xdl:")) != EOF) {
+ while ((c = getopt(argcnt, args, "Hhrs:S:e:o:xdl:")) != EOF) {
switch(c)
{
case 'H':
@@ -3246,10 +3247,15 @@
break;
case 's':
- if (ld->structname_args++ == 0)
- hq_open();
- hq_enter((ulong)optarg);
- break;
+ case 'S':
+ if (ld->entries == 8)
+ error(WARNING, "Too many `-S` arguments."
+ " Ignoring argument: '%s'\n", optarg);
+ else {
+ ld->e[ld->entries] = fill_member_offsets(optarg);
+ ld->e[ld->entries++]->ff = (c == 's' ? FANCY : FAST);
+ }
+ break;
case 'l':
if (IS_A_NUMBER(optarg))
@@ -3313,13 +3319,10 @@
cmd_usage(pc->curcmd, SYNOPSIS);
}
- if (ld->structname_args) {
- ld->structname = (char **)GETBUF(sizeof(char *) * ld->structname_args);
- retrieve_list((ulong *)ld->structname, ld->structname_args);
- hq_close();
+ if (ld->entries) {
ld->struct_list_offset = struct_list_offset;
} else if (struct_list_offset) {
- error(INFO, "-l option can only be used with -s option\n");
+ error(INFO, "-l option can only be used with -s or -S option\n");
cmd_usage(pc->curcmd, SYNOPSIS);
}
@@ -3478,9 +3481,6 @@
hq_open();
c = do_list(ld);
hq_close();
-
- if (ld->structname_args)
- FREEBUF(ld->structname);
}
@@ -3493,8 +3493,9 @@
{
ulong next, last, first;
ulong searchfor, readflag;
- int i, count, others, close_hq_on_return;
+ int i, j, count, others, close_hq_on_return;
unsigned int radix;
+ char b[BUFSIZE];
if (CRASHDEBUG(1)) {
others = 0;
@@ -3531,11 +3532,16 @@
console(" list_head_offset: %ld\n", ld->list_head_offset);
console(" end: %lx\n", ld->end);
console(" searchfor: %lx\n", ld->searchfor);
- console(" structname_args: %lx\n", ld->structname_args);
- if (!ld->structname_args)
- console(" structname: (unused)\n");
- for (i = 0; i < ld->structname_args; i++)
- console(" structname[%d]: %s\n", i, ld->structname[i]);
+ console(" entries: %lx\n", ld->entries);
+ for (i = 0; i < ld->entries; i++) {
+ console(" entry[%d]: ", i);
+ for (j = 0; j < ld->e[i]->count; j++) {
+ snprintf(b, BUFSIZE, "{ member: %s, width: %d, offset: %d }",
+ ld->e[i]->member[j], ld->e[i]->width[j], ld->e[i]->offset[j]);
+ console("%s", b);
+ console(j == ld->e[i]->count - 1 ? "\n" : ", ");
+ }
+ }
console(" header: %s\n", ld->header);
console(" list_ptr: %lx\n", (ulong)ld->list_ptr);
console(" callback_func: %lx\n", (ulong)ld->callback_func);
@@ -3584,21 +3590,16 @@
if (ld->flags & VERBOSE) {
fprintf(fp, "%lx\n", next - ld->list_head_offset);
- if (ld->structname) {
- for (i = 0; i < ld->structname_args; i++) {
- switch (count_chars(ld->structname[i], '.'))
- {
- case 0:
- dump_struct(ld->structname[i],
- next - ld->list_head_offset - ld->struct_list_offset,
- radix);
- break;
- default:
- dump_struct_members(ld, i, next);
- break;
- }
- }
- }
+ for (i = 0; i < ld->entries; i++) {
+ struct struct_req_entry *e = ld->e[i];
+ if (e->count == 0)
+ dump_struct(e->name,
+ next - ld->list_head_offset - ld->struct_list_offset,
+ radix);
+ else
+ dump_struct_members(e, radix,
+ next - ld->list_head_offset - ld->struct_list_offset);
+ }
}
if (next && !hq_enter(next - ld->list_head_offset)) {
@@ -3689,41 +3690,22 @@
* struct.member1,member2,member3
*/
void
-dump_struct_members(struct list_data *ld, int idx, ulong next)
+dump_struct_members(struct struct_req_entry *e, int radix, ulong p)
{
- int i, argc;
- char *p1, *p2;
- char *structname, *members;
- char *arglist[MAXARGS];
- unsigned int radix;
+ unsigned int i;
+ char b[BUFSIZE];
- if (ld->flags & LIST_STRUCT_RADIX_10)
- radix = 10;
- else if (ld->flags & LIST_STRUCT_RADIX_16)
- radix = 16;
- else
- radix = 0;
-
- structname = GETBUF(strlen(ld->structname[idx])+1);
- members = GETBUF(strlen(ld->structname[idx])+1);
-
- strcpy(structname, ld->structname[idx]);
- p1 = strstr(structname, ".") + 1;
-
- p2 = strstr(ld->structname[idx], ".") + 1;
- strcpy(members, p2);
- replace_string(members, ",", ' ');
- argc = parse_line(members, arglist);
+ if (!IS_KVADDR(p))
+ return;
- for (i = 0; i < argc; i++) {
- *p1 = NULLCHAR;
- strcat(structname, arglist[i]);
- dump_struct_member(structname,
- next - ld->list_head_offset - ld->struct_list_offset, radix);
+ for (i = 0; i < e->count; i++) {
+ if (e->ff == FANCY || e->width[i] == 0 || e->width[i] > 8) {
+ snprintf(b, BUFSIZE, "%s.%s", e->name, e->member[i]);
+ dump_struct_member(b, p, radix);
+ } else {
+ print_value(e->member[i], p + e->offset[i], e->width[i], radix);
+ }
}
-
- FREEBUF(structname);
- FREEBUF(members);
}
#define RADIXTREE_REQUEST (0x1)
@@ -3745,7 +3727,7 @@
td = &tree_data;
BZERO(td, sizeof(struct tree_data));
- while ((c = getopt(argcnt, args, "xdt:r:o:s:pN")) != EOF) {
+ while ((c = getopt(argcnt, args, "xdt:r:o:s:S:pN")) != EOF) {
switch (c)
{
case 't':
@@ -3799,11 +3781,15 @@
break;
case 's':
- if (td->structname_args++ == 0)
- hq_open();
- hq_enter((ulong)optarg);
- break;
-
+ case 'S':
+ if (td->entries == 8)
+ error(WARNING, "Too many `-S` arguments."
+ " Ignoring argument: '%s'\n", optarg);
+ else {
+ td->e[td->entries] = fill_member_offsets(optarg);
+ td->e[td->entries++]->ff = (c == 's' ? FANCY : FAST);
+ }
+ break;
case 'p':
td->flags |= TREE_POSITION_DISPLAY;
break;
@@ -3878,13 +3864,6 @@
cmd_usage(pc->curcmd, SYNOPSIS);
}
- if (td->structname_args) {
- td->structname = (char **)GETBUF(sizeof(char *) *
- td->structname_args);
- retrieve_list((ulong *)td->structname, td->structname_args);
- hq_close();
- }
-
if (!(td->flags & TREE_NODE_POINTER))
td->start = td->start + root_offset;
@@ -3916,7 +3895,7 @@
td->flags & TREE_NODE_POINTER ? "yes" : "no");
fprintf(fp, " start: %lx\n", td->start);
fprintf(fp, "node_member_offset: %ld\n", td->node_member_offset);
- fprintf(fp, " structname_args: %d\n", td->structname_args);
+ fprintf(fp, " entries: %d\n", td->entries);
fprintf(fp, " count: %d\n", td->count);
}
@@ -3924,20 +3903,68 @@
td->flags |= VERBOSE;
hq_open();
+
if (type_flag & RADIXTREE_REQUEST)
do_rdtree(td);
else
do_rbtree(td);
hq_close();
-
- if (td->structname_args)
- FREEBUF(td->structname);
}
static ulong RADIX_TREE_MAP_SHIFT = UNINITIALIZED;
static ulong RADIX_TREE_MAP_SIZE = UNINITIALIZED;
static ulong RADIX_TREE_MAP_MASK = UNINITIALIZED;
+static struct struct_req_entry *
+fill_member_offsets(char *arg)
+{
+ int j;
+ char *p, m;
+ struct struct_req_entry *e;
+ char b[BUFSIZE];
+
+ if (!(arg && *arg))
+ return NULL;
+
+ j = count_chars(arg, ',') + 1;
+ e = (struct struct_req_entry *)GETBUF(sizeof(*e));
+
+ e->arg = GETBUF(strlen(arg + 1));
+ strcpy(e->arg, arg);
+
+ m = ((p = strchr(e->arg, '.')) != NULL);
+ if (!p++)
+ p = e->arg + strlen(e->arg) + 1;
+
+ e->name = GETBUF(p - e->arg);
+ strncpy(e->name, e->arg, p - e->arg - 1);
+
+ if (!m)
+ return e;
+
+ e->count = count_chars(p, ',') + 1;
+ e->width = GETBUF(e->count);
+ e->member = (char **)GETBUF(e->count * sizeof(char *));
+ e->offset = (short *)GETBUF(e->count * sizeof(short));
+
+ replace_string(p, ",", ' ');
+ parse_line(p, e->member);
+
+ for (j = 0; j < e->count; j++) {
+ e->offset[j] = MEMBER_OFFSET(e->name, e->member[j]);
+ if (e->offset[j] == -1)
+ e->offset[j] = ANON_MEMBER_OFFSET(e->name, e->member[j]);
+ if (e->offset[j] == -1)
+ break;
+
+ // Dirty hack for obtaining size of particular field
+ snprintf(b, BUFSIZE, "%s + 1", e->member[j]);
+ e->width[j] = ANON_MEMBER_OFFSET(e->name, b) - e->offset[j];
+ }
+
+ return e;
+}
+
int
do_rdtree(struct tree_data *td)
{
@@ -4049,28 +4076,20 @@
if (td->flags & TREE_POSITION_DISPLAY)
fprintf(fp, " position: %s/%d\n", pos, 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;
+ 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],
- slot, print_radix);
- break;
- default:
- dump_struct_members_for_tree(td, i,
- slot);
- break;
- }
- }
- }
+ for (i = 0; i < td->entries; i++) {
+ struct struct_req_entry *e = td->e[i];
+ if (e->count == 0)
+ dump_struct(e->name, slot, print_radix);
+ else
+ dump_struct_members(td->e[i], print_radix, slot);
+ }
} else
rdtree_iteration(slot, td, pos, index, height-1);
}
@@ -4124,26 +4143,20 @@
if (td->flags & TREE_POSITION_DISPLAY)
fprintf(fp, " position: %s\n", pos);
- 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;
+ 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], struct_p, print_radix);
- break;
- default:
- dump_struct_members_for_tree(td, i, struct_p);
- break;
- }
- }
- }
+ for (i = 0; i < td->entries; i++) {
+ struct struct_req_entry *e = td->e[i];
+ if (e->count == 0)
+ dump_struct(e->name, struct_p, print_radix);
+ else
+ dump_struct_members(td->e[i], print_radix, struct_p);
+ }
readmem(node_p+OFFSET(rb_node_rb_left), KVADDR, &left_p,
sizeof(void *), "rb_node rb_left", FAULT_ON_ERROR);
@@ -4157,40 +4170,32 @@
rbtree_iteration(right_p, td, right_pos);
}
-void
-dump_struct_members_for_tree(struct tree_data *td, int idx, ulong struct_p)
+static void
+print_value(char *name, ulong addr, short width, unsigned int radix)
{
- int i, argc;
- uint print_radix;
- char *p1;
- char *structname, *members;
- char *arglist[MAXARGS];
-
- 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;
-
- structname = GETBUF(strlen(td->structname[idx])+1);
- members = GETBUF(strlen(td->structname[idx])+1);
-
- strcpy(structname, td->structname[idx]);
- p1 = strstr(structname, ".") + 1;
+ union { uint64_t v64; uint32_t v32;
+ uint16_t v16; uint8_t v8;
+ } v;
+ char fmt[BUFSIZE];
+
+ if (!readmem(addr, KVADDR, &v, width,
+ "structure value", RETURN_ON_ERROR | QUIET)) {
+ error(INFO, "cannot access field: %s at %lx\n", name, addr);
+ return;
+ }
+ snprintf(fmt, BUFSIZE, " %%s = %s%%%s%s\n",
+ (radix == 16 ? "0x" : ""),
+ (width == 8 ? "l" : ""),
+ (radix == 16 ? "x" : "u" )
+ );
- strcpy(members, p1);
- replace_string(members, ",", ' ');
- argc = parse_line(members, arglist);
- for (i = 0; i <argc; i++) {
- *p1 = NULLCHAR;
- strcat(structname, arglist[i]);
- dump_struct_member(structname, struct_p, print_radix);
+ switch (width) {
+ case 1: fprintf(fp, fmt, name, v.v8); break;
+ case 2: fprintf(fp, fmt, name, v.v16); break;
+ case 4: fprintf(fp, fmt, name, v.v32); break;
+ case 8: fprintf(fp, fmt, name, v.v64); break;
}
-
- FREEBUF(structname);
- FREEBUF(members);
}
/*
--- crash-7.1.5.orig/defs.h 2016-04-27 21:46:50.000000000 +0300
+++ crash-7.1.5/defs.h 2016-07-25 14:43:32.224688448 +0300
@@ -2376,6 +2376,15 @@
#define union_name struct_name
+enum fast_or_fancy { FAST, FANCY };
+struct struct_req_entry {
+ char *arg, *name;
+ char **member, *width;
+ short *offset;
+ unsigned char count;
+ enum fast_or_fancy ff;
+};
+
struct list_data { /* generic structure used by do_list() to walk */
ulong flags; /* through linked lists in the kernel */
ulong start;
@@ -2383,13 +2392,14 @@
long list_head_offset;
ulong end;
ulong searchfor;
- char **structname;
- int structname_args;
char *header;
ulong *list_ptr;
int (*callback_func)(void *, void *);
void *callback_data;
long struct_list_offset;
+ int count;
+ int entries;
+ struct struct_req_entry *e[8];
};
#define LIST_OFFSET_ENTERED (VERBOSE << 1)
#define LIST_START_ENTERED (VERBOSE << 2)
@@ -2408,9 +2418,9 @@
ulong flags;
ulong start;
long node_member_offset;
- char **structname;
- int structname_args;
int count;
+ int entries;
+ struct struct_req_entry *e[8];
};
#define TREE_ROOT_OFFSET_ENTERED (VERBOSE << 1)
--- crash-7.1.5.orig/help.c 2016-04-27 21:46:50.000000000 +0300
+++ crash-7.1.5/help.c 2016-07-26 14:02:42.192044349 +0300
@@ -5583,6 +5583,9 @@
" or \"struct.member[index]\"; embedded member specifications may",
" extend beyond one level deep by expressing the struct argument as",
" \"struct.member.member.member...\".",
+" -S struct Do exactly the same thing as `-s`, but instead of parsing gdb output",
+" it reads value from memory, therefore it works much faster for"
+" 1-, 2-, 4-, and 8-bytes fields."
" -x Override default output format with hexadecimal format.",
" -d Override default output format with decimal format.",
" -p Display the node's position information, showing the relationship",
8 years, 5 months
[PATCH v5 0/4] arm64: more improvement of bt -f
by AKASHI Takahiro
Changes in v5:
* add a workaround against an exceptional case of backtracing
(See "FIXME" in arm64_back_trace_cmd())
* update comments in arm64_unwind_frame()
* add patch[4/4]
Changes in v4:
* use arm64_on_irq_stack() to check whether or not we are on IRQ stack.
mistakendly used 'flags & IRQ_STACKS'.
* fix a bug at critical timing around switching stacks in arm64_unwind_frame().
We need to take are of a possibility that we get back to process stack,
but fp still points to IRQ stack.
* add patch[2/3]
This should be applied even withtout patch[1/3]
* add patch[3/3]
applying this patch would be a discussion.
AKASHI Takahiro (4):
arm64: more improvement of bt -f
arm64: find a correct starting stackframe at bt
arm64: correct a PC shown in bt
arm64: add VHE support
arm64.c | 603 ++++++++++++++++++++++++++++++++++++++++++++--------------------
defs.h | 6 +
2 files changed, 423 insertions(+), 186 deletions(-)
--
2.9.0
8 years, 5 months
[PATCH] extensions/trace: Fix ftrace_get_event_type_name()
by Namhyung Kim
The recent kernel change dcb0b5575d24 ("tracing: Remove
TRACE_EVENT_FL_USE_CALL_FILTER logic") changed the bit index so it makes
checking TRACE_EVENT_FL_TRACEPOINT flag failed. It should be 0x20 for
newer kernels. Without this patch, the crash tool refused to load
trace.so extension due to invalid access to event names:
crash> extend trace.so
extend: /path/to/crash/extensions/trace.so: no commands registered: shared object unloaded
Instead of using the hard-coded value, read the enum value from the
kernel dynamically.
Reported-by: Minchan Kim <minchan(a)kernel.org>
Cc: Steven Rostedt <rostedt(a)goodmis.org>
Signed-off-by: Namhyung Kim <namhyung(a)gmail.com>
---
extensions/trace.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/extensions/trace.c b/extensions/trace.c
index 782d62f..f8ccd91 100644
--- a/extensions/trace.c
+++ b/extensions/trace.c
@@ -1015,8 +1015,6 @@ static void ftrace_destroy_event_types(void)
free(ftrace_common_fields);
}
-#define TRACE_EVENT_FL_TRACEPOINT 0x40
-
static
int ftrace_get_event_type_name(ulong call, char *name, int len)
{
@@ -1024,8 +1022,9 @@ int ftrace_get_event_type_name(ulong call, char *name, int len)
static int name_offset;
static int flags_offset;
static int tp_name_offset;
- uint flags;
+ static long tracepoint_flag;
+ uint flags;
ulong name_addr;
if (inited)
@@ -1051,6 +1050,9 @@ int ftrace_get_event_type_name(ulong call, char *name, int len)
if (tp_name_offset < 0)
return -1;
+ if (!enumerator_value("TRACE_EVENT_FL_TRACEPOINT", &tracepoint_flag))
+ return -1;
+
inited = 2;
work:
@@ -1067,7 +1069,7 @@ work:
RETURN_ON_ERROR))
return -1;
- if (flags & TRACE_EVENT_FL_TRACEPOINT) {
+ if (flags & (uint)tracepoint_flag) {
if (!readmem(name_addr + tp_name_offset, KVADDR,
&name_addr, sizeof(name_addr),
"read tracepoint name", RETURN_ON_ERROR))
--
2.8.0
8 years, 5 months