Re: [Crash-utility] How do I get IA64 register R32 and above?
by Dave Anderson
Correction: actually rse_function_params() was written by me,
but what I meant was that it uses the kernel's unw_access_gr()
function to read the argument registers. Here's the part of
unw_access_gr() that that accesses registers 32 and above:
} else {
/* access a stacked register */
addr = ia64_rse_skip_regs((unsigned long *) info->bsp,
regnum - 32);
nat_addr = ia64_rse_rnat_addr(addr);
if ((unsigned long) addr < info->regstk.limit
|| (unsigned long) addr >= info->regstk.top)
{
error(INFO, "unwind: ignoring attempt to access
register outside of rbs\n");
return -1;
}
if ((unsigned long) nat_addr >= info->regstk.top)
nat_addr = &info->sw->ar_rnat;
nat_mask = (1UL << ia64_rse_slot_num(addr));
}
I don't remember much about the ia64 backing store stuff, but
I guess it is possible that the arguments shown by "bt -f" may
very well be their current state.
Dave
----- Original Message -----
> On Mon, 2013-04-22 at 16:38 -0700, Jay Lan wrote:
> > Hi,
> >
> > I got an IA64 vmcore. The stack backtrace only
> > printed registers up to R31. How do I get the contents
> > of R32 and above?
> >
> > Thanks,
> > Jay
>
> Jay, here's an excerpt from an email I answered in 2006. It's not clear
> that I remember anything about this now :-) Hope it helps.
>
> Bob Montgomery
>
> --------------------------------
>
>
> > #8 [BSP:e00000404ae490e8] mdc_replay_open at a00000020122f490
> > (e0000040ffcd1f10)
> > ...mdc/mdc_request.c: 332
> > #9 [BSP:e00000404ae49078] ptlrpc_replay_interpret at a0000002013ed930
> > (e0000040ff86f300)
> > ...ptlrpc/client.c: 1636
> > #10 [BSP:e00000404ae48fe8] ptlrpc_check_set at a0000002013e14c0
> > (e0000000015eda80)
> >
>
> There are three big secrets:
>
> 1) The saved values of the stack frame registers (r32, r33, ... up to
> the limit set by the alloc statement at the beginning of the function
> for that frame) are located at the Backing Store Pointer (BSP) shown for
> the frame. If you want to see r32, r33, r34, r35 for frame #8, do
> crash> x/4xg 0xe00000404ae490e8
>
> 2) The saved values of the stack frame registers are their current
> values, not necessarily the values passed in to the function (for those
> registers that were used as input registers, for example). In other
> words, the first parameter is passed as r32, but r32 might be modified
> by that function before the point in the code represented by the stack
> trace. Check for this by disassembling:
> crash> dis mdc_replay_open | grep r32
> and looking to see where (if ever) r32 is modified (appears on the left
> hand side of an "=") in that function.
>
> 3) Every 64th word in the backing store is a NaT register store, not a
> regular register. So when you're counting words from the BSP pointer
> for that frame to match up with registers, skip any word whose address
> ends in 0x1f8, 0x3f8, 0x5f8, ...
>
> crash is trying to show you the passed parameters. If that's working,
> those values in parentheses at each level should correspond to r32,
> r33 ... for as many as shown. If I remember right, crash doesn't do
> that very well for functions in modules.
> ---------------------------------------------------------------
The "bt -f" option uses the rse_function_params() function backported
from the kernel's ia64 unwind facility. And they do appear to be as
you described, i.e., at the BSP address location. For example:
crash> bt -f
PID: 1 TASK: e0000100ff118000 CPU: 0 COMMAND: "init"
#0 [BSP:e0000100ff119358] schedule at a000000100678b90
(void)
#1 [BSP:e0000100ff119328] schedule_timeout at a00000010067a1b0
(1388)
#2 [BSP:e0000100ff119250] do_select at a0000001001b0090
(e0000100fe518180, e0000100ff11fce0, e0000100ff11fe10)
#3 [BSP:e0000100ff1191f0] core_sys_select at a0000001001b0990
(b, 60000fffffdf77a8, 0, 0, e0000100ff11fe10)
#4 [BSP:e0000100ff119160] sys_select at a0000001001b18b0
(b, 60000fffffdf77a8, 0, 0, 60000fffffdf7828)
#5 [BSP:e0000100ff119160] ia64_ret_from_syscall at a00000010000be40
EFRAME: e0000100ff11fe40
B0: 400000000000aee0 CR_IIP: a000000000010620
CR_IPSR: 00001213085a6010 CR_IFS: 0000000000000005
AR_PFS: c000000000000005 AR_RSC: 000000000000000f
AR_UNAT: 0000000000000000 AR_RNAT: 0000000000000000
AR_CCV: 0000000000000000 AR_FPSR: 0009804c8a70033f
LOADRS: 0000000000c00000 AR_BSPSTORE: 600007ffffdfc138
B6: 20000000002cb1a0 B7: a00000010000fc20
PR: 0000000000026241 R1: 2000000000328238
R2: a000000000010640 R3: e0000100ff11fef8
R8: 0000000000000001 R9: 0000000051763204
R10: 0000000000000000 R11: c000000000000611
R12: 60000fffffdf7670 R13: 20000000003b55f0
R14: a000000100707f18 R15: 0000000000000441
R16: e0000100ff118000 R17: 000000000000003f
R18: a00000010000fc20 R19: 000000000000011d
R20: 0009804c8a70033f R21: 0009804c8a70033f
R22: 0000000000000000 R23: 600007ffffdfc138
R24: 0000000000000000 R25: 0000000000000000
R26: c000000000000002 R27: 000000000000000f
R28: a000000000010620 R29: 00000010085a2010
R30: 0000000000000005 R31: 0000000000026241
F6: 000000000000000000000 F7: 000000000000000000000
F8: 000000000000000000000 F9: 000000000000000000000
F10: 000000000000000000000 F11: 000000000000000000000
#6 [BSP:e0000100ff119160] __kernel_syscall_via_break at a000000000010620
crash>
So if I look at the BSP location for the sys_select() frame #4:
#4 [BSP:e0000100ff119160] sys_select at a0000001001b18b0
(b, 60000fffffdf77a8, 0, 0, 60000fffffdf7828)
the arguments match up:
crash> rd e0000100ff119160 5
e0000100ff119160: 000000000000000b 60000fffffdf77a8 .........w.....`
e0000100ff119170: 0000000000000000 0000000000000000 ................
e0000100ff119180: 60000fffffdf7828 (x.....`
crash>
I would presume that even if they were modified in sys_select() that
rse_function_params() would still reflect the arguments as they were
passed in to the function. Otherwise, what's the point of the function?
And I don't know why it would behave any differently for a module function?
Dave
11 years, 7 months
Re: [Crash-utility] How do I get IA64 register R32 and above? [RESEND]
by Dave Anderson
(my first response from my redhat.com address has been sitting in the
"sent" bucket for ~20 minutes...)
----- Original Message -----
> On Mon, 2013-04-22 at 16:38 -0700, Jay Lan wrote:
> > Hi,
> >
> > I got an IA64 vmcore. The stack backtrace only
> > printed registers up to R31. How do I get the contents
> > of R32 and above?
> >
> > Thanks,
> > Jay
>
> Jay, here's an excerpt from an email I answered in 2006. It's not clear
> that I remember anything about this now :-) Hope it helps.
>
> Bob Montgomery
>
> --------------------------------
>
>
> > #8 [BSP:e00000404ae490e8] mdc_replay_open at a00000020122f490
> > (e0000040ffcd1f10)
> > ...mdc/mdc_request.c: 332
> > #9 [BSP:e00000404ae49078] ptlrpc_replay_interpret at a0000002013ed930
> > (e0000040ff86f300)
> > ...ptlrpc/client.c: 1636
> > #10 [BSP:e00000404ae48fe8] ptlrpc_check_set at a0000002013e14c0
> > (e0000000015eda80)
> >
>
> There are three big secrets:
>
> 1) The saved values of the stack frame registers (r32, r33, ... up to
> the limit set by the alloc statement at the beginning of the function
> for that frame) are located at the Backing Store Pointer (BSP) shown for
> the frame. If you want to see r32, r33, r34, r35 for frame #8, do
> crash> x/4xg 0xe00000404ae490e8
>
> 2) The saved values of the stack frame registers are their current
> values, not necessarily the values passed in to the function (for those
> registers that were used as input registers, for example). In other
> words, the first parameter is passed as r32, but r32 might be modified
> by that function before the point in the code represented by the stack
> trace. Check for this by disassembling:
> crash> dis mdc_replay_open | grep r32
> and looking to see where (if ever) r32 is modified (appears on the left
> hand side of an "=") in that function.
>
> 3) Every 64th word in the backing store is a NaT register store, not a
> regular register. So when you're counting words from the BSP pointer
> for that frame to match up with registers, skip any word whose address
> ends in 0x1f8, 0x3f8, 0x5f8, ...
>
> crash is trying to show you the passed parameters. If that's working,
> those values in parentheses at each level should correspond to r32,
> r33 ... for as many as shown. If I remember right, crash doesn't do
> that very well for functions in modules.
> ---------------------------------------------------------------
The "bt -f" option uses the rse_function_params() function backported
from the kernel's ia64 unwind facility. And they do appear to be as
you described, i.e., at the BSP address location. For example:
crash> bt -f
PID: 1 TASK: e0000100ff118000 CPU: 0 COMMAND: "init"
#0 [BSP:e0000100ff119358] schedule at a000000100678b90
(void)
#1 [BSP:e0000100ff119328] schedule_timeout at a00000010067a1b0
(1388)
#2 [BSP:e0000100ff119250] do_select at a0000001001b0090
(e0000100fe518180, e0000100ff11fce0, e0000100ff11fe10)
#3 [BSP:e0000100ff1191f0] core_sys_select at a0000001001b0990
(b, 60000fffffdf77a8, 0, 0, e0000100ff11fe10)
#4 [BSP:e0000100ff119160] sys_select at a0000001001b18b0
(b, 60000fffffdf77a8, 0, 0, 60000fffffdf7828)
#5 [BSP:e0000100ff119160] ia64_ret_from_syscall at a00000010000be40
EFRAME: e0000100ff11fe40
B0: 400000000000aee0 CR_IIP: a000000000010620
CR_IPSR: 00001213085a6010 CR_IFS: 0000000000000005
AR_PFS: c000000000000005 AR_RSC: 000000000000000f
AR_UNAT: 0000000000000000 AR_RNAT: 0000000000000000
AR_CCV: 0000000000000000 AR_FPSR: 0009804c8a70033f
LOADRS: 0000000000c00000 AR_BSPSTORE: 600007ffffdfc138
B6: 20000000002cb1a0 B7: a00000010000fc20
PR: 0000000000026241 R1: 2000000000328238
R2: a000000000010640 R3: e0000100ff11fef8
R8: 0000000000000001 R9: 0000000051763204
R10: 0000000000000000 R11: c000000000000611
R12: 60000fffffdf7670 R13: 20000000003b55f0
R14: a000000100707f18 R15: 0000000000000441
R16: e0000100ff118000 R17: 000000000000003f
R18: a00000010000fc20 R19: 000000000000011d
R20: 0009804c8a70033f R21: 0009804c8a70033f
R22: 0000000000000000 R23: 600007ffffdfc138
R24: 0000000000000000 R25: 0000000000000000
R26: c000000000000002 R27: 000000000000000f
R28: a000000000010620 R29: 00000010085a2010
R30: 0000000000000005 R31: 0000000000026241
F6: 000000000000000000000 F7: 000000000000000000000
F8: 000000000000000000000 F9: 000000000000000000000
F10: 000000000000000000000 F11: 000000000000000000000
#6 [BSP:e0000100ff119160] __kernel_syscall_via_break at a000000000010620
crash>
So if I look at the BSP location for the sys_select() frame #4:
#4 [BSP:e0000100ff119160] sys_select at a0000001001b18b0
(b, 60000fffffdf77a8, 0, 0, 60000fffffdf7828)
the arguments match up:
crash> rd e0000100ff119160 5
e0000100ff119160: 000000000000000b 60000fffffdf77a8 .........w.....`
e0000100ff119170: 0000000000000000 0000000000000000 ................
e0000100ff119180: 60000fffffdf7828 (x.....`
crash>
I would presume that even if they were modified in sys_select() that
rse_function_params() would still reflect the arguments as they were
passed in to the function. Otherwise, what's the point of the function?
And I don't know why it would behave any differently for a module function?
Dave
11 years, 7 months
fix bug of struct command
by qiaonuohan
Hello Dave,
The attachment is used to fix a bug of struct command.
When using command like below, struct command displays wrong data.
<cut>
crash> task_struct.fs ffff88003dfb5540
fs = 140234226652928
crash> task_struct ffff88003dfb5540
...
es = 0,
ds = 0,
fsindex = 0,
gsindex = 0,
*fs = 140234226652928,*
gs = 0,
debugreg0 = 0,
...
io_bitmap_ptr = 0x0,
iopl = 0,
io_bitmap_max = 0
},
*fs = 0xffff880037795f00,*
files = 0xffff8800371b6940,
...
<cut>
fs showed by struct command is a member of "struct thread_struct thread;",
not struct task_struct. This bug is involved by adding support to anonymous
member modified by me...
--
--
Regards
Qiao Nuohan
11 years, 7 months
Threaded crash tool? Is it time?
by James Washer
Machines are getting ever bigger. I routinely look at crash dumps from
systems with 2TB or more of memory. I'm finding I'm wasting too much time
waiting on crash to complete a command. For example "kmem -s" took close to
an hour on the dump I'm looking at now.
Has anyone ever looked into mutli-threading crash? Given the kmem -s
example above, a thread could be created for each cache (up to some defined
limit of threads).
Things like "foreach" could spawn threads. I'm sure there are lots of other
opportunities.
Yes, I know, it's open source, I should just go do it myself. Still, I'd
like to hear pro's and con's on this idea.
--
- jim
11 years, 7 months
'crash' compilation on Arch fails with -D_FORTIFY_SOURCE=2
by Anatol Pomozov
Hi,
Starting from recently Arch uses -D_FORTIFY_SOURCE=2 flag for
compilation that seems affects latest glibc. This flag causes 'crash
tool' compilation error on Arch:
/fibheap.c:265:7: warning: implicit declaration of function ‘abort’
[-Wimplicit-function-declaration]
abort ();
^
./fibheap.c:265:7: warning: incompatible implicit declaration of
built-in function ‘abort’ [enabled by default]
./fibheap.c: In function ‘fibheap_delete’:
./fibheap.c:277:5: warning: incompatible implicit declaration of
built-in function ‘free’ [enabled by default]
free (fibheap_extr_min_node (heap));
^
./fibheap.c: In function ‘fibheap_consolidate’:
./fibheap.c:368:3: warning: implicit declaration of function ‘memset’
[-Wimplicit-function-declaration]
memset (a, 0, sizeof (fibnode_t) * D);
^
./fibheap.c:368:3: warning: incompatible implicit declaration of
built-in function ‘memset’ [enabled by default]
make[4]: *** [fibheap.o] Error 1
make[3]: *** [all-libiberty] Error 2
make[2]: *** [all] Error 2
gdb build failed: gdb-7.3.1/gdb/libgdb.a does not exist
11 years, 7 months
[PATCH v2] Add -m option to kmem
by Zhang Yanfei
kmem -m|-M is used for displaying information of all ksm pages or
some ksm pages for specified ksm stable tree node addresses
for example:
crash> kmem -m
STABLE_NODE : ffff88083fc927e0
PAGE : ffffea000e667998
PHYSICAL ADDRESS: 41d475000
PID: 2967 MAPPING: 3
STABLE_NODE : ffff88083fc84a10
PAGE : ffffea000e3dd5d8
PHYSICAL ADDRESS: 411aad000
PID: 2967 MAPPING: 7
STABLE_NODE : ffff88041980dda8
PAGE : ffffea000e335568
PHYSICAL ADDRESS: 40eaab000
PID: 2967 MAPPING: 8
...
STABLE_NODE : ffff880841ea43f8
PAGE : ffffea000f62de38
PHYSICAL ADDRESS: 465641000
PID: 2967 MAPPING: 729
PID: 3017 MAPPING: 499
P.S.
This patch is based on the patch from Qiao(qiaonuohan(a)cn.fujitsu.com)
0001-make-rbtree-manipulation-functions-global.patch
Because this patch also uses rb_tree operations.
Signed-off-by: Zhang Yanfei <zhangyanfei(a)cn.fujitsu.com>
---
defs.h | 6 ++
help.c | 41 +++++++++++-
memory.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
symbols.c | 12 ++++
4 files changed, 259 insertions(+), 9 deletions(-)
diff --git a/defs.h b/defs.h
index 2993f2b..f6996be 100755
--- a/defs.h
+++ b/defs.h
@@ -1848,6 +1848,12 @@ struct offset_table { /* stash of commonly-used offsets */
long vmap_area_list;
long vmap_area_flags;
long vmap_area_vm;
+ long stable_node_node;
+ long stable_node_hlist;
+ long stable_node_kpfn;
+ long rmap_item_mm;
+ long rmap_item_address;
+ long rmap_item_hlist;
};
struct size_table { /* stash of commonly-used sizes */
diff --git a/help.c b/help.c
index c542743..38a3341 100755
--- a/help.c
+++ b/help.c
@@ -5147,8 +5147,8 @@ NULL
char *help_kmem[] = {
"kmem",
"kernel memory",
-"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z-o] [slab] [[-P] address]\n"
-" [-g [flags]]",
+"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z|-o|-m|-M] [slab] [[-P] address]\n"
+" [-g [flags]",
" This command displays information about the use of kernel memory.\n",
" -f displays the contents of the system free memory headers.",
" also verifies that the page count equals nr_free_pages.",
@@ -5172,6 +5172,9 @@ char *help_kmem[] = {
" -z displays per-zone memory statistics.",
" -o displays each cpu's offset value that is added to per-cpu symbol",
" values to translate them into kernel virtual addresses.",
+" -m displays information of ksm pages.",
+" -M same as -m, but also dumps virtual addresses that mapping the",
+" ksm pages.",
" -g displays the enumerator value of all bits in the page structure's",
" \"flags\" field.",
" flags when used with -g, translates all bits in this hexadecimal page",
@@ -5204,7 +5207,10 @@ char *help_kmem[] = {
" the page address is displayed if it is contained with the list.",
" address when used with -v, the address can be a mapped kernel virtual",
" address or physical address; the mapped region containing the",
-" address is displayed.\n",
+" address is displayed.",
+" address when used with -m or -M, the address can be either a ksm stable",
+" tree node address, a page's physical address, or a page pointer,",
+" the information of the ksm page (if it is) is displayed.\n",
" All address arguments above must be expressed in hexadecimal format.",
"\nEXAMPLES",
" Display memory usage information:\n",
@@ -5605,6 +5611,35 @@ char *help_kmem[] = {
" PG_slab 7 0000080",
" PG_head 14 0004000",
" %s>",
+"\n Display information of ksm pages:\n",
+" %s> kmem -m ffff88086f22eec0 ffff8803573964c0",
+" STABLE_NODE : ffff88083fc927e0",
+" PAGE : ffffea000e667998",
+" PHYSICAL ADDRESS: 41d475000",
+"",
+" PID: 2967 MAPPING: 3",
+"",
+" STABLE_NODE : ffff88083fc84a10",
+" PAGE : ffffea000e3dd5d8",
+" PHYSICAL ADDRESS: 411aad000",
+"",
+" PID: 2967 MAPPING: 7",
+"",
+" STABLE_NODE : ffff88041980dda8",
+" PAGE : ffffea000e335568",
+" PHYSICAL ADDRESS: 40eaab000",
+"",
+" PID: 2967 MAPPING: 8",
+"",
+" ......",
+"",
+" STABLE_NODE : ffff880841ea43f8",
+" PAGE : ffffea000f62de38",
+" PHYSICAL ADDRESS: 465641000",
+"",
+" PID: 2967 MAPPING: 729",
+" PID: 3017 MAPPING: 499",
+"",
NULL
};
diff --git a/memory.c b/memory.c
index 02a6de1..9623949 100755
--- a/memory.c
+++ b/memory.c
@@ -264,6 +264,7 @@ static int verify_pfn(ulong);
static void dump_per_cpu_offsets(void);
static void dump_page_flags(ulonglong);
static ulong kmem_cache_nodelists(ulong);
+static void dump_ksm(struct meminfo *);
/*
* Memory display modes specific to this file.
@@ -1012,6 +1013,16 @@ vm_init(void)
PG_reserved_flag_init();
PG_slab_flag_init();
+ if (STRUCT_EXISTS("stable_node")) {
+ MEMBER_OFFSET_INIT(stable_node_node, "stable_node", "node");
+ MEMBER_OFFSET_INIT(stable_node_hlist, "stable_node", "hlist");
+ MEMBER_OFFSET_INIT(stable_node_kpfn, "stable_node", "kpfn");
+ MEMBER_OFFSET_INIT(stable_node_node, "stable_node", "node");
+ MEMBER_OFFSET_INIT(rmap_item_mm, "rmap_item", "mm");
+ MEMBER_OFFSET_INIT(rmap_item_address, "rmap_item", "address");
+ ANON_MEMBER_OFFSET_INIT(rmap_item_hlist, "rmap_item", "hlist");
+ }
+
vt->flags |= VM_INIT;
}
@@ -4090,22 +4101,25 @@ cmd_kmem(void)
int i;
int c;
int sflag, Sflag, pflag, fflag, Fflag, vflag, zflag, oflag, gflag;
- int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag;
+ int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag, mflag;
+ int Mflag;
struct meminfo meminfo;
ulonglong value[MAXARGS];
char buf[BUFSIZE];
char *p1;
int spec_addr, escape;
+ ulong ksm_pages_shared;
spec_addr = 0;
sflag = Sflag = pflag = fflag = Fflag = Pflag = zflag = oflag = 0;
vflag = Cflag = cflag = iflag = nflag = lflag = Lflag = Vflag = 0;
- gflag = 0;
+ gflag = mflag = Mflag = 0;
escape = FALSE;
+ ksm_pages_shared = 0;
BZERO(&meminfo, sizeof(struct meminfo));
BZERO(&value[0], sizeof(ulonglong)*MAXARGS);
- while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVo")) != EOF) {
+ while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVomM")) != EOF) {
switch(c)
{
case 'V':
@@ -4206,6 +4220,18 @@ cmd_kmem(void)
gflag = 1;
break;
+ case 'm':
+ if (INVALID_MEMBER(stable_node_node))
+ option_not_supported(c);
+ mflag = 1;
+ break;
+
+ case 'M':
+ if (INVALID_MEMBER(stable_node_node))
+ option_not_supported(c);
+ Mflag = 1;
+ break;
+
default:
argerrs++;
break;
@@ -4216,7 +4242,8 @@ cmd_kmem(void)
cmd_usage(pc->curcmd, SYNOPSIS);
if ((sflag + Sflag + pflag + fflag + Fflag + Vflag + oflag +
- vflag + Cflag + cflag + iflag + lflag + Lflag + gflag) > 1) {
+ vflag + Cflag + cflag + iflag + lflag + Lflag + gflag +
+ mflag + Mflag) > 1) {
error(INFO, "only one flag allowed!\n");
cmd_usage(pc->curcmd, SYNOPSIS);
}
@@ -4224,6 +4251,15 @@ cmd_kmem(void)
if (sflag || Sflag || !(vt->flags & KMEM_CACHE_INIT))
kmem_cache_init();
+ if (mflag || Mflag) {
+ get_symbol_data("ksm_pages_shared", sizeof(ulong),
+ &ksm_pages_shared);
+ if (!ksm_pages_shared) {
+ fprintf(fp, "ksm may not be enabled\n");
+ return;
+ }
+ }
+
while (args[optind]) {
if (hexadecimal(args[optind], 0)) {
value[spec_addr++] =
@@ -4347,6 +4383,18 @@ cmd_kmem(void)
gflag++;
}
+ if (mflag || Mflag) {
+ meminfo.spec_addr = value[i];
+ meminfo.flags = ADDRESS_SPECIFIED;
+ if (Mflag)
+ meminfo.flags |= VERBOSE;
+ dump_ksm(&meminfo);
+ if (mflag)
+ mflag++;
+ if (Mflag)
+ Mflag++;
+ }
+
/*
* no value arguments allowed!
*/
@@ -4358,7 +4406,7 @@ cmd_kmem(void)
}
if (!(sflag + Sflag + pflag + fflag + vflag + cflag +
- lflag + Lflag + gflag)) {
+ lflag + Lflag + gflag + mflag + Mflag)) {
meminfo.spec_addr = value[i];
meminfo.flags = ADDRESS_SPECIFIED;
if (meminfo.calls++)
@@ -4444,9 +4492,18 @@ cmd_kmem(void)
if (gflag == 1)
dump_page_flags(0);
+ if (mflag == 1)
+ dump_ksm(NULL);
+
+ if (Mflag == 1) {
+ meminfo.flags |= VERBOSE;
+ dump_ksm(&meminfo);
+ }
+
if (!(sflag + Sflag + pflag + fflag + Fflag + vflag +
Vflag + zflag + oflag + cflag + Cflag + iflag +
- nflag + lflag + Lflag + gflag + meminfo.calls))
+ nflag + lflag + Lflag + gflag + mflag + Mflag +
+ meminfo.calls))
cmd_usage(pc->curcmd, SYNOPSIS);
}
@@ -15799,6 +15856,146 @@ dump_page_flags(ulonglong flags)
close_tmpfile();
}
+struct page_ref {
+ ulong mm;
+ ulong pid;
+ int ref;
+};
+
+/*
+ * dump_ksm() displays information of ksm pages.
+ */
+static void
+dump_ksm(struct meminfo *mi)
+{
+ ulong root_stable_tree, stable_node, kpfn;
+ ulong rmap_item, mm, paddr;
+ struct rb_root *root;
+ struct rb_node *node;
+ ulong first, next;
+ struct task_context *tc;
+ int i, ref_size, refs, found;
+ struct page_ref *ref;
+ ulong page, address;
+
+ if (!symbol_exists("root_stable_tree")) {
+ error(INFO, "cannot determine ksm stable tree address from root_stable_tree\n");
+ return;
+ }
+ root_stable_tree = symbol_value("root_stable_tree");
+ root = (struct rb_root *)root_stable_tree;
+
+ refs = 0;
+ ref_size = sizeof(struct page_ref) * RUNNING_TASKS();
+ ref = (struct page_ref *)GETBUF(ref_size);
+ BZERO(ref, ref_size);
+
+ found = (mi && mi->flags & ADDRESS_SPECIFIED) ? 0 : -1;
+ for (node = rb_first(root); node; node = rb_next(node)) {
+ stable_node = (ulong) node - OFFSET(stable_node_node);
+ if (CRASHDEBUG(1))
+ fprintf(fp, " stable_node = %lx\n", stable_node);
+
+ readmem(stable_node + OFFSET(stable_node_hlist),
+ KVADDR, &first, sizeof(ulong),
+ "stable_node hlist", FAULT_ON_ERROR);
+ readmem(stable_node + OFFSET(stable_node_kpfn),
+ KVADDR, &kpfn, sizeof(ulong),
+ "stable_node kpfn", FAULT_ON_ERROR);
+ paddr = kpfn << PAGE_SHIFT;
+ phys_to_page(paddr, &page);
+
+ if (found == 0) {
+ if ((mi->memtype == KVADDR) &&
+ (((mi->spec_addr & ~0x3) == stable_node) ||
+ (mi->spec_addr == page)))
+ found = 1;
+ if ((mi->memtype == PHYSADDR) &&
+ (mi->spec_addr == paddr))
+ found = 1;
+ }
+ if (found == 0)
+ continue;
+
+ fprintf(fp, "STABLE_NODE : %lx\n", stable_node);
+ fprintf(fp, "PAGE : %lx\n", page);
+ fprintf(fp, "PHYSICAL ADDRESS: %lx\n\n", paddr);
+
+ readmem(stable_node + OFFSET(stable_node_hlist),
+ KVADDR, &first, sizeof(ulong),
+ "stable_node hlist", FAULT_ON_ERROR);
+
+ next = first;
+ while (next) {
+ rmap_item = next - OFFSET(rmap_item_hlist);
+ readmem(rmap_item + OFFSET(rmap_item_mm),
+ KVADDR, &mm, sizeof(ulong),
+ "rmap_item mm", FAULT_ON_ERROR);
+
+ for (i = 0; i < refs; i++) {
+ if (ref[i].mm == mm) {
+ ref[i].ref += 1;
+ goto next;
+ }
+ }
+
+ tc = FIRST_CONTEXT();
+ for (i = 0; i < RUNNING_TASKS(); i++, tc++) {
+ if (tc->mm_struct == mm) {
+ ref[refs].mm = mm;
+ ref[refs].pid = tc->pid;
+ ref[refs++].ref = 1;
+ break;
+ }
+ }
+
+next:
+ readmem(next + OFFSET(hlist_node_next),
+ KVADDR, &next, sizeof(ulong),
+ "hlist_node next", FAULT_ON_ERROR);
+ };
+
+ for (i = 0; i < refs; i++) {
+ fprintf(fp, " PID: %ld ", ref[i].pid);
+ fprintf(fp, "MAPPING: %d\n", ref[i].ref);
+
+ if (!(mi && mi->flags & VERBOSE))
+ continue;
+
+ fprintf(fp, " VIRTUAL:\n");
+ next = first;
+ while (next) {
+ rmap_item = next - OFFSET(rmap_item_hlist);
+ readmem(rmap_item + OFFSET(rmap_item_mm),
+ KVADDR, &mm, sizeof(ulong),
+ "rmap_item mm", FAULT_ON_ERROR);
+ if (ref[i].mm == mm) {
+ readmem(rmap_item + OFFSET(rmap_item_address),
+ KVADDR, &address, sizeof(ulong),
+ "rmap_item address", FAULT_ON_ERROR);
+ fprintf(fp, " %lx\n",
+ PAGEBASE(address));
+ }
+ readmem(next + OFFSET(hlist_node_next),
+ KVADDR, &next, sizeof(ulong),
+ "hlist_node next", FAULT_ON_ERROR);
+ }
+ fprintf(fp, "\n");
+ }
+ if (!(mi && mi->flags & VERBOSE))
+ fprintf(fp, "\n");
+ refs = 0;
+
+ if (found == 1)
+ break;
+ }
+
+ if (found == 0)
+ fprintf(fp, "address 0x%llx cannot specify a ksm stable tree node\n",
+ mi->spec_addr);
+
+ FREEBUF(ref);
+}
/*
* Support for slub.c slab cache.
diff --git a/symbols.c b/symbols.c
index 4fb397c..6c730ad 100755
--- a/symbols.c
+++ b/symbols.c
@@ -8860,6 +8860,18 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(rt_rq_highest_prio));
fprintf(fp, " rt_rq_rt_nr_running: %ld\n",
OFFSET(rt_rq_rt_nr_running));
+ fprintf(fp, " stable_node_node: %ld\n",
+ OFFSET(stable_node_node));
+ fprintf(fp, " stable_node_hlist: %ld\n",
+ OFFSET(stable_node_hlist));
+ fprintf(fp, " stable_node_kpfn: %ld\n",
+ OFFSET(stable_node_kpfn));
+ fprintf(fp, " rmap_item_mm: %ld\n",
+ OFFSET(rmap_item_mm));
+ fprintf(fp, " rmap_item_address: %ld\n",
+ OFFSET(rmap_item_address));
+ fprintf(fp, " rmap_item_hlist: %ld\n",
+ OFFSET(rmap_item_hlist));
fprintf(fp, "\n size_table:\n");
fprintf(fp, " page: %ld\n", SIZE(page));
--
1.7.1
11 years, 7 months
[PATCH] crash: Show module taint flags via cmd_mod
by Aaron Tomlin
Hi Dave, et al,
Example output:
crash> mod
MODULE NAME TAINT SIZE OBJECT FILE
ffffffffa0008ee0 scsi_transport_iscsi (PFUT) 57491 (not loaded) [CONFIG_KALLSYMS]
ffffffffa0021020 libiscsi 50543 (not loaded) [CONFIG_KALLSYMS]
ffffffffa0055a20 qla4xxx (U) 221130 (not loaded) [CONFIG_KALLSYMS]
ffffffffa0060160 video 18992 (not loaded) [CONFIG_KALLSYMS]
ffffffffa0065000 mdio 13436 (not loaded) [CONFIG_KALLSYMS]
ffffffffa006c000 libiscsi_tcp (T) 24177 (not loaded) [CONFIG_KALLSYMS]
ffffffffa007c040 libcxgbi 56493 (not loaded) [CONFIG_KALLSYMS]
...
Any thoughts?
Regards,
Aaron
---8<---
--- kernel.c.org 2013-02-14 20:38:54.000000000 +0000
+++ kernel.c 2013-03-15 16:36:19.116726704 +0000
@@ -3424,6 +3424,54 @@
return retval;
}
+char *show_module_taint(ulong module_address, char *buf)
+{
+ int gpgsig_ok;
+ unsigned int taints;
+ int bx = 0;
+
+ if (MEMBER_EXISTS("module", "gpgsig_ok")) {
+ readmem(module_address + MEMBER_OFFSET("module", "gpgsig_ok"), KVADDR, &gpgsig_ok,
+ sizeof(int), "module gpgsig_ok", FAULT_ON_ERROR);
+
+ if (!gpgsig_ok) {
+ buf[bx++] = '(';
+ buf[bx++] = 'U';
+ buf[bx++] = ')';
+ }
+ }
+
+ if (MEMBER_EXISTS("module", "taints")) {
+ readmem(module_address + MEMBER_OFFSET("module", "taints"), KVADDR, &taints,
+ sizeof(ulong), "module taints", FAULT_ON_ERROR);
+
+ if (taints) {
+ buf[bx++] = '(';
+ if (taints & (1 << TAINT_PROPRIETARY_MODULE))
+ buf[bx++] = 'P';
+
+ if (taints & (1 << TAINT_OOT_MODULE))
+ buf[bx++] = 'O';
+
+ if (taints & (1 << TAINT_FORCED_MODULE))
+ buf[bx++] = 'F';
+
+ if (taints & (1 << TAINT_UNSIGNED_MODULE))
+ buf[bx++] = 'U';
+
+ if (taints & (1 << TAINT_CRAP))
+ buf[bx++] = 'C';
+
+ if (taints & (1 << TAINT_TECH_PREVIEW))
+ buf[bx++] = 'T';
+
+ buf[bx++] = ')';
+ }
+ buf[bx] = '\0';
+ }
+ return buf;
+}
+
/*
* Do the simple list work for cmd_mod().
@@ -3437,9 +3485,12 @@
struct load_module *lm, *lmp;
int maxnamelen;
int maxsizelen;
+ int maxtaintlen = 12;
+ char buf[maxtaintlen];
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
+ char buf4[BUFSIZE];
if (NO_MODULES())
return;
@@ -3461,11 +3512,12 @@
}
if (flag == LIST_MODULE_HDR) {
- fprintf(fp, "%s %s %s OBJECT FILE\n",
+ fprintf(fp, "%s %s%s %s OBJECT FILE\n",
mkstring(buf1, VADDR_PRLEN, CENTER|LJUST,
"MODULE"),
mkstring(buf2, maxnamelen, LJUST, "NAME"),
- mkstring(buf3, maxsizelen, RJUST, "SIZE"));
+ mkstring(buf3, maxtaintlen, LJUST, "TAINT"),
+ mkstring(buf4, maxsizelen, RJUST, "SIZE"));
}
for (i = 0; i < kt->mods_installed; i++) {
@@ -3474,9 +3526,12 @@
(lm->mod_base == address)) {
fprintf(fp, "%s ", mkstring(buf1, VADDR_PRLEN,
LONG_HEX|RJUST, MKSTR(lm->module_struct)));
- fprintf(fp, "%s ", mkstring(buf2, maxnamelen,
+ fprintf(fp, "%s", mkstring(buf2, maxnamelen,
LJUST, lm->mod_name));
- fprintf(fp, "%s ", mkstring(buf3, maxsizelen,
+ /* Print module taint */
+ fprintf(fp, "%s ", mkstring(buf3, maxtaintlen,
+ LJUST, show_module_taint(lm->module_struct, buf)));
+ fprintf(fp, "%s ", mkstring(buf4, maxsizelen,
RJUST|LONG_DEC, MKSTR(lm->mod_size)));
// fprintf(fp, "%6ld ", lm->mod_size);
--- defs.h.org 2013-02-14 20:38:54.000000000 +0000
+++ defs.h 2013-03-15 16:36:16.505726642 +0000
@@ -177,6 +177,17 @@
};
/*
+ * Module taint flags
+ */
+
+#define TAINT_PROPRIETARY_MODULE 0
+#define TAINT_FORCED_MODULE 1
+#define TAINT_UNSIGNED_MODULE 6
+#define TAINT_CRAP 10
+#define TAINT_OOT_MODULE 12
+#define TAINT_TECH_PREVIEW 29
+
+/*
* program_context flags
*/
#define LIVE_SYSTEM (0x1ULL)
11 years, 7 months
[ANNOUNCE] crash version 6.1.6 is available
by Dave Anderson
Download from: http://people.redhat.com/anderson
Changelog:
- Fix for a crash-6.1.5 regression that causes the "mount" command
to fail on kernel versions prior to Linux 3.3. Without the patch,
the command fails with the message "mount: invalid structure member
offset: mount_mnt_devname".
The regression was caused by this patch:
- Patch to the internal gdb_get_datatype() function to return the
typecode and length of integer variables.
(adrian.wenl(a)gmail.com, anderson(a)redhat.com)
which inadvertently caused the STRUCT_SIZE("mount") macro to return
a false positive for the non-existent "mount" data structure due to
the existence of a "mount" kernel symbol in "security/inode.c".
The patch above was requested as an aid for an extension module,
and had no use with respect to the base crash utility. However, the
patch has the unintended side effect of allowing macros such as
STRUCT_SIZE(), STRUCT_EXISTS(), MEMBER_OFFSET() and MEMBER_EXISTS()
to return false positives. All of the macros call datatype_info(),
a function that expects a data type argument. If the passed-in
data type argument does not exist, but there does happen to be a
kernel variable with the same name, then it used to be rejected
because the internal gdb_get_datatype() function purposefully did
not return the typecode and length of kernel variables. However,
the patch above modified that functionality, and gdb_get_datatype()
started to return the typecode and length of kernel variables.
In order to allow an extension module the capability of utilizing
the internal gdb_get_datatype() function with a kernel variable name
instead of a data type, the patch above has been modified to return
the typecode and length of data variables only if an additional, new,
GNU_VAR_LENGTH_TYPECODE flag is set in the gnu_request.flags field.
As it stands now, that flag is not used by the base crash utility.
Furthermore, as a defensive mechanism against future breakage, the
STRUCT_SIZE() and STRUCT_EXISTS() macros have been modified to pass
a special non-NULL, third argument to datatype_info() that will
enforce the fact that the request is only functional for data type
names. In addition, the MEMBER_OFFSET() and MEMBER_EXISTS() handling
in datatype_info() has been fortified to ensure that the base data
type is in fact a structure or union. It should also be noted that
extension modules that were compiled with the old STRUCT_SIZE() or
STRUCT_EXISTS() macro definitions will still work as they did before.
(anderson(a)redhat.com)
11 years, 7 months
Re: [Crash-utility] [ANNOUNCE] crash-6.1.5 is available
by Daniel Kiper
Hey Dave,
> Download from: http://people.redhat.com/anderson
>
> Changelog:
[...]
> - Two Xen hypervisor fixes:
> (1) Fix console buffer content length calculation:
> Xen changeset 26447 (x86: re-introduce map_domain_page() et
> al) once again altered virtual address space. The current
> algorithm calculating its start could not cope with that
> change. New version establishes this value on the base of
> image start address and is more generic.
> (2) Improve calculation of beginning of virtual address space:
> Function displaying console buffer always assumes its content
> length equal to console buffer size. This is not true and
> sometimes it sends garbage to the screen. This patch fixes
> this issue.
> (daniel.kiper(a)oracle.com)
Thanks. There is only one small issue. Second subject should
be linked with first comment and vice versa.
Daniel
11 years, 7 months
[PATCH] kmem option to display pages per migrate type
by vinayak menon
Hi Dave,
Please share your thoughts on adding a -m option to kmem to display
the free pages per migrate type.
This is similar to /proc/pagetypeinfo.
Sample output (without formatting). Patch attached.
crash>
Free pages count per migrate type at order [0-10]:
Node 0, zone Normal, type Unmovable 155 172 92
39 20 8 10 15 7 3 1
Node 0, zone HighMem, type Unmovable 1 2 0
0 0 0 0 0 0 0 0
Node 0, zone Movable, type Unmovable 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Reclaimable 9 3 0
0 1 1 0 0 0 0 0
Node 0, zone HighMem, type Reclaimable 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Movable, type Reclaimable 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Movable 7 68 35
253 137 38 16 4 0 0 66
Node 0, zone HighMem, type Movable 0 1 0
0 0 0 0 0 0 0 0
Node 0, zone Movable, type Movable 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Reserve 0 0 0
0 0 0 0 0 0 0 1
Node 0, zone HighMem, type Reserve 11 7 5
1 0 0 0 0 0 0 0
Node 0, zone Movable, type Reserve 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Isolate 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone HighMem, type Isolate 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Movable, type Isolate 0 0 0
0 0 0 0 0 0 0 0
diff --git a/crash-6.0.8/help.c b/crash-6.0.8/help.c
index 6d6ac5e..9ad6c00 100755
--- a/crash-6.0.8/help.c
+++ b/crash-6.0.8/help.c
@@ -5147,7 +5147,7 @@ NULL
char *help_kmem[] = {
"kmem",
"kernel memory",
-"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z-o] [slab] [[-P] address]\n"
+"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-m|-z-o] [slab] [[-P] address]\n"
" [-g [flags]]",
" This command displays information about the use of kernel memory.\n",
" -f displays the contents of the system free memory headers.",
@@ -5174,6 +5174,8 @@ char *help_kmem[] = {
" values to translate them into kernel virtual addresses.",
" -g displays the enumerator value of all bits in the page
structure's",
" \"flags\" field.",
+" -m displays the number of pages per migrate type for all
orders, for all",
+" nodes.",
" flags when used with -g, translates all bits in this hexadecimal page",
" structure flags value into its enumerator values.",
" slab when used with -s or -S, limits the command to only the
slab cache",
@@ -5605,6 +5607,24 @@ char *help_kmem[] = {
" PG_slab 7 0000080",
" PG_head 14 0004000",
" %s>",
+"\n Display pages per migrate type for all orders, for all nodes:\n",
+" %s> kmem -m",
+" Free pages count per migrate type at order [0-10]:",
+" Node 0, zone Normal, type Unmovable 155 172 92
39 20 8 10 15 7 3 1",
+" Node 0, zone HighMem, type Unmovable 1 2 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Movable, type Unmovable 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Normal, type Reclaimable 9 3 0
0 1 1 0 0 0 0 0",
+" Node 0, zone HighMem, type Reclaimable 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Movable, type Reclaimable 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Normal, type Movable 7 68 35
253 137 38 16 4 0 0 66",
+" Node 0, zone HighMem, type Movable 0 1 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Movable, type Movable 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Normal, type Reserve 0 0 0
0 0 0 0 0 0 0 1",
+" Node 0, zone HighMem, type Reserve 11 7 5
1 0 0 0 0 0 0 0",
+" Node 0, zone Movable, type Reserve 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Normal, type Isolate 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone HighMem, type Isolate 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Movable, type Isolate 0 0 0
0 0 0 0 0 0 0 0",
NULL
};
diff --git a/crash-6.0.8/memory.c b/crash-6.0.8/memory.c
index 02a6de1..e03db84 100755
--- a/crash-6.0.8/memory.c
+++ b/crash-6.0.8/memory.c
@@ -264,6 +264,7 @@ static int verify_pfn(ulong);
static void dump_per_cpu_offsets(void);
static void dump_page_flags(ulonglong);
static ulong kmem_cache_nodelists(ulong);
+static void dump_pgtype_info(void);
/*
* Memory display modes specific to this file.
@@ -4044,6 +4045,8 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm)
* -c displays the number of pages in the page_hash_table.
* -C displays all entries in the page_hash_table.
* -i displays informational data shown by /proc/meminfo.
+ * -m displays information on the number of pages per migrate type
+ * for all orders, for all nodes.
*
* -P forces address to be defined as a physical address
* address when used with -f, the address can be either a page pointer
@@ -4090,7 +4093,7 @@ cmd_kmem(void)
int i;
int c;
int sflag, Sflag, pflag, fflag, Fflag, vflag, zflag, oflag, gflag;
- int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag;
+ int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag, mflag;
struct meminfo meminfo;
ulonglong value[MAXARGS];
char buf[BUFSIZE];
@@ -4100,12 +4103,12 @@ cmd_kmem(void)
spec_addr = 0;
sflag = Sflag = pflag = fflag = Fflag = Pflag = zflag = oflag = 0;
vflag = Cflag = cflag = iflag = nflag = lflag = Lflag = Vflag = 0;
- gflag = 0;
+ gflag = mflag = 0;
escape = FALSE;
BZERO(&meminfo, sizeof(struct meminfo));
BZERO(&value[0], sizeof(ulonglong)*MAXARGS);
- while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVo")) != EOF) {
+ while ((c = getopt(argcnt, args, "gI:sSFfpvczCinml:L:PVo")) != EOF) {
switch(c)
{
case 'V':
@@ -4206,6 +4209,10 @@ cmd_kmem(void)
gflag = 1;
break;
+ case 'm':
+ mflag = 1;
+ break;
+
default:
argerrs++;
break;
@@ -4215,8 +4222,8 @@ cmd_kmem(void)
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
- if ((sflag + Sflag + pflag + fflag + Fflag + Vflag + oflag +
- vflag + Cflag + cflag + iflag + lflag + Lflag + gflag) > 1) {
+ if ((sflag + Sflag + pflag + fflag + Fflag + Vflag + oflag + vflag +
+ Cflag + cflag + iflag + lflag + Lflag + gflag + mflag) > 1) {
error(INFO, "only one flag allowed!\n");
cmd_usage(pc->curcmd, SYNOPSIS);
}
@@ -4444,9 +4451,12 @@ cmd_kmem(void)
if (gflag == 1)
dump_page_flags(0);
+ if (mflag == 1)
+ dump_pgtype_info();
+
if (!(sflag + Sflag + pflag + fflag + Fflag + vflag +
Vflag + zflag + oflag + cflag + Cflag + iflag +
- nflag + lflag + Lflag + gflag + meminfo.calls))
+ nflag + lflag + Lflag + gflag + mflag + meminfo.calls))
cmd_usage(pc->curcmd, SYNOPSIS);
}
@@ -7051,6 +7061,163 @@ bailout:
return total_free;
}
+static void dump_pgtype_info(void)
+{
+ int n, m, z, o;
+ int list_count = 0;
+ int free_cnt = 0;
+ int mtype_sym = 0;
+ int mtype_len = 0;
+ ulong *mtypes;
+ ulong node_zones;
+ ulong temp;
+ ulong freelist;
+ ulong *free_ptr;
+ char *free_list_buf;
+ char name_buf[BUFSIZE];
+ char buf[BUFSIZE];
+ struct node_table *nt;
+ struct list_data list_data;
+
+ if (!(vt->flags & (NODES|ZONES)))
+ error(FATAL,
+ "dump_pgtype_info called without (NODES|ZONES)\n");
+
+ if (!VALID_STRUCT(zone))
+ error(FATAL,
+ "zone struct not available in this kernel\n");
+
+ if (VALID_STRUCT(free_area)) {
+ if (SIZE(free_area) == (3 * sizeof(ulong)))
+ error(FATAL,
+ "free_area type not supported by command\n");
+ else
+ list_count = MEMBER_SIZE("free_area",
+ "free_list")/SIZE(list_head);
+ } else
+ error(FATAL,
+ "free_area structure not found\n");
+
+ free_list_buf = GETBUF(SIZE(list_head));
+
+ do {
+ if (symbol_exists("migratetype_names") &&
+ (get_symbol_type("migratetype_names",
+ NULL, NULL) == TYPE_CODE_ARRAY)) {
+
+ open_tmpfile();
+ sprintf(buf, "whatis migratetype_names");
+ if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) {
+ close_tmpfile();
+ break;
+ }
+
+ rewind(pc->tmpfile);
+ while (fgets(buf, BUFSIZE, pc->tmpfile)) {
+ if (STRNEQ(buf, "type = "))
+ break;
+ }
+ close_tmpfile();
+
+ if (!strstr(buf, "char *") ||
+ (count_chars(buf, '[') != 1) ||
+ (count_chars(buf, ']') != 1))
+ break;
+
+ mtype_len = get_array_length("migratetype_names",
+ NULL, 0);
+
+ mtypes = (ulong *)GETBUF(mtype_len * sizeof(ulong));
+
+ readmem(symbol_value("migratetype_names"),
+ KVADDR, mtypes,
+ (mtype_len * sizeof(ulong)),
+ NULL, FAULT_ON_ERROR);
+
+ mtype_sym = 1;
+ }
+ } while (0);
+
+ fprintf(fp, "%-43s [%d-%d]:",
+ "Free pages count per migrate type at order",
+ 0, vt->nr_free_areas - 1);
+
+ fprintf(fp, "\n");
+
+ for (n = 0; n < vt->numnodes; n++) {
+ nt = &vt->node_table[n];
+ node_zones = nt->pgdat + OFFSET(pglist_data_node_zones);
+
+ for (m = 0; m < list_count; m++) {
+
+ for (z = 0; z < vt->nr_zones; z++) {
+ readmem((node_zones + (z * SIZE(zone)))
+ + OFFSET(zone_name), KVADDR, &temp,
+ sizeof(void *), "node_zones name",
+ FAULT_ON_ERROR);
+ read_string(temp, name_buf, BUFSIZE-1);
+
+ fprintf(fp, "Node %4d, ", nt->node_id);
+ fprintf(fp, "zone %8s, ", name_buf);
+
+ if (mtype_sym) {
+ read_string(mtypes[m],
+ name_buf, BUFSIZE-1);
+ fprintf(fp, "type %12s ", name_buf);
+ } else
+ fprintf(fp, "type %12d ", m);
+
+ for (o = 0; o < vt->nr_free_areas; o++) {
+ freelist =
+ (node_zones + (z * SIZE(zone)))
+ + (OFFSET(zone_free_area) +
+ (o * SIZE(free_area))) +
+ (m * SIZE(list_head));
+
+ readmem(freelist, KVADDR, free_list_buf,
+ SIZE(list_head),
+ "free_area free_list",
+ FAULT_ON_ERROR);
+
+ free_ptr = (ulong *)free_list_buf;
+
+ if (!(*free_ptr) ||
+ (*free_ptr == freelist)) {
+ fprintf(fp, "%6lu ", 0);
+ continue;
+ }
+
+ BZERO(&list_data,
+ sizeof(struct list_data));
+ list_data.flags = RETURN_ON_DUPLICATE;
+ list_data.start = *free_ptr;
+ list_data.end = freelist;
+ list_data.list_head_offset =
+ OFFSET(page_lru) +
+ OFFSET(list_head_next);
+
+ free_cnt = do_list(&list_data);
+ if (free_cnt < 0) {
+ error(pc->curcmd_flags &
+ IGNORE_ERRORS ? INFO : FATAL,
+ "corrupted free list\n");
+ free_cnt = 0;
+ }
+
+ fprintf(fp, "%6lu ", free_cnt);
+ }
+ fprintf(fp, "\n");
+ }
+ }
+ node_zones + OFFSET(zone_free_area);
+ }
+
+ FREEBUF(free_list_buf);
+
+ if (mtype_sym)
+ FREEBUF(mtypes);
+}
+
/*
* dump_kmeminfo displays basic memory use information typically shown
* by /proc/meminfo, and then some...
--
1.7.6
11 years, 8 months