----- Original Message ----- > Hello Dave, > > I think it is necessary to see what is hided in the union where > _mapcount lies. However, as you said, it's hard to pick which fields are > more important than others when adding new items to "kmem -p". So I > think over using struct sub-command to show what I want. > > What if I change struct sub-command to this: > > 1. it can refer to anonymous members (e.g., page._mapcount) > 2. it can refer to submembers(e.g., page._count.counter) > 3. it can output easy-parsing format (using an option to specify), maybe > like 'kmem -p'. For example, > crash> struct page.flags,_count.counter -.. < PAGE_list.txt > 1024 0 > 1024 1 > 1024 1 > 1024 1 > > After adding these features to struct sub-command, I guess it is more > easier to get information hiding in structs and parsing it. Before > implementing, I feel the necessity to ask you for some advices. So what > about these features? That would certainly be useful. The problem in getting that to work would be twofold: (1) handling a "member" request that has a "." in it. crash> struct page._count.counter ffffea0000000400 struct: invalid format: page._count.counter crash> (2) getting a successful return value from the call to arg_to_datatype() in cmd_datatype_common(). crash> struct page.private ffffea0000000400 struct: invalid data structure reference: page.private crash> And both of the above would require getting the get_member_data() function in gdb-7.3.1/gdb/symtab.c to dig out the information for anonymous members, which it currently does not do. In this part of get_member_data(), the requested member name string is searched for: for (i = 0; i < nfields; i++) { if (STREQ(req->member, nextfield->name)) { req->member_offset = nextfield->loc.bitpos; req->member_length = TYPE_LENGTH(nextfield->type); req->member_typecode = TYPE_CODE(nextfield->type); if ((req->member_typecode == TYPE_CODE_TYPEDEF) && (typedef_type = check_typedef(nextfield->type))) req->member_length = TYPE_LENGTH(typedef_type); return; } nextfield++; } When get_member_data() walks through the page stucture, it does find the anonymous members above, but nextfield->name points to a NULL name string. That seems to be related to gdb's behavior when asking it to simply print a page structure, which is requested with a "ptype struct page" gdb command: crash> struct page struct page { long unsigned int flags; struct address_space *mapping; struct { union {...}; union {...}; }; struct list_head lru; union { long unsigned int private; spinlock_t ptl; struct kmem_cache *slab; struct page *first_page; }; } SIZE: 64 crash> I don't know how to get gdb to display the "full" structure declaration? Anyway, when given an internal request to display a page structure from memory, it does display them: crash> page ffffea0000000400 struct page { flags = 0, mapping = 0x0, { { index = 18446612132314288112, freelist = 0xffff880000010ff0 }, { counters = 4294967168, { { _mapcount = { counter = -128 }, { inuse = 65408, objects = 32767, frozen = 1 } }, _count = { counter = 0 } } } }, lru = { next = 0xffffea00000042a0, prev = 0xffffea00000005a0 }, { private = 1, ptl = { { rlock = { raw_lock = { slock = 1 } } } }, slab = 0x1, first_page = 0x1 } } crash> And because that works OK, the ANON_MEMBER_OFFSET_REQUEST() macro exists to handle cases for required offset_table entries. Here, if I put a debug printf each time though the member loop in get_member_data(), you'll see this: crash> page.slab ffffea0000000400 page -> flags page -> mapping page -> page -> lru page -> struct: invalid data structure reference: page.slab crash> which again, reflects what happens when a page struct is printed: crash> struct page struct page { long unsigned int flags; struct address_space *mapping; struct { union {...}; union {...}; }; struct list_head lru; union { long unsigned int private; spinlock_t ptl; struct kmem_cache *slab; struct page *first_page; }; } SIZE: 64 crash> So, anyway, I would presume that perhaps something could be applied to get_member_data() to and check out the fields with NULL name strings, i.e.: for (i = 0; i < nfields; i++) { if (STREQ(req->member, nextfield->name)) { req->member_offset = nextfield->loc.bitpos; req->member_length = TYPE_LENGTH(nextfield->type); req->member_typecode = TYPE_CODE(nextfield->type); if ((req->member_typecode == TYPE_CODE_TYPEDEF) && (typedef_type = check_typedef(nextfield->type))) req->member_length = TYPE_LENGTH(typedef_type); return; } + if (strlen(nextfield->name) == 0) { + ... + } nextfield++; } And that section would have to somehow deal with members that are part of anonymous struct members (like "private"), as well as with anonymous members that are expressed with a "." in them (like "_mapcount.counter). I don't expect it will be very easy to accomplish. But it would be a desirable capability, so please be my guest! Thanks, Dave > At 2012-1-6 3:37, Dave Anderson wrote: > > I appreciate the effort, but I'm not sure whether it's worth changing > > it at this point, or whether it could be accomplished in a different > > manner. > > > > The primary purpose for "kmem -p" is to show the page structure > > address associated with each physical address in the system -- along > > with "basic information about each page". It's had those basic > > fields in it forever -- which BTW, fit into 80 columns. I prefer not > > to have command output exceed 80 columns unless it is impossible to > > predict the size of an output field. > > > > Anyway, the page structure definition keeps changing over time, more > > specifically the embedded anonymous structures contained within it, and > > the fields within the anonymous structs have multiple meanings. With > > your patch, the output becomes cluttered and hard to understand, especially > > due to the strange values that can be seen in the MCNT column when it's > > not a counter value, but rather a slab-page construct: > > > > union { > > atomic_t _mapcount; > > > > struct { > > unsigned inuse:16; > > unsigned objects:15; > > unsigned frozen:1; > > }; > > }; > > > > And so it's hard to pick which fields are more important than > > others, > > because it pretty much depends upon what's being debugged. You > > have > > picked the private field (which can have numerous meanings), but > > for > > example, there have been times in the past where I wanted to see > > the > > lru list_head contents. > > > > That all being said, your patch does have merit, but I wonder if > > there > > could be an alternate way of selecting or filtering what fields are > > displayed? > > > -- > -- > Regards > Qiao Nuohan > > -- > Crash-utility mailing list > Crash-utility@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/crash-utility > -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility