----- 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(a)redhat.com
 
https://www.redhat.com/mailman/listinfo/crash-utility