[Crash-utility] kmem -s issue (gdb can't get offest of struct page lru member)
Dave Anderson
anderson at redhat.com
Mon Jan 9 19:06:39 UTC 2012
----- Original Message -----
> Hello Dave,
>
> When issuing "kmem -s" with crash 6.0.2 (same with 6.0.0) on a s390x
> linux-3.2 kernel dump, I get the following:
>
> ...
> 1ff0a600 signal_cache 1104 112 150 6 32k
> 1ff0a540 sighand_cache 2088 82 98 7 32k
>
> kmem: invalid structure member offset: page_lru
> FILE: memory.c LINE: 15856 FUNCTION: count_partial()
>
> [./crash] error trace: 80099674 => 80097156 => 80083c40 => 801206ba
>
> 801206ba: OFFSET_verify+138
> 80083c40: get_kmem_cache_slub_data+1028
> 80097156: dump_kmem_cache_slub+902
> 80099674: cmd_kmem+6636
>
> kmem: invalid structure member offset: page_lru
> FILE: memory.c LINE: 15856 FUNCTION: count_partial()
>
>
>
> I think the reason is that MEMBER_OFFSET_INIT(page_lru, "page", "lru") fails.
> See the following gdb session:
>
>
> Breakpoint 1, vm_init () at memory.c:375
> 375 MEMBER_OFFSET_INIT(page_lru, "page", "lru");
> (gdb) s
> datatype_info (name=0x80415c4a "page", member=0x803ce36c "lru",
> dm=0x0)
> at symbols.c:4919
> 4919 if (dm == ANON_MEMBER_OFFSET_REQUEST)
> (gdb) n
> 4922 strcpy(buf, name);
> (gdb) n
> 4924 req = (struct gnu_request *)GETBUF(sizeof(struct
> gnu_request));
> (gdb) n
> 4925 req->command = GNU_GET_DATATYPE;
> (gdb) n
> 4926 req->flags |= GNU_RETURN_ON_ERROR;
> (gdb) n
> 4927 req->name = buf;
> (gdb) n
> 4928 req->member = member;
> (gdb) n
> 4929 req->fp = pc->nullfp;
> (gdb) n
> 4931 gdb_interface(req);
> (gdb) n
> 4932 if (req->flags & GNU_COMMAND_FAILED) {
> (gdb) print *req
> $1 = {command = 5, buf = 0x0, fp = 0x8060d540, addr = 0, addr2 = 0,
> count = 0,
> flags = 8, name = 0x3ffffffda94 "page", length = 56, typecode = 3,
> typename = 0x0, target_typename = 0x0, target_length = 0,
> target_typecode = 0, is_typedef = 0, member = 0x803ce36c "lru",
> member_offset = -1, member_length = 0, member_typecode = 0, value =
> 0,
> tagname = 0x0, pc = 0, sp = 0, ra = 0, curframe = 0, frame = 0,
> prevsp = 0,
> prevpc = 0, lastsp = 0, task = 0, debug = 0, hookp = 0x0}
>
> ---> member_offset = -1
>
> (gdb) n
> 4937 if (!req->typecode) {
> (gdb) n
> 4942 if (!req->typecode) {
> (gdb) n
> 4947 member_typecode = TYPE_CODE_UNDEF;
> (gdb) n
> 4948 member_size = 0;
> (gdb) n
> 4949 type_found = 0;
> (gdb) n
> 4951 if (CRASHDEBUG(2)) {
> (gdb) n
> 4965 switch (req->typecode)
> (gdb) n
> 4968 type_found = STRUCT_REQUEST;
> (gdb) n
> 4969 size = req->length;
> (gdb) n
> 4970 if (req->member_offset >= 0) {
> (gdb) n
> 4975 offset = -1;
> (gdb) n
> 4976 member_size = 0;
>
> Also crash can't evaluate the offset of the "lru" member:
>
> crash> struct page
> struct page {
> long unsigned int flags;
> struct address_space *mapping;
> struct {
> union {...};
> union {...};
> };
> union {
> struct list_head lru;
> struct {...};
> };
> union {
> long unsigned int private;
> spinlock_t ptl;
> struct kmem_cache *slab;
> struct page *first_page;
> };
> }
> SIZE: 56
>
> crash> struct page.mapping
> struct page {
> [8] struct address_space *mapping;
> }
>
> crash> struct page.lru
> struct: invalid data structure reference: page.lru
>
> Any idea why we do not get the offset from gdb?
> Perhaps a problem with the anonymous union?
Right -- it's due to commit 49e2258586b423684f03c278149ab46d8f8b6700,
which moved the page.lru field into an anonymous structure:
/* Third double word block */
- struct list_head lru; /* Pageout list, eg. active_list
+ union {
+ struct list_head lru; /* Pageout list, eg. active_list
* protected by zone->lru_lock !
*/
+ struct { /* slub per cpu partial pages */
+ struct page *next; /* Next partial slab */
+#ifdef CONFIG_64BIT
+ int pages; /* Nr of partial slabs left */
+ int pobjects; /* Approximate # of objects */
+#else
+ short int pages;
+ short int pobjects;
+#endif
+ };
+ };
And see https://www.redhat.com/archives/crash-utility/2012-January/msg00023.html
for the gdb-related details.
Can you try a patch like this to vm_init():
MEMBER_OFFSET_INIT(page_lru, "page", "lru");
+ if (INVALID_MEMBER(page_lru))
+ ANON_MEMBER_OFFSET_INIT(page_lru, "page", "lru");
Thanks,
Dave
More information about the Crash-utility
mailing list