--- crash-4.0-4.7/memory.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/memory.c 2007-10-30 08:56:51.000000000 -0500 @@ -35,11 +35,14 @@ ulong order; ulong slabsize; ulong num_slabs; + ulong objects; ulonglong spec_addr; ulong flags; ulong size; + ulong objsize; int memtype; int free; + int slab_offset; char *reqname; char *curname; ulong *addrlist; @@ -53,12 +56,14 @@ int errors; int calls; int cpu; + int cache_count; ulong get_shared; ulong get_totalram; ulong get_buffers; ulong get_slabs; char *slab_buf; char *cache_buf; + ulong *cache_list; struct vmlist { ulong addr; ulong size; @@ -79,20 +84,26 @@ static void dump_page_hash_table(struct meminfo *); static void kmem_search(struct meminfo *); static void kmem_cache_init(void); +static void kmem_cache_init_slub(void); static ulong max_cpudata_limit(ulong, ulong *); static int ignore_cache(struct meminfo *, char *); static char *is_kmem_cache_addr(ulong, char *); +static char *is_kmem_cache_addr_slub(ulong, char *); static void kmem_cache_list(void); static void dump_kmem_cache(struct meminfo *); static void dump_kmem_cache_percpu_v1(struct meminfo *); static void dump_kmem_cache_percpu_v2(struct meminfo *); +static void dump_kmem_cache_slub(struct meminfo *); static void dump_kmem_cache_info_v2(struct meminfo *); +static void kmem_cache_list_slub(void); static char *vaddr_to_kmem_cache(ulong, char *); static ulong vaddr_to_slab(ulong); static void do_slab_chain(int, struct meminfo *); static void do_slab_chain_percpu_v1(long, struct meminfo *); static void do_slab_chain_percpu_v2(long, struct meminfo *); static void do_slab_chain_percpu_v2_nodes(long, struct meminfo *); +static void do_slab_slub(struct meminfo *, int); +static void do_kmem_cache_slub(struct meminfo *); static void save_slab_data(struct meminfo *); static int slab_data_saved(struct meminfo *); static void dump_saved_slab_data(void); @@ -155,6 +166,14 @@ static int dump_vm_stat(char *, long *); static int generic_read_dumpfile(ulonglong, void *, long, char *, ulong); static int generic_write_dumpfile(ulonglong, void *, long, char *, ulong); +static int page_to_nid(ulong); +static int get_kmem_cache_list(ulong **); +static int get_kmem_cache_slub_data(long, struct meminfo *); +static ulong compound_head(ulong); +static long count_partial(ulong); +static ulong get_freepointer(struct meminfo *, void *); +char *is_slab_page(struct meminfo *, char *); +static void do_node_lists_slub(struct meminfo *, ulong, int); /* * Memory display modes specific to this file. @@ -411,6 +430,42 @@ } else if (MEMBER_EXISTS("kmem_cache", "cpu_slab") && STRUCT_EXISTS("kmem_cache_node")) { vt->flags |= KMALLOC_SLUB; + + STRUCT_SIZE_INIT(kmem_cache, "kmem_cache"); + MEMBER_OFFSET_INIT(kmem_cache_size, "kmem_cache", "size"); + MEMBER_OFFSET_INIT(kmem_cache_objsize, "kmem_cache", "objsize"); + MEMBER_OFFSET_INIT(kmem_cache_offset, "kmem_cache", "offset"); + MEMBER_OFFSET_INIT(kmem_cache_order, "kmem_cache", "order"); + MEMBER_OFFSET_INIT(kmem_cache_local_node, "kmem_cache", "local_node"); + MEMBER_OFFSET_INIT(kmem_cache_objects, "kmem_cache", "objects"); + MEMBER_OFFSET_INIT(kmem_cache_inuse, "kmem_cache", "inuse"); + MEMBER_OFFSET_INIT(kmem_cache_align, "kmem_cache", "align"); + MEMBER_OFFSET_INIT(kmem_cache_node, "kmem_cache", "node"); + MEMBER_OFFSET_INIT(kmem_cache_cpu_slab, "kmem_cache", "cpu_slab"); + MEMBER_OFFSET_INIT(kmem_cache_list, "kmem_cache", "list"); + MEMBER_OFFSET_INIT(kmem_cache_name, "kmem_cache", "name"); + ANON_MEMBER_OFFSET_INIT(page_inuse, "page", "inuse"); + ANON_MEMBER_OFFSET_INIT(page_offset, "page", "offset"); + ANON_MEMBER_OFFSET_INIT(page_lockless_freelist, "page", + "lockless_freelist"); + ANON_MEMBER_OFFSET_INIT(page_slab, "page", "slab"); + ANON_MEMBER_OFFSET_INIT(page_first_page, "page", "first_page"); + ANON_MEMBER_OFFSET_INIT(page_freelist, "page", "freelist"); + if (VALID_MEMBER(kmem_cache_node)) { + ARRAY_LENGTH_INIT(len, NULL, "kmem_cache.node", NULL, 0); + vt->flags |= CONFIG_NUMA; + } + ARRAY_LENGTH_INIT(len, NULL, "kmem_cache.cpu_slab", NULL, 0); + + STRUCT_SIZE_INIT(kmem_cache_node, "kmem_cache_node"); + MEMBER_OFFSET_INIT(kmem_cache_node_nr_partial, + "kmem_cache_node", "nr_partial"); + MEMBER_OFFSET_INIT(kmem_cache_node_nr_slabs, + "kmem_cache_node", "nr_slabs"); + MEMBER_OFFSET_INIT(kmem_cache_node_partial, + "kmem_cache_node", "partial"); + MEMBER_OFFSET_INIT(kmem_cache_node_full, + "kmem_cache_node", "full"); } else { MEMBER_OFFSET_INIT(kmem_cache_s_c_nextp, "kmem_cache_s", "c_nextp"); @@ -450,9 +505,12 @@ } if (!kt->kernel_NR_CPUS) { - kt->kernel_NR_CPUS = ARRAY_LENGTH(kmem_cache_s_cpudata) ? - ARRAY_LENGTH(kmem_cache_s_cpudata) : - ARRAY_LENGTH(kmem_cache_s_array); + if (ARRAY_LENGTH(kmem_cache_s_cpudata)) + kt->kernel_NR_CPUS = ARRAY_LENGTH(kmem_cache_s_cpudata); + else if (ARRAY_LENGTH(kmem_cache_s_array)) + kt->kernel_NR_CPUS = ARRAY_LENGTH(kmem_cache_s_array); + else if (ARRAY_LENGTH(kmem_cache_cpu_slab)) + kt->kernel_NR_CPUS = ARRAY_LENGTH(kmem_cache_cpu_slab); } if (kt->kernel_NR_CPUS > NR_CPUS) { @@ -710,7 +768,7 @@ else if (vt->flags & PERCPU_KMALLOC_V2) vt->dump_kmem_cache = dump_kmem_cache_percpu_v2; else if (vt->flags & KMALLOC_SLUB) - vt->flags |= KMEM_CACHE_UNAVAIL; /* TBD */ + vt->dump_kmem_cache = dump_kmem_cache_slub; else vt->dump_kmem_cache = dump_kmem_cache; @@ -3321,6 +3379,8 @@ #define GET_VMLIST_COUNT (ADDRESS_SPECIFIED << 16) #define GET_VMLIST (ADDRESS_SPECIFIED << 17) #define SLAB_DATA_NOSAVE (ADDRESS_SPECIFIED << 18) +#define GET_SLUB_SLABS (ADDRESS_SPECIFIED << 19) +#define GET_SLUB_OBJECTS (ADDRESS_SPECIFIED << 20) #define GET_ALL \ (GET_SHARED_PAGES|GET_TOTALRAM_PAGES|GET_BUFFERS_PAGES|GET_SLAB_PAGES) @@ -3521,6 +3581,8 @@ } else { meminfo.spec_addr = value[i]; meminfo.flags = ADDRESS_SPECIFIED; + if (Sflag && (vt->flags & KMALLOC_SLUB)) + meminfo.flags |= VERBOSE; if (meminfo.calls++) fprintf(fp, "\n"); vt->dump_kmem_cache(&meminfo); @@ -3594,24 +3656,25 @@ } if (sflag == 1) { - if (vt->flags & KMEM_CACHE_UNAVAIL) - error(FATAL, - "kmem cache slab subsystem not available\n"); if (STREQ(meminfo.reqname, "list")) kmem_cache_list(); + else if (vt->flags & KMEM_CACHE_UNAVAIL) + error(FATAL, + "kmem cache slab subsystem not available\n"); else vt->dump_kmem_cache(&meminfo); } if (Sflag == 1) { - if (vt->flags & KMEM_CACHE_UNAVAIL) - error(FATAL, - "kmem cache slab subsystem not available\n"); - meminfo.flags = VERBOSE; if (STREQ(meminfo.reqname, "list")) kmem_cache_list(); - else + else if (vt->flags & KMEM_CACHE_UNAVAIL) + error(FATAL, + "kmem cache slab subsystem not available\n"); + else { + meminfo.flags = VERBOSE; vt->dump_kmem_cache(&meminfo); + } } if (vflag == 1) @@ -3700,6 +3763,20 @@ } else if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) vt->PG_slab = 7; + if (vt->flags & KMALLOC_SLUB) { + /* + * PG_slab and the following are hardwired for + * now -- at least until I can come up with + * better way. (PG_slab test below fails because + * slub.c uses lower-bit PG_active and PG_error) + */ +#define PG_compound 14 /* Part of a compound page */ +#define PG_reclaim 17 /* To be reclaimed asap */ + vt->PG_head_tail_mask = ((1L << PG_compound) | (1L << PG_reclaim)); + + return; + } + if (try_get_symbol_data("vm_area_cachep", sizeof(void *), &vaddr) && phys_to_page((physaddr_t)VTOP(vaddr), &pageptr) && readmem(pageptr, KVADDR, buf, SIZE(page), @@ -5741,7 +5818,7 @@ continue; } - if ((i == 0) && (vt->flags & NODES)) { + if ((i == 0) && ((vt->flags & NODES) || (vt->numnodes > 1))) { if (n) { fprintf(fp, "\n"); pad_line(fp, @@ -6182,6 +6259,11 @@ if (vm_stat_init()) { if (dump_vm_stat("NR_SLAB", &nr_slab)) get_slabs = nr_slab; + else if (dump_vm_stat("NR_SLAB_RECLAIMABLE", &nr_slab)) { + get_slabs = nr_slab; + if (dump_vm_stat("NR_SLAB_UNRECLAIMABLE", &nr_slab)) + get_slabs += nr_slab; + } } fprintf(fp, kmeminfo_hdr); @@ -6808,6 +6890,9 @@ return NULL; } + if (vt->flags & KMALLOC_SLUB) + return is_kmem_cache_addr_slub(vaddr, kbuf); + name_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ? OFFSET(kmem_cache_s_name) : OFFSET(kmem_cache_s_c_name); next_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ? @@ -6871,6 +6956,11 @@ return; } + if (vt->flags & KMALLOC_SLUB) { + kmem_cache_list_slub(); + return; + } + name_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ? OFFSET(kmem_cache_s_name) : OFFSET(kmem_cache_s_c_name); next_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ? @@ -6939,7 +7029,11 @@ return NULL; } - if (VALID_MEMBER(page_next)) + if (vt->flags & KMALLOC_SLUB) { + readmem(compound_head(page)+OFFSET(page_slab), + KVADDR, &cache, sizeof(void *), + "page.slab", FAULT_ON_ERROR); + } else if (VALID_MEMBER(page_next)) readmem(page+OFFSET(page_next), KVADDR, &cache, sizeof(void *), "page.next", FAULT_ON_ERROR); @@ -6984,7 +7078,9 @@ slab = 0; - if (VALID_MEMBER(page_prev)) + if (vt->flags & KMALLOC_SLUB) + slab = compound_head(page); + else if (VALID_MEMBER(page_prev)) readmem(page+OFFSET(page_prev), KVADDR, &slab, sizeof(void *), "page.prev", FAULT_ON_ERROR); @@ -7007,9 +7103,9 @@ * Initialize any data required for scouring the kmalloc subsystem more * efficiently. */ -char slab_hdr[BUFSIZE] = { 0 }; -char kmem_cache_hdr[BUFSIZE] = { 0 }; -char free_inuse_hdr[BUFSIZE] = { 0 }; +char slab_hdr[100] = { 0 }; +char kmem_cache_hdr[100] = { 0 }; +char free_inuse_hdr[100] = { 0 }; static void kmem_cache_init(void) @@ -7029,11 +7125,18 @@ please_wait("gathering kmem slab cache data"); - if (!strlen(slab_hdr)) - sprintf(slab_hdr, - "SLAB%sMEMORY%sTOTAL ALLOCATED FREE\n", - space(VADDR_PRLEN > 8 ? 14 : 6), - space(VADDR_PRLEN > 8 ? 12 : 4)); + if (!strlen(slab_hdr)) { + if (vt->flags & KMALLOC_SLUB) + sprintf(slab_hdr, + "SLAB%sMEMORY%sNODE TOTAL ALLOCATED FREE\n", + space(VADDR_PRLEN > 8 ? 14 : 6), + space(VADDR_PRLEN > 8 ? 12 : 4)); + else + sprintf(slab_hdr, + "SLAB%sMEMORY%sTOTAL ALLOCATED FREE\n", + space(VADDR_PRLEN > 8 ? 14 : 6), + space(VADDR_PRLEN > 8 ? 12 : 4)); + } if (!strlen(kmem_cache_hdr)) sprintf(kmem_cache_hdr, @@ -7043,6 +7146,11 @@ if (!strlen(free_inuse_hdr)) sprintf(free_inuse_hdr, "FREE / [ALLOCATED]\n"); + if (vt->flags & KMALLOC_SLUB) { + kmem_cache_init_slub(); + return; + } + num_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ? OFFSET(kmem_cache_s_num) : OFFSET(kmem_cache_s_c_num); next_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ? @@ -10027,6 +10135,14 @@ vt->dump_kmem_cache(&tmp_meminfo); fprintf(fp, "\n"); } + if ((vaddr != BADADDR) && is_slab_page(mi, buf)) { + BZERO(&tmp_meminfo, sizeof(struct meminfo)); + tmp_meminfo.spec_addr = vaddr; + tmp_meminfo.memtype = KVADDR; + tmp_meminfo.flags = mi->flags; + vt->dump_kmem_cache(&tmp_meminfo); + fprintf(fp, "\n"); + } /* * Check free list. @@ -10309,6 +10425,8 @@ fprintf(fp, "%sVM_STAT", others++ ? "|" : "");\ if (vt->flags & KMALLOC_SLUB) fprintf(fp, "%sKMALLOC_SLUB", others++ ? "|" : "");\ + if (vt->flags & CONFIG_NUMA) + fprintf(fp, "%sCONFIG_NUMA", others++ ? "|" : "");\ fprintf(fp, ")\n"); if (vt->kernel_pgd[0] == vt->kernel_pgd[1]) @@ -10340,7 +10458,9 @@ fprintf(fp, " kmem_cache_namelen: %d\n", vt->kmem_cache_namelen); fprintf(fp, "kmem_cache_nodelist_len: %ld\n", vt->kmem_cache_len_nodes); fprintf(fp, " PG_reserved: %lx\n", vt->PG_reserved); - fprintf(fp, " PG_slab: %ld\n", vt->PG_slab); + fprintf(fp, " PG_slab: %ld (%lx)\n", vt->PG_slab, + (ulong)1 << vt->PG_slab); + fprintf(fp, " PG_head_tail_mask: %lx\n", vt->PG_head_tail_mask); fprintf(fp, " paddr_prlen: %d\n", vt->paddr_prlen); fprintf(fp, " numnodes: %d\n", vt->numnodes); fprintf(fp, " nr_zones: %d\n", vt->nr_zones); @@ -10376,6 +10496,8 @@ fprintf(fp, "dump_kmem_cache_percpu_v1()\n"); else if (vt->dump_kmem_cache == dump_kmem_cache_percpu_v2) fprintf(fp, "dump_kmem_cache_percpu_v2()\n"); + else if (vt->dump_kmem_cache == dump_kmem_cache_slub) + fprintf(fp, "dump_kmem_cache_slub()\n"); else fprintf(fp, "%lx (unknown)\n", (ulong)vt->dump_kmem_cache); fprintf(fp, " slab_data: %lx\n", (ulong)vt->slab_data); @@ -10385,6 +10507,7 @@ fprintf(fp, " last_swap_read: %lx\n", vt->last_swap_read); fprintf(fp, " swap_info_struct: %lx\n", (ulong)vt->swap_info_struct); fprintf(fp, " mem_sec: %lx\n", (ulong)vt->mem_sec); + fprintf(fp, " mem_section: %lx\n", (ulong)vt->mem_section); fprintf(fp, " ZONE_HIGHMEM: %d\n", vt->ZONE_HIGHMEM); fprintf(fp, "node_online_map_len: %d\n", vt->node_online_map_len); if (vt->node_online_map_len) { @@ -11914,22 +12037,22 @@ int l1_cache_size(void) { - ulong cache_cache; + ulong cache; ulong c_align; int colour_off; int retval; - cache_cache = symbol_value("cache_cache"); - retval = -1; if (VALID_MEMBER(kmem_cache_s_c_align)) { - readmem(cache_cache+OFFSET(kmem_cache_s_c_align), + cache = symbol_value("cache_cache"); + readmem(cache+OFFSET(kmem_cache_s_c_align), KVADDR, &c_align, sizeof(ulong), "c_align", FAULT_ON_ERROR); retval = (int)c_align; } else if (VALID_MEMBER(kmem_cache_s_colour_off)) { - readmem(cache_cache+OFFSET(kmem_cache_s_colour_off), + cache = symbol_value("cache_cache"); + readmem(cache+OFFSET(kmem_cache_s_colour_off), KVADDR, &colour_off, sizeof(int), "colour_off", FAULT_ON_ERROR); retval = colour_off; @@ -12071,30 +12194,26 @@ fprintf(fp, "PAGES_PER_SECTION = %ld\n", PAGES_PER_SECTION()); } - if (!(vt->mem_sec = malloc(mem_section_size))) + if (!(vt->mem_sec = (void *)malloc(mem_section_size))) error(FATAL, "cannot malloc mem_sec cache\n"); + if (!(vt->mem_section = (char *)malloc(SIZE(mem_section)))) + error(FATAL, "cannot malloc mem_section cache\n"); addr = symbol_value("mem_section"); readmem(addr, KVADDR,vt->mem_sec ,mem_section_size, "memory section root table", FAULT_ON_ERROR); } -char -*read_mem_section(ulong addr) +char * +read_mem_section(ulong addr) { - static char *mem_section; - - if (!mem_section) { - mem_section = GETBUF(SIZE(mem_section)); - } - if (!IS_KVADDR(addr)) return 0; - readmem(addr, KVADDR, mem_section, SIZE(mem_section), + readmem(addr, KVADDR, vt->mem_section, SIZE(mem_section), "memory section", FAULT_ON_ERROR); - return mem_section; + return vt->mem_section; } ulong @@ -12568,7 +12687,7 @@ if (!item) { vp = (ulong *)buf; for (i = 0; i < vt->nr_vm_stat_items; i++) - fprintf(fp, "%20s: %ld\n", vt->vm_stat_items[i], vp[i]); + fprintf(fp, "%21s: %ld\n", vt->vm_stat_items[i], vp[i]); return TRUE; } @@ -12582,3 +12701,765 @@ return FALSE; } + +/* + * Support for slub.c slab cache. + */ +static void +kmem_cache_init_slub(void) +{ + vt->flags |= KMEM_CACHE_INIT; +} + +static void +kmem_cache_list_slub(void) +{ + int i, cnt; + ulong *cache_list; + ulong name; + char *cache_buf; + char buf[BUFSIZE]; + + cnt = get_kmem_cache_list(&cache_list); + cache_buf = GETBUF(SIZE(kmem_cache)); + + for (i = 0; i < cnt; i++) { + fprintf(fp, "%lx ", cache_list[i]); + + readmem(cache_list[i], KVADDR, cache_buf, + SIZE(kmem_cache), "kmem_cache buffer", + FAULT_ON_ERROR); + + name = ULONG(cache_buf + OFFSET(kmem_cache_name)); + if (!read_string(name, buf, BUFSIZE-1)) + sprintf(buf, "(unknown)\n"); + + fprintf(fp, "%s\n", buf); + } + + FREEBUF(cache_list); + FREEBUF(cache_buf); +} + +#define DUMP_KMEM_CACHE_INFO_SLUB() dump_kmem_cache_info_slub(si) + +static void +dump_kmem_cache_info_slub(struct meminfo *si) +{ + char b1[BUFSIZE]; + char b2[BUFSIZE]; + int namelen, sizelen, spacelen; + + fprintf(fp, "%s ", + mkstring(b1, VADDR_PRLEN, LJUST|LONG_HEX, MKSTR(si->cache))); + + namelen = strlen(si->curname); + sprintf(b2, "%ld", si->objsize); + sizelen = strlen(b2); + spacelen = 0; + + if (namelen++ > 18) { + spacelen = 29 - namelen - sizelen; + fprintf(fp, "%s%s%ld ", si->curname, + space(spacelen <= 0 ? 1 : spacelen), si->objsize); + if (spacelen > 0) + spacelen = 1; + sprintf(b1, "%c%dld ", '%', 9 + spacelen - 1); + } else { + fprintf(fp, "%-18s %8ld ", si->curname, si->objsize); + sprintf(b1, "%c%dld ", '%', 9); + } + + fprintf(fp, b1, si->inuse); + + fprintf(fp, "%8ld %5ld %4ldk\n", + si->num_slabs * si->objects, + si->num_slabs, si->slabsize/1024); +} + +static void +dump_kmem_cache_slub(struct meminfo *si) +{ + int i; + ulong name; + unsigned int size, objsize, objects, order, offset; + char *reqname, *p1; + char kbuf[BUFSIZE]; + char buf[BUFSIZE]; + + si->cache_count = get_kmem_cache_list(&si->cache_list); + si->cache_buf = GETBUF(SIZE(kmem_cache)); + + if (!si->reqname && + !(si->flags & (ADDRESS_SPECIFIED|GET_SLAB_PAGES))) + fprintf(fp, kmem_cache_hdr); + + if (si->flags & ADDRESS_SPECIFIED) { + if ((p1 = is_slab_page(si, kbuf))) { + si->flags |= VERBOSE; + si->slab = (ulong)si->spec_addr; + } else if (!(p1 = vaddr_to_kmem_cache(si->spec_addr, kbuf))) { + error(INFO, + "address is not allocated in slab subsystem: %lx\n", + si->spec_addr); + goto bailout; + } + + if (si->reqname && (si->reqname != p1)) + error(INFO, + "ignoring pre-selected %s cache for address: %lx\n", + si->reqname, si->spec_addr, si->reqname); + reqname = p1; + } else + reqname = si->reqname; + + for (i = 0; i < si->cache_count; i++) { + if (!readmem(si->cache_list[i], KVADDR, si->cache_buf, + SIZE(kmem_cache), "kmem_cache buffer", RETURN_ON_ERROR)) + goto next_cache; + + name = ULONG(si->cache_buf + OFFSET(kmem_cache_name)); + if (!read_string(name, buf, BUFSIZE-1)) + sprintf(buf, "(unknown)"); + if (reqname) { + if (!STREQ(reqname, buf)) + continue; + fprintf(fp, kmem_cache_hdr); + } + objsize = UINT(si->cache_buf + OFFSET(kmem_cache_objsize)); + size = UINT(si->cache_buf + OFFSET(kmem_cache_size)); + objects = UINT(si->cache_buf + OFFSET(kmem_cache_objects)); + order = UINT(si->cache_buf + OFFSET(kmem_cache_order)); + offset = UINT(si->cache_buf + OFFSET(kmem_cache_offset)); + + si->cache = si->cache_list[i]; + si->curname = buf; + si->objsize = objsize; + si->size = size; + si->objects = objects; + si->slabsize = (PAGESIZE() << order); + si->inuse = si->num_slabs = 0; + si->slab_offset = offset; + if (!get_kmem_cache_slub_data(GET_SLUB_SLABS, si) || + !get_kmem_cache_slub_data(GET_SLUB_OBJECTS, si)) + goto next_cache; + + DUMP_KMEM_CACHE_INFO_SLUB(); + + if (si->flags & ADDRESS_SPECIFIED) { + if (!si->slab) + si->slab = vaddr_to_slab(si->spec_addr); + do_slab_slub(si, VERBOSE); + } else if (si->flags & VERBOSE) { + do_kmem_cache_slub(si); + if (!reqname && ((i+1) < si->cache_count)) + fprintf(fp, kmem_cache_hdr); + } + +next_cache: + if (reqname) + break; + } + +bailout: + FREEBUF(si->cache_list); + FREEBUF(si->cache_buf); +} + +/* + * Emulate the total count calculation done by the + * slab_objects() sysfs function in slub.c. + */ +static int +get_kmem_cache_slub_data(long cmd, struct meminfo *si) +{ + int i, n, node; + ulong total_objects, total_slabs; + ulong cpu_slab_ptr, node_ptr; + ulong node_nr_partial, node_nr_slabs; + int full_slabs, objects; + long p; + short inuse; + ulong *nodes, *per_cpu; + + /* + * nodes[n] is not being used (for now) + * per_cpu[n] is a count of cpu_slab pages per node. + */ + nodes = (ulong *)GETBUF(2 * sizeof(ulong) * vt->numnodes); + per_cpu = nodes + vt->numnodes; + + total_slabs = total_objects = 0; + + for (i = 0; i < kt->cpus; i++) { + cpu_slab_ptr = ULONG(si->cache_buf + + OFFSET(kmem_cache_cpu_slab) + (sizeof(void *)*i)); + if (!cpu_slab_ptr) + continue; + + if ((node = page_to_nid(cpu_slab_ptr)) < 0) + goto bailout; + + switch (cmd) + { + case GET_SLUB_OBJECTS: + if (!readmem(cpu_slab_ptr + OFFSET(page_inuse), + KVADDR, &inuse, sizeof(short), + "page inuse", RETURN_ON_ERROR)) + return FALSE; + total_objects += inuse; + break; + + case GET_SLUB_SLABS: + total_slabs++; + break; + } + per_cpu[node]++; + } + + for (n = 0; n < vt->numnodes; n++) { + if (vt->flags & CONFIG_NUMA) + node_ptr = ULONG(si->cache_buf + + OFFSET(kmem_cache_node) + + (sizeof(void *)*n)); + else + node_ptr = si->cache + + OFFSET(kmem_cache_local_node); + + if (!readmem(node_ptr + OFFSET(kmem_cache_node_nr_partial), + KVADDR, &node_nr_partial, sizeof(ulong), + "kmem_cache_node nr_partial", RETURN_ON_ERROR)) + goto bailout; + if (!readmem(node_ptr + OFFSET(kmem_cache_node_nr_slabs), + KVADDR, &node_nr_slabs, sizeof(ulong), + "kmem_cache_node nr_slabs", RETURN_ON_ERROR)) + goto bailout; + + switch (cmd) + { + case GET_SLUB_OBJECTS: + if ((p = count_partial(node_ptr)) < 0) + return FALSE; + total_objects += p; + break; + + case GET_SLUB_SLABS: + total_slabs += node_nr_partial; + break; + } + + full_slabs = node_nr_slabs - per_cpu[n] - node_nr_partial; + objects = INT(si->cache_buf + OFFSET(kmem_cache_objects)); + + switch (cmd) + { + case GET_SLUB_OBJECTS: + total_objects += (full_slabs * objects); + break; + + case GET_SLUB_SLABS: + total_slabs += full_slabs; + break; + } + } + + switch (cmd) + { + case GET_SLUB_OBJECTS: + si->inuse = total_objects; + break; + + case GET_SLUB_SLABS: + si->num_slabs = total_slabs; + break; + } + + FREEBUF(nodes); + return TRUE; + +bailout: + FREEBUF(nodes); + return FALSE; +} + + +static void +do_kmem_cache_slub(struct meminfo *si) +{ + int i, n; + ulong cpu_slab_ptr, node_ptr; + ulong node_nr_partial, node_nr_slabs; + ulong *per_cpu; + + per_cpu = (ulong *)GETBUF(sizeof(ulong) * vt->numnodes); + + for (i = 0; i < kt->cpus; i++) { + cpu_slab_ptr = ULONG(si->cache_buf + + OFFSET(kmem_cache_cpu_slab) + (sizeof(void *)*i)); + + fprintf(fp, "CPU %d SLAB:\n%s", i, + cpu_slab_ptr ? "" : " (empty)\n"); + + if (!cpu_slab_ptr) + continue; + + if ((n = page_to_nid(cpu_slab_ptr)) >= 0) + per_cpu[n]++; + + si->slab = cpu_slab_ptr; + do_slab_slub(si, VERBOSE); + + if (received_SIGINT()) + restart(0); + } + + for (n = 0; n < vt->numnodes; n++) { + if (vt->flags & CONFIG_NUMA) + node_ptr = ULONG(si->cache_buf + + OFFSET(kmem_cache_node) + + (sizeof(void *)*n)); + else + node_ptr = si->cache + + OFFSET(kmem_cache_local_node); + + if (!readmem(node_ptr + OFFSET(kmem_cache_node_nr_partial), + KVADDR, &node_nr_partial, sizeof(ulong), + "kmem_cache_node nr_partial", RETURN_ON_ERROR)) + break; + if (!readmem(node_ptr + OFFSET(kmem_cache_node_nr_slabs), + KVADDR, &node_nr_slabs, sizeof(ulong), + "kmem_cache_node nr_slabs", RETURN_ON_ERROR)) + break; + + fprintf(fp, "KMEM_CACHE_NODE NODE SLABS PARTIAL PER-CPU\n"); + + fprintf(fp, "%lx%s", node_ptr, space(VADDR_PRLEN > 8 ? 2 : 10)); + fprintf(fp, "%4d %5ld %7ld %7ld\n", + n, node_nr_slabs, node_nr_partial, per_cpu[n]); + + do_node_lists_slub(si, node_ptr, n); + } + + fprintf(fp, "\n"); + + FREEBUF(per_cpu); +} + +#define DUMP_SLAB_INFO_SLUB() \ + { \ + char b1[BUFSIZE], b2[BUFSIZE]; \ + fprintf(fp, " %s %s %4d %5ld %9d %4ld\n", \ + mkstring(b1, VADDR_PRLEN, LJUST|LONG_HEX, MKSTR(si->slab)), \ + mkstring(b2, VADDR_PRLEN, LJUST|LONG_HEX, MKSTR(vaddr)), \ + node, si->objects, inuse, si->objects - inuse); \ + } + +static void +do_slab_slub(struct meminfo *si, int verbose) +{ + physaddr_t paddr; + ulong vaddr; + ushort inuse; + ulong freelist, lockless_freelist, cpu_slab_ptr; + int i, cpu_slab, is_free, node; + ulong p, q; + + if (!si->slab) { + if (CRASHDEBUG(1)) + error(INFO, "-S option not supported for CONFIG_SLUB\n"); + return; + } + + if (!page_to_phys(si->slab, &paddr)) { + error(WARNING, + "%lx: cannot tranlate slab page to physical address\n", + si->slab); + return; + } + node = page_to_nid(si->slab); + + vaddr = PTOV(paddr); + + if (verbose) + fprintf(fp, " %s", slab_hdr); + + if (!readmem(si->slab + OFFSET(page_inuse), KVADDR, &inuse, + sizeof(ushort), "page.inuse", RETURN_ON_ERROR)) + return; + if (!readmem(si->slab + OFFSET(page_freelist), KVADDR, &freelist, + sizeof(void *), "page.freelist", RETURN_ON_ERROR)) + return; + if (!readmem(si->slab + OFFSET(page_lockless_freelist), KVADDR, + &lockless_freelist, sizeof(void *), "page.lockless_freelist", + RETURN_ON_ERROR)) + return; + + DUMP_SLAB_INFO_SLUB(); + + if (!verbose) + return; + + for (i = 0, cpu_slab = -1; i < kt->cpus; i++) { + cpu_slab_ptr = ULONG(si->cache_buf + + OFFSET(kmem_cache_cpu_slab) + (sizeof(void *)*i)); + if (!cpu_slab_ptr) + continue; + if (cpu_slab_ptr == si->slab) { + cpu_slab = i; + break; + } + } + + fprintf(fp, " %s", free_inuse_hdr); + + for (p = vaddr; p < vaddr + si->objects * si->size; p += si->size) { + is_free = FALSE; + for (is_free = 0, q = freelist; q; + q = get_freepointer(si, (void *)q)) { + if (q == BADADDR) + return; + if (p == q) { + is_free = TRUE; + break; + } + } + + if (si->flags & ADDRESS_SPECIFIED) { + if ((si->spec_addr < p) || + (si->spec_addr >= (p + si->size))) { + if (!(si->flags & VERBOSE)) + continue; + } + } + + fprintf(fp, " %s%lx%s", + is_free ? " " : "[", + p, is_free ? " " : "]"); + if (is_free && (cpu_slab >= 0)) + fprintf(fp, "(cpu %d cache)", cpu_slab); + fprintf(fp, "\n"); + + } +} + +static ulong +get_freepointer(struct meminfo *si, void *object) +{ + ulong vaddr, nextfree; + + vaddr = (ulong)(object + si->slab_offset); + if (!readmem(vaddr, KVADDR, &nextfree, + sizeof(void *), "get_freepointer", RETURN_ON_ERROR)) + return BADADDR; + + return nextfree; +} + +static void +do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node) +{ + ulong next, list_head; + int first; + + list_head = node_ptr + OFFSET(kmem_cache_node_partial); + if (!readmem(list_head, KVADDR, &next, sizeof(ulong), + "kmem_cache_node partial", RETURN_ON_ERROR)) + return; + + fprintf(fp, "NODE %d PARTIAL:\n%s", node, + next == list_head ? " (empty)\n" : ""); + first = 0; + while (next != list_head) { + si->slab = next - OFFSET(page_lru); + if (first++ == 0) + fprintf(fp, " %s", slab_hdr); + do_slab_slub(si, !VERBOSE); + + if (received_SIGINT()) + restart(0); + + if (!readmem(next, KVADDR, &next, sizeof(ulong), + "page.lru.next", RETURN_ON_ERROR)) + return; + } + + if (INVALID_MEMBER(kmem_cache_node_full)) { + fprintf(fp, "NODE %d FULL:\n (not tracked)\n", node); + return; + } + + list_head = node_ptr + OFFSET(kmem_cache_node_full); + if (!readmem(list_head, KVADDR, &next, sizeof(ulong), + "kmem_cache_node full", RETURN_ON_ERROR)) + return; + + fprintf(fp, "NODE %d FULL:\n%s", node, + next == list_head ? " (empty)\n" : ""); + first = 0; + while (next != list_head) { + si->slab = next - OFFSET(page_lru); + if (first++ == 0) + fprintf(fp, " %s", slab_hdr); + do_slab_slub(si, !VERBOSE); + + if (received_SIGINT()) + restart(0); + + if (!readmem(next, KVADDR, &next, sizeof(ulong), + "page.lru.next", RETURN_ON_ERROR)) + return; + } +} + + +static char * +is_kmem_cache_addr_slub(ulong vaddr, char *kbuf) +{ + int i, cnt; + ulong *cache_list; + ulong name; + char *cache_buf; + int found; + + cnt = get_kmem_cache_list(&cache_list); + cache_buf = GETBUF(SIZE(kmem_cache)); + + for (i = 0, found = FALSE; i < cnt; i++) { + if (cache_list[i] != vaddr) + continue; + + if (!readmem(cache_list[i], KVADDR, cache_buf, + SIZE(kmem_cache), "kmem_cache buffer", + RETURN_ON_ERROR)) + break; + + name = ULONG(cache_buf + OFFSET(kmem_cache_name)); + if (!read_string(name, kbuf, BUFSIZE-1)) + sprintf(kbuf, "(unknown)"); + + found = TRUE; + break; + } + + FREEBUF(cache_list); + FREEBUF(cache_buf); + + return (found ? kbuf : NULL); +} + +/* + * Kernel-config-neutral page-to-node evaluator. + */ +static int +page_to_nid(ulong page) +{ + int i; + physaddr_t paddr; + struct node_table *nt; + physaddr_t end_paddr; + + if (!page_to_phys(page, &paddr)) { + error(INFO, "page_to_nid: invalid page: %lx\n", page); + return -1; + } + + for (i = 0; i < vt->numnodes; i++) { + nt = &vt->node_table[i]; + + end_paddr = nt->start_paddr + + ((physaddr_t)nt->size * (physaddr_t)PAGESIZE()); + + if ((paddr >= nt->start_paddr) && (paddr < end_paddr)) + return i; + } + + error(INFO, "page_to_nid: cannot determine node for pages: %lx\n", + page); + + return -1; +} + +/* + * Allocate and fill the passed-in buffer with a list of + * the current kmem_cache structures. + */ +static int +get_kmem_cache_list(ulong **cache_buf) +{ + int cnt; + ulong vaddr; + struct list_data list_data, *ld; + + get_symbol_data("slab_caches", sizeof(void *), &vaddr); + + ld = &list_data; + BZERO(ld, sizeof(struct list_data)); + ld->start = vaddr; + ld->list_head_offset = OFFSET(kmem_cache_list); + ld->end = symbol_value("slab_caches"); + if (CRASHDEBUG(3)) + ld->flags |= VERBOSE; + + hq_open(); + cnt = do_list(ld); + *cache_buf = (ulong *)GETBUF(cnt * sizeof(ulong)); + cnt = retrieve_list(*cache_buf, cnt); + hq_close(); + + return cnt; +} + + +/* + * Get the address of the head page of a compound page. + */ +static ulong +compound_head(ulong page) +{ + ulong flags, first_page;; + + first_page = page; + + if (!readmem(page+OFFSET(page_flags), KVADDR, &flags, sizeof(ulong), + "page.flags", RETURN_ON_ERROR)) + return first_page; + + if ((flags & vt->PG_head_tail_mask) == vt->PG_head_tail_mask) + readmem(page+OFFSET(page_first_page), KVADDR, &first_page, + sizeof(ulong), "page.first_page", RETURN_ON_ERROR); + + return first_page; +} + +long +count_partial(ulong node) +{ + ulong list_head, next; + short inuse; + ulong total_inuse; + + total_inuse = 0; + list_head = node + OFFSET(kmem_cache_node_partial); + if (!readmem(list_head, KVADDR, &next, sizeof(ulong), + "kmem_cache_node.partial", RETURN_ON_ERROR)) + return -1; + + while (next != list_head) { + if (!readmem(next - OFFSET(page_lru) + OFFSET(page_inuse), KVADDR, &inuse, + sizeof(ushort), "page.inuse", RETURN_ON_ERROR)) + return -1; + total_inuse += inuse; + if (!readmem(next, KVADDR, &next, sizeof(ulong), + "page.lru.next", RETURN_ON_ERROR)) + return -1; + } + return total_inuse; +} + +char * +is_slab_page(struct meminfo *si, char *buf) +{ + int i, cnt; + ulong page_slab, page_flags, name; + ulong *cache_list; + char *cache_buf, *retval; + + if (!(vt->flags & KMALLOC_SLUB)) + return NULL; + + if (!is_page_ptr((ulong)si->spec_addr, NULL)) + return NULL; + + if (!readmem(si->spec_addr + OFFSET(page_flags), KVADDR, + &page_flags, sizeof(ulong), "page.flags", + RETURN_ON_ERROR|QUIET)) + return NULL; + + if (!(page_flags & vt->PG_slab)) + return NULL; + + if (!readmem(si->spec_addr + OFFSET(page_slab), KVADDR, + &page_slab, sizeof(ulong), "page.slab", + RETURN_ON_ERROR|QUIET)) + return NULL; + + retval = NULL; + cnt = get_kmem_cache_list(&cache_list); + cache_buf = GETBUF(SIZE(kmem_cache)); + + for (i = 0; i < cnt; i++) { + if (page_slab == cache_list[i]) { + if (!readmem(cache_list[i], KVADDR, cache_buf, + SIZE(kmem_cache), "kmem_cache buffer", + QUIET|RETURN_ON_ERROR)) + goto bailout; + + name = ULONG(cache_buf + OFFSET(kmem_cache_name)); + if (!read_string(name, buf, BUFSIZE-1)) + goto bailout; + + retval = buf; + break; + } + } + +bailout: + FREEBUF(cache_list); + FREEBUF(cache_buf); + + return retval; +} + +#ifdef NOT_USED +ulong +slab_to_kmem_cache_node(struct meminfo *si, ulong slab_page) +{ + int node; + ulong node_ptr; + + if (vt->flags & CONFIG_NUMA) { + node = page_to_nid(slab_page); + node_ptr = ULONG(si->cache_buf + + OFFSET(kmem_cache_node) + + (sizeof(void *)*node)); + } else + node_ptr = si->cache + OFFSET(kmem_cache_local_node); + + return node_ptr; +} + +ulong +get_kmem_cache_by_name(char *request) +{ + int i, cnt; + ulong *cache_list; + ulong name; + char *cache_buf; + char buf[BUFSIZE]; + ulong found; + + cnt = get_kmem_cache_list(&cache_list); + cache_buf = GETBUF(SIZE(kmem_cache)); + found = 0; + + for (i = 0; i < cnt; i++) { + readmem(cache_list[i], KVADDR, cache_buf, + SIZE(kmem_cache), "kmem_cache buffer", + FAULT_ON_ERROR); + + name = ULONG(cache_buf + OFFSET(kmem_cache_name)); + if (!read_string(name, buf, BUFSIZE-1)) + continue; + + if (STREQ(buf, request)) { + found = cache_list[i]; + break; + } + } + + FREEBUF(cache_list); + FREEBUF(cache_buf); + + return found; +} +#endif /* NOT_USED */ --- crash-4.0-4.7/help.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/help.c 2007-10-29 13:20:13.000000000 -0500 @@ -1656,7 +1656,7 @@ " PROCESSOR SPEED: 1993 Mhz", " HZ: 100", " PAGE SIZE: 4096", -" L1 CACHE SIZE: 32", +// " L1 CACHE SIZE: 32", " KERNEL VIRTUAL BASE: c0000000", " KERNEL VMALLOC BASE: e0800000", " KERNEL STACK SIZE: 8192", @@ -3873,7 +3873,10 @@ " -i displays general memory usage information", " -s displays basic kmalloc() slab data.", " -S displays all kmalloc() slab data, including all slab objects,", -" and whether each object is in use or is free.", +" and whether each object is in use or is free. If CONFIG_SLUB,", +" slab data for each per-cpu slab is displayed, along with the", +" address of each kmem_cache_node, its count of full and partial", +" slabs, and a list of all tracked slabs.", " -v displays the vmlist entries.", " -V displays the kernel vm_stat table.", " -n display memory node data (if supported).", --- crash-4.0-4.7/kernel.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/kernel.c 2007-10-30 09:01:58.000000000 -0500 @@ -2102,6 +2102,11 @@ return; } + /* try to get it from the header */ + if (get_lkcd_regs_for_cpu(bt, eip, esp) == 0) + return; + + /* if that fails: do guessing */ sysrq_eip = sysrq_esp = 0; for (i = 0, up = (ulong *)bt->stackbuf; i < LONGS_PER_STACK; i++, up++){ @@ -3111,7 +3116,7 @@ dump_log(int msg_level) { int i; - ulong log_buf, log_start, logged_chars; + ulong log_buf, logged_chars; char *buf; char last; ulong index; @@ -3138,13 +3143,16 @@ buf = GETBUF(log_buf_len); log_wrap = FALSE; - get_symbol_data("log_start", sizeof(ulong), &log_start); get_symbol_data("logged_chars", sizeof(ulong), &logged_chars); readmem(log_buf, KVADDR, buf, log_buf_len, "log_buf contents", FAULT_ON_ERROR); - log_start &= log_buf_len-1; - index = (logged_chars < log_buf_len) ? 0 : log_start; + if (logged_chars < log_buf_len) { + index = 0; + } else { + get_symbol_data("log_end", sizeof(ulong), &index); + index &= log_buf_len-1; + } if ((logged_chars < log_buf_len) && (index == 0) && (buf[index] == '<')) loglevel = TRUE; --- crash-4.0-4.7/x86.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/x86.c 2007-10-29 13:19:41.000000000 -0500 @@ -3858,7 +3858,7 @@ fprintf(fp, "(unknown)\n"); fprintf(fp, " HZ: %d\n", machdep->hz); fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE()); - fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size()); +// fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size()); fprintf(fp, "KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase); fprintf(fp, "KERNEL VMALLOC BASE: %lx\n", vt->vmalloc_start); fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE()); --- crash-4.0-4.7/ia64.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/ia64.c 2007-10-29 13:19:48.000000000 -0500 @@ -2315,7 +2315,7 @@ fprintf(fp, "(unknown)\n"); fprintf(fp, " HZ: %d\n", machdep->hz); fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE()); - fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size()); +// fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size()); fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE()); fprintf(fp, " KERNEL CACHED REGION: %lx\n", (ulong)KERNEL_CACHED_REGION << REGION_SHIFT); --- crash-4.0-4.7/ppc64.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/ppc64.c 2007-10-29 13:19:53.000000000 -0500 @@ -2107,7 +2107,7 @@ fprintf(fp, "(unknown)\n"); fprintf(fp, " HZ: %d\n", machdep->hz); fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE()); - fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size()); +// fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size()); fprintf(fp, "KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase); fprintf(fp, "KERNEL VMALLOC BASE: %lx\n", vt->vmalloc_start); fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE()); --- crash-4.0-4.7/x86_64.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/x86_64.c 2007-10-29 13:19:43.000000000 -0500 @@ -3949,7 +3949,7 @@ fprintf(fp, "(unknown)\n"); fprintf(fp, " HZ: %d\n", machdep->hz); fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE()); - fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size()); +// fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size()); fprintf(fp, "KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase); fprintf(fp, "KERNEL VMALLOC BASE: %lx\n", vt->vmalloc_start); fprintf(fp, " KERNEL START MAP: %lx\n", __START_KERNEL_map); --- crash-4.0-4.7/symbols.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/symbols.c 2007-10-29 13:20:33.000000000 -0500 @@ -119,6 +119,7 @@ static void dump_datatype_member(FILE *, struct datatype_member *); static void dump_datatype_flags(ulong, FILE *); static void dump_enumerator_list(char *); +static long anon_member_offset(char *, char *); static int gdb_whatis(char *); static void do_datatype_declaration(struct datatype_member *, ulong); @@ -3794,6 +3795,7 @@ * #define STRUCT_EXISTS(X) (datatype_info((X), NULL, NULL) >= 0) * #define MEMBER_EXISTS(X,Y) (datatype_info((X), (Y), NULL) >= 0) * #define MEMBER_SIZE(X,Y) datatype_info((X), (Y), MEMBER_SIZE_REQUEST) + * #define ANON_MEMBER_OFFSET(X,Y) datatype_info((X), (Y), ANON_MEMBER_OFFSET_REQUEST) * * to determine structure or union sizes, or member offsets. */ @@ -3806,6 +3808,9 @@ ulong type_found; char buf[BUFSIZE]; + if (dm == ANON_MEMBER_OFFSET_REQUEST) + return anon_member_offset(name, member); + strcpy(buf, name); req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request)); @@ -3956,6 +3961,33 @@ } /* + * Determine the offset of a member in an anonymous union + * in a structure. + */ +static long +anon_member_offset(char *name, char *member) +{ + int c; + char buf[BUFSIZE]; + char *arglist[MAXARGS]; + ulong value; + + value = -1; + sprintf(buf, "print &((struct %s *)0x0)->%s", name, member); + + open_tmpfile(); + if (gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { + rewind(pc->tmpfile); + if (fgets(buf, BUFSIZE, pc->tmpfile) && + (c = parse_line(strip_linefeeds(buf), arglist))) + value = stol(arglist[c-1], RETURN_ON_ERROR|QUIET, NULL); + } + close_tmpfile(); + + return value; +} + +/* * Get the basic type info for a symbol. Let the caller pass in the * gnu_request structure to have access to the full response; in either * case, return the type code. The member field can be used for structures @@ -5655,7 +5687,10 @@ lenptr = &array_table.free_area; if (two_dim) dimptr = &array_table.free_area_DIMENSION; - } + } else if (STREQ(s, "kmem_cache.node")) + lenptr = &array_table.kmem_cache_node; + else if (STREQ(s, "kmem_cache.cpu_slab")) + lenptr = &array_table.kmem_cache_cpu_slab; if (!lenptr) /* not stored */ return(len); @@ -6093,6 +6128,17 @@ fprintf(fp, " page_pte: %ld\n", OFFSET(page_pte)); + fprintf(fp, " page_inuse: %ld\n", + OFFSET(page_inuse)); + fprintf(fp, " page_lockless_freelist: %ld\n", + OFFSET(page_lockless_freelist)); + fprintf(fp, " page_slab: %ld\n", + OFFSET(page_slab)); + fprintf(fp, " page_first_page: %ld\n", + OFFSET(page_first_page)); + fprintf(fp, " page_freelist: %ld\n", + OFFSET(page_freelist)); + fprintf(fp, " swap_info_struct_swap_file: %ld\n", OFFSET(swap_info_struct_swap_file)); fprintf(fp, " swap_info_struct_swap_vfsmnt: %ld\n", @@ -6422,6 +6468,40 @@ fprintf(fp, " slab_free: %ld\n", OFFSET(slab_free)); + fprintf(fp, " kmem_cache_size: %ld\n", + OFFSET(kmem_cache_size)); + fprintf(fp, " kmem_cache_objsize: %ld\n", + OFFSET(kmem_cache_objsize)); + fprintf(fp, " kmem_cache_offset: %ld\n", + OFFSET(kmem_cache_offset)); + fprintf(fp, " kmem_cache_order: %ld\n", + OFFSET(kmem_cache_order)); + fprintf(fp, " kmem_cache_local_node: %ld\n", + OFFSET(kmem_cache_local_node)); + fprintf(fp, " kmem_cache_objects: %ld\n", + OFFSET(kmem_cache_objects)); + fprintf(fp, " kmem_cache_inuse: %ld\n", + OFFSET(kmem_cache_inuse)); + fprintf(fp, " kmem_cache_align: %ld\n", + OFFSET(kmem_cache_align)); + fprintf(fp, " kmem_cache_name: %ld\n", + OFFSET(kmem_cache_name)); + fprintf(fp, " kmem_cache_list: %ld\n", + OFFSET(kmem_cache_list)); + fprintf(fp, " kmem_cache_node: %ld\n", + OFFSET(kmem_cache_node)); + fprintf(fp, " kmem_cache_cpu_slab: %ld\n", + OFFSET(kmem_cache_cpu_slab)); + + fprintf(fp, " kmem_cache_node_nr_partial: %ld\n", + OFFSET(kmem_cache_node_nr_partial)); + fprintf(fp, " kmem_cache_node_nr_slabs: %ld\n", + OFFSET(kmem_cache_node_nr_slabs)); + fprintf(fp, " kmem_cache_node_partial: %ld\n", + OFFSET(kmem_cache_node_partial)); + fprintf(fp, " kmem_cache_node_full: %ld\n", + OFFSET(kmem_cache_node_full)); + fprintf(fp, " net_device_next: %ld\n", OFFSET(net_device_next)); fprintf(fp, " net_device_name: %ld\n", @@ -6804,6 +6884,9 @@ fprintf(fp, " array_cache: %ld\n", SIZE(array_cache)); fprintf(fp, " kmem_bufctl_t: %ld\n", SIZE(kmem_bufctl_t)); + fprintf(fp, " kmem_cache: %ld\n", SIZE(kmem_cache)); + fprintf(fp, " kmem_cache_node: %ld\n", SIZE(kmem_cache_node)); + fprintf(fp, " swap_info_struct: %ld\n", SIZE(swap_info_struct)); fprintf(fp, " vm_area_struct: %ld\n", @@ -6989,6 +7072,10 @@ ARRAY_LENGTH(height_to_maxindex)); fprintf(fp, " pid_hash: %d\n", ARRAY_LENGTH(pid_hash)); + fprintf(fp, " kmem_cache_node: %d\n", + ARRAY_LENGTH(kmem_cache_node)); + fprintf(fp, " kmem_cache_cpu_slab: %d\n", + ARRAY_LENGTH(kmem_cache_cpu_slab)); if (spec) { int in_size_table, in_array_table, arrays, offsets, sizes; --- crash-4.0-4.7/lkcd_common.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/lkcd_common.c 2007-10-30 09:07:03.000000000 -0500 @@ -1401,3 +1401,15 @@ } } +int +get_lkcd_regs_for_cpu(struct bt_info *bt, ulong *eip, ulong *esp) +{ + switch (lkcd->version) { + case LKCD_DUMP_V8: + case LKCD_DUMP_V9: + return get_lkcd_regs_for_cpu_v8(bt, eip, esp); + default: + return -1; + } +} + --- crash-4.0-4.7/lkcd_v8.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/lkcd_v8.c 2007-10-30 09:07:03.000000000 -0500 @@ -23,11 +23,188 @@ #include "lkcd_dump_v8.h" /* REMIND */ static dump_header_t dump_header_v8 = { 0 }; -// static dump_header_asm_t dump_header_asm_v8 = { 0 }; +#ifndef HAVE_NO_DUMP_HEADER_ASM +static dump_header_asm_t dump_header_asm_v8 = { 0 }; +#endif static dump_page_t dump_page = { 0 }; static void mclx_cache_page_headers_v8(void); static off_t lkcd_offset_to_first_page = LKCD_OFFSET_TO_FIRST_PAGE; +#if defined(X86_64) + +int +get_lkcd_regs_for_cpu_arch(int cpu, ulong *eip, ulong *esp) +{ + if (eip) + *eip = dump_header_asm_v8.dha_smp_regs[cpu].rip; + if (esp) + *esp = dump_header_asm_v8.dha_smp_regs[cpu].rsp; + + return 0; +} + +#elif defined(X86) + +int +get_lkcd_regs_for_cpu_arch(int cpu, ulong *eip, ulong *esp) +{ + if (eip) + *eip = dump_header_asm_v8.dha_smp_regs[cpu].eip; + if (esp) + *esp = dump_header_asm_v8.dha_smp_regs[cpu].esp; + + return 0; +} + +#else + +int +get_lkcd_regs_for_cpu_arch(int cpu, ulong *eip, ulong *esp) +{ + return -1; +} + +#endif + + + +int +get_lkcd_regs_for_cpu_v8(struct bt_info *bt, ulong *eip, ulong *esp) +{ + int cpu; + + if (!bt || !bt->tc) { + fprintf(stderr, "get_lkcd_regs_for_cpu_v8: invalid tc " + "(CPU=%d)\n", cpu); + return -EINVAL; + } + + cpu = bt->tc->processor; + + if (cpu >= NR_CPUS) { + fprintf(stderr, "get_lkcd_regs_for_cpu_v8, cpu (%d) too high\n", cpu); + return -EINVAL; + } + + return get_lkcd_regs_for_cpu_arch(cpu, eip, esp); +} + + +#ifndef HAVE_NO_DUMP_HEADER_ASM +int +lkcd_dump_init_v8_arch(dump_header_t *dh) +{ + off_t ret_of; + ssize_t ret_sz; + uint32_t hdr_size, offset, nr_cpus; + dump_header_asm_t arch_hdr; + char *hdr_buf = NULL; + + ret_of = lseek(lkcd->fd, dh->dh_header_size + + offsetof(dump_header_asm_t, dha_header_size), + SEEK_SET); + if (ret_of < 0) { + perror("lseek failed in " __FILE__ ":" STR(__LINE__)); + goto err; + } + + ret_sz = read(lkcd->fd, (char *)&hdr_size, sizeof(hdr_size)); + if (ret_sz != sizeof(hdr_size)) { + perror("Reading hdr_size failed in " __FILE__ ":" STR(__LINE__)); + goto err; + } + + ret_of = lseek(lkcd->fd, dh->dh_header_size, SEEK_SET); + if (ret_of < 0) { + perror("lseek failed in " __FILE__ ":" STR(__LINE__)); + goto err; + } + + hdr_buf = (char *)malloc(hdr_size); + if (!hdr_buf) { + perror("Could not allocate memory for dump header\n"); + goto err; + } + + ret_sz = read(lkcd->fd, (char *)hdr_buf, hdr_size); + if (ret_sz != hdr_size) { + perror("Could not read header " __FILE__ ":" STR(__LINE__)); + goto err; + } + + + /* + * Though we have KL_NR_CPUS is 128, the header size is different + * CONFIG_NR_CPUS might be different in the kernel. Hence, need + * to find out how many CPUs are configured. + */ + offset = offsetof(dump_header_asm_t, dha_smp_regs[0]); + nr_cpus = (hdr_size - offset) / sizeof(dump_CPU_info_t); + + /* check for CPU overflow */ + if (nr_cpus > NR_CPUS) { + fprintf(stderr, "CPU number too high %d (%s:%d)\n", + nr_cpus, __FILE__, __LINE__); + goto err; + } + + /* parts that don't depend on the number of CPUs */ + memcpy(&arch_hdr, (void *)hdr_buf, offset); + + /* registers */ + memcpy(&arch_hdr.dha_smp_regs, (void *)&hdr_buf[offset], + nr_cpus * sizeof(struct pt_regs)); + offset += nr_cpus * sizeof(struct pt_regs); + + /* current task */ + memcpy(&arch_hdr.dha_smp_current_task, (void *)&hdr_buf[offset], + nr_cpus * sizeof(&arch_hdr.dha_smp_current_task[0])); + offset += nr_cpus * sizeof(&arch_hdr.dha_smp_current_task[0]); + + /* stack */ + memcpy(&arch_hdr.dha_stack, (void *)&hdr_buf[offset], + nr_cpus * sizeof(&arch_hdr.dha_stack[0])); + offset += nr_cpus * sizeof(&arch_hdr.dha_stack[0]); + + /* stack_ptr */ + memcpy(&arch_hdr.dha_stack_ptr, (void *)&hdr_buf[offset], + nr_cpus * sizeof(&arch_hdr.dha_stack_ptr[0])); + offset += nr_cpus * sizeof(&arch_hdr.dha_stack_ptr[0]); + + if (arch_hdr.dha_magic_number != DUMP_ASM_MAGIC_NUMBER) { + fprintf(stderr, "Invalid magic number for x86_64\n"); + goto err; + } + + /* + * read the kernel load address on IA64 -- other architectures have + * no relocatable kernel at the lifetime of LKCD + */ +#ifdef IA64 + memcpy(&arch_hdr.dha_kernel_addr, (void *)&hdr_buf[offset], sizeof(uint64_t)); +#endif + + memcpy(&dump_header_asm_v8, &arch_hdr, sizeof(dump_header_asm_t)); + + return 0; + +err: + free(hdr_buf); + return -1; +} + +#else /* architecture that has no lkcd_dump_init_v8 */ + +int +lkcd_dump_init_v8_arch(dump_header_t *dh) +{ + return 0; +} + +#endif + + + /* * Verify and initialize the LKCD environment, storing the common data * in the global lkcd_environment structure. @@ -69,8 +246,14 @@ lkcd->dump_header = dh; if (lkcd->debug) dump_lkcd_environment(LKCD_DUMP_HEADER_ONLY); + + if (lkcd_dump_init_v8_arch(dh) != 0) { + fprintf(stderr, "Warning: Failed to initialise " + "arch specific dump code\n"); + } + #ifdef IA64 - if ( (fix_addr_v8(fd) == -1) ) + if ( (fix_addr_v8(&dump_header_asm_v8) == -1) ) return FALSE; #endif --- crash-4.0-4.7/lkcd_fix_mem.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/lkcd_fix_mem.c 2007-10-30 09:01:58.000000000 -0500 @@ -20,21 +20,13 @@ #define LKCD_COMMON #include "defs.h" -#include "lkcd_fix_mem.h" +#include "lkcd_dump_v8.h" static int fix_addr(dump_header_asm_t *); int -fix_addr_v8(int fd) +fix_addr_v8(dump_header_asm_t *dha) { - static dump_header_asm_t dump_header_asm_v8 = { 0 }; - dump_header_asm_t *dha; - dha = &dump_header_asm_v8; - - if (read(lkcd->fd, dha, sizeof(dump_header_asm_t)) != - sizeof(dump_header_asm_t)) - return -1; - fix_addr(dha); return 0; @@ -59,14 +51,6 @@ static int fix_addr(dump_header_asm_t *dha) { - - - if (dha->dha_header_size != sizeof(dump_header_asm_t)) { - error(INFO, "LKCD machine specific dump header doesn't match crash version\n"); - error(INFO, "traceback of currently executing threads may not work\n\n"); - } - - lkcd->dump_header_asm = dha; @@ -83,7 +67,7 @@ if (dha->dha_stack[i] && dha->dha_smp_current_task[i]) { lkcd->fix_addr[i].task = (ulong)dha->dha_smp_current_task[i]; lkcd->fix_addr[i].saddr = (ulong)dha->dha_stack[i]; - lkcd->fix_addr[i].sw = (ulong)dha->dha_switch_stack[i]; + lkcd->fix_addr[i].sw = (ulong)dha->dha_stack_ptr[i]; /* remember the highest non-zero entry */ lkcd->fix_addr_num = i + 1; } else { --- crash-4.0-4.7/netdump.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/netdump.c 2007-10-30 09:01:58.000000000 -0500 @@ -13,6 +13,8 @@ * Author: David Anderson */ +#define _LARGEFILE64_SOURCE 1 /* stat64() */ + #include "defs.h" #include "netdump.h" @@ -28,6 +30,7 @@ static size_t dump_Elf64_Nhdr(Elf64_Off offset, int); static void get_netdump_regs_ppc64(struct bt_info *, ulong *, ulong *); static physaddr_t xen_kdump_p2m(physaddr_t); +static void check_dumpfile_size(char *); #define ELFSTORE 1 #define ELFREAD 0 @@ -319,6 +322,40 @@ return -1; } +/* + * Check whether any PT_LOAD segment goes beyond the file size. + */ +static void +check_dumpfile_size(char *file) +{ + int i; + struct stat64 stat; + struct pt_load_segment *pls; + uint64_t segment_end; + + if (stat64(file, &stat) < 0) + return; + + for (i = 0; i < nd->num_pt_load_segments; i++) { + pls = &nd->pt_load_segments[i]; + + segment_end = pls->file_offset + + (pls->phys_end - pls->phys_start); + + if (segment_end > stat.st_size) { + error(WARNING, "%s: may be truncated or incomplete\n" + " PT_LOAD p_offset: %lld\n" + " p_filesz: %lld\n" + " bytes required: %lld\n" + " dumpfile size: %lld\n\n", + file, pls->file_offset, + pls->phys_end - pls->phys_start, + segment_end, stat.st_size); + return; + } + } +} + /* * Perform any post-dumpfile determination stuff here. */ @@ -329,6 +366,9 @@ return FALSE; nd->ofp = fptr; + + check_dumpfile_size(pc->dumpfile); + return TRUE; } @@ -1757,7 +1797,6 @@ unsigned long fs_base, gs_base; unsigned long ds,es,fs,gs; }; -#define offsetof(TYPE, MEMBER) ((ulong)&((TYPE *)0)->MEMBER) void get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp) --- crash-4.0-4.7/defs.h 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/defs.h 2007-10-30 09:53:18.000000000 -0500 @@ -54,6 +54,10 @@ #define TRUE (1) #define FALSE (0) +#define STR(x) #x +#ifndef offsetof +# define offsetof(TYPE, MEMBER) ((ulong)&((TYPE *)0)->MEMBER) +#endif #ifdef X86 #define NR_CPUS (256) @@ -68,7 +72,7 @@ #define NR_CPUS (32) #endif #ifdef IA64 -#define NR_CPUS (1024) +#define NR_CPUS (4096) #endif #ifdef PPC64 #define NR_CPUS (128) @@ -1395,6 +1399,28 @@ long task_struct_se; long sched_entity_run_node; long rt_rq_active; + long kmem_cache_size; + long kmem_cache_objsize; + long kmem_cache_offset; + long kmem_cache_order; + long kmem_cache_local_node; + long kmem_cache_objects; + long kmem_cache_inuse; + long kmem_cache_align; + long kmem_cache_name; + long kmem_cache_list; + long kmem_cache_node; + long kmem_cache_cpu_slab; + long page_inuse; +/* long page_offset; use "old" page->offset */ + long page_lockless_freelist; + long page_slab; + long page_first_page; + long page_freelist; + long kmem_cache_node_nr_partial; + long kmem_cache_node_nr_slabs; + long kmem_cache_node_partial; + long kmem_cache_node_full; }; struct size_table { /* stash of commonly-used sizes */ @@ -1493,6 +1519,8 @@ long pid_link; long unwind_table; long rlimit; + long kmem_cache; + long kmem_cache_node; }; struct array_table { @@ -1520,6 +1548,8 @@ int prio_array_queue; int height_to_maxindex; int pid_hash; + int kmem_cache_node; + int kmem_cache_cpu_slab; }; /* @@ -1537,6 +1567,9 @@ #define MEMBER_SIZE_REQUEST ((struct datatype_member *)(-1)) #define MEMBER_SIZE(X,Y) datatype_info((X), (Y), MEMBER_SIZE_REQUEST) +#define ANON_MEMBER_OFFSET_REQUEST ((struct datatype_member *)(-2)) +#define ANON_MEMBER_OFFSET(X,Y) datatype_info((X), (Y), ANON_MEMBER_OFFSET_REQUEST) + /* * The following set of macros can only be used with pre-intialized fields * in the offset table, size table or array_table. @@ -1560,6 +1593,7 @@ #define ARRAY_LENGTH_INIT(A, B, C, D, E) ((A) = get_array_length(C, D, E)) #define ARRAY_LENGTH_INIT_ALT(A, B, C, D, E) ((A) = get_array_length_alt(B, C, D, E)) #define MEMBER_SIZE_INIT(X, Y, Z) (ASSIGN_SIZE(X) = MEMBER_SIZE(Y, Z)) +#define ANON_MEMBER_OFFSET_INIT(X, Y, Z) (ASSIGN_OFFSET(X) = ANON_MEMBER_OFFSET(Y, Z)) /* * For use with non-debug kernels. @@ -1619,6 +1653,7 @@ ulong kmem_cache_len_nodes; ulong PG_reserved; ulong PG_slab; + ulong PG_head_tail_mask; int kmem_cache_namelen; ulong page_hash_table; int page_hash_table_len; @@ -1639,6 +1674,7 @@ int vma_cache_index; ulong vma_cache_fills; void *mem_sec; + char *mem_section; int ZONE_HIGHMEM; ulong *node_online_map; int node_online_map_len; @@ -1663,6 +1699,7 @@ #define NODES_ONLINE (0x4000) #define VM_STAT (0x8000) #define KMALLOC_SLUB (0x10000) +#define CONFIG_NUMA (0x20000) #define IS_FLATMEM() (vt->flags & FLATMEM) #define IS_DISCONTIGMEM() (vt->flags & DISCONTIGMEM) @@ -3830,9 +3867,18 @@ * lkcd_fix_mem.c */ +struct _dump_header_asm_s; +struct _dump_header_s; ulong get_lkcd_switch_stack(ulong); -int fix_addr_v8(int); +int fix_addr_v8(struct _dump_header_asm_s *); +int lkcd_dump_init_v8_arch(struct _dump_header_s *dh); int fix_addr_v7(int); +int get_lkcd_regs_for_cpu_arch(int cpu, ulong *eip, ulong *esp); + +/* + * lkcd_v8.c + */ +int get_lkcd_regs_for_cpu_v8(struct bt_info *bt, ulong *eip, ulong *esp); /* * ia64.c @@ -4098,6 +4144,7 @@ void lkcd_dumpfile_complaint(uint32_t, uint32_t, int); int set_mb_benchmark(ulong); ulonglong fix_lkcd_address(ulonglong); +int get_lkcd_regs_for_cpu(struct bt_info *bt, ulong *eip, ulong *esp); /* * lkcd_v1.c --- crash-4.0-4.7/lkcd_dump_v8.h 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/lkcd_dump_v8.h 2007-10-30 09:01:58.000000000 -0500 @@ -235,4 +235,304 @@ int stack_offset; } lkcdinfo_t; +/* + * + * machine specific dump headers + * + */ + +/* + * IA64 --------------------------------------------------------- + */ + +#if defined(IA64) + +#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */ +#define DUMP_ASM_VERSION_NUMBER 0x5 /* version number */ + + +struct pt_regs { + /* The following registers are saved by SAVE_MIN: */ + unsigned long b6; /* scratch */ + unsigned long b7; /* scratch */ + + unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */ + unsigned long ar_ssd; /* reserved for future use (scratch) */ + + unsigned long r8; /* scratch (return value register 0) */ + unsigned long r9; /* scratch (return value register 1) */ + unsigned long r10; /* scratch (return value register 2) */ + unsigned long r11; /* scratch (return value register 3) */ + + unsigned long cr_ipsr; /* interrupted task's psr */ + unsigned long cr_iip; /* interrupted task's instruction pointer */ + unsigned long cr_ifs; /* interrupted task's function state */ + + unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ + unsigned long ar_pfs; /* prev function state */ + unsigned long ar_rsc; /* RSE configuration */ + /* The following two are valid only if cr_ipsr.cpl > 0: */ + unsigned long ar_rnat; /* RSE NaT */ + unsigned long ar_bspstore; /* RSE bspstore */ + + unsigned long pr; /* 64 predicate registers (1 bit each) */ + unsigned long b0; /* return pointer (bp) */ + unsigned long loadrs; /* size of dirty partition << 16 */ + + unsigned long r1; /* the gp pointer */ + unsigned long r12; /* interrupted task's memory stack pointer */ + unsigned long r13; /* thread pointer */ + + unsigned long ar_fpsr; /* floating point status (preserved) */ + unsigned long r15; /* scratch */ + + /* The remaining registers are NOT saved for system calls. */ + + unsigned long r14; /* scratch */ + unsigned long r2; /* scratch */ + unsigned long r3; /* scratch */ + + /* The following registers are saved by SAVE_REST: */ + unsigned long r16; /* scratch */ + unsigned long r17; /* scratch */ + unsigned long r18; /* scratch */ + unsigned long r19; /* scratch */ + unsigned long r20; /* scratch */ + unsigned long r21; /* scratch */ + unsigned long r22; /* scratch */ + unsigned long r23; /* scratch */ + unsigned long r24; /* scratch */ + unsigned long r25; /* scratch */ + unsigned long r26; /* scratch */ + unsigned long r27; /* scratch */ + unsigned long r28; /* scratch */ + unsigned long r29; /* scratch */ + unsigned long r30; /* scratch */ + unsigned long r31; /* scratch */ + + unsigned long ar_ccv; /* compare/exchange value (scratch) */ + + /* + * Floating point registers that the kernel considers scratch: + */ + struct ia64_fpreg f6; /* scratch */ + struct ia64_fpreg f7; /* scratch */ + struct ia64_fpreg f8; /* scratch */ + struct ia64_fpreg f9; /* scratch */ + struct ia64_fpreg f10; /* scratch */ + struct ia64_fpreg f11; /* scratch */ +}; + + + +/* + * Structure: dump_header_asm_t + * Function: This is the header for architecture-specific stuff. It + * follows right after the dump header. + * + */ +typedef struct _dump_header_asm_s { + + /* the dump magic number -- unique to verify dump is valid */ + uint64_t dha_magic_number; + + /* the version number of this dump */ + uint32_t dha_version; + + /* the size of this header (in case we can't read it) */ + uint32_t dha_header_size; + + /* pointer to pt_regs, (OLD: (struct pt_regs *, NEW: (uint64_t)) */ + uint64_t dha_pt_regs; + + /* the dump registers */ + struct pt_regs dha_regs; + + /* the rnat register saved after flushrs */ + uint64_t dha_rnat; + + /* the pfs register saved after flushrs */ + uint64_t dha_pfs; + + /* the bspstore register saved after flushrs */ + uint64_t dha_bspstore; + + /* smp specific */ + uint32_t dha_smp_num_cpus; + uint32_t dha_dumping_cpu; + struct pt_regs dha_smp_regs[NR_CPUS]; + uint64_t dha_smp_current_task[NR_CPUS]; + uint64_t dha_stack[NR_CPUS]; + uint64_t dha_stack_ptr[NR_CPUS]; + + /* load address of kernel */ + uint64_t dha_kernel_addr; + +} __attribute__((packed)) dump_header_asm_t; + +struct dump_CPU_info_ia64 { + struct pt_regs dha_smp_regs; + uint64_t dha_smp_current_task; + uint64_t dha_stack; + uint64_t dha_stack_ptr; +} __attribute__((packed)) dump_CPU_info_ia64_t; + +typedef struct dump_CPU_info_ia64 dump_CPU_info_t; + +/* + * i386 --------------------------------------------------------- + */ + +#elif defined(X86) + +#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */ +#define DUMP_ASM_VERSION_NUMBER 0x5 /* version number */ + + +struct pt_regs { + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + int xds; + int xes; + long orig_eax; + long eip; + int xcs; + long eflags; + long esp; + int xss; +}; + +/* + * Structure: __dump_header_asm + * Function: This is the header for architecture-specific stuff. It + * follows right after the dump header. + */ +typedef struct _dump_header_asm_s { + /* the dump magic number -- unique to verify dump is valid */ + uint64_t dha_magic_number; + + /* the version number of this dump */ + uint32_t dha_version; + + /* the size of this header (in case we can't read it) */ + uint32_t dha_header_size; + + /* the esp for i386 systems */ + uint32_t dha_esp; + + /* the eip for i386 systems */ + uint32_t dha_eip; + + /* the dump registers */ + struct pt_regs dha_regs; + + /* smp specific */ + uint32_t dha_smp_num_cpus; + uint32_t dha_dumping_cpu; + struct pt_regs dha_smp_regs[NR_CPUS]; + uint32_t dha_smp_current_task[NR_CPUS]; + uint32_t dha_stack[NR_CPUS]; + uint32_t dha_stack_ptr[NR_CPUS]; +} __attribute__((packed)) dump_header_asm_t; + +/* + * CPU specific part of dump_header_asm_t + */ +typedef struct dump_CPU_info_s { + struct pt_regs dha_smp_regs; + uint64_t dha_smp_current_task; + uint64_t dha_stack; + uint64_t dha_stack_ptr; +} __attribute__ ((packed)) dump_CPU_info_t; + + +/* + * x86-64 --------------------------------------------------------- + */ + +#elif defined(X86_64) + +/* definitions */ +#define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */ +#define DUMP_ASM_VERSION_NUMBER 0x2 /* version number */ + + +struct pt_regs { + unsigned long r15; + unsigned long r14; + unsigned long r13; + unsigned long r12; + unsigned long rbp; + unsigned long rbx; +/* arguments: non interrupts/non tracing syscalls only save upto here*/ + unsigned long r11; + unsigned long r10; + unsigned long r9; + unsigned long r8; + unsigned long rax; + unsigned long rcx; + unsigned long rdx; + unsigned long rsi; + unsigned long rdi; + unsigned long orig_rax; +/* end of arguments */ +/* cpu exception frame or undefined */ + unsigned long rip; + unsigned long cs; + unsigned long eflags; + unsigned long rsp; + unsigned long ss; +/* top of stack page */ +}; + +/* + * Structure: dump_header_asm_t + * Function: This is the header for architecture-specific stuff. It + * follows right after the dump header. + */ +typedef struct _dump_header_asm_s { + + /* the dump magic number -- unique to verify dump is valid */ + uint64_t dha_magic_number; + + /* the version number of this dump */ + uint32_t dha_version; + + /* the size of this header (in case we can't read it) */ + uint32_t dha_header_size; + + /* the dump registers */ + struct pt_regs dha_regs; + + /* smp specific */ + uint32_t dha_smp_num_cpus; + int dha_dumping_cpu; + struct pt_regs dha_smp_regs[NR_CPUS]; + uint64_t dha_smp_current_task[NR_CPUS]; + uint64_t dha_stack[NR_CPUS]; + uint64_t dha_stack_ptr[NR_CPUS]; +} __attribute__((packed)) dump_header_asm_t; + + +/* + * CPU specific part of dump_header_asm_t + */ +typedef struct dump_CPU_info_s { + struct pt_regs dha_smp_regs; + uint64_t dha_smp_current_task; + uint64_t dha_stack; + uint64_t dha_stack_ptr; +} __attribute__ ((packed)) dump_CPU_info_t; + +#else + +#define HAVE_NO_DUMP_HEADER_ASM 1 + +#endif + #endif /* _DUMP_H */ --- crash-4.0-4.7/lkcd_fix_mem.h 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/lkcd_fix_mem.h 2007-10-30 09:06:16.000000000 -0500 @@ -1,3 +1,5 @@ +/* OBSOLETE */ + #ifdef IA64 #define UTSNAME_ENTRY_SZ 65 --- crash-4.0-4.7/Makefile 2007-10-30 10:58:12.000000000 -0500 +++ crash-4.0-4.8/Makefile 2007-10-30 10:58:11.000000000 -0500 @@ -66,7 +66,8 @@ MCORE_HFILES=va_server.h vas_crash.h REDHAT_HFILES=netdump.h diskdump.h xendump.h LKCD_DUMP_HFILES=lkcd_vmdump_v1.h lkcd_vmdump_v2_v3.h lkcd_dump_v5.h \ - lkcd_dump_v7.h lkcd_dump_v8.h lkcd_fix_mem.h + lkcd_dump_v7.h lkcd_dump_v8.h +LKCD_OBSOLETE_HFILES=lkcd_fix_mem.h LKCD_TRACE_HFILES=lkcd_x86_trace.h IBM_HFILES=ibm_common.h UNWIND_HFILES=unwind.h unwind_i.h rse.h unwind_x86.h unwind_x86_64.h @@ -84,7 +85,8 @@ SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \ ${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \ - ${LKCD_DUMP_HFILES} ${LKCD_TRACE_HFILES} ${IBM_HFILES} + ${LKCD_DUMP_HFILES} ${LKCD_TRACE_HFILES} ${LKCD_OBSOLETE_HFILES}\ + ${IBM_HFILES} OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \ build_data.o kernel.o test.o gdb_interface.o net.o dev.o \ @@ -437,7 +439,7 @@ cc -c ${CFLAGS} -DREDHAT -DUNWIND_V3 unwind.c -o unwind_v3.o ${WARNING_OPTIONS} ${WARNING_ERROR} lkcd_fix_mem.o: ${GENERIC_HFILES} ${LKCD_HFILES} lkcd_fix_mem.c - cc -c ${CFLAGS} lkcd_fix_mem.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CFLAGS} -DMCLX lkcd_fix_mem.c ${WARNING_OPTIONS} ${WARNING_ERROR} xen_hyper.o: ${GENERIC_HFILES} xen_hyper.c cc -c ${CFLAGS} xen_hyper.c ${WARNING_OPTIONS} ${WARNING_ERROR} --- crash-4.0-4.7/extensions/libsial/Makefile 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/Makefile 2007-10-30 09:55:47.000000000 -0500 @@ -15,7 +15,10 @@ LIBDIR = /usr/lib TARGETS = libsial.a -CFLAGS += -O3 -fPIC +CFLAGS += -O3 -g -fPIC +ifeq ($(TARGET), PPC64) + CFLAGS += -m64 +endif CFILES = sial_util.c sial_node.c sial_var.c sial_func.c sial_str.c \ sial_op.c sial_num.c sial_stat.c sial_builtin.c sial_type.c \ --- crash-4.0-4.7/extensions/libsial/sial_alloc.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/sial_alloc.c 2007-10-30 09:55:47.000000000 -0500 @@ -14,14 +14,14 @@ #include #include -#if linux -#define __return_address (void*)0 +#ifdef __GNUC__ # if __LP64__ # define NKPC 16 # else # define NKPC 4 # endif #else +// must be the SGI Mips compiler. # if (_MIPS_SZLONG == 64) # define NKPC 16 # else @@ -50,6 +50,20 @@ } blist; #define SIZEBL (((sizeof(blist)+8)/8)*8) + +void pbl(void *p) +{ +blist *bl=(blist*)(((char*)p)-SIZEBL); + sial_msg("struct blklist *%p {", bl); + sial_msg(" next=%p", bl->next); + sial_msg(" prev=%p", bl->prev); + sial_msg(" size=%d", bl->size); + sial_msg(" istmp=%d", bl->istmp); + sial_msg(" level=%d", bl->level); + sial_msg(" caller=%p", bl->caller); + sial_msg(" freer=%p", bl->freer); +} + static blist temp={ &temp, &temp, 0, 0, 0, 0, 0 }; value_t* @@ -150,7 +164,9 @@ void sial_caller(char *p, void *retaddr) { - +blist *bl=(blist*)(((char*)p)-SIZEBL); + + bl->caller=retaddr; } #define PAGEMASK 0xfffffffffffff000ll --- crash-4.0-4.7/extensions/libsial/sial_api.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/sial_api.c 2007-10-30 09:55:47.000000000 -0500 @@ -22,7 +22,7 @@ /* running key to new structures */ static ull nextidx=0, abitype=ABI_MIPS; -#define LOCALTYPESBASE 0x80000000 +#define LOCALTYPESBASE 0x8000000000000000ll static ull sial_nextidx(void) { return LOCALTYPESBASE+nextidx++; } /* this set of function is used to cleanup tdefs after their use. @@ -132,12 +132,11 @@ static neg_t *nlist=0; -static void -sial_addneg(int ctype, char *name) +void +sial_addneg(char *name) { neg_t *neg; - if(ctype != V_TYPEDEF) return; neg=sial_alloc(sizeof *neg); neg->name=sial_strdup(name); neg->next=nlist; @@ -389,6 +388,7 @@ stmember_t *stm=sial_calloc(sizeof(stmember_t)), **last=&st->stm; char *pname; + sial_dbg_named(DBG_STRUCT, st->name, 2, "Fill St started [local=%d].\n", (idx & LOCALTYPESBASE) ? 1 : 0); /* bail out if this is local type */ if(idx & LOCALTYPESBASE) return; @@ -396,6 +396,7 @@ while((pname=API_MEMBER(mname, idx, &stm->type, &stm->m, &lidx))) { + sial_dbg_named(DBG_STRUCT, st->name, 2, "member '%s'\n", pname); sial_memstinfo(stm, pname); stm->next=0; *last=stm; @@ -415,19 +416,20 @@ type_t *t=sial_newtype(); sial_chkinit(); + sial_dbg_named(DBG_TYPE, name, 2, "getctype [%d] [%s] [s=%d]\n", ctype, name, silent); if(!(st=sial_getst(name, ctype))) { + sial_dbg_named(DBG_TYPE, name, 2, "getctype [%s] not found in cache\n", name); if(silent && sial_isneg(name)) return 0; -//sial_msg("Sial_getctype '%s' type %d\n", name, ctype); - st=sial_calloc(sizeof(stinfo_t)); if(!API_GETCTYPE(ctype, name, &st->ctype)) { + sial_dbg_named(DBG_TYPE, name, 2, "[%s] not found in image\n", name); sial_free(st); sial_freetype(t); // add any tdef to the neg list - sial_addneg(ctype, name); + if(ctype == V_TYPEDEF) sial_addneg(name); if(silent) return 0; /* we fill a partial structure for this one assuming it will be defined later. This is to permit cross @@ -435,9 +437,11 @@ undefined structure (opaque structures) irix: see types.c : __pasid_opaque */ + sial_dbg_named(DBG_TYPE, name, 2, "[%s] creating partial type\n", name); sial_partialctype(ctype, name); return sial_getctype(ctype, name, silent); } + sial_dbg_named(DBG_TYPE, name, 2, "getctype [%s] found in image\n", name); st->name=sial_alloc(strlen(name)+1); strcpy(st->name, name); st->stm=0; @@ -512,6 +516,8 @@ sial_fillst(st); } } + else sial_dbg_named(DBG_TYPE, name, 2, "getctype [%s] found in cache\n", name); + if(ctype == V_ENUM || (ctype == V_TYPEDEF && st->rtype.type == V_ENUM)) { st->enums=API_GETENUM(name); sial_pushenums(st->enums); --- crash-4.0-4.7/extensions/libsial/sial_api.h 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/sial_api.h 2007-10-30 09:55:47.000000000 -0500 @@ -13,6 +13,9 @@ #define ABI_MIPS 1 #define ABI_INTEL_X86 2 #define ABI_INTEL_IA 3 +#define ABI_S390 4 +#define ABI_S390X 5 +#define ABI_PPC64 6 /* types of variables */ #define V_BASE 1 @@ -225,6 +228,12 @@ void sial_duptype(TYPE_S*to, TYPE_S*from); int sial_defbsize(void); TYPE_S*sial_newbtype(int token); +void sial_setdbg(unsigned int lvl); +unsigned int sial_getdbg(void); +void sial_setname(char *name); +char *sial_getname(void); +void sial_setclass(char *class); +char **sial_getclass(void); /* struct member functions */ void sial_member_soffset(MEMBER_S*m, int offset); @@ -246,6 +255,13 @@ void sial_warning(char *, ...); /* display a message and continue */ void sial_msg(char *, ...); +/* display a debug message */ +#define DBG_TYPE 0x00000001 +#define DBG_STRUCT 0x00000002 +#define DBG_NAME 0x10000000 // +#define DBG_ALL 0x0fffffff +void sial_dbg(int class, int level, char *, ...); +void sial_dbg_named(int class, char *name, int level, char *, ...); /* parsers debug flags */ extern int sialdebug, sialppdebug; --- crash-4.0-4.7/extensions/libsial/sial_define.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/sial_define.c 2007-10-30 09:55:47.000000000 -0500 @@ -421,6 +421,7 @@ } mname[i]='\0'; if((m=sial_getmac(mname, 1))) sial_freemac(m); + else sial_addneg(mname); } /* --- crash-4.0-4.7/extensions/libsial/sial.h 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/sial.h 2007-10-30 09:55:47.000000000 -0500 @@ -232,7 +232,12 @@ #define NODE_NAME(n) ((n)->name?((n)->name((n)->data)):0) #define NODE_FREE(n) (sial_freenode(n)) -#if 0 +#ifdef __GNUC__ +#define __return_address (void*)(__builtin_return_address(0)) +#else +// must be the SGI Mips compiler. +#endif +#if 1 #define TAG(p) sial_caller(p, __return_address) #else #define TAG(p) ; @@ -351,6 +356,7 @@ void sial_fillst(stinfo_t *st); void sial_exememlocal(value_t *vp, stmember_t* stm, value_t *v); void sial_do_deref(int n, value_t *v, value_t *ref); +void sial_addneg(char *name); stmember_t*sial_member(char *mname, type_t*tp); @@ -425,6 +431,7 @@ int sial_isenum(int atr); int sial_funcexists(char *name); int sial_isnew(void* p); +int sial_isneg(char *name); char *sial_vartofunc(node_t *name); char *sial_gettdefname(ull idx); @@ -446,6 +453,7 @@ type_t *sial_getvoidstruct(int ctype); extern int lineno, needvar, instruct, nomacs; +node_t *lastv; #define NULLNODE ((node_t*)0) --- crash-4.0-4.7/extensions/libsial/sial_input.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/sial_input.c 2007-10-30 09:55:47.000000000 -0500 @@ -797,6 +797,6 @@ } else { - sial_error("Include file not found: %s", name); + sial_msg("Include file not found: '%s' [include path is '%s']", name, sial_getipath()); } } --- crash-4.0-4.7/extensions/libsial/sial.l 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/sial.l 2007-10-30 09:55:47.000000000 -0500 @@ -22,6 +22,7 @@ #define retok(t) return(t) int needvar=0, instruct=0; +node_t *lastv; static char *lastvar=0; char *sial_lastvar(void) { return lastvar; } extern void sial_skip_directive(void); @@ -38,7 +39,13 @@ X [0-9a-fA-F] W [ \t\n] P #[ \t]* +OP [(] +CP [)] +%s var1 +%s var2 +%s var3 +%s var4 %% {W} { ; } @@ -158,6 +165,11 @@ printx { retok(PRINTX); } take_array { retok(TAKE_ARR); } +__var__ { BEGIN(var1); } +{W}*{OP}{W}* { BEGIN(var2); } +{ABC}{ABCN}* { BEGIN(var3); goto forcevar; } +{W}*{CP}{W}* { BEGIN(INITIAL); } + {ABC}{ABCN}* { if((!needvar) && (yylval.t=sial_getctype(V_TYPEDEF, yytext, 1))) @@ -169,6 +181,7 @@ needvar++; retok(TYPEDEF); } +forcevar: needvar=0; if(strlen(yytext) > MAX_SYMNAMELEN) { --- crash-4.0-4.7/extensions/libsial/sial_util.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/sial_util.c 2007-10-30 09:55:47.000000000 -0500 @@ -731,6 +731,97 @@ sial_exit(1); } +/****************************************************************** + Debug messaging support. +******************************************************************/ +static unsigned int dbglvl=0, clist=DBG_ALL; +static char *dbg_name=0; +unsigned int sial_getdbg(void) +{ + return(dbglvl); +} + +void sial_setdbg(unsigned int lvl) +{ + if(lvl > 9) + sial_msg("Invalid debug level value.\n"); + else + dbglvl=lvl; +} +char *sial_getname(void) +{ + return dbg_name; +} + +void sial_setname(char *name) +{ + if(dbg_name) sial_free(dbg_name); + dbg_name=sial_strdup(name); +} + +#define MAXCLASSES 10 +static struct { + char *name; + int class; +} classes [MAXCLASSES] = { + { "type", DBG_TYPE }, + { "struct", DBG_STRUCT }, + { 0 }, +}; + +char **sial_getclass(void) +{ +int i,j; +static char *ptrs[MAXCLASSES+1]; + + for(i=j=0;classes[i].name;i++) { + if(clist&classes[i].class) ptrs[j++]=classes[i].name; + } + ptrs[i]=0; + return ptrs; +} + +void sial_setclass(char *cl) +{ +int i,j; + + for(i=0;classes[i].name;i++) { + if(!strcmp(classes[i].name,cl)) { + clist |= classes[i].class; + return; + } + } + sial_msg("Invalid class '%s' specified.\n", cl); +} + +static void +sial_dbg_all(int class, char *name, int lvl, char *fmt, va_list ap) +{ + if(lvl<=dbglvl && (clist & class) && (!dbg_name || !strcmp(name, dbg_name))) { + fprintf(ofile, "dbg(%d) : ", lvl); + vfprintf(ofile, fmt, ap); + } +} + +void +sial_dbg(int class, int lvl, char *fmt, ...) +{ +va_list ap; + va_start(ap, fmt); + sial_dbg_all(class, 0, lvl, fmt, ap); + va_end(ap); +} + +void +sial_dbg_named(int class, char *name, int lvl, char *fmt, ...) +{ +va_list ap; + va_start(ap, fmt); + sial_dbg_all(class, name, lvl, fmt, ap); + va_end(ap); +} +/******************************************************************/ + void sial_rerror(srcpos_t *p, char *fmt, ...) { --- crash-4.0-4.7/extensions/libsial/sial_var.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/sial_var.c 2007-10-30 09:55:47.000000000 -0500 @@ -134,7 +134,7 @@ if(t) { sial_freetype(t); - sial_error("Variable '%s' already defined as typedef.\n"); + sial_warning("Variable '%s' already defined as typedef.\n"); } } @@ -673,7 +673,6 @@ var_t*p=sial_newvar(""); TAG(p); TAG(p->name); - TAG(p->array); return p; } --- crash-4.0-4.7/extensions/libsial/sial.y 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/libsial/sial.y 2007-10-30 09:55:47.000000000 -0500 @@ -219,9 +219,9 @@ | term DECR { $$ = sial_newop(POSTDECR, 1, $1); } | term INCR { $$ = sial_newop(POSTINCR, 1, $1); } | term INDIRECT var { $$ = sial_newmem(INDIRECT, $1, $3); } + | term INDIRECT tdef { $$ = sial_newmem(INDIRECT, $1, sial_tdeftovar($3)); } // resolve ambiguity | term DIRECT var { $$ = sial_newmem(DIRECT, $1, $3); } - | term INDIRECT tdef { $$ = sial_newmem(INDIRECT, $1, sial_tdeftovar($3)); } - | term DIRECT tdef { $$ = sial_newmem(DIRECT, $1, sial_tdeftovar($3)); } + | term DIRECT tdef { $$ = sial_newmem(DIRECT, $1, sial_tdeftovar($3)); } // resolve ambiguity | term '[' term ']' %prec ARRAY { $$ = sial_newindex($1, $3); } | NUMBER @@ -262,12 +262,11 @@ var_decl: - type_decl dvarlist { needvar=0; $$ = sial_vardecl($2, $1); } - | type_decl tdef { needvar=0; $$ = sial_vardecl(sial_newdvar(sial_tdeftovar($2)), $1); } + type_decl dvarlist { needvar=0; $$ = sial_vardecl($2, $1); } ; one_var_decl: - type_decl dvar { needvar=0; $$ = sial_vardecl($2, $1); } + type_decl dvar { needvar=0; $$ = sial_vardecl($2, $1); } ; type_decl: @@ -290,8 +289,8 @@ ctype_decl: ctype_tok var '{' {sial_startctype(sial_toctype($1),$2);instruct++;} var_decl_list '}' { instruct--; $$ = sial_ctype_decl(sial_toctype($1), $2, $5); } - | ctype_tok tdef '{' {sial_startctype(sial_toctype($1),sial_tdeftovar($2));instruct++;} var_decl_list '}' - { instruct--; $$ = sial_ctype_decl(sial_toctype($1), sial_tdeftovar($2), $5); } + | ctype_tok tdef '{' {sial_startctype(sial_toctype($1),lastv=sial_tdeftovar($2));instruct++;} var_decl_list '}' + { instruct--; $$ = sial_ctype_decl(sial_toctype($1), lastv, $5); } | ctype_tok var '{' dvarlist '}' { $$ = sial_enum_decl(sial_toctype($1), $2, $4); } | ctype_tok tdef '{' dvarlist '}' @@ -389,7 +388,6 @@ dvar: opt_var { $$ = sial_newdvar($1); needvar=0; } - | tdef { $$ = sial_newdvar(sial_tdeftovar($1)); needvar=0; } | ':' term { $$ = sial_dvarfld(sial_newdvar(0), $2); } | dvar ':' term { $$ = sial_dvarfld($1, $3); } | dvar '[' opt_term ']' { $$ = sial_dvaridx($1, $3); } --- crash-4.0-4.7/extensions/sial.c 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/sial.c 2007-10-30 10:50:57.000000000 -0500 @@ -1,5 +1,5 @@ /* - * $Id: sial.c,v 1.1 2007/09/24 19:53:32 anderson Exp $ + * $Id: sial.c,v 1.3 2007/10/30 15:50:57 anderson Exp $ * * This file is part of lcrash, an analysis tool for Linux memory dumps. * @@ -137,25 +137,37 @@ { struct symbol *sym; struct type *type; - static int a=0; - + int v=0; + + sial_dbg_named(DBG_TYPE, name, 2, "Looking for type %d name [%s] in struct domain...", ctype, name); sym = lookup_symbol(name, 0, STRUCT_DOMAIN, 0, (struct symtab **) NULL); - if(!sym) + if(!sym) { + sial_dbg_named(DBG_TYPE, name, 2, "Not found.\nLooking for type %d name [%s] in var domain...", ctype, name); sym = lookup_symbol(name, 0, VAR_DOMAIN, 0, (struct symtab **) NULL); + if(sym) { + sial_dbg_named(DBG_TYPE, name, 2, "found class=%d\n", sym->aclass); + if(sym->aclass == LOC_TYPEDEF) v=1; + } + } if (sym) { type=sym->type; + if(sial_is_typedef(ctype) && v) goto match; switch(TYPE_CODE(type)) { - case TYPE_CODE_TYPEDEF: if(sial_is_typedef(ctype)) goto match; break; + case TYPE_CODE_TYPEDEF: case TYPE_CODE_INT: + if(sial_is_typedef(ctype)) goto match; break; case TYPE_CODE_ENUM: if(sial_is_enum(ctype)) goto match; break; case TYPE_CODE_STRUCT: if(sial_is_struct(ctype)) goto match; break; case TYPE_CODE_UNION: if(sial_is_union(ctype)) goto match; break; } + sial_dbg_named(DBG_TYPE, name, 2, "Found but no match.\n"); } + else sial_dbg_named(DBG_TYPE, name, 2, "Not Found.\n"); + return 0; match: - + sial_dbg_named(DBG_TYPE, name, 2, "Found.\n"); /* populate */ sial_type_settype(tout, ctype); sial_type_setsize(tout, TYPE_LENGTH(type)); @@ -451,13 +463,14 @@ { DEF_S *dt=0; int i; -struct linuxdefs_s { +static struct linuxdefs_s { char *name; char *value; } linuxdefs[] = { + {"crash", "1"}, {"linux", "1"}, {"__linux", "1"}, {"__linux__", "1"}, @@ -486,7 +499,7 @@ {"__s390x", "1"}, {"__s390x__", "1"}, #endif -#ifdef ia64 +#ifdef __ia64__ {"ia64", "1"}, {"__ia64", "1"}, {"__ia64__", "1"}, @@ -494,7 +507,25 @@ {"_LONGLONG", "1"}, {"__LONG_MAX__", "9223372036854775807L"}, #endif +#ifdef ppc64 + {"ppc64", "1"}, + {"__ppc64", "1"}, + {"__ppc64__", "1"}, +#endif }; + +static char *untdef[] = { + "clock", + "mode", + "pid", + "uid", + "xtime", + "init_task", + "size", + "type", + "level", + 0 +}; #if 0 How to extract basic set of -D flags from the kernel image @@ -526,6 +557,22 @@ } } #endif + + /* remove some tdef with very usual identifier. + could also be cases where the kernel defined a type and variable with same name e.g. xtime. + the same can be accomplished in source using #undef or forcing the evaluation of + a indentifier as a variable name ex: __var(xtime). + + I tried to make the grammar as unambiqguous as I could. + + If this becomes to much of a problem I might diable usage of all image typedefs usage in sial! + */ + { + char **tdefname=untdef; + while(*tdefname) sial_addneg(*tdefname++);; + + } + /* insert constant defines from list above */ for(i=0;irun->editing sequences are executed.", "To edit a known sial macro file use the -f option. To edit the file", "at the location of a known function's declaration omit the -f option.", + "Use a single -l option to be brought to the last compile error location.", "", "EXAMPLES:", " %s> edit -f ps", " %s> edit ps", " %s> edit ps_opt", + " %s> edit -l", NULL }; @@ -681,12 +731,74 @@ NULL }; +void +sdebug_cmd(void) +{ + if(argcnt < 2) sial_msg("Current sial debug level is %d\n", sial_getdbg()); + else sial_setdbg(atoi(args[1])); +} + +char *sdebug_help[]={ + "sdebug", + "Print or set sial debug level", + "", + " Set the debug of sial. Without any parameter, shows the current debug level.", + NULL +}; + +void +sname_cmd(void) +{ + if(argcnt < 2) { + if(sial_getname()) sial_msg("Current sial name match is '%s'\n", sial_getname()); + else sial_msg("No name match specified yet.\n"); + } else sial_setname(args[1]); +} + +char *sname_help[]={ + "sname", + "Print or set sial name match.", + "", + " Set sial name string for matches. Debug messages that are object oriented", + " will only be displayed if the object name (struct, type, ...) matches this", + " value.", + NULL +}; + +void +sclass_cmd(void) +{ + if(argcnt < 2) { + char **classes=sial_getclass(); + sial_msg("Current sial classes are :"); + while(*classes) sial_msg("'%s' ", *classes++); + sial_msg("\n"); + + } + else { + int i; + for(i=1; i[, ]", + " Set sial debug classes. Only debug messages that are in the specified classes", + " will be displayed.", + NULL +}; + #define NCMDS 100 static struct command_table_entry command_table[NCMDS] = { {"edit", edit_cmd, edit_help}, {"load", load_cmd, load_help}, {"unload", unload_cmd, unload_help}, + {"sdebug", sdebug_cmd, sdebug_help}, + {"sname", sname_cmd, sname_help}, + {"sclass", sclass_cmd, sclass_help}, {(char *)0 } }; @@ -808,16 +920,28 @@ #ifdef i386 #define SIAL_ABI ABI_INTEL_X86 #else -#ifdef ia64 +#ifdef __ia64__ #define SIAL_ABI ABI_INTEL_IA #else #ifdef __x86_64__ #define SIAL_ABI ABI_INTEL_IA #else +#ifdef __s390__ +#define SIAL_ABI ABI_S390 +#else +#ifdef __s390x__ +#define SIAL_ABI ABI_S390X +#else +#ifdef PPC64 +#define SIAL_ABI ABI_PPC64 +#else #error sial: Unkown ABI #endif #endif #endif +#endif +#endif +#endif sial_apiset(&icops, SIAL_ABI, sizeof(long), 0); sial_version(); --- crash-4.0-4.7/extensions/sial.mk 2007-10-30 10:31:16.000000000 -0500 +++ crash-4.0-4.8/extensions/sial.mk 2007-10-30 09:55:47.000000000 -0500 @@ -1,11 +1,17 @@ # +ifeq ($(TARGET), PPC64) + TARGET_FLAGS = -D$(TARGET) -m64 +else + TARGET_FLAGS = -D$(TARGET) +endif + all: sial.so lib-sial: cd libsial && make sial.so: ../defs.h sial.c lib-sial - gcc -g -I.. -Ilibsial -I../gdb-6.1/bfd -I../gdb-6.1/include -I../gdb-6.1/gdb -I../gdb-6.1/gdb/config -nostartfiles -shared -rdynamic -o sial.so sial.c -fPIC -D$(TARGET) -Llibsial -lsial + gcc -g -I.. -Ilibsial -I../gdb-6.1/bfd -I../gdb-6.1/include -I../gdb-6.1/gdb -I../gdb-6.1/gdb/config -nostartfiles -shared -rdynamic -o sial.so sial.c -fPIC $(TARGET_FLAGS) -Llibsial -lsial clean: cd libsial && make clean