--- crash-4.0.9/main.c 2009-10-07 11:39:57.000000000 -0400 +++ crash-4.1.0/main.c 2009-09-15 08:51:58.000000000 -0400 @@ -784,7 +784,8 @@ else strcat(command, args[i]); } - system(command); + if (system(command) == -1) + perror(command); return TRUE; } --- crash-4.0.9/tools.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/tools.c 2009-09-14 14:31:41.000000000 -0400 @@ -42,7 +42,7 @@ int end_of_line, new_line; char buf[BUFSIZE]; char *spacebuf; - ulong retaddr[NUMBER_STACKFRAMES] = { 0 }; + void *retaddr[NUMBER_STACKFRAMES] = { 0 }; va_list ap; if (CRASHDEBUG(1) || (pc->flags & DROP_CORE)) { @@ -69,6 +69,8 @@ if (type == CONT) spacebuf = space(strlen(pc->curcmd)); + else + spacebuf = NULL; if (pc->stdpipe) { fprintf(pc->stdpipe, "%s%s%s %s%s", @@ -965,9 +967,10 @@ char *p; int cnt; - if (!count) + if (!count) { strip_line_end(s); - else + cnt = 0; + } else cnt = count; for (p = &s[0]; *p; p++) { @@ -1013,7 +1016,7 @@ strcpy(buf, s); argc = parse_line(buf, arglist); - for (i = found = 0; i < argc; i++) { + for (i = found = value = 0; i < argc; i++) { if (stripchar) strip_ending_char(arglist[i], stripchar); @@ -1069,9 +1072,10 @@ char *p; int cnt; - if (!count) + if (!count) { strip_line_end(s); - else + cnt = 0; + } else cnt = count; for (p = &s[0]; *p; p++) { @@ -1130,9 +1134,10 @@ char *p; int cnt, only; - if (!count) + if (!count) { strip_line_end(s); - else + cnt = 0; + } else cnt = count; only = 0; --- crash-4.0.9/memory.c 2009-10-07 11:39:57.000000000 -0400 +++ crash-4.1.0/memory.c 2009-10-06 14:12:16.000000000 -0400 @@ -87,6 +87,7 @@ static void kmem_cache_init(void); static void kmem_cache_init_slub(void); static ulong max_cpudata_limit(ulong, ulong *); +static void kmem_cache_downsize(void); static int ignore_cache(struct meminfo *, char *); static char *is_kmem_cache_addr(ulong, char *); static char *is_kmem_cache_addr_slub(ulong, char *); @@ -287,6 +288,7 @@ if (INVALID_MEMBER(page_count)) MEMBER_OFFSET_INIT(page_count, "page", "_count"); MEMBER_OFFSET_INIT(page_flags, "page", "flags"); + MEMBER_SIZE_INIT(page_flags, "page", "flags"); MEMBER_OFFSET_INIT(page_mapping, "page", "mapping"); if (INVALID_MEMBER(page_mapping)) ANON_MEMBER_OFFSET_INIT(page_mapping, "page", "mapping"); @@ -782,6 +784,8 @@ "zone", "pages_low"); MEMBER_OFFSET_INIT(zone_pages_high, "zone", "pages_high"); + MEMBER_OFFSET_INIT(zone_watermark, + "zone", "watermark"); MEMBER_OFFSET_INIT(zone_nr_active, "zone", "nr_active"); MEMBER_OFFSET_INIT(zone_nr_inactive, @@ -884,6 +888,7 @@ flag = HEXADECIMAL|DISPLAY_DEFAULT; endaddr = 0; + offset = 0; memtype = KVADDR; count = -1; @@ -1134,6 +1139,9 @@ case FILEADDR: addrtype = "FILEADDR"; break; + default: + addrtype = NULL; + break; } if (CRASHDEBUG(4)) @@ -1142,6 +1150,8 @@ origaddr = addr; BZERO(&mem, sizeof(struct memloc)); + hx = linelen = typesz = per_line = ascii_start = 0; + location = NULL; switch (flag & (DISPLAY_TYPES)) { @@ -1395,6 +1405,8 @@ error(FATAL, "not allowed on dumpfiles\n"); memtype = 0; + buf = NULL; + addr = 0; size = sizeof(void*); addr_entered = value_entered = FALSE; @@ -2432,7 +2444,7 @@ ulong vtop_flags, loop_vtop_flags; struct task_context *tc; - vtop_flags = 0; + vtop_flags = loop_vtop_flags = 0; tc = NULL; while ((c = getopt(argcnt, args, "ukc:")) != EOF) { @@ -2519,7 +2531,7 @@ struct meminfo meminfo; char buf1[BUFSIZE]; char buf2[BUFSIZE]; - int memtype; + int memtype = 0; switch (vtop_flags & (UVADDR|KVADDR)) { @@ -2553,7 +2565,7 @@ break; } - paddr = 0; + page_exists = paddr = 0; switch (memtype) { case UVADDR: @@ -3121,6 +3133,7 @@ if (vm_file && !(flag & VERIFY_ADDR)) { file_buf = fill_file_cache(vm_file); dentry = ULONG(file_buf + OFFSET(file_f_dentry)); + dentry_buf = NULL; if (dentry) { dentry_buf = fill_dentry_cache(dentry); if (VALID_MEMBER(file_f_vfsmnt)) { @@ -3848,6 +3861,7 @@ PG_reserved_flag_init(void) { ulong pageptr; + int count; ulong vaddr, flags; char *buf; @@ -3865,11 +3879,15 @@ } flags = ULONG(buf + OFFSET(page_flags)); + count = INT(buf + OFFSET(page_count)); if (count_bits_long(flags) == 1) vt->PG_reserved = flags; else - vt->PG_reserved = 0; + vt->PG_reserved = 1 << (ffsl(flags)-1); + + if (count == -1) + vt->flags |= PGCNT_ADJ; if (CRASHDEBUG(2)) fprintf(fp, @@ -4026,8 +4044,10 @@ mkstring(buf4, 8, CENTER|RJUST, "INDEX")); } + mapping = index = 0; + reserved = shared = slabs = buffers = inode = offset = 0; pg_spec = phys_spec = print_hdr = FALSE; - + switch (mi->flags) { case ADDRESS_SPECIFIED: @@ -4175,6 +4195,8 @@ continue; flags = ULONG(pcache + OFFSET(page_flags)); + if (SIZE(page_flags) == 4) + flags &= 0xffffffff; count = UINT(pcache + OFFSET(page_count)); switch (mi->flags) @@ -4226,7 +4248,8 @@ if (flags & PG_reserved_flag) { reserved++; } else { - if (count > 1) + if ((int)count > + (vt->flags & PGCNT_ADJ ? 0 : 1)) shared++; } continue; @@ -4511,6 +4534,8 @@ mkstring(buf4, 8, CENTER|RJUST, "INDEX")); } + mapping = index = 0; + reserved = shared = slabs = buffers = inode = offset = 0; pg_spec = phys_spec = print_hdr = FALSE; switch (mi->flags) @@ -4621,6 +4646,8 @@ continue; flags = ULONG(pcache + OFFSET(page_flags)); + if (SIZE(page_flags) == 4) + flags &= 0xffffffff; count = UINT(pcache + OFFSET(page_count)); switch (mi->flags) @@ -4672,7 +4699,8 @@ if (flags & PG_reserved_flag) { reserved++; } else { - if (count > 1) + if ((int)count > + (vt->flags & PGCNT_ADJ ? 0 : 1)) shared++; } continue; @@ -5021,10 +5049,9 @@ entry_len = VALID_STRUCT(page_cache_bucket) ? SIZE(page_cache_bucket) : sizeof(void *); - if (CRASHDEBUG(1)) { - populated = 0; + populated = 0; + if (CRASHDEBUG(1)) fprintf(fp, "page_hash_table length: %d\n", len); - } get_symbol_type("page_cache_size", NULL, &req); if (req.length == sizeof(int)) { @@ -5178,6 +5205,7 @@ ld = &list_data; total_free = 0; searchphys = 0; + chunk_size = 0; do_search = FALSE; get_symbol_data("nr_free_pages", sizeof(int), &nr_free_pages); @@ -5270,7 +5298,7 @@ found = FALSE; rewind(pc->tmpfile); - order = offset = 0; + order = offset = this_addr = 0; while (fgets(buf, BUFSIZE, pc->tmpfile)) { if (CRASHDEBUG(1) && STRNEQ(buf, "tmpfile); - order = offset = 0; + order = offset = this_addr = 0; while (fgets(buf, BUFSIZE, pc->tmpfile)) { if (CRASHDEBUG(1) && STRNEQ(buf, "tmpfile); + p = fgets(buf, BUFSIZE, pc->tmpfile); strcpy(last_area, strip_linefeeds(buf)); p = strstr(buf, "k"); *p = NULLCHAR; @@ -5612,6 +5641,9 @@ } verbose = (do_search || (fi->flags & VERBOSE)) ? TRUE : FALSE; + chunk_size = 0; + zone_size_offset = 0; + if (VALID_MEMBER(zone_struct_size)) zone_size_offset = OFFSET(zone_struct_size); else if (VALID_MEMBER(zone_struct_memsize)) @@ -5751,7 +5783,7 @@ found = FALSE; rewind(pc->tmpfile); - order = offset = 0; + order = offset = this_addr = 0; last_node[0] = NULLCHAR; last_zone[0] = NULLCHAR; last_area[0] = NULLCHAR; @@ -5766,18 +5798,18 @@ continue; if (STRNEQ(buf, "NODE")) { - fgets(buf, BUFSIZE, pc->tmpfile); + p = fgets(buf, BUFSIZE, pc->tmpfile); strcpy(last_node, strip_linefeeds(buf)); continue; } if (STRNEQ(buf, "ZONE")) { - fgets(buf, BUFSIZE, pc->tmpfile); + p = fgets(buf, BUFSIZE, pc->tmpfile); strcpy(last_zone, strip_linefeeds(buf)); continue; } if (STRNEQ(buf, "AREA")) { strcpy(last_area_hdr, buf); - fgets(buf, BUFSIZE, pc->tmpfile); + p = fgets(buf, BUFSIZE, pc->tmpfile); strcpy(last_area, strip_linefeeds(buf)); p = strstr(buf, "k"); *p = NULLCHAR; @@ -5905,6 +5937,10 @@ verbose = (do_search || (fi->flags & VERBOSE)) ? TRUE : FALSE; + zone_size_offset = 0; + chunk_size = 0; + this_addr = 0; + if (VALID_MEMBER(zone_spanned_pages)) zone_size_offset = OFFSET(zone_spanned_pages); else @@ -6080,18 +6116,18 @@ continue; if (STRNEQ(buf, "NODE")) { - fgets(buf, BUFSIZE, pc->tmpfile); + p = fgets(buf, BUFSIZE, pc->tmpfile); strcpy(last_node, strip_linefeeds(buf)); continue; } if (STRNEQ(buf, "ZONE")) { - fgets(buf, BUFSIZE, pc->tmpfile); + p = fgets(buf, BUFSIZE, pc->tmpfile); strcpy(last_zone, strip_linefeeds(buf)); continue; } if (STRNEQ(buf, "AREA")) { strcpy(last_area_hdr, buf); - fgets(buf, BUFSIZE, pc->tmpfile); + p = fgets(buf, BUFSIZE, pc->tmpfile); strcpy(last_area, strip_linefeeds(buf)); p = strstr(buf, "k"); *p = NULLCHAR; @@ -6193,7 +6229,7 @@ nt = &vt->node_table[n]; node_zones = nt->pgdat + OFFSET(pglist_data_node_zones); - if ((i == 0) && (vt->flags & NODES)) { + if ((vt->numnodes > 1) && (vt->flags & NODES)) { fprintf(fp, "%sNODE\n %2d\n", n ? "\n" : "", nt->node_id); } @@ -6275,6 +6311,9 @@ int list_count; ulong *free_ptr; + list_count = 0; + free_list_buf = free_area_buf2 = NULL; + if (VALID_STRUCT(free_area_struct)) { if (SIZE(free_area_struct) != (3 * sizeof(ulong))) error(FATAL, @@ -7122,7 +7161,7 @@ do { readmem(cache, KVADDR, cache_buf, SIZE(kmem_cache_s), - "kmem_cache_s buffer", FAULT_ON_ERROR); + "kmem_cache buffer", FAULT_ON_ERROR); if (cache == vaddr) { if (vt->kmem_cache_namelen) { @@ -7191,7 +7230,7 @@ do { readmem(cache, KVADDR, cache_buf, SIZE(kmem_cache_s), - "kmem_cache_s buffer", FAULT_ON_ERROR); + "kmem_cache buffer", FAULT_ON_ERROR); if (vt->kmem_cache_namelen) { BCOPY(cache_buf+name_offset, buf, @@ -7392,13 +7431,16 @@ } else cache = cache_end = symbol_value("cache_cache"); + if (!(pc->flags & RUNTIME)) + kmem_cache_downsize(); + cache_buf = GETBUF(SIZE(kmem_cache_s)); do { cache_count++; if (!readmem(cache, KVADDR, cache_buf, SIZE(kmem_cache_s), - "kmem_cache_s buffer", RETURN_ON_ERROR)) { + "kmem_cache buffer", RETURN_ON_ERROR)) { FREEBUF(cache_buf); vt->flags |= KMEM_CACHE_UNAVAIL; error(INFO, @@ -7473,6 +7515,55 @@ vt->flags |= KMEM_CACHE_INIT; } +static void +kmem_cache_downsize(void) +{ + char *cache_buf; + uint buffer_size; + int nr_node_ids; + + if ((THIS_KERNEL_VERSION < LINUX(2,6,22)) || + !kernel_symbol_exists("cache_cache") || + !MEMBER_EXISTS("kmem_cache", "buffer_size")) + return; + + cache_buf = GETBUF(SIZE(kmem_cache_s)); + + if (!readmem(symbol_value("cache_cache"), KVADDR, cache_buf, + SIZE(kmem_cache_s), "kmem_cache buffer", FAULT_ON_ERROR)) { + FREEBUF(cache_buf); + return; + } + + buffer_size = UINT(cache_buf + + MEMBER_OFFSET("kmem_cache", "buffer_size")); + + if (buffer_size < SIZE(kmem_cache_s)) { + ASSIGN_SIZE(kmem_cache_s) = buffer_size; + + if (kernel_symbol_exists("nr_node_ids")) { + get_symbol_data("nr_node_ids", sizeof(int), + &nr_node_ids); + vt->kmem_cache_len_nodes = nr_node_ids; + + } else + vt->kmem_cache_len_nodes = 1; + + if (CRASHDEBUG(1)) { + fprintf(fp, + "\nkmem_cache_downsize: SIZE(kmem_cache_s): %ld " + "cache_cache.buffer_size: %d\n", + STRUCT_SIZE("kmem_cache"), buffer_size); + fprintf(fp, + "kmem_cache_downsize: nr_node_ids: %ld\n", + vt->kmem_cache_len_nodes); + } + } + + FREEBUF(cache_buf); +} + + /* * Determine the largest cpudata limit for a given cache. */ @@ -7786,7 +7877,7 @@ fprintf(fp, "%s%s", cnt++ ? "\n" : "", kmem_cache_hdr); readmem(si->cache, KVADDR, si->cache_buf, SIZE(kmem_cache_s), - "kmem_cache_s buffer", FAULT_ON_ERROR); + "kmem_cache buffer", FAULT_ON_ERROR); if (vt->kmem_cache_namelen) { BCOPY(si->cache_buf + OFFSET(kmem_cache_s_c_name), @@ -9005,6 +9096,7 @@ int index; list_borked = 0; + slab_buf = NULL; si->slabsize = (power(2, si->order) * PAGESIZE()); si->cpucached_slab = 0; start_address = (ulong *)GETBUF(sizeof(ulong) * vt->kmem_cache_len_nodes); @@ -10326,6 +10418,7 @@ ulong task; struct task_context *tc; + vaddr = 0; pc->curcmd_flags &= ~HEADER_PRINTED; switch (mi->memtype) @@ -10705,6 +10798,8 @@ fprintf(fp, "%sCONFIG_NUMA", others++ ? "|" : "");\ if (vt->flags & VM_EVENT) fprintf(fp, "%sVM_EVENT", others++ ? "|" : "");\ + if (vt->flags & PGCNT_ADJ) + fprintf(fp, "%sPGCNT_ADJ", others++ ? "|" : "");\ fprintf(fp, ")\n"); if (vt->kernel_pgd[0] == vt->kernel_pgd[1]) @@ -10734,7 +10829,7 @@ fprintf(fp, " kmem_max_cpus: %ld\n", vt->kmem_max_cpus); fprintf(fp, " kmem_cache_count: %ld\n", vt->kmem_cache_count); 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, "kmem_cache_len_nodes: %ld\n", vt->kmem_cache_len_nodes); fprintf(fp, " PG_reserved: %lx\n", vt->PG_reserved); fprintf(fp, " PG_slab: %ld (%lx)\n", vt->PG_slab, (ulong)1 << vt->PG_slab); @@ -11700,6 +11795,7 @@ else goto no_file_offset; + offset = 0; if (vm_offset != 0xdeadbeef) offset = VIRTPAGEBASE(vaddr) - vm_start + vm_offset; else if (vm_pgoff != 0xdeadbeef) { @@ -11775,6 +11871,8 @@ char buf5[BUFSIZE]; struct node_table *nt; + node = slen = 0; + if (!(vt->flags & (NODES|NODES_ONLINE)) && initialize) { nt = &vt->node_table[0]; nt->node_id = 0; @@ -12178,7 +12276,10 @@ ulong value4; ulong value5; ulong value6; + long min, low, high; + value1 = value2 = value3 = value4 = value5 = value6 = 0; + min = low = high = 0; pgdat = vt->node_table[0].pgdat; zonebuf = GETBUF(SIZE_OPTION(zone_struct, zone)); vm_stat_init(); @@ -12213,12 +12314,28 @@ } else error(FATAL, "zone struct has unknown size field\n"); - value2 = ULONG(zonebuf + OFFSET_OPTION(zone_pages_min, - zone_struct_pages_min)); - value3 = ULONG(zonebuf + OFFSET_OPTION(zone_pages_low, - zone_struct_pages_low)); - value4 = ULONG(zonebuf + OFFSET_OPTION(zone_pages_high, - zone_struct_pages_high)); + if (VALID_MEMBER(zone_watermark)) { + if (!enumerator_value("WMARK_MIN", &min) || + !enumerator_value("WMARK_LOW", &low) || + !enumerator_value("WMARK_HIGH", &high)) { + min = 0; + low = 1; + high = 2; + } + value2 = ULONG(zonebuf + OFFSET(zone_watermark) + + (sizeof(long) * min)); + value3 = ULONG(zonebuf + OFFSET(zone_watermark) + + (sizeof(long) * low)); + value4 = ULONG(zonebuf + OFFSET(zone_watermark) + + (sizeof(long) * high)); + } else { + value2 = ULONG(zonebuf + OFFSET_OPTION(zone_pages_min, + zone_struct_pages_min)); + value3 = ULONG(zonebuf + OFFSET_OPTION(zone_pages_low, + zone_struct_pages_low)); + value4 = ULONG(zonebuf + OFFSET_OPTION(zone_pages_high, + zone_struct_pages_high)); + } value5 = ULONG(zonebuf + OFFSET_OPTION(zone_free_pages, zone_struct_free_pages)); @@ -12263,7 +12380,12 @@ dump_vm_stat(NULL, NULL, node_zones + OFFSET(zone_vm_stat)); } else { - fprintf(fp, " FREE: %ld\n", value5); + if (VALID_MEMBER(zone_vm_stat)) { + fprintf(fp, "\n VM_STAT:\n"); + dump_vm_stat(NULL, NULL, node_zones + + OFFSET(zone_vm_stat)); + } else + fprintf(fp, " FREE: %ld\n", value5); goto next_zone; } @@ -12430,6 +12552,7 @@ break; default: + psz = 0; error(FATAL, "memory_page_size: invalid pc->flags: %lx\n", pc->flags & MEMORY_SOURCES); } @@ -12450,6 +12573,7 @@ k = 1; err = FALSE; + psize = 0; switch (LASTCHAR(s)) { @@ -12966,6 +13090,8 @@ !symbol_exists("node_states")) return 0; + len = mapaddr = 0; + if (symbol_exists("node_online_map")) { if (LKCD_KERNTYPES()) { if ((len = STRUCT_SIZE("nodemask_t")) < 0) @@ -13617,6 +13743,7 @@ return; } + order = objects = 0; si->cache_count = get_kmem_cache_list(&si->cache_list); si->cache_buf = GETBUF(SIZE(kmem_cache)); @@ -14401,6 +14528,7 @@ break; default: + cpu_slab_ptr = 0; error(FATAL, "cannot determine location of kmem_cache.cpu_slab page\n"); } --- crash-4.0.9/filesys.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/filesys.c 2009-09-15 15:31:45.000000000 -0400 @@ -1026,6 +1026,8 @@ void open_tmpfile(void) { + int ret; + if (pc->tmpfile) error(FATAL, "recursive temporary file usage\n"); @@ -1035,7 +1037,7 @@ } fflush(pc->tmpfile); - ftruncate(fileno(pc->tmp_fp), 0); + ret = ftruncate(fileno(pc->tmp_fp), 0); rewind(pc->tmp_fp); pc->tmpfile = pc->tmp_fp; @@ -1066,9 +1068,11 @@ void close_tmpfile(void) { + int ret; + if (pc->tmpfile) { fflush(pc->tmpfile); - ftruncate(fileno(pc->tmpfile), 0); + ret = ftruncate(fileno(pc->tmpfile), 0); rewind(pc->tmpfile); pc->tmpfile = NULL; fp = pc->saved_fp; @@ -1274,6 +1278,8 @@ s_dirty = OFFSET(super_block_s_dirty); + dirp = dentry = mnt_parent = sb_s_files = 0; + dentry_list = NULL; mntlist = 0; ld = &list_data; @@ -1543,8 +1549,10 @@ if (inode) { inode_buf = fill_inode_cache(inode); superblock = ULONG(inode_buf + OFFSET(inode_i_sb)); - } else + } else { + inode_buf = NULL; superblock = 0; + } if (!inode || !superblock) goto nopath; @@ -1954,6 +1962,7 @@ char *refarg; ref = NULL; + refarg = NULL; flag = 0; while ((c = getopt(argcnt, args, "d:lR:")) != EOF) { @@ -2082,6 +2091,7 @@ char *files_struct_buf, *fdtable_buf = NULL; ulong fs_struct_addr; char *dentry_buf, *fs_struct_buf; + char *ret; ulong root_dentry, pwd_dentry; ulong root_inode, pwd_inode; ulong vfsmnt; @@ -2325,7 +2335,7 @@ DUMP_FULL_NAME|DUMP_EMPTY_FILE)) { BZERO(buf4, BUFSIZE); rewind(pc->tmpfile); - fgets(buf4, BUFSIZE, + ret = fgets(buf4, BUFSIZE, pc->tmpfile); close_tmpfile(); ref->refp = buf4; @@ -2535,6 +2545,8 @@ char buf2[BUFSIZE]; char buf3[BUFSIZE]; + file_buf = NULL; + if (!dentry && file) { file_buf = fill_file_cache(file); dentry = ULONG(file_buf + OFFSET(file_f_dentry)); @@ -3008,6 +3020,7 @@ sprintf(fuser_header, " PID %s COMM USAGE\n", mkstring(buf, VADDR_PRLEN, CENTER, "TASK")); + doing_lockd = doing_fds = doing_mmap = 0; subsequent = 0; while (args[optind]) { spec_string = args[optind]; @@ -3184,6 +3197,7 @@ return FALSE; params = 0; + freemem = memtotal = freeswap = swaptotal = 0; while (fgets(buf, BUFSIZE, mp)) { if (strstr(buf, "SwapFree")) { @@ -3640,6 +3654,8 @@ ulong root_rnode; void *ret; + count = 0; + if (!VALID_STRUCT(radix_tree_root) || !VALID_STRUCT(radix_tree_node) || !VALID_MEMBER(radix_tree_root_height) || !VALID_MEMBER(radix_tree_root_rnode) || --- crash-4.0.9/help.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/help.c 2009-09-21 08:44:58.000000000 -0400 @@ -809,7 +809,7 @@ char *help_ps[] = { "ps", "display process status information", -"[-k|-u][-s][-p|-c|-t|-l|-a|-g|-r] [pid | taskp | command] ...", +"[-k|-u|-G][-s][-p|-c|-t|-l|-a|-g|-r] [pid | taskp | command] ...", " This command displays process status for selected, or all, processes" , " in the system. If no arguments are entered, the process data is", " is displayed for all processes. Selected process identifiers can be", @@ -820,6 +820,7 @@ " are all numerical values, precede the name string with a \"\\\".", " -k select all kernel threads.", " -u select all user tasks.", +" -G display only the thread group leader in a thread group.", " ", " The process identifier types may be mixed. For each task, the following", " items are displayed:", @@ -945,6 +946,25 @@ " PID: 686 TASK: c13fa000 CPU: 0 COMMAND: \"kpanel\"", " PID: 687 TASK: c13f0000 CPU: 1 COMMAND: \"kbgndwm\"", " ", +" Display all threads in a firefox session:\n", +" %s> ps firefox", +" PID PPID CPU TASK ST %MEM VSZ RSS COMM", +" 21273 21256 6 ffff81003ec15080 IN 46.3 1138276 484364 firefox", +" 21276 21256 6 ffff81003f49e7e0 IN 46.3 1138276 484364 firefox", +" 21280 21256 0 ffff81003ec1d7e0 IN 46.3 1138276 484364 firefox", +" 21286 21256 6 ffff81000b0d1820 IN 46.3 1138276 484364 firefox", +" 21287 21256 2 ffff81000b0d10c0 IN 46.3 1138276 484364 firefox", +" 26975 21256 5 ffff81003b5c1820 IN 46.3 1138276 484364 firefox", +" 26976 21256 5 ffff810023232820 IN 46.3 1138276 484364 firefox", +" 26977 21256 4 ffff810021a11820 IN 46.3 1138276 484364 firefox", +" 26978 21256 5 ffff810003159040 IN 46.3 1138276 484364 firefox", +" 26979 21256 5 ffff81003a058820 IN 46.3 1138276 484364 firefox", +" ", +" Display only the thread group leader in the firefox session:\n", +" %s> ps -G firefox", +" PID PPID CPU TASK ST %MEM VSZ RSS COMM", +" 21273 21256 0 ffff81003ec15080 IN 46.3 1138276 484364 firefox", +" ", " Show the time usage data for pid 18844:\n", " %s> ps -t 18844", " PID: 18844 TASK: c3012000 CPU: 0 COMMAND: \"bash\"", --- crash-4.0.9/task.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/task.c 2009-10-06 15:07:43.000000000 -0400 @@ -35,6 +35,7 @@ static void parent_list(ulong); static void child_list(ulong); static void initialize_task_state(void); +static void show_ps_data(ulong, struct task_context *); static void show_task_times(struct task_context *, ulong); static void show_task_args(struct task_context *); static void show_task_rlimit(struct task_context *); @@ -635,6 +636,9 @@ if (ACTIVE() && !(tt->flags & TASK_REFRESH)) return; + curpid = NO_PID; + curtask = NO_TASK; + /* * The current task's task_context entry may change, * or the task may not even exist anymore. @@ -718,7 +722,7 @@ for (i = 0; i < NR_CPUS; i++) { if (tc->task == tt->active_set[i]) { error(WARNING, - "active task %lx on cpu %d: corrupt cpu value: %d\n\n", + "active task %lx on cpu %d: corrupt cpu value: %u\n\n", tc->task, i, tc->processor); tc->processor = i; return TRUE; @@ -727,7 +731,7 @@ if (CRASHDEBUG(1)) error(INFO, - "verify_task: task: %lx invalid processor: %d", + "verify_task: task: %lx invalid processor: %u", tc->task, tc->processor); return FALSE; } @@ -775,6 +779,10 @@ if (ACTIVE() && !(tt->flags & TASK_REFRESH)) return; + curpid = NO_PID; + curtask = NO_TASK; + tp = NULL; + /* * The current task's task_context entry may change, * or the task may not even exist anymore. @@ -944,6 +952,9 @@ if (ACTIVE() && !(tt->flags & TASK_REFRESH)) return; + curpid = NO_PID; + curtask = NO_TASK; + /* * The current task's task_context entry may change, * or the task may not even exist anymore. @@ -1157,6 +1168,9 @@ if (ACTIVE() && !(tt->flags & TASK_REFRESH)) return; + curpid = NO_PID; + curtask = NO_TASK; + /* * The current task's task_context entry may change, * or the task may not even exist anymore. @@ -1358,6 +1372,9 @@ if (ACTIVE() && !(tt->flags & TASK_REFRESH)) return; + curpid = NO_PID; + curtask = NO_TASK; + /* * The current task's task_context entry may change, * or the task may not even exist anymore. @@ -1625,6 +1642,9 @@ if (ACTIVE() && !(tt->flags & TASK_REFRESH)) return; + curpid = NO_PID; + curtask = NO_TASK; + /* * The current task's task_context entry may change, * or the task may not even exist anymore. @@ -1860,6 +1880,9 @@ if (ACTIVE() && !(tt->flags & TASK_REFRESH)) return; + curpid = NO_PID; + curtask = NO_TASK; + /* * The current task's task_context entry may change, * or the task may not even exist anymore. @@ -2090,6 +2113,10 @@ if (ACTIVE() && !(tt->flags & TASK_REFRESH)) return; + curtask = NO_TASK; + curpid = NO_PID; + retries = 0; + get_active_set(); /* * The current task's task_context entry may change, @@ -2200,6 +2227,8 @@ int has_cpu; int do_verify; + processor_addr = NULL; + if (tt->refresh_task_table == refresh_fixed_task_table) do_verify = 1; else if (tt->refresh_task_table == refresh_pid_hash_task_table) @@ -2685,7 +2714,7 @@ BZERO(&psinfo, sizeof(struct psinfo)); flag = 0; - while ((c = getopt(argcnt, args, "gstcpkular")) != EOF) { + while ((c = getopt(argcnt, args, "gstcpkuGlar")) != EOF) { switch(c) { case 'k': @@ -2698,6 +2727,9 @@ flag &= ~PS_KERNEL; break; + case 'G': + flag |= PS_GROUP; + break; /* * The a, t, c, p, g and l flags are all mutually-exclusive. */ @@ -2808,80 +2840,95 @@ /* * Do the work requested by cmd_ps(). */ +static void +show_ps_data(ulong flag, struct task_context *tc) +{ + struct task_mem_usage task_mem_usage, *tm; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; + char buf3[BUFSIZE]; + ulong tgid; -#define SHOW_PS_DATA() \ - if ((flag & PS_USER) && is_kernel_thread(tc->task)) \ - continue; \ - if ((flag & PS_KERNEL) && !is_kernel_thread(tc->task)) \ - continue; \ - if (flag & PS_PPID_LIST) { \ - parent_list(tc->task); \ - fprintf(fp, "\n"); \ - continue; \ - } \ - if (flag & PS_CHILD_LIST) { \ - child_list(tc->task); \ - fprintf(fp, "\n"); \ - continue; \ - } \ - if (flag & PS_LAST_RUN) { \ - show_last_run(tc); \ - continue; \ - } \ - if (flag & PS_ARGV_ENVP) { \ - show_task_args(tc); \ - continue; \ - } \ - if (flag & PS_RLIMIT) { \ - show_task_rlimit(tc); \ - continue; \ - } \ - if (flag & PS_TGID_LIST) { \ - show_tgid_list(tc->task); \ - continue; \ - } \ - get_task_mem_usage(tc->task, tm); \ - fprintf(fp, "%s", is_task_active(tc->task) ? "> " : " "); \ - fprintf(fp, "%5ld %5ld %2s %s %3s", \ - tc->pid, task_to_pid(tc->ptask), \ - task_cpu(tc->processor, buf2, !VERBOSE), \ - task_pointer_string(tc, flag & PS_KSTACKP, buf3), \ - task_state_string(tc->task, buf1, !VERBOSE)); \ - pad_line(fp, strlen(buf1) > 3 ? 1 : 2, ' '); \ - sprintf(buf1, "%.1f", tm->pct_physmem); \ - if (strlen(buf1) == 3) \ - mkstring(buf1, 4, CENTER|RJUST, NULL); \ - fprintf(fp, "%s ", buf1); \ - fprintf(fp, "%7ld ", (tm->total_vm * PAGESIZE())/1024); \ - fprintf(fp, "%6ld ", (tm->rss * PAGESIZE())/1024); \ - if (is_kernel_thread(tc->task)) \ - fprintf(fp, "[%s]\n", tc->comm); \ - else \ - fprintf(fp, "%s\n", tc->comm); + if ((flag & PS_USER) && is_kernel_thread(tc->task)) + return; + if ((flag & PS_KERNEL) && !is_kernel_thread(tc->task)) + return; + if (flag & PS_PPID_LIST) { + parent_list(tc->task); + fprintf(fp, "\n"); + return; + } + if (flag & PS_CHILD_LIST) { + child_list(tc->task); + fprintf(fp, "\n"); + return; + } + if (flag & PS_LAST_RUN) { + show_last_run(tc); + return; + } + if (flag & PS_ARGV_ENVP) { + show_task_args(tc); + return; + } + if (flag & PS_RLIMIT) { + show_task_rlimit(tc); + return; + } + if (flag & PS_TGID_LIST) { + show_tgid_list(tc->task); + return; + } + if (flag & PS_GROUP) { + tgid = task_tgid(tc->task); + if (tc->pid != tgid) { + if (pc->curcmd_flags & TASK_SPECIFIED) { + if (!(tc = tgid_to_context(tgid))) + return; + } else + return; + } + } + tm = &task_mem_usage; + get_task_mem_usage(tc->task, tm); + fprintf(fp, "%s", is_task_active(tc->task) ? "> " : " "); + fprintf(fp, "%5ld %5ld %2s %s %3s", + tc->pid, task_to_pid(tc->ptask), + task_cpu(tc->processor, buf2, !VERBOSE), + task_pointer_string(tc, flag & PS_KSTACKP, buf3), + task_state_string(tc->task, buf1, !VERBOSE)); + pad_line(fp, strlen(buf1) > 3 ? 1 : 2, ' '); + sprintf(buf1, "%.1f", tm->pct_physmem); + if (strlen(buf1) == 3) + mkstring(buf1, 4, CENTER|RJUST, NULL); + fprintf(fp, "%s ", buf1); + fprintf(fp, "%7ld ", (tm->total_vm * PAGESIZE())/1024); + fprintf(fp, "%6ld ", (tm->rss * PAGESIZE())/1024); + if (is_kernel_thread(tc->task)) + fprintf(fp, "[%s]\n", tc->comm); + else + fprintf(fp, "%s\n", tc->comm); +} static void show_ps(ulong flag, struct psinfo *psi) { int i, ac; struct task_context *tc; - struct task_mem_usage task_mem_usage, *tm; int print; - char buf1[BUFSIZE]; - char buf2[BUFSIZE]; - char buf3[BUFSIZE]; + char buf[BUFSIZE]; if (!(flag & PS_EXCLUSIVE)) fprintf(fp, " PID PPID CPU %s ST %%MEM VSZ RSS COMM\n", flag & PS_KSTACKP ? - mkstring(buf1, VADDR_PRLEN, CENTER|RJUST, "KSTACKP") : - mkstring(buf1, VADDR_PRLEN, CENTER, "TASK")); + mkstring(buf, VADDR_PRLEN, CENTER|RJUST, "KSTACKP") : + mkstring(buf, VADDR_PRLEN, CENTER, "TASK")); if (flag & PS_LAST_RUN) sort_context_array_by_last_run(); if (flag & PS_SHOW_ALL) { - tm = &task_mem_usage; if (flag & PS_TIMES) { show_task_times(NULL, flag); @@ -2889,9 +2936,8 @@ } tc = FIRST_CONTEXT(); - for (i = 0; i < RUNNING_TASKS(); i++, tc++) { - SHOW_PS_DATA(); - } + for (i = 0; i < RUNNING_TASKS(); i++, tc++) + show_ps_data(flag, tc); return; } @@ -2899,7 +2945,6 @@ pc->curcmd_flags |= TASK_SPECIFIED; for (ac = 0; ac < psi->argc; ac++) { - tm = &task_mem_usage; tc = FIRST_CONTEXT(); for (i = 0; i < RUNNING_TASKS(); i++, tc++) { @@ -2919,7 +2964,7 @@ case PS_BY_CMD: if (STREQ(tc->comm, psi->comm[ac])) { - if (flag & PS_TGID_LIST) { + if (flag & (PS_TGID_LIST|PS_GROUP)) { if (tc->pid == task_tgid(tc->task)) print = TRUE; else @@ -2935,9 +2980,8 @@ show_task_times(tc, flag); else if (flag & PS_LAST_RUN) show_last_run(tc); - else { - SHOW_PS_DATA(); - } + else + show_ps_data(flag, tc); } } } @@ -3119,6 +3163,8 @@ char buf2[BUFSIZE]; char buf3[BUFSIZE]; + rlimit_index = 0; + if (!VALID_MEMBER(task_struct_rlim) && !VALID_MEMBER(signal_struct_rlim)) { MEMBER_OFFSET_INIT(task_struct_rlim, "task_struct", "rlim"); MEMBER_OFFSET_INIT(signal_struct_rlim, "signal_struct", "rlim"); @@ -4373,6 +4419,7 @@ ulong last_run; ulonglong timestamp; + timestamp = 0; fill_task_struct(task); if (VALID_MEMBER(task_struct_last_run)) { @@ -5030,6 +5077,7 @@ } print_header = TRUE; + bt = NULL; for (k = 0; k < fd->keys; k++) { switch(fd->keyword_array[k]) @@ -5624,6 +5672,7 @@ tc = tt->current; others = 0; + more = FALSE; fprintf(fp, " current: %lx [%ld]\n", (ulong)tt->current, (ulong)(tt->current - tt->context_array)); @@ -6163,6 +6212,8 @@ if (tt->flags & ACTIVE_SET) return TRUE; + per_cpu = FALSE; + if (symbol_exists("runqueues")) { runq = symbol_value("runqueues"); per_cpu = FALSE; @@ -6547,6 +6598,7 @@ return; } + offs = runqueue_head = 0; qlen = 1000; start_again: @@ -6608,14 +6660,16 @@ struct task_context *tc; int per_cpu; - if (symbol_exists("runqueues")) { runq = symbol_value("runqueues"); per_cpu = FALSE; } else if (symbol_exists("per_cpu__runqueues")) { runq = symbol_value("per_cpu__runqueues"); per_cpu = TRUE; - } + } else { + runq = 0; + per_cpu = FALSE; + } get_active_set(); runqbuf = GETBUF(SIZE(runqueue)); @@ -7376,6 +7430,9 @@ char buf3[BUFSIZE]; char buf4[BUFSIZE]; + sigpending = sigqueue = 0; + sighand_struct = signal_struct = 0; + if (VALID_STRUCT(sigqueue) && !VALID_MEMBER(sigqueue_next)) { MEMBER_OFFSET_INIT(sigqueue_next, "sigqueue", "next"); MEMBER_OFFSET_INIT(sigqueue_list, "sigqueue", "list"); @@ -7688,8 +7745,8 @@ static ulonglong task_signal(ulong task, ulong *signal) { - ulonglong sigset; ulong *sigset_ptr; + ulonglong sigset = 0; if (task) { fill_task_struct(task); @@ -7757,6 +7814,7 @@ ulonglong sigset; ulong *sigset_ptr; + sigset = 0; sigset_ptr = (ulong *)(sigaction + OFFSET(sigaction_sa_mask)); switch (_NSIG_WORDS) --- crash-4.0.9/kernel.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/kernel.c 2009-10-05 10:12:15.000000000 -0400 @@ -204,6 +204,10 @@ rqstruct = "runqueue"; else if (STRUCT_EXISTS("rq")) rqstruct = "rq"; + else { + rqstruct = NULL; + error(FATAL, "neither runqueue nor rq structures exist\n"); + } MEMBER_OFFSET_INIT(runqueue_cpu, rqstruct, "cpu"); /* @@ -1109,7 +1113,7 @@ ulong offset; struct syment *sp; struct gnu_request *req; - char *savename; + char *savename, *ret; char buf1[BUFSIZE]; char buf2[BUFSIZE]; char buf3[BUFSIZE]; @@ -1414,7 +1418,7 @@ if (LASTCHAR(clean_line(buf2)) != ':') break; - fgets(buf2, BUFSIZE, pc->tmpfile); + ret = fgets(buf2, BUFSIZE, pc->tmpfile); if (do_load_module_filter) load_module_filter(buf2, LM_DIS_FILTER); @@ -1522,6 +1526,7 @@ sprintf(buf1, "x/%ldi 0x%lx", spn->value - sp->value, sp->value); found = FALSE; + vaddr = 0; open_tmpfile(); gdb_pass_through(buf1, pc->tmpfile, GNU_RETURN_ON_ERROR); rewind(pc->tmpfile); @@ -2575,6 +2580,7 @@ STRUCT_SIZE_INIT(module, "module"); MEMBER_OFFSET_INIT(module_name, "module", "name"); MEMBER_OFFSET_INIT(module_syms, "module", "syms"); + mod_next = nsyms = 0; switch (kt->flags & (KMOD_V1|KMOD_V2)) { @@ -2801,6 +2807,7 @@ } mods_installed = irregularities = 0; + mod_base = mod_next = 0; modbuf = GETBUF(SIZE(module)); for (mod = module_list; mod != kt->kernel_module; mod = mod_next) { @@ -3604,6 +3611,7 @@ buf = GETBUF(log_buf_len); log_wrap = FALSE; + last = 0; get_symbol_data("log_end", sizeof(ulong), &log_end); readmem(log_buf, KVADDR, buf, log_buf_len, "log_buf contents", FAULT_ON_ERROR); @@ -4155,6 +4163,7 @@ int others; others = 0; + more = FALSE; uts = &kt->utsname; fprintf(fp, " flags: %lx\n (", kt->flags); @@ -4513,6 +4522,7 @@ { struct datatype_member datatype_member, *dm; ulong irq_desc_addr; + ulong irq_desc_ptr; long len; char buf[BUFSIZE]; int status, depth, others; @@ -4529,8 +4539,22 @@ irq_desc_addr = symbol_value("irq_desc") + (len * irq); else if (symbol_exists("_irq_desc")) irq_desc_addr = symbol_value("_irq_desc") + (len * irq); - else - error(FATAL, "neither irq_desc nor _irq_desc symbols exist\n"); + else if (symbol_exists("irq_desc_ptrs")) { + get_symbol_data("irq_desc_ptrs", sizeof(void *), &irq_desc_ptr); + irq_desc_ptr += (irq * sizeof(void *)); + readmem(irq_desc_ptr, KVADDR, &irq_desc_addr, + sizeof(void *), "irq_desc_ptrs entry", + FAULT_ON_ERROR); + if (!irq_desc_addr) { + fprintf(fp, " IRQ: %d (unused)\n\n", irq); + return; + } + } else { + irq_desc_addr = 0; + error(FATAL, + "neither irq_desc, _irq_desc, nor irq_desc_ptrs " + "symbols exist\n"); + } readmem(irq_desc_addr + OFFSET(irq_desc_t_status), KVADDR, &status, sizeof(int), "irq_desc entry", FAULT_ON_ERROR); @@ -4921,30 +4945,7 @@ readmem(action+OFFSET(irqaction_flags), KVADDR, &value, sizeof(void *), "irqaction flags", FAULT_ON_ERROR); - fprintf(fp, " flags: %lx ", value); - if (value) { - others = 0; - fprintf(fp, "("); - - if (value & SA_INTERRUPT) - fprintf(fp, "%sSA_INTERRUPT", - others++ ? "|" : ""); - if (value & SA_PROBE) - fprintf(fp, "%sSA_PROBE", - others++ ? "|" : ""); - if (value & SA_SAMPLE_RANDOM) - fprintf(fp, "%sSA_SAMPLE_RANDOM", - others++ ? "|" : ""); - if (value & SA_SHIRQ) - fprintf(fp, "%sSA_SHIRQ", others++ ? "|" : ""); - - fprintf(fp, ")"); - if (value & ~ACTION_FLAGS) { - fprintf(fp, " (bits %lx not translated)", - value & ~ACTION_FLAGS); - } - } - fprintf(fp, "\n"); + fprintf(fp, " flags: %lx\n", value); readmem(action+OFFSET(irqaction_mask), KVADDR, &tmp1, sizeof(void *), @@ -5724,9 +5725,9 @@ long sz; ulong offset; + tdx = 0; td = option ? (struct timer_data *)option : NULL; if (td) { - tdx = 0; while (td[tdx].function) tdx++; } --- crash-4.0.9/gdb_interface.c 2009-10-07 11:39:57.000000000 -0400 +++ crash-4.1.0/gdb_interface.c 2009-09-15 08:50:52.000000000 -0400 @@ -619,9 +619,11 @@ FREEBUF(req); if (retval && merge_orig_args) { - argcnt = 2; + int i; + for (i = argcnt; i; i--) + args[i] = args[i-1]; args[0] = "gdb"; - args[1] = pc->orig_line; + argcnt++; } return retval; --- crash-4.0.9/configure.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/configure.c 2009-09-28 11:19:47.000000000 -0400 @@ -75,7 +75,6 @@ void make_build_data(char *); void make_spec_file(void); void gdb_configure(void); -int verify_rpm_targets(void); int parse_line(char *, char **); int setup_gdb_defaults(void); struct supported_gdb_version; @@ -424,6 +423,9 @@ get_current_configuration(); + target = target_CFLAGS = NULL; + gdb_version = gdb_version_in = gdb_files = gdb_ofiles = NULL; + switch (target_data.target) { case X86: @@ -528,9 +530,6 @@ char buf[512]; char gdb_files[MAXSTRLEN]; - if (!verify_rpm_targets()) - exit(1); - get_current_configuration(); sprintf(buf, "%s/gdb", gdb_version); @@ -631,90 +630,6 @@ fclose(fp); } -/* - * Verify that the rpm build area will be in /usr/src/redhat by checking - * for the default settings (indicated by "rpm --showrc"). - */ - -#define DEFAULT_RPM_DIR "%{_topdir}/" -#define DEFAULT_TOPDIR "%{_usrsrc}/redhat" -#define DEFAULT_USRSRC "%{_usr}/src" -#define DEFAULT_USR "/usr" - -int -verify_rpm_targets(void) -{ - int errors; - char inbuf[4096], *p1, *p2; - FILE *fpr; - - errors = 0; - fpr = popen("/bin/rpm --showrc", "r"); - - while (fgets(inbuf, 4095, fpr)) { - if ((p1 = strstr(inbuf, ": _topdir ")) && - !strstr(p1, DEFAULT_TOPDIR)) { - p2 = p1 + strlen(": _topdir"); - fprintf(stderr, "non-default rpm top directory: %s", - p2+1); - errors++; - } - if ((p1 = strstr(inbuf, ": _usrsrc ")) && - !strstr(p1, DEFAULT_USRSRC)) { - p2 = p1 + strlen(": _usrsrc"); - fprintf(stderr,"non-default rpm /usr/src directory: %s", - p2+1); - errors++; - } - if ((p1 = strstr(inbuf, ": _usr ")) && - !strstr(p1, DEFAULT_USR)) { - p2 = p1 + strlen(": _usr"); - fprintf(stderr,"non-default rpm /usr directory: %s", p2+1); - errors++; - } - - if ((p1 = strstr(inbuf, ": _builddir ")) && - !strstr(p1, DEFAULT_RPM_DIR "BUILD")) { - p2 = p1 + strlen(": _builddir"); - fprintf(stderr, "non-default rpm BUILD directory: %s", - p2+1); - errors++; - } - if ((p1 = strstr(inbuf, ": _rpmdir ")) && - !strstr(p1, DEFAULT_RPM_DIR "RPMS")) { - p2 = p1 + strlen(": _rpmdir"); - fprintf(stderr, "non-default rpm RPMS directory: %s", - p2+1); - errors++; - } - if ((p1 = strstr(inbuf, ": _sourcedir ")) && - !strstr(p1, DEFAULT_RPM_DIR "SOURCES")) { - p2 = p1 + strlen(": _sourcedir"); - fprintf(stderr, "non-default rpm SOURCES directory: %s", - p2+1); - errors++; - } - if ((p1 = strstr(inbuf, ": _specdir ")) && - !strstr(p1, DEFAULT_RPM_DIR "SPECS")) { - p2 = p1 + strlen(": _specdir"); - fprintf(stderr, "non-default rpm SPECS directory: %s", - p2+1); - errors++; - } - if ((p1 = strstr(inbuf, ": _srcrpmdir ")) && - !strstr(p1, DEFAULT_RPM_DIR "SRPMS")) { - p2 = p1 + strlen(": _srcrpmdir"); - fprintf(stderr, "non-default rpm SRPMS directory: %s", - p2+1); - errors++; - } - } - - return (errors ? FALSE : TRUE); -} - - - void gdb_configure(void) { @@ -724,6 +639,8 @@ get_current_configuration(); + gdb_version = NULL; + switch (target_data.target) { case X86: @@ -1095,14 +1012,14 @@ if (gethostname(hostname, MAXSTRLEN) != 0) hostname[0] = '\0'; - fgets(inbuf1, 79, fp1); + p = fgets(inbuf1, 79, fp1); - fgets(inbuf2, 79, fp2); + p = fgets(inbuf2, 79, fp2); p = strstr(inbuf2, ")"); p++; *p = '\0'; - fgets(inbuf3, 79, fp3); + p = fgets(inbuf3, 79, fp3); lower_case(target_data.program, progname); @@ -1199,6 +1116,7 @@ printf("* sial: Provides C-like language for writing dump analysis scripts\n"); printf("* dminfo: Device-mapper target analyzer\n"); printf("* snap: Takes a snapshot of live memory and creates a kdump dumpfile\n"); + printf("* trace: Displays kernel tracing data and traced events that occurred prior to a panic.\n"); printf("\n"); printf("%%prep\n"); printf("%%setup -n %%{name}-%%{version}\n"); @@ -1222,11 +1140,13 @@ printf("cp extensions/sial.so %%{buildroot}%%{_libdir}/crash/extensions\n"); printf("cp extensions/dminfo.so %%{buildroot}%%{_libdir}/crash/extensions\n"); printf("cp extensions/snap.so %%{buildroot}%%{_libdir}/crash/extensions\n"); + printf("cp extensions/trace.so %%{buildroot}%%{_libdir}/crash/extensions\n"); printf("\n"); printf("%%clean\n"); printf("rm -rf %%{buildroot}\n"); printf("\n"); printf("%%files\n"); + printf("%%defattr(-,root,root)\n"); printf("/usr/bin/crash\n"); printf("%%{_mandir}/man8/crash.8*\n"); /* printf("/usr/bin/crashd\n"); */ --- crash-4.0.9/net.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/net.c 2009-09-14 16:13:39.000000000 -0400 @@ -788,6 +788,9 @@ BZERO(buf, BUFSIZE); BZERO(buf2, BUFSIZE); sockbuf = inet_sockbuf = NULL; + dport = sport = 0; + family = type = 0; + ipv6_pinfo = 0; switch (net->flags & (SOCK_V1|SOCK_V2)) { --- crash-4.0.9/dev.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/dev.c 2009-09-14 16:11:44.000000000 -0400 @@ -651,6 +651,7 @@ fprintf(fp, "%s\n", mkstring(buf, VADDR_PRLEN, LJUST, "OPERATIONS")); blk_major_name_buf = GETBUF(SIZE(blk_major_name)); + gendisk = 0; for (i = 0; i < len; i++) { addr = symbol_value("major_names") + (i * sizeof(void *)); @@ -896,6 +897,8 @@ char buf1[BUFSIZE]; char *fmt, *p1; + fmt = NULL; + switch (size) { case 4: --- crash-4.0.9/x86.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/x86.c 2009-10-02 14:50:29.000000000 -0400 @@ -476,13 +476,13 @@ text_value_cache(addr, 0, (uint32_t *)&value)) return value; - if (!readmem(addr, KVADDR, data, size, "db_get_value", + if (!readmem(addr, KVADDR, &value, size, "db_get_value", RETURN_ON_ERROR)) error(FATAL, "db_get_value: read error: address: %lx\n", addr); if (size == sizeof(int)) - text_value_cache(addr, *((db_expr_t *)data), NULL); + text_value_cache(addr, value, NULL); } #endif @@ -1821,6 +1821,9 @@ if (symbol_exists("irq_desc")) ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, "irq_desc", NULL, 0); + else if (kernel_symbol_exists("nr_irqs")) + get_symbol_data("nr_irqs", sizeof(unsigned int), + &machdep->nr_irqs); else machdep->nr_irqs = 224; /* NR_IRQS */ if (!machdep->hz) { @@ -3629,6 +3632,7 @@ struct syment *sp; struct machine_specific *ms; + idt = NULL; ms = machdep->machspec; if (ms->idt_table) @@ -3964,7 +3968,7 @@ x86_display_cpu_data(void) { int cpu; - ulong cpu_data; + ulong cpu_data = 0; if (symbol_exists("cpu_data")) cpu_data = symbol_value("cpu_data"); @@ -4109,6 +4113,7 @@ sprintf(buf1, "x/10i 0x%lx", eip); buf2[0] = NULLCHAR; + value = 0; open_tmpfile2(); if (gdb_pass_through(buf1, pc->tmpfile2, GNU_RETURN_ON_ERROR)) { --- crash-4.0.9/ia64.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/ia64.c 2009-10-02 15:05:00.000000000 -0400 @@ -238,10 +238,11 @@ "cpuinfo_ia64", "unimpl_va_mask"); MEMBER_OFFSET_INIT(cpuinfo_ia64_unimpl_pa_mask, "cpuinfo_ia64", "unimpl_pa_mask"); - ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, - "irq_desc", NULL, 0); - if (symbol_exists("irq_desc")) - ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, + if (kernel_symbol_exists("nr_irqs")) + get_symbol_data("nr_irqs", sizeof(unsigned int), + &machdep->nr_irqs); + else if (symbol_exists("irq_desc")) + ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, "irq_desc", NULL, 0); else if (symbol_exists("_irq_desc")) ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, @@ -767,7 +768,8 @@ static void ia64_dump_irq(int irq) { - if (symbol_exists("irq_desc") || symbol_exists("_irq_desc")) { + if (symbol_exists("irq_desc") || symbol_exists("_irq_desc") || + kernel_symbol_exists("irq_desc_ptrs")) { machdep->dump_irq = generic_dump_irq; return(generic_dump_irq(irq)); } --- crash-4.0.9/s390.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/s390.c 2009-10-07 15:16:15.000000000 -0400 @@ -163,7 +163,7 @@ fprintf(fp, " hz: %d\n", machdep->hz); fprintf(fp, " mhz: %ld\n", machdep->mhz); fprintf(fp, " memsize: %lld (0x%llx)\n", - machdep->memsize, machdep->memsize); + (ulonglong)machdep->memsize, (ulonglong)machdep->memsize); fprintf(fp, " bits: %d\n", machdep->bits); fprintf(fp, " nr_irqs: %d\n", machdep->nr_irqs); fprintf(fp, " eframe_search: s390_eframe_search()\n"); @@ -458,13 +458,17 @@ if ((c = parse_line(buf, arglist)) != 3) error(FATAL, "cannot determine swap location\n"); + sprintf(ptebuf, "%lx", pte); + len1 = MAX(strlen(ptebuf), strlen("PTE")); len2 = MAX(strlen(arglist[0]), strlen("SWAP")); len3 = MAX(strlen(arglist[2]), strlen("OFFSET")); - fprintf(fp, "%s %s\n", + fprintf(fp, "%s %s %s\n", + mkstring(ptebuf, len1, CENTER|LJUST, "PTE"), mkstring(buf2, len2, CENTER|LJUST, "SWAP"), mkstring(buf3, len3, CENTER|LJUST, "OFFSET")); + sprintf(ptebuf, "%lx", pte); strcpy(buf2, arglist[0]); strcpy(buf3, arglist[2]); fprintf(fp, "%s %s %s\n", @@ -614,6 +618,7 @@ error(WARNING, "instruction pointer argument ignored on this architecture!\n"); } + async_end = async_start = 0; ksp = bt->stkptr; /* print lowcore and get async stack when task has cpu */ --- crash-4.0.9/s390x.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/s390x.c 2009-09-15 16:43:50.000000000 -0400 @@ -467,13 +467,17 @@ if ((c = parse_line(buf, arglist)) != 3) error(FATAL, "cannot determine swap location\n"); + sprintf(ptebuf, "%lx", pte); + len1 = MAX(strlen(ptebuf), strlen("PTE")); len2 = MAX(strlen(arglist[0]), strlen("SWAP")); len3 = MAX(strlen(arglist[2]), strlen("OFFSET")); - fprintf(fp, "%s %s\n", + fprintf(fp, "%s %s %s\n", + mkstring(ptebuf, len1, CENTER|LJUST, "PTE"), mkstring(buf2, len2, CENTER|LJUST, "SWAP"), mkstring(buf3, len3, CENTER|LJUST, "OFFSET")); + sprintf(ptebuf, "%lx", pte); strcpy(buf2, arglist[0]); strcpy(buf3, arglist[2]); fprintf(fp, "%s %s %s\n", --- crash-4.0.9/s390dbf.c 2009-10-07 11:39:57.000000000 -0400 +++ crash-4.1.0/s390dbf.c 2009-09-15 16:14:35.000000000 -0400 @@ -715,11 +715,12 @@ debug_entry_t *act_entry, *last_entry; char *act_entry_data; char buf[2048]; + size_t items; /* print prolog */ if (view->prolog_proc) { len = view->prolog_proc(debug_area, view, buf); - fwrite(buf,len, 1, ofp); + items = fwrite(buf,len, 1, ofp); memset(buf, 0, 2048); } /* print debug records */ @@ -744,13 +745,13 @@ if (view->header_proc) { len = view->header_proc(debug_area, view, i, act_entry, buf); - fwrite(buf,len, 1, ofp); + items = fwrite(buf,len, 1, ofp); memset(buf, 0, 2048); } if (view->format_proc) { len = view->format_proc(debug_area, view, buf, act_entry_data); - fwrite(buf,len, 1, ofp); + items = fwrite(buf,len, 1, ofp); memset(buf, 0, 2048); } act_entry = @@ -776,11 +777,12 @@ debug_entry_t *act_entry; char *act_entry_data; char buf[2048]; + size_t items; /* print prolog */ if (view->prolog_proc) { len = view->prolog_proc(debug_area, view, buf); - fwrite(buf,len, 1, ofp); + items = fwrite(buf,len, 1, ofp); memset(buf, 0, 2048); } /* print debug records */ @@ -801,13 +803,13 @@ if (view->header_proc) { len = view->header_proc(debug_area, view, i, act_entry, buf); - fwrite(buf,len, 1, ofp); + items = fwrite(buf,len, 1, ofp); memset(buf, 0, 2048); } if (view->format_proc) { len = view->format_proc(debug_area, view, buf, act_entry_data); - fwrite(buf,len, 1, ofp); + items = fwrite(buf,len, 1, ofp); memset(buf, 0, 2048); } act_entry = (debug_entry_t *) (((char *) --- crash-4.0.9/ppc64.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/ppc64.c 2009-10-02 14:52:30.000000000 -0400 @@ -223,6 +223,9 @@ if (symbol_exists("irq_desc")) ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, "irq_desc", NULL, 0); + else if (kernel_symbol_exists("nr_irqs")) + get_symbol_data("nr_irqs", sizeof(unsigned int), + &machdep->nr_irqs); else machdep->nr_irqs = 0; @@ -1803,6 +1806,8 @@ { ulong ksp, nip; + nip = ksp = 0; + if (DUMPFILE() && is_task_active(bt->task)) ppc64_get_dumpfile_stack_frame(bt, &nip, &ksp); else @@ -1919,11 +1924,12 @@ /* typename */ readmem(ctl + OFFSET(hw_interrupt_type_typename), KVADDR, &addr, sizeof(ulong), "typename pointer", FAULT_ON_ERROR); - read_string(addr, typename, 32); - if(typename) - fprintf(fp, " typename: %08lx \"%s\"\n", - addr, typename); + fprintf(fp, " typename: %08lx ", addr); + if (read_string(addr, typename, 32)) + fprintf(fp, "\"%s\"\n", typename); + else + fprintf(fp, "\n"); /* startup...I think this is always 0 */ readmem(ctl + OFFSET(hw_interrupt_type_startup), KVADDR, &addr, @@ -2032,11 +2038,12 @@ /* name */ readmem(action + OFFSET(irqaction_name), KVADDR, &addr, sizeof(ulong), "action name", FAULT_ON_ERROR); - read_string(addr, typename, 32); - if(typename) - fprintf(fp, " name: %08lx \"%s\"\n", - addr, typename); + fprintf(fp, " name: %08lx ", addr); + if (read_string(addr, typename, 32)) + fprintf(fp, "\"%s\"\n", typename); + else + fprintf(fp, "\n"); /* dev_id */ readmem(action + OFFSET(irqaction_dev_id), KVADDR, &value, @@ -2421,10 +2428,12 @@ map = PRESENT; else if (cpu_map_addr("online")) map = ONLINE; - else + else { + map = 0; error(FATAL, "PPC64: cannot find 'cpu_possible_map' or\ 'cpu_present_map' or 'cpu_online_map' symbols\n"); + } if (!MEMBER_EXISTS("paca_struct", "data_offset")) return; --- crash-4.0.9/x86_64.c 2009-10-07 11:39:57.000000000 -0400 +++ crash-4.1.0/x86_64.c 2009-10-06 09:58:06.000000000 -0400 @@ -262,7 +262,7 @@ case POST_GDB: if (THIS_KERNEL_VERSION >= LINUX(2,6,26) && THIS_KERNEL_VERSION < LINUX(2,6,31)) { - machdep->machspec->vmalloc_start_addr = VMALLOC_START_ADDR_2_6_26; + machdep->machspec->modules_vaddr = MODULES_VADDR_2_6_26; } if (THIS_KERNEL_VERSION >= LINUX(2,6,27) && THIS_KERNEL_VERSION < LINUX(2,6,31)) { @@ -330,7 +330,10 @@ else ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, "irq_desc", NULL, 0); - } else + } else if (kernel_symbol_exists("nr_irqs")) + get_symbol_data("nr_irqs", sizeof(unsigned int), + &machdep->nr_irqs); + else machdep->nr_irqs = 224; /* NR_IRQS (at least) */ machdep->vmalloc_start = x86_64_vmalloc_start; machdep->dump_irq = x86_64_dump_irq; @@ -628,6 +631,9 @@ struct syment *sp, *nsp; ulong offset, istacksize; + _boot_cpu_pda = FALSE; + level4_pgt = 0; + STRUCT_SIZE_INIT(x8664_pda, "x8664_pda"); MEMBER_OFFSET_INIT(x8664_pda_pcurrent, "x8664_pda", "pcurrent"); MEMBER_OFFSET_INIT(x8664_pda_data_offset, "x8664_pda", "data_offset"); @@ -857,7 +863,7 @@ break; } } else if (symbol_exists("per_cpu__init_tss")) { - for (c = 0; c < NR_CPUS; c++) { + for (c = 0; c < kt->cpus; c++) { if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF)) { if (kt->__per_cpu_offset[c] == 0) break; @@ -2132,8 +2138,8 @@ static void x86_64_do_bt_reference_check(struct bt_info *bt, ulong text, char *name) { - struct syment *sp; ulong offset; + struct syment *sp = NULL; if (!name) sp = value_search(text, &offset); @@ -4011,7 +4017,8 @@ static void x86_64_dump_irq(int irq) { - if (symbol_exists("irq_desc")) { + if (symbol_exists("irq_desc") || + kernel_symbol_exists("irq_desc_ptrs")) { machdep->dump_irq = generic_dump_irq; return(generic_dump_irq(irq)); } @@ -4207,6 +4214,7 @@ return cpus; } + _boot_cpu_pda = FALSE; cpu_pda_buf = GETBUF(SIZE(x8664_pda)); if (LKCD_KERNTYPES()) { @@ -4334,6 +4342,10 @@ ulong cpu_data; ulong cpu_pda, cpu_pda_addr; + boot_cpu = _cpu_pda = FALSE; + cpu_data = cpu_pda = 0; + cpus = 0; + if (symbol_exists("cpu_data")) { cpu_data = symbol_value("cpu_data"); cpus = kt->cpus; --- crash-4.0.9/remote.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/remote.c 2009-09-14 15:55:26.000000000 -0400 @@ -2953,6 +2953,8 @@ long pct, last; ulong size, offset, filesize; ulong ret, req, tot; + int sysret; + ssize_t bytes; last = -1; lseek(fd, 0, SEEK_SET); @@ -2964,7 +2966,7 @@ BZERO(sendbuf, BUFSIZE); sprintf(sendbuf, "READ %d %lx %ld", rfp->fd, offset, size); - write(pc->sockfd, sendbuf, strlen(sendbuf)); + bytes = write(pc->sockfd, sendbuf, strlen(sendbuf)); bzero(readbuf, READBUFSIZE); @@ -3012,7 +3014,7 @@ sprintf(readbuf, "echo -e -n \"\\b\\b\\b\\b%ld%%)\"", pct); - system(readbuf); + sysret = system(readbuf); last = pct; } } @@ -3060,6 +3062,7 @@ bzero(readbuf, READBUFSIZE); done = total = 0; + gtot = 0; while (!done) { @@ -3307,6 +3310,7 @@ bzero(readbuf, READBUFSIZE); done = total = 0; + dtot = 0; while (!done) { @@ -3490,6 +3494,7 @@ bzero(readbuf, READBUFSIZE); done = total = 0; + dtot = 0; while (!done) { --- crash-4.0.9/symbols.c 2009-10-07 11:39:57.000000000 -0400 +++ crash-4.1.0/symbols.c 2009-10-06 14:50:49.000000000 -0400 @@ -61,7 +61,7 @@ static int separate_debug_file_exists(const char *, unsigned long, int *); static int store_module_kallsyms_v1(struct load_module *, int, int, char *); static int store_module_kallsyms_v2(struct load_module *, int, int, char *); -static void datatype_error(ulong *, char *, char *, char *, int); +static void datatype_error(void **, char *, char *, char *, int); static char *get_thisfile(void); struct elf_common; static void Elf32_Sym_to_common(Elf32_Sym *, struct elf_common *); @@ -1019,7 +1019,7 @@ modbuf = GETBUF(SIZE(module)); modsymbuf = NULL; - m = mcnt = 0; + m = mcnt = mod_next = 0; for (mod = kt->module_list; mod != kt->kernel_module; mod = mod_next) { @@ -1269,7 +1269,7 @@ modbuf = GETBUF(SIZE(module)); modsymbuf = NULL; - m = mcnt = 0; + m = mcnt = mod_next = 0; for (mod = kt->module_list; mod != kt->kernel_module; mod = mod_next) { @@ -1738,6 +1738,7 @@ return 0; mcnt = 0; + BZERO(&elf_common, sizeof(struct elf_common)); mcnt_idx = curr; ns = &st->ext_module_namespace; ec = &elf_common; @@ -2140,6 +2141,8 @@ ulong start, end; struct syment *sp; + start = 0; + if (pc->flags & SYSMAP) { sp = st->symtable; if ((value >= sp->value) && (value < kt->etext)) @@ -2689,7 +2692,7 @@ switch (swap16(elf32->e_machine, swap)) { case EM_386: - if (machine_type("x86")) + if (machine_type("X86")) return TRUE; break; @@ -2723,6 +2726,11 @@ if (machine_type("X86_64")) return TRUE; break; + + case EM_S390: + if (machine_type("S390X")) + return TRUE; + break; } if (CRASHDEBUG(1)) @@ -3090,11 +3098,17 @@ struct gnu_request request, *req; struct line_number_hook *lnh; char bldbuf[BUFSIZE], *name; + struct load_module *lm; buf[0] = NULLCHAR; if (!is_kernel_text(addr) || GDB_PATCHED()) return(buf); + if (module_symbol(addr, NULL, &lm, NULL, 0)) { + if (!(lm->mod_flags & MOD_LOAD_SYMS)) + return(buf); + } + if ((lnh = machdep->line_number_hooks)) { name = closest_symbol(addr); while (lnh->func) { @@ -4120,6 +4134,10 @@ gdb_interface(req); } + member_typecode = TYPE_CODE_UNDEF; + member_size = 0; + type_found = 0; + if (CRASHDEBUG(2)) { if (req->typecode) { console("name: %s ", req->name); @@ -4326,6 +4344,8 @@ unsigned restore_radix; long len; + restore_radix = 0; + if ((len = STRUCT_SIZE(s)) < 0) error(FATAL, "invalid structure name: %s\n", s); @@ -4354,6 +4374,7 @@ unsigned restore_radix; char *buf, *p1; + restore_radix = 0; buf = GETBUF(strlen(s)+1); strcpy(buf, s); @@ -4404,6 +4425,8 @@ unsigned restore_radix; long len; + restore_radix = 0; + if ((len = UNION_SIZE(s)) < 0) error(FATAL, "invalid union name: %s\n", s); @@ -4480,9 +4503,10 @@ dm = &datatype_member; count = 0xdeadbeef; rawdata = 0; - aflag = 0; + aflag = addr = 0; list_head_offset = 0; argc_members = 0; + separator = members = NULL; while ((c = getopt(argcnt, args, "fuc:rvol:")) != EOF) { switch (c) @@ -4796,6 +4820,7 @@ int both; BZERO(dm, sizeof(struct datatype_member)); + both = FALSE; dm->name = s; @@ -5312,6 +5337,7 @@ case INT32: rdarg = "-32"; break; case INT16: rdarg = "-16"; break; case INT8: rdarg = "-8"; break; + default: rdarg = NULL; break; } if (args[1]) { @@ -5654,9 +5680,11 @@ return FALSE; } - if (STRNEQ(inbuf, " ")) - goto do_empty_offset; + if (STRNEQ(inbuf, " ")) { + end_of_block = FALSE; + goto do_empty_offset; + } if (STRNEQ(inbuf, " union {")) dm->flags |= IN_UNION; if (STRNEQ(inbuf, " struct {")) @@ -6014,6 +6042,7 @@ data_debug = pc->flags & DATADEBUG; pc->flags &= ~DATADEBUG; + uts = NULL; if (makestruct) { uts = &kt->utsname; @@ -6985,6 +7014,8 @@ fprintf(fp, " zone_free_pages: %ld\n", OFFSET(zone_free_pages)); + fprintf(fp, " zone_watermark: %ld\n", + OFFSET(zone_watermark)); fprintf(fp, " zone_free_area: %ld\n", OFFSET(zone_free_area)); fprintf(fp, " zone_zone_pgdat: %ld\n", @@ -7229,6 +7260,7 @@ fprintf(fp, "\n size_table:\n"); fprintf(fp, " page: %ld\n", SIZE(page)); + fprintf(fp, " page_flags: %ld\n", SIZE(page_flags)); fprintf(fp, " free_area_struct: %ld\n", SIZE(free_area_struct)); fprintf(fp, " free_area: %ld\n", @@ -7817,6 +7849,8 @@ ulong alignment; ulong offset; + offset = 0; + switch (kt->flags & (KMOD_V1|KMOD_V2)) { case KMOD_V1: @@ -8269,7 +8303,7 @@ if ((store = bfd_make_empty_symbol(bfd)) == NULL) error(FATAL, "bfd_make_empty_symbol() failed\n"); - st->current = NULL; + st->current = lm = NULL; /* * Find out whether this module has already been loaded. Coming @@ -8277,7 +8311,7 @@ * a reusable symbol table, or NULL if it needs to be re-malloc'd. */ - for (i = 0; i < st->mods_installed; i++) { + for (i = symalloc = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (lm->mod_base == base_addr) { @@ -9130,7 +9164,7 @@ return offset2; if (pc->flags & DATADEBUG) { - ulong retaddr[NUMBER_STACKFRAMES] = { 0 }; + void *retaddr[NUMBER_STACKFRAMES] = { 0 }; SAVE_RETURN_ADDRESS(retaddr); sprintf(errmsg, "invalid (optional) structure member offsets: %s or %s", @@ -9153,7 +9187,7 @@ return size2; if (pc->flags & DATADEBUG) { - ulong retaddr[NUMBER_STACKFRAMES] = { 0 }; + void *retaddr[NUMBER_STACKFRAMES] = { 0 }; SAVE_RETURN_ADDRESS(retaddr); sprintf(errmsg, "invalid (optional) structure sizes: %s or %s", item1, item2); @@ -9181,7 +9215,7 @@ return offset; if (offset < 0) { - ulong retaddr[NUMBER_STACKFRAMES] = { 0 }; + void *retaddr[NUMBER_STACKFRAMES] = { 0 }; SAVE_RETURN_ADDRESS(retaddr); sprintf(errmsg, "invalid structure member offset: %s", item); @@ -9199,7 +9233,7 @@ return size; if (size < 0) { - ulong retaddr[NUMBER_STACKFRAMES] = { 0 }; + void *retaddr[NUMBER_STACKFRAMES] = { 0 }; SAVE_RETURN_ADDRESS(retaddr); sprintf(errmsg, "invalid structure size: %s", item); datatype_error(retaddr, errmsg, func, file, line); @@ -9211,7 +9245,7 @@ * Perform the common datatype error handling. */ static void -datatype_error(ulong *retaddr, char *errmsg, char *func, char *file, int line) +datatype_error(void **retaddr, char *errmsg, char *func, char *file, int line) { char buf[BUFSIZE]; int fd; @@ -9250,7 +9284,7 @@ * Dump a trace leading to the improper datatype usage. */ void -dump_trace(ulong *retaddr) +dump_trace(void **retaddr) { int i, c; char *thisfile; @@ -9273,7 +9307,7 @@ if (retaddr[i]) fprintf(stderr, "%s%lx%s", i == 3 ? "" : "=> ", - retaddr[i], + (ulong)retaddr[i], i == 0 ? "\n" : " "); } fflush(stderr); @@ -9288,8 +9322,10 @@ else nm_call = "/usr/bin/nm -BSn %s"; + last_size = 0; + for (i = 0; i < NUMBER_STACKFRAMES; i++) { - if (!(lookfor = retaddr[i])) + if (!(lookfor = (ulong)retaddr[i])) continue; sprintf(buf, nm_call, thisfile); --- crash-4.0.9/cmdline.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/cmdline.c 2009-10-06 16:48:38.000000000 -0400 @@ -436,6 +436,7 @@ int append; int expression; int string; + int ret; FILE *pipe; FILE *ofile; @@ -445,7 +446,7 @@ p = pc->command_line; if (STREQ(p, "|") || STREQ(p, "!")) { - system("/bin/sh"); + ret = system("/bin/sh"); pc->redirect |= REDIRECT_SHELL_ESCAPE; return REDIRECT_SHELL_ESCAPE; } @@ -684,8 +685,11 @@ return FALSE; break; - case (REDIRECT_TO_PIPE|FROM_COMMAND_LINE): case (REDIRECT_TO_PIPE|FROM_INPUT_FILE): + if (pc->curcmd_flags & REPEAT) + break; + /* FALLTHROUGH */ + case (REDIRECT_TO_PIPE|FROM_COMMAND_LINE): switch (pc->redirect & (REDIRECT_MULTI_PIPE)) { case REDIRECT_MULTI_PIPE: @@ -1167,6 +1171,10 @@ if (pc->flags & _SIGINT_) { pc->flags &= ~_SIGINT_; pc->sigint_cnt = 0; + if (pc->ifile_in_progress) { + pc->ifile_in_progress = 0; + pc->ifile_offset = 0; + } return TRUE; } else return FALSE; @@ -1847,6 +1855,7 @@ ulong delay; char buf[BUFSIZE]; char bufsave[BUFSIZE]; + FILE *incoming_fp; if (argcnt == 1) cmd_usage(pc->curcmd, SYNOPSIS); @@ -1901,12 +1910,14 @@ "scrolling must be turned off when repeating an input file\n"); pc->curcmd_flags |= REPEAT; + incoming_fp = fp; while (TRUE) { optind = 0; - + fp = incoming_fp; exec_command(); free_all_bufs(); + wait_for_children(ZOMBIES_ONLY); if (received_SIGINT() || !output_open()) break; @@ -2043,6 +2054,8 @@ return FALSE; } + path = NULL; + if (pc->stdpipe_pid > 0) { pc->redirect |= REDIRECT_PID_KNOWN; --- crash-4.0.9/lkcd_common.c 2009-10-07 11:39:57.000000000 -0400 +++ crash-4.1.0/lkcd_common.c 2009-09-14 15:48:33.000000000 -0400 @@ -677,6 +677,7 @@ int max_zones; struct physmem_zone *zones; + ret = -1; zone = paddr & lkcd->zone_mask; page = (paddr & ~lkcd->zone_mask) >> lkcd->page_shift; @@ -1063,6 +1064,8 @@ ulong type; int found, newsz; uint32_t rawsz; + ssize_t bytes; + for (i = found = 0; i < LKCD_CACHED_PAGES; i++) { if (LKCD_VALID_PAGE(lkcd->page_cache_hdr[i].pg_flags)) @@ -1092,7 +1095,7 @@ newsz = 0; BZERO(lkcd->compressed_page, lkcd->page_size); - read(lkcd->fd, lkcd->compressed_page, lkcd->get_dp_size()); + bytes = read(lkcd->fd, lkcd->compressed_page, lkcd->get_dp_size()); switch (lkcd->compression) { @@ -1139,7 +1142,7 @@ BZERO(lkcd->page_cache_hdr[i].pg_bufptr, lkcd->page_size); else if (rawsz == lkcd->page_size) - read(lkcd->fd, lkcd->page_cache_hdr[i].pg_bufptr, + bytes = read(lkcd->fd, lkcd->page_cache_hdr[i].pg_bufptr, lkcd->page_size); else { lkcd_print("cache_page: " --- crash-4.0.9/s390_dump.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/s390_dump.c 2009-09-14 15:43:00.000000000 -0400 @@ -26,10 +26,11 @@ { FILE* fh; long long int magic; + size_t items; int rc; fh = fopen(file,"r"); - fread(&magic, sizeof(magic), 1,fh); + items = fread(&magic, sizeof(magic), 1,fh); if(magic == 0xa8190173618f23fdLL) rc = TRUE; else --- crash-4.0.9/lkcd_x86_trace.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/lkcd_x86_trace.c 2009-09-15 14:55:12.000000000 -0400 @@ -1351,6 +1351,8 @@ int interrupted_system_call = FALSE; struct bt_info *bt = trace->bt; uaddr_t *pt; + + curframe = NULL; #endif sbp = trace->stack[curstkidx].ptr; sbase = trace->stack[curstkidx].addr; @@ -1948,6 +1950,7 @@ int nframes = 0; kaddr_t task = bt->task; KL_ERROR = 0; + tsp = NULL; if (bt->flags & BT_FRAMESIZE_DEBUG) return(framesize_debug(bt, ofp)); @@ -2178,6 +2181,7 @@ errcnt = 0; KL_ERROR = 0; + tsp = NULL; if (!XEN_HYPER_MODE()) { if (!(tsp = kl_alloc_block(TASK_STRUCT_SZ, K_TEMP))) @@ -4983,6 +4987,8 @@ { int opcode, opdata; + opcode = opdata = 0; + switch(opnum) { case 0: opcode = irp->opcodep->Op1; @@ -5575,6 +5581,7 @@ instr_rec_t *fst = (instr_rec_t *)NULL, *lst, *ptr, *cur; #ifdef REDHAT + cur = NULL; if ((sp = x86_is_entry_tramp_address(pc, &offset))) pc = sp->value + offset; #endif --- crash-4.0.9/netdump.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/netdump.c 2009-09-14 15:39:42.000000000 -0400 @@ -125,6 +125,8 @@ goto bailout; } + load32 = NULL; + load64 = NULL; tmp_flags = 0; elf32 = (Elf32_Ehdr *)&eheader[0]; elf64 = (Elf64_Ehdr *)&eheader[0]; @@ -450,6 +452,8 @@ struct pt_load_segment *pls; int i; + offset = 0; + /* * The Elf32_Phdr has 32-bit fields for p_paddr, p_filesz and * p_memsz, so for now, multiple PT_LOAD segment support is @@ -513,6 +517,8 @@ struct pt_load_segment *pls; int i; + offset = 0; + switch (DUMPFILE_FORMAT(nd->flags)) { case NETDUMP_ELF32: @@ -671,6 +677,10 @@ if ((nd->num_prstatus_notes > 1) && (crashing_cpu == -1)) goto panic_task_undetermined; break; + + default: + crashing_cpu = -1; + break; } if (nd->elf32 && (nd->elf32->e_machine == EM_386)) { @@ -1290,6 +1300,8 @@ if (store_pt_load_data) pls = &nd->pt_load_segments[store_pt_load_data-1]; + else + pls = NULL; netdump_print("Elf32_Phdr:\n"); netdump_print(" p_type: %lx ", prog->p_type); @@ -1372,6 +1384,8 @@ if (store_pt_load_data) pls = &nd->pt_load_segments[store_pt_load_data-1]; + else + pls = NULL; netdump_print("Elf64_Phdr:\n"); netdump_print(" p_type: %lx ", prog->p_type); @@ -2591,6 +2605,9 @@ size_t len; void *pt_regs; + len = 0; + pt_regs = NULL; + if ((tc->task == tt->panic_task) || (is_task_active(tc->task) && (nd->num_prstatus_notes > 1))) { if (nd->num_prstatus_notes > 1) @@ -2627,6 +2644,8 @@ size_t len; void *pt_regs; + pt_regs = NULL; + if ((tc->task == tt->panic_task) || (is_task_active(tc->task) && (nd->num_prstatus_notes > 1))) { if (nd->num_prstatus_notes > 1) @@ -2654,6 +2673,8 @@ void *pt_regs; extern struct vmcore_data *nd; + pt_regs = NULL; + if ((tc->task == tt->panic_task) || (is_task_active(tc->task) && (nd->num_prstatus_notes > 1))) { /* --- crash-4.0.9/xendump.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/xendump.c 2009-09-14 15:32:08.000000000 -0400 @@ -1724,6 +1724,7 @@ * Initialize the start_index. */ xd->xc_core.last_batch.accesses++; + start_index = 0; if ((pfn >= xd->xc_core.last_batch.start) && (pfn <= xd->xc_core.last_batch.end)) { @@ -1853,6 +1854,7 @@ * Initialize the start_index. */ xd->xc_core.last_batch.accesses++; + start_index = 0; if ((pfn >= xd->xc_core.last_batch.start) && (pfn <= xd->xc_core.last_batch.end)) { @@ -2702,6 +2704,7 @@ struct xen_dumpcore_elfnote_format_version_desc *format_version; elfnote_header = NULL; + format_version = NULL; if (!(notes_buffer = (char *)malloc(sh_size))) error(FATAL, "cannot malloc notes space."); --- crash-4.0.9/xen_hyper.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/xen_hyper.c 2009-09-14 15:28:36.000000000 -0400 @@ -335,7 +335,8 @@ sp = ULONG(buf + XEN_HYPER_OFFSET(tss_struct_esp0)); } else if (machine_type("X86_64")) { sp = ULONG(buf + XEN_HYPER_OFFSET(tss_struct_rsp0)); - } + } else + sp = 0; cpu_info = XEN_HYPER_GET_CPU_INFO(sp); if (CRASHDEBUG(1)) { fprintf(fp, "sp=%lx, cpu_info=%lx\n", sp, cpu_info); @@ -756,6 +757,7 @@ } nccp = xhdit->crash_note_core_array; BZERO(nccp, size); + xccp = NULL; /* allocate xen core */ if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V2) { --- crash-4.0.9/xen_hyper_command.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/xen_hyper_command.c 2009-09-14 15:24:09.000000000 -0400 @@ -353,7 +353,8 @@ int c, cnt, type, bogus; BZERO(&dia, sizeof(struct xen_hyper_cmd_args)); - flag= 0; + flag = val =0; + dic = NULL; while ((c = getopt(argcnt, args, "rt")) != EOF) { switch(c) { @@ -606,6 +607,7 @@ "conring contents", FAULT_ON_ERROR); idx = start; len = XEN_HYPER_CONRING_SIZE; + last = 0; wrap_around: for (i = idx; i < len; i++) { --- crash-4.0.9/qemu.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/qemu.c 2009-09-14 15:19:53.000000000 -0400 @@ -254,6 +254,8 @@ else if (machine_type("X86_64")) dl = qemu_load(devices_x86_64, QEMU_FEATURE_CPU|QEMU_FEATURE_RAM, kvm->vmp); + else + dl = NULL; please_wait_done(); --- crash-4.0.9/qemu-load.c 2009-10-07 11:39:57.000000000 -0400 +++ crash-4.1.0/qemu-load.c 2009-09-14 15:15:03.000000000 -0400 @@ -225,6 +225,8 @@ ram_read_phys_page (struct qemu_device_ram *dram, void *buf, uint64_t addr) { off_t ofs; + ssize_t bytes; + if (addr >= dram->last_ram_offset) return false; assert ((addr & 0xfff) == 0); @@ -234,7 +236,7 @@ if ((ofs & RAM_OFFSET_COMPRESSED) == RAM_OFFSET_COMPRESSED) memset (buf, ofs & 255, 4096); else - pread (fileno (dram->fp), buf, 4096, ofs); + bytes = pread (fileno (dram->fp), buf, 4096, ofs); return true; } @@ -595,6 +597,7 @@ char name[257]; uint32_t section_id, instance_id, version_id; // bool live; + size_t items; int sz; section_id = get_be32 (fp); @@ -605,7 +608,7 @@ sz = getc (fp); if (sz == EOF) return NULL; - fread (name, sz, 1, fp); + items = fread (name, sz, 1, fp); name[sz] = 0; instance_id = get_be32 (fp); @@ -625,6 +628,7 @@ FILE *fp) { struct qemu_device_list *result = NULL; + size_t items; switch (get_be32 (fp)) { case QEMU_VM_FILE_MAGIC: @@ -633,7 +637,7 @@ case LIBVIRT_QEMU_VM_FILE_MAGIC: { struct libvirt_header header; memcpy (header.magic, "Libv", 4); - fread (&header.magic[4], sizeof (header) - 4, 1, fp); + items = fread (&header.magic[4], sizeof (header) - 4, 1, fp); if (memcmp ("LibvirtQemudSave", header.magic, 16)) goto fail; @@ -698,6 +702,7 @@ { struct libvirt_header header; int retval; + size_t items; char *xml; if ((kvm->vmp = fopen(filename, "r")) == NULL) { @@ -705,6 +710,7 @@ return FALSE; } + retval = FALSE; xml = NULL; switch (get_be32(kvm->vmp)) @@ -715,10 +721,10 @@ case LIBVIRT_QEMU_VM_FILE_MAGIC: rewind(kvm->vmp); - fread(&header.magic[0], sizeof(header), 1, kvm->vmp); + items = fread(&header.magic[0], sizeof(header), 1, kvm->vmp); if (STRNEQ(header.magic, "LibvirtQemudSave")) { if ((xml = (char *)malloc(header.xml_length))) { - fread(xml, header.xml_length, 1, kvm->vmp); + items = fread(xml, header.xml_length, 1, kvm->vmp); /* * Parse here if necessary or desirable. */ @@ -749,6 +755,7 @@ struct libvirt_header header; char magic[4]; uint8_t c; + size_t items; rewind(kvm->vmp); if (get_be32(kvm->vmp) == QEMU_VM_FILE_MAGIC) { @@ -757,7 +764,7 @@ } rewind(kvm->vmp); - fread(&header, sizeof(header), 1, kvm->vmp); + items = fread(&header, sizeof(header), 1, kvm->vmp); fprintf(out, "%s: libvirt_header:\n\n", pc->dumpfile); fprintf(out, " magic: "); @@ -774,7 +781,7 @@ fprintf(out, "%c", c); } fprintf(out, "\n"); - fread(&magic, sizeof(char), 4, kvm->vmp); + items = fread(&magic, sizeof(char), 4, kvm->vmp); for (i = 0; i < 4; i++) fprintf(out, "%c", magic[i]); fprintf(out, "\n"); --- crash-4.0.9/defs.h 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/defs.h 2009-10-07 11:17:32.000000000 -0400 @@ -1481,6 +1481,7 @@ long probe_data; long kobj_map_probes; long task_struct_prio; + long zone_watermark; }; struct size_table { /* stash of commonly-used sizes */ @@ -1589,6 +1590,7 @@ long cdev; long probe; long kobj_map; + long page_flags; }; struct array_table { @@ -1774,6 +1776,7 @@ #define KMALLOC_SLUB (0x10000) #define CONFIG_NUMA (0x20000) #define VM_EVENT (0x40000) +#define PGCNT_ADJ (0x80000) #define IS_FLATMEM() (vt->flags & FLATMEM) #define IS_DISCONTIGMEM() (vt->flags & DISCONTIGMEM) @@ -2159,7 +2162,7 @@ #define VMEMMAP_VADDR_2_6_24 0xffffe20000000000 #define VMEMMAP_END_2_6_24 0xffffe2ffffffffff -#define VMALLOC_START_ADDR_2_6_26 0xffffffffa0000000 +#define MODULES_VADDR_2_6_26 0xffffffffa0000000 #define PAGE_OFFSET_2_6_27 0xffff880000000000 #define MODULES_END_2_6_27 0xffffffffff000000 @@ -3036,6 +3039,7 @@ #define PS_ARGV_ENVP (0x800) #define PS_TGID_LIST (0x1000) #define PS_RLIMIT (0x2000) +#define PS_GROUP (0x4000) #define PS_EXCLUSIVE (PS_TGID_LIST|PS_ARGV_ENVP|PS_TIMES|PS_CHILD_LIST|PS_PPID_LIST|PS_LAST_RUN|PS_RLIMIT) @@ -3398,7 +3402,7 @@ long SIZE_verify(long, char *, char *, int, char *); long OFFSET_option(long, long, char *, char *, int, char *, char *); long SIZE_option(long, long, char *, char *, int, char *, char *); -void dump_trace(ulong *); +void dump_trace(void **); int enumerator_value(char *, long *); /* --- crash-4.0.9/Makefile 2009-10-07 15:21:18.000000000 -0400 +++ crash-4.1.0/Makefile 2009-10-07 15:21:17.000000000 -0400 @@ -107,6 +107,7 @@ EXTENSIONS=extensions EXTENSION_SOURCE_FILES=${EXTENSIONS}/Makefile ${EXTENSIONS}/echo.c ${EXTENSIONS}/dminfo.c \ ${EXTENSIONS}/snap.c ${EXTENSIONS}/snap.mk \ + ${EXTENSIONS}/trace.c \ ${EXTENSIONS}/libsial/Makefile \ ${EXTENSIONS}/libsial/mkbaseop.c \ ${EXTENSIONS}/libsial/README \ @@ -218,13 +219,13 @@ # usefulness is also dependent upon the processor's compiler -- your mileage # may vary. # -#WARNING_OPTIONS=-Wall -Wstrict-prototypes -Wmissing-prototypes +#WARNING_OPTIONS=-Wall -O2 -Wstrict-prototypes -Wmissing-prototypes -fstack-protector -Wp,-D_FORTIFY_SOURCE=2 #WARNING_ERROR=-Werror # TARGET_CFLAGS will be configured automatically by configure TARGET_CFLAGS= -CRASH_CFLAGS=${CFLAGS} -g -D${TARGET} ${TARGET_CFLAGS} +CRASH_CFLAGS=-g -D${TARGET} ${TARGET_CFLAGS} ${CFLAGS} TAR_FILES=${SOURCE_FILES} Makefile COPYING README .rh_rpm_package crash.8 \ ${EXTENSION_SOURCE_FILES} @@ -312,7 +313,7 @@ cc -c ${CRASH_CFLAGS} main.c ${WARNING_OPTIONS} ${WARNING_ERROR} cmdline.o: ${GENERIC_HFILES} cmdline.c - cc -c ${CRASH_CFLAGS} ${GDB_FLAGS} cmdline.c -I${READLINE_DIRECTORY} ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} cmdline.c ${GDB_FLAGS} -I${READLINE_DIRECTORY} ${WARNING_OPTIONS} ${WARNING_ERROR} tools.o: ${GENERIC_HFILES} tools.c cc -c ${CRASH_CFLAGS} tools.c ${WARNING_OPTIONS} ${WARNING_ERROR} @@ -321,13 +322,13 @@ cc -c ${CRASH_CFLAGS} global_data.c ${WARNING_OPTIONS} ${WARNING_ERROR} symbols.o: ${GENERIC_HFILES} symbols.c - cc -c ${CRASH_CFLAGS} ${GDB_FLAGS} symbols.c -I${BFD_DIRECTORY} -I${GDB_INCLUDE_DIRECTORY} ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} symbols.c ${GDB_FLAGS} -I${BFD_DIRECTORY} -I${GDB_INCLUDE_DIRECTORY} ${WARNING_OPTIONS} ${WARNING_ERROR} filesys.o: ${GENERIC_HFILES} filesys.c cc -c ${CRASH_CFLAGS} filesys.c ${WARNING_OPTIONS} ${WARNING_ERROR} help.o: ${GENERIC_HFILES} help.c - cc -c ${CRASH_CFLAGS} ${GDB_FLAGS} help.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} help.c ${GDB_FLAGS} ${WARNING_OPTIONS} ${WARNING_ERROR} memory.o: ${GENERIC_HFILES} memory.c cc -c ${CRASH_CFLAGS} memory.c ${WARNING_OPTIONS} ${WARNING_ERROR} @@ -336,13 +337,13 @@ cc -c ${CRASH_CFLAGS} test.c ${WARNING_OPTIONS} ${WARNING_ERROR} task.o: ${GENERIC_HFILES} task.c - cc -c ${CRASH_CFLAGS} ${GDB_FLAGS} task.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} task.c ${GDB_FLAGS} ${WARNING_OPTIONS} ${WARNING_ERROR} kernel.o: ${GENERIC_HFILES} kernel.c - cc -c ${CRASH_CFLAGS} ${GDB_FLAGS} kernel.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} kernel.c ${GDB_FLAGS} ${WARNING_OPTIONS} ${WARNING_ERROR} gdb_interface.o: ${GENERIC_HFILES} gdb_interface.c - cc -c ${CRASH_CFLAGS} ${GDB_FLAGS} gdb_interface.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} gdb_interface.c ${GDB_FLAGS} ${WARNING_OPTIONS} ${WARNING_ERROR} va_server.o: ${MCORE_HFILES} va_server.c cc -c ${CRASH_CFLAGS} va_server.c ${WARNING_OPTIONS} ${WARNING_ERROR} @@ -354,19 +355,19 @@ cc -c ${CRASH_CFLAGS} lkcd_common.c ${WARNING_OPTIONS} ${WARNING_ERROR} lkcd_v1.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_v1.c - cc -c ${CRASH_CFLAGS} -DMCLX lkcd_v1.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} lkcd_v1.c -DMCLX ${WARNING_OPTIONS} ${WARNING_ERROR} lkcd_v2_v3.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_v2_v3.c - cc -c ${CRASH_CFLAGS} -DMCLX lkcd_v2_v3.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} lkcd_v2_v3.c -DMCLX ${WARNING_OPTIONS} ${WARNING_ERROR} lkcd_v5.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_v5.c - cc -c ${CRASH_CFLAGS} -DMCLX lkcd_v5.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} lkcd_v5.c -DMCLX ${WARNING_OPTIONS} ${WARNING_ERROR} lkcd_v7.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_v7.c - cc -c ${CRASH_CFLAGS} -DMCLX lkcd_v7.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} lkcd_v7.c -DMCLX ${WARNING_OPTIONS} ${WARNING_ERROR} lkcd_v8.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_v8.c - cc -c ${CRASH_CFLAGS} -DMCLX lkcd_v8.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} lkcd_v8.c -DMCLX ${WARNING_OPTIONS} ${WARNING_ERROR} net.o: ${GENERIC_HFILES} net.c cc -c ${CRASH_CFLAGS} net.c ${WARNING_OPTIONS} ${WARNING_ERROR} @@ -381,10 +382,10 @@ cc -c ${CRASH_CFLAGS} -DDAEMON remote.c -o remote_daemon.o ${WARNING_OPTIONS} ${WARNING_ERROR} x86.o: ${GENERIC_HFILES} ${REDHAT_HFILES} x86.c - cc -c ${CRASH_CFLAGS} -DMCLX x86.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} x86.c -DMCLX ${WARNING_OPTIONS} ${WARNING_ERROR} alpha.o: ${GENERIC_HFILES} alpha.c - cc -c ${CRASH_CFLAGS} ${GDB_FLAGS} alpha.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} alpha.c ${GDB_FLAGS} ${WARNING_OPTIONS} ${WARNING_ERROR} ppc.o: ${GENERIC_HFILES} ppc.c cc -c ${CRASH_CFLAGS} ppc.c ${WARNING_OPTIONS} ${WARNING_ERROR} @@ -434,22 +435,22 @@ cc -c ${CRASH_CFLAGS} extensions.c ${WARNING_OPTIONS} ${WARNING_ERROR} lkcd_x86_trace.o: ${GENERIC_HFILES} ${LKCD_TRACE_HFILES} lkcd_x86_trace.c - cc -c ${CRASH_CFLAGS} -DREDHAT lkcd_x86_trace.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} lkcd_x86_trace.c -DREDHAT ${WARNING_OPTIONS} ${WARNING_ERROR} unwind_x86_32_64.o: ${GENERIC_HFILES} ${UNWIND_HFILES} unwind_x86_32_64.c cc -c ${CRASH_CFLAGS} unwind_x86_32_64.c -o unwind_x86_32_64.o ${WARNING_OPTIONS} ${WARNING_ERROR} unwind_v1.o: ${GENERIC_HFILES} ${UNWIND_HFILES} unwind.c unwind_decoder.c - cc -c ${CRASH_CFLAGS} -DREDHAT -DUNWIND_V1 unwind.c -o unwind_v1.o ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} unwind.c -DREDHAT -DUNWIND_V1 -o unwind_v1.o ${WARNING_OPTIONS} ${WARNING_ERROR} unwind_v2.o: ${GENERIC_HFILES} ${UNWIND_HFILES} unwind.c unwind_decoder.c - cc -c ${CRASH_CFLAGS} -DREDHAT -DUNWIND_V2 unwind.c -o unwind_v2.o ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} unwind.c -DREDHAT -DUNWIND_V2 -o unwind_v2.o ${WARNING_OPTIONS} ${WARNING_ERROR} unwind_v3.o: ${GENERIC_HFILES} ${UNWIND_HFILES} unwind.c unwind_decoder.c - cc -c ${CRASH_CFLAGS} -DREDHAT -DUNWIND_V3 unwind.c -o unwind_v3.o ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} unwind.c -DREDHAT -DUNWIND_V3 -o unwind_v3.o ${WARNING_OPTIONS} ${WARNING_ERROR} lkcd_fix_mem.o: ${GENERIC_HFILES} ${LKCD_HFILES} lkcd_fix_mem.c - cc -c ${CRASH_CFLAGS} -DMCLX lkcd_fix_mem.c ${WARNING_OPTIONS} ${WARNING_ERROR} + cc -c ${CRASH_CFLAGS} lkcd_fix_mem.c -DMCLX ${WARNING_OPTIONS} ${WARNING_ERROR} xen_hyper.o: ${GENERIC_HFILES} xen_hyper.c cc -c ${CRASH_CFLAGS} xen_hyper.c ${WARNING_OPTIONS} ${WARNING_ERROR} @@ -547,12 +548,18 @@ @ls -l ${PROGRAM}-${VERSION}.tar.gz @./configure -s -u > ${PROGRAM}.spec @if [ -s ${PROGRAM}.spec ]; then \ - cp ${PROGRAM}-${VERSION}.tar.gz /usr/src/redhat/SOURCES; \ - /usr/bin/rpmbuild -bs ${PROGRAM}.spec > /dev/null; \ - rm -f /usr/src/redhat/SOURCES/${PROGRAM}-${VERSION}.tar.gz; \ - mv /usr/src/redhat/SRPMS/${PROGRAM}-${VERSION}-${RELEASE}.src.rpm . ; \ - ls -l ${PROGRAM}-${VERSION}-${RELEASE}.src.rpm; \ - exit 0; fi + rm -rf ./RPMBUILD; \ + mkdir -p ./RPMBUILD/SOURCES ./RPMBUILD/SPECS ./RPMBUILD/SRPMS; \ + cp ${PROGRAM}-${VERSION}.tar.gz ./RPMBUILD/SOURCES; \ + cp ${PROGRAM}.spec ./RPMBUILD/SPECS; \ + rpmbuild --define "_sourcedir ./RPMBUILD/SOURCES" \ + --define "_srcrpmdir ./RPMBUILD/SRPMS" \ + --define "_specdir ./RPMBUILD/SPECS" \ + --nodeps -bs ./RPMBUILD/SPECS/${PROGRAM}.spec > /dev/null; \ + mv ./RPMBUILD/SRPMS/${PROGRAM}-${VERSION}-${RELEASE}.src.rpm . ; \ + rm -rf ./RPMBUILD; \ + ls -l ${PROGRAM}-${VERSION}-${RELEASE}.src.rpm; \ + fi ref: make ctags cscope --- crash-4.0.9/gdb-6.1/gdb/symtab.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/gdb-6.1/gdb/symtab.c 2009-09-24 14:44:06.000000000 -0400 @@ -684,6 +684,8 @@ struct partial_symtab *pst; struct objfile *objfile; struct minimal_symbol *msymbol; + struct partial_symtab *best_pst = NULL; + struct partial_symbol *best_psym = NULL; /* If we know that this is not a text address, return failure. This is necessary because we loop based on texthigh and textlow, which do @@ -701,9 +703,7 @@ { if (pc >= pst->textlow && pc < pst->texthigh) { - struct partial_symtab *tpst; - struct partial_symtab *best_pst = pst; - struct partial_symbol *best_psym = NULL; + struct partial_symbol *p; /* An objfile that has its functions reordered might have many partial symbol tables containing the PC, but @@ -717,23 +717,17 @@ return (pst); /* The code range of partial symtabs sometimes overlap, so, in - the loop below, we need to check all partial symtabs and + the code below, we need to check all partial symtabs and find the one that fits better for the given PC address. We select the partial symtab that contains a symbol whose address is closest to the PC address. By closest we mean that find_pc_sect_symbol returns the symbol with address that is closest and still less than the given PC. */ - for (tpst = pst; tpst != NULL; tpst = tpst->next) - { - if (pc >= tpst->textlow && pc < tpst->texthigh) - { - struct partial_symbol *p; - - p = find_pc_sect_psymbol (tpst, pc, section); + p = find_pc_sect_psymbol (pst, pc, section); if (p != NULL && SYMBOL_VALUE_ADDRESS (p) == SYMBOL_VALUE_ADDRESS (msymbol)) - return (tpst); + return (pst); if (p != NULL) { /* We found a symbol in this partial symtab which @@ -754,16 +748,12 @@ > SYMBOL_VALUE_ADDRESS (best_psym)) { best_psym = p; - best_pst = tpst; + best_pst = pst; } } - - } - } - return (best_pst); } } - return (NULL); + return (best_pst); } /* Find which partial symtab contains PC. Return 0 if none. --- crash-4.0.9/gdb-6.1.patch 2009-10-07 11:39:57.000000000 -0400 +++ crash-4.1.0/gdb-6.1.patch 2009-10-07 10:48:21.000000000 -0400 @@ -11752,3 +11752,14 @@ + +/* max size of register name in insn mnemonics. */ +#define MAX_REG_NAME_SIZE 8 +--- gdb-6.1/readline/misc.c.orig ++++ gdb-6.1/readline/misc.c +@@ -299,7 +299,7 @@ _rl_history_set_point () + + #if defined (VI_MODE) + if (rl_editing_mode == vi_mode) +- rl_point = 0; ++ rl_point = rl_end; + #endif /* VI_MODE */ + + if (rl_editing_mode == emacs_mode) --- crash-4.0.9/extensions/trace.c 2009-10-07 15:21:17.000000000 -0400 +++ crash-4.1.0/extensions/trace.c 2009-09-28 11:04:43.000000000 -0400 @@ -0,0 +1,2534 @@ +/* + * trace extension module for crash + * + * Copyright (C) 2009 FUJITSU LIMITED + * Author: Lai Jiangshan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + */ + +#define _GNU_SOURCE +#include "defs.h" +#include +#include +#include + +static int verbose = 0; + +static int nr_cpu_ids; + +/* + * lockless ring_buffer and old non-lockless ring_buffer are both supported. + */ +static int lockless_ring_buffer; + +#define koffset(struct, member) struct##_##member##_offset + +static int koffset(trace_array, buffer); +static int koffset(tracer, name); + +static int koffset(ring_buffer, pages); +static int koffset(ring_buffer, flags); +static int koffset(ring_buffer, cpus); +static int koffset(ring_buffer, buffers); + +static int koffset(ring_buffer_per_cpu, cpu); +static int koffset(ring_buffer_per_cpu, pages); +static int koffset(ring_buffer_per_cpu, head_page); +static int koffset(ring_buffer_per_cpu, tail_page); +static int koffset(ring_buffer_per_cpu, commit_page); +static int koffset(ring_buffer_per_cpu, reader_page); +static int koffset(ring_buffer_per_cpu, overrun); +static int koffset(ring_buffer_per_cpu, entries); + +static int koffset(buffer_page, read); +static int koffset(buffer_page, list); +static int koffset(buffer_page, page); + +static int koffset(list_head, next); + +static int koffset(ftrace_event_call, list); +static int koffset(ftrace_event_call, name); +static int koffset(ftrace_event_call, system); +static int koffset(ftrace_event_call, id); +static int koffset(ftrace_event_call, fields); + +static int koffset(ftrace_event_field, link); +static int koffset(ftrace_event_field, name); +static int koffset(ftrace_event_field, type); +static int koffset(ftrace_event_field, offset); +static int koffset(ftrace_event_field, size); +static int koffset(ftrace_event_field, is_signed); + +static int koffset(POINTER_SYM, POINTER) = 0; + +struct ring_buffer_per_cpu { + ulong kaddr; + + ulong head_page; + ulong tail_page; + ulong commit_page; + ulong reader_page; + ulong real_head_page; + + ulong *pages; + int head_page_index; + + ulong overrun; + ulong entries; +}; + +static ulong global_trace; +static ulong global_ring_buffer; +static unsigned global_pages; +static struct ring_buffer_per_cpu *global_buffers; + +static ulong max_tr_trace; +static ulong max_tr_ring_buffer; +static unsigned max_tr_pages; +static struct ring_buffer_per_cpu *max_tr_buffers; + +static ulong ftrace_events; +static ulong current_trace; +static const char *current_tracer_name; + +static void ftrace_destroy_event_types(void); +static int ftrace_init_event_types(void); +static int ftrace_show_init(void); +static void ftrace_show_destroy(void); + +/* at = ((struct *)ptr)->member */ +#define read_value(at, ptr, struct, member) \ + do { \ + if (!readmem(ptr + koffset(struct, member), KVADDR, \ + &at, sizeof(at), #struct "'s " #member, \ + RETURN_ON_ERROR)) \ + goto out_fail;\ + } while (0) + +/* Remove the "const" qualifiers for ptr */ +#define free(ptr) free((void *)(ptr)) + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +static void init_offsets(void) +{ +#define init_offset(struct, member) \ + koffset(struct, member) = MEMBER_OFFSET(#struct, #member); + + init_offset(trace_array, buffer); + init_offset(tracer, name); + + init_offset(ring_buffer, pages); + init_offset(ring_buffer, flags); + init_offset(ring_buffer, cpus); + init_offset(ring_buffer, buffers); + + if (MEMBER_SIZE("ring_buffer_per_cpu", "pages") == sizeof(ulong)) { + lockless_ring_buffer = 1; + if (verbose) + fprintf(fp, "lockless\n"); + } + + init_offset(ring_buffer_per_cpu, cpu); + init_offset(ring_buffer_per_cpu, pages); + init_offset(ring_buffer_per_cpu, head_page); + init_offset(ring_buffer_per_cpu, tail_page); + init_offset(ring_buffer_per_cpu, commit_page); + init_offset(ring_buffer_per_cpu, reader_page); + init_offset(ring_buffer_per_cpu, overrun); + init_offset(ring_buffer_per_cpu, entries); + + init_offset(buffer_page, read); + init_offset(buffer_page, list); + init_offset(buffer_page, page); + + init_offset(list_head, next); + + init_offset(ftrace_event_call, list); + init_offset(ftrace_event_call, name); + init_offset(ftrace_event_call, system); + init_offset(ftrace_event_call, id); + init_offset(ftrace_event_call, fields); + + init_offset(ftrace_event_field, link); + init_offset(ftrace_event_field, name); + init_offset(ftrace_event_field, type); + init_offset(ftrace_event_field, offset); + init_offset(ftrace_event_field, size); + init_offset(ftrace_event_field, is_signed); +#undef init_offset +} + +static void print_offsets(void) +{ + if (!verbose) + return; + +#define print_offset(struct, member) fprintf(fp, \ + "koffset(" #struct ", " #member ") = %d\n", koffset(struct, member)) + + print_offset(trace_array, buffer); + print_offset(tracer, name); + + print_offset(ring_buffer, pages); + print_offset(ring_buffer, flags); + print_offset(ring_buffer, cpus); + print_offset(ring_buffer, buffers); + + print_offset(ring_buffer_per_cpu, cpu); + print_offset(ring_buffer_per_cpu, pages); + print_offset(ring_buffer_per_cpu, head_page); + print_offset(ring_buffer_per_cpu, tail_page); + print_offset(ring_buffer_per_cpu, commit_page); + print_offset(ring_buffer_per_cpu, reader_page); + print_offset(ring_buffer_per_cpu, overrun); + print_offset(ring_buffer_per_cpu, entries); + + print_offset(buffer_page, read); + print_offset(buffer_page, list); + print_offset(buffer_page, page); + + print_offset(list_head, next); + + print_offset(ftrace_event_call, list); + print_offset(ftrace_event_call, name); + print_offset(ftrace_event_call, system); + print_offset(ftrace_event_call, id); + print_offset(ftrace_event_call, fields); + + print_offset(ftrace_event_field, link); + print_offset(ftrace_event_field, name); + print_offset(ftrace_event_field, type); + print_offset(ftrace_event_field, offset); + print_offset(ftrace_event_field, size); + print_offset(ftrace_event_field, is_signed); +#undef print_offset +} + +static int ftrace_init_pages(struct ring_buffer_per_cpu *cpu_buffer, + unsigned nr_pages) +{ + unsigned j = 0; + ulong head, page; + ulong real_head_page = cpu_buffer->head_page; + + cpu_buffer->pages = calloc(sizeof(ulong), nr_pages); + if (cpu_buffer->pages == NULL) + return -1; + + if (lockless_ring_buffer) { + read_value(head, cpu_buffer->kaddr, ring_buffer_per_cpu, pages); + cpu_buffer->pages[j++] = head - koffset(buffer_page, list); + } else + head = cpu_buffer->kaddr + koffset(ring_buffer_per_cpu, pages); + + page = head; + for (;;) { + read_value(page, page, list_head, next); + if (page & 3) { + /* lockless_ring_buffer */ + page &= ~3; + real_head_page = page - koffset(buffer_page, list); + } + + if (j == nr_pages) + break; + + if (page == head) { + error(INFO, "Num of pages is less than %d\n", nr_pages); + goto out_fail; + } + + cpu_buffer->pages[j++] = page - koffset(buffer_page, list); + } + + if (page != head) { + error(INFO, "Num of pages is larger than %d\n", nr_pages); + goto out_fail; + } + + cpu_buffer->real_head_page = real_head_page; + cpu_buffer->head_page_index = -1; + + for (j = 0; j < nr_pages; j++) { + if (cpu_buffer->pages[j] == real_head_page) { + cpu_buffer->head_page_index = j; + break; + } + } + + if (cpu_buffer->head_page_index == -1) { + error(INFO, "error for resolve head_page_index\n"); + goto out_fail; + } + + return 0; + +out_fail: + free(cpu_buffer->pages); + return -1; +} + +static void ftrace_destroy_buffers(struct ring_buffer_per_cpu *buffers) +{ + int i; + + for (i = 0; i < nr_cpu_ids; i++) + free(buffers[i].pages); +} + +static int ftrace_init_buffers(struct ring_buffer_per_cpu *buffers, + ulong ring_buffer, unsigned pages) +{ + int i; + ulong buffers_array; + + read_value(buffers_array, ring_buffer, ring_buffer, buffers); + + for (i = 0; i < nr_cpu_ids; i++) { + if (!readmem(buffers_array + sizeof(ulong) * i, KVADDR, + &buffers[i].kaddr, sizeof(ulong), + "ring_buffer's cpu buffer", RETURN_ON_ERROR)) + goto out_fail; + + if (!buffers[i].kaddr) + continue; + +#define buffer_read_value(member) read_value(buffers[i].member, \ + buffers[i].kaddr, ring_buffer_per_cpu, member) + + buffer_read_value(head_page); + buffer_read_value(tail_page); + buffer_read_value(commit_page); + buffer_read_value(reader_page); + buffer_read_value(overrun); + buffer_read_value(entries); +#undef buffer_read_value + + if (ftrace_init_pages(buffers + i, pages) < 0) + goto out_fail; + + if (verbose) { + fprintf(fp, "overrun=%lu\n", buffers[i].overrun); + fprintf(fp, "entries=%lu\n", buffers[i].entries); + } + } + + return 0; + +out_fail: + ftrace_destroy_buffers(buffers); + return -1; +} + +static int ftrace_int_global_trace(void) +{ + read_value(global_ring_buffer, global_trace, trace_array, buffer); + read_value(global_pages, global_ring_buffer, ring_buffer, pages); + + global_buffers = calloc(sizeof(*global_buffers), nr_cpu_ids); + if (global_buffers == NULL) + goto out_fail; + + if (ftrace_init_buffers(global_buffers, global_ring_buffer, + global_pages) < 0) + goto out_fail; + + return 0; + +out_fail: + free(global_buffers); + return -1; +} + +static int ftrace_int_max_tr_trace(void) +{ + read_value(max_tr_ring_buffer, max_tr_trace, trace_array, buffer); + + if (!max_tr_ring_buffer) + return 0; + + read_value(max_tr_pages, max_tr_ring_buffer, ring_buffer, pages); + + max_tr_buffers = calloc(sizeof(*max_tr_buffers), nr_cpu_ids); + if (max_tr_buffers == NULL) + goto out_fail; + + if (ftrace_init_buffers(max_tr_buffers, max_tr_ring_buffer, + max_tr_pages) < 0) + goto out_fail; + + return 0; + +out_fail: + free(max_tr_buffers); + max_tr_ring_buffer = 0; + return -1; +} + +static int ftrace_init_current_tracer(void) +{ + ulong addr; + char tmp[128]; + + /* Get current tracer name */ + read_value(addr, current_trace, POINTER_SYM, POINTER); + read_value(addr, addr, tracer, name); + read_string(addr, tmp, 128); + + current_tracer_name = strdup(tmp); + if (current_tracer_name == NULL) + goto out_fail; + + return 0; + +out_fail: + return -1; +} + +static int ftrace_init(void) +{ + struct syment *sym_global_trace; + struct syment *sym_max_tr_trace; + struct syment *sym_ftrace_events; + struct syment *sym_current_trace; + + sym_global_trace = symbol_search("global_trace"); + sym_max_tr_trace = symbol_search("max_tr"); + sym_ftrace_events = symbol_search("ftrace_events"); + sym_current_trace = symbol_search("current_trace"); + + if (sym_global_trace == NULL || sym_max_tr_trace == NULL + || sym_ftrace_events == NULL + || sym_current_trace == NULL) + return -1; + + global_trace = sym_global_trace->value; + max_tr_trace = sym_max_tr_trace->value; + ftrace_events = sym_ftrace_events->value; + current_trace = sym_current_trace->value; + + if (!try_get_symbol_data("nr_cpu_ids", sizeof(int), &nr_cpu_ids)) + nr_cpu_ids = 1; + + init_offsets(); + print_offsets(); + + if (ftrace_int_global_trace() < 0) + goto out_0; + + ftrace_int_max_tr_trace(); + + if (ftrace_init_event_types() < 0) + goto out_1; + + if (ftrace_init_current_tracer() < 0) + goto out_2; + + if (ftrace_show_init() < 0) + goto out_3; + + return 0; + +out_3: + free(current_tracer_name); +out_2: + ftrace_destroy_event_types(); +out_1: + if (max_tr_ring_buffer) { + ftrace_destroy_buffers(max_tr_buffers); + free(max_tr_buffers); + } + ftrace_destroy_buffers(global_buffers); + free(global_buffers); +out_0: + return -1; +} + +static void ftrace_destroy(void) +{ + ftrace_show_destroy(); + free(current_tracer_name); + ftrace_destroy_event_types(); + + if (max_tr_ring_buffer) { + ftrace_destroy_buffers(max_tr_buffers); + free(max_tr_buffers); + } + + ftrace_destroy_buffers(global_buffers); + free(global_buffers); +} + +static int ftrace_dump_page(FILE *out, ulong page, void *page_tmp) +{ + ulong raw_page; + + read_value(raw_page, page, buffer_page, page); + + if (!readmem(raw_page, KVADDR, page_tmp, PAGESIZE(), "get page context", + RETURN_ON_ERROR)) + goto out_fail; + + fwrite(page_tmp, 1, PAGESIZE(), out); + + return 0; + +out_fail: + return -1; +} + +static +void ftrace_dump_buffer(FILE *out, struct ring_buffer_per_cpu *cpu_buffer, + unsigned pages, void *page_tmp) +{ + unsigned i; + + if (ftrace_dump_page(out, cpu_buffer->reader_page, page_tmp) < 0) + return; + + if (cpu_buffer->reader_page == cpu_buffer->commit_page) + return; + + i = cpu_buffer->head_page_index; + for (;;) { + if (ftrace_dump_page(out, cpu_buffer->pages[i], page_tmp) < 0) + break; + + if (cpu_buffer->pages[i] == cpu_buffer->commit_page) + break; + + i++; + if (i == pages) + i = 0; + + if (i == cpu_buffer->head_page_index) { + /* cpu_buffer->commit_page may be corrupted */ + break; + } + } +} + +static int try_mkdir(const char *pathname, mode_t mode) +{ + int ret; + + ret = mkdir(pathname, mode); + if (ret < 0) { + if (errno == EEXIST) + return 0; + + error(INFO, "mkdir failed\n"); + return -1; + } + + return 0; +} + +static int ftrace_dump_buffers(const char *per_cpu_path) +{ + int i; + void *page_tmp; + char path[PATH_MAX]; + FILE *out; + + page_tmp = malloc(PAGESIZE()); + if (page_tmp == NULL) + return -1; + + for (i = 0; i < nr_cpu_ids; i++) { + struct ring_buffer_per_cpu *cpu_buffer = &global_buffers[i]; + + if (!cpu_buffer->kaddr) + continue; + + snprintf(path, sizeof(path), "%s/cpu%d", per_cpu_path, i); + if (try_mkdir(path, 0755) < 0) + goto out_fail; + + snprintf(path, sizeof(path), "%s/cpu%d/trace_pipe_raw", + per_cpu_path, i); + out = fopen(path, "wb"); + if (out == NULL) + goto out_fail; + + ftrace_dump_buffer(out, cpu_buffer, global_pages, page_tmp); + fclose(out); + } + + free(page_tmp); + return 0; + +out_fail: + free(page_tmp); + return -1; +} + +typedef uint64_t u64; +typedef int64_t s64; +typedef uint32_t u32; + +#define MAX_CACHE_ID 256 + +struct ftrace_field; +typedef u64 (*access_op)(struct ftrace_field *aop, void *data); +static void ftrace_field_access_init(struct ftrace_field *f); + +struct ftrace_field { + const char *name; + const char *type; + access_op op; + int offset; + int size; + int is_signed; +}; + +struct event_type; +struct format_context; +typedef void (*event_printer)(struct event_type *t, struct format_context *fc); + + /* SIGH, we cann't get "print fmt" from core-file */ + +struct event_type { + struct event_type *next; + const char *system; + const char *name; + int plugin; + event_printer printer; + const char *print_fmt; + int id; + int nfields; + struct ftrace_field *fields; +}; + +static struct event_type *event_type_cache[MAX_CACHE_ID]; +static struct event_type **event_types; +static int nr_event_types; + +/* + * TODO: implement event_generic_print_fmt_print() when the print fmt + * in tracing/events/$SYSTEM/$TRACE/format becomes a will-defined + * language. + * + * static void event_generic_print_fmt_print(struct event_type *t, + * struct format_context *fc); + */ +static void event_default_print(struct event_type *t, + struct format_context *fc); + +static int ftrace_init_event_type(ulong call, struct event_type *aevent_type) +{ + ulong fields_addr, pos; + + int nfields = 0, max_fields = 16; + struct ftrace_field *fields = NULL; + + fields_addr = call + koffset(ftrace_event_call, fields); + read_value(pos, fields_addr, list_head, next); + + if (pos == 0) { + if (verbose) + fprintf(fp, "no field %lu\n", call); + return 0; + } + + fields = malloc(sizeof(*fields) * max_fields); + if (fields == NULL) + return -1; + + while (pos != fields_addr) { + ulong field; + ulong name_addr, type_addr; + char field_name[128], field_type[128]; + int offset, size, is_signed; + + field = pos - koffset(ftrace_event_field, link); + + /* Read a field from the core */ + read_value(name_addr, field, ftrace_event_field, name); + read_value(type_addr, field, ftrace_event_field, type); + read_value(offset, field, ftrace_event_field, offset); + read_value(size, field, ftrace_event_field, size); + read_value(is_signed, field, ftrace_event_field, is_signed); + + if (!read_string(name_addr, field_name, 128)) + goto out_fail; + if (!read_string(type_addr, field_type, 128)) + goto out_fail; + + /* Enlarge fields array when need */ + if (nfields >= max_fields) { + void *tmp; + + max_fields = nfields * 2; + tmp = realloc(fields, sizeof(*fields) * max_fields); + if (tmp == NULL) + goto out_fail; + + fields = tmp; + } + + /* Set up and Add a field */ + fields[nfields].offset = offset; + fields[nfields].size = size; + fields[nfields].is_signed = is_signed; + + fields[nfields].name = strdup(field_name); + if (fields[nfields].name == NULL) + goto out_fail; + + fields[nfields].type = strdup(field_type); + if (fields[nfields].type == NULL) { + free(fields[nfields].name); + goto out_fail; + } + + ftrace_field_access_init(&fields[nfields]); + nfields++; + + /* Advance to the next field */ + read_value(pos, pos, list_head, next); + } + + aevent_type->nfields = nfields; + aevent_type->fields = fields; + + return 0; + +out_fail: + for (nfields--; nfields >= 0; nfields--) { + free(fields[nfields].name); + free(fields[nfields].type); + } + + free(fields); + return -1; +} + +static void ftrace_destroy_event_types(void) +{ + int i, j; + + for (i = 0; i < nr_event_types; i++) { + for (j = 0; j < event_types[i]->nfields; j++) { + free(event_types[i]->fields[j].name); + free(event_types[i]->fields[j].type); + } + + free(event_types[i]->fields); + free(event_types[i]->system); + free(event_types[i]->name); + free(event_types[i]); + } + + free(event_types); +} + +static int ftrace_init_event_types(void) +{ + ulong event; + struct event_type *aevent_type; + int max_types = 128; + + event_types = malloc(sizeof(*event_types) * max_types); + if (event_types == NULL) + return -1; + + read_value(event, ftrace_events, list_head, next); + while (event != ftrace_events) { + ulong call; + ulong name_addr, system_addr; + char name[128], system[128]; + int id; + + call = event - koffset(ftrace_event_call, list); + + /* Read a event type from the core */ + read_value(id, call, ftrace_event_call, id); + read_value(name_addr, call, ftrace_event_call, name); + read_value(system_addr, call, ftrace_event_call, system); + + if (!read_string(name_addr, name, 128)) + goto out_fail; + if (!read_string(system_addr, system, 128)) + goto out_fail; + + /* Enlarge event types array when need */ + if (nr_event_types >= max_types) { + void *tmp; + + max_types = 2 * nr_event_types; + tmp = realloc(event_types, + sizeof(*event_types) * max_types); + if (tmp == NULL) + goto out_fail; + + event_types = tmp; + } + + /* Create a event type */ + aevent_type = malloc(sizeof(*aevent_type)); + if (aevent_type == NULL) + goto out_fail; + + aevent_type->system = strdup(system); + aevent_type->name = strdup(name); + aevent_type->id = id; + aevent_type->nfields = 0; + aevent_type->fields = NULL; + + if (aevent_type->system == NULL || aevent_type->name == NULL) + goto out_fail_free_aevent_type; + + if (ftrace_init_event_type(call, aevent_type) < 0) + goto out_fail_free_aevent_type; + + if (!strcmp("ftrace", aevent_type->system)) + aevent_type->plugin = 1; + else + aevent_type->plugin = 0; + aevent_type->printer = event_default_print; + + /* Add a event type */ + event_types[nr_event_types++] = aevent_type; + if ((unsigned)id < MAX_CACHE_ID) + event_type_cache[id] = aevent_type; + + /* Advance to the next event type */ + read_value(event, event, list_head, next); + } + + return 0; + +out_fail_free_aevent_type: + free(aevent_type->system); + free(aevent_type->name); + free(aevent_type); +out_fail: + ftrace_destroy_event_types(); + return -1; +} + +static +struct ftrace_field *find_event_field(struct event_type *t, const char *name) +{ + int i; + struct ftrace_field *f; + + for (i = 0; i < t->nfields; i++) { + f = &t->fields[i]; + if (!strcmp(name, f->name)) + return f; + } + + return NULL; +} + +static struct event_type *find_event_type(int id) +{ + int i; + + if ((unsigned int)id < MAX_CACHE_ID) + return event_type_cache[id]; + + for (i = 0; i < nr_event_types; i++) { + if (event_types[i]->id == id) + return event_types[i]; + } + + return NULL; +} + +static +struct event_type *find_event_type_by_name(const char *system, const char *name) +{ + int i; + + for (i = 0; i < nr_event_types; i++) { + if (system && strcmp(system, event_types[i]->system)) + continue; + if (!strcmp(name, event_types[i]->name)) + return event_types[i]; + } + + return NULL; +} + +static int ftrace_dump_event_type(struct event_type *t, const char *path) +{ + char format_path[PATH_MAX]; + FILE *out; + int i; + + snprintf(format_path, sizeof(format_path), "%s/format", path); + out = fopen(format_path, "w"); + if (out == NULL) + return -1; + + fprintf(out, "name: %s\n", t->name); + fprintf(out, "ID: %d\n", t->id); + fprintf(out, "format:\n"); + + for (i = 0; i < t->nfields; i++) { + struct ftrace_field *f = &t->fields[i]; + + fprintf(out, "\tfield:%s %s;\toffset:%d;\tsize:%d;\n", + f->type, f->name, f->offset, f->size); + } + + /* TODO */ + fprintf(out, "\nprint fmt: \"unknow fmt from dump\"\n"); + fclose(out); + + return 0; +} + +static int ftrace_dump_event_types(const char *events_path) +{ + int i; + + for (i = 0; i < nr_event_types; i++) { + char path[PATH_MAX]; + struct event_type *t = event_types[i]; + + snprintf(path, sizeof(path), "%s/%s", events_path, t->system); + if (try_mkdir(path, 0755) < 0) + return -1; + + snprintf(path, sizeof(path), "%s/%s/%s", events_path, + t->system, t->name); + if (try_mkdir(path, 0755) < 0) + return -1; + + if (ftrace_dump_event_type(t, path) < 0) + return -1; + } + + return 0; +} + +struct ring_buffer_per_cpu_stream { + ulong *pages; + void *curr_page; + int available_pages; + int curr_page_indx; + + uint64_t ts; + uint32_t *offset; + uint32_t *commit; +}; + +static +int ring_buffer_per_cpu_stream_init(struct ring_buffer_per_cpu *cpu_buffer, + unsigned pages, struct ring_buffer_per_cpu_stream *s) +{ + unsigned i, count = 0; + + s->curr_page = malloc(PAGESIZE()); + if (s->curr_page == NULL) + return -1; + + s->pages = malloc(sizeof(ulong) * (pages + 1)); + if (s->pages == NULL) { + free(s->curr_page); + return -1; + } + + s->pages[count++] = cpu_buffer->reader_page; + + if (cpu_buffer->reader_page == cpu_buffer->commit_page) + goto pages_done; + + i = cpu_buffer->head_page_index; + for (;;) { + s->pages[count++] = cpu_buffer->pages[i]; + + if (cpu_buffer->pages[i] == cpu_buffer->commit_page) + break; + + i++; + if (i == pages) + i = 0; + + if (i == cpu_buffer->head_page_index) { + /* cpu_buffer->commit_page may be corrupted */ + break; + } + } + +pages_done: + s->available_pages = count; + s->curr_page_indx = -1; + return 0; +} + +static +void ring_buffer_per_cpu_stream_destroy(struct ring_buffer_per_cpu_stream *s) +{ + free(s->curr_page); + free(s->pages); +} + +struct ftrace_event { + uint64_t ts; + int length; + void *data; +}; + +struct event { + u32 type_len:5, time_delta:27; +}; + +#define RINGBUF_TYPE_PADDING 29 +#define RINGBUF_TYPE_TIME_EXTEND 30 +#define RINGBUF_TYPE_TIME_STAMP 31 +#define RINGBUF_TYPE_DATA 0 ... 28 + +#define sizeof_local_t (sizeof(ulong)) +#define PAGE_HEADER_LEN (8 + sizeof_local_t) + +static +int ring_buffer_per_cpu_stream_get_page(struct ring_buffer_per_cpu_stream *s) +{ + ulong raw_page; + + read_value(raw_page, s->pages[s->curr_page_indx], buffer_page, page); + + if (!readmem(raw_page, KVADDR, s->curr_page, PAGESIZE(), + "get page context", RETURN_ON_ERROR)) + return -1; + + s->ts = *(u64 *)s->curr_page; + s->offset = s->curr_page + PAGE_HEADER_LEN; + s->commit = s->offset + *(ulong *)(s->curr_page + 8) / 4; + + return 0; + +out_fail: + return -1; +} + +static +int ring_buffer_per_cpu_stream_pop_event(struct ring_buffer_per_cpu_stream *s, + struct ftrace_event *res) +{ + struct event *event; + + res->data = NULL; + + if (s->curr_page_indx >= s->available_pages) + return -1; + +again: + if ((s->curr_page_indx == -1) || (s->offset >= s->commit)) { + s->curr_page_indx++; + + if (s->curr_page_indx == s->available_pages) + return -1; + + if (ring_buffer_per_cpu_stream_get_page(s) < 0) { + s->curr_page_indx = s->available_pages; + return -1; + } + + if (s->offset >= s->commit) + goto again; + } + + event = (void *)s->offset; + + switch (event->type_len) { + case RINGBUF_TYPE_PADDING: + if (event->time_delta) + s->offset += 1 + ((*(s->offset + 1) + 3) / 4); + else + s->offset = s->commit; + goto again; + + case RINGBUF_TYPE_TIME_EXTEND: + s->ts +=event->time_delta; + s->ts += ((u64)*(s->offset + 1)) << 27; + s->offset += 2; + goto again; + + case RINGBUF_TYPE_TIME_STAMP: + /* FIXME: not implemented */ + s->offset += 4; + goto again; + + case RINGBUF_TYPE_DATA: + if (!event->type_len) { + res->data = s->offset + 2; + res->length = *(s->offset + 1) - 4; + + s->offset += 1 + ((*(s->offset + 1) + 3) / 4); + } else { + res->data = s->offset + 1; + res->length = event->type_len * 4; + + s->offset += 1 + event->type_len; + } + + if (s->offset > s->commit) { + fprintf(fp, "corrupt\n"); + res->data = NULL; + goto again; + } + + s->ts += event->time_delta; + res->ts = s->ts; + + return 0; + + default:; + } + + return -1; +} + +struct ring_buffer_stream { + struct ring_buffer_per_cpu_stream *ss; + struct ftrace_event *es; + u64 ts; + int popped_cpu; + int pushed; +}; + +static void __rbs_destroy(struct ring_buffer_stream *s, int *cpulist, int nr) +{ + int cpu; + + for (cpu = 0; cpu < nr; cpu++) { + if (!global_buffers[cpu].kaddr) + continue; + if (cpulist && !cpulist[cpu]) + continue; + + ring_buffer_per_cpu_stream_destroy(s->ss + cpu); + } + + free(s->ss); + free(s->es); +} + +static +int ring_buffer_stream_init(struct ring_buffer_stream *s, int *cpulist) +{ + int cpu; + + s->ss = malloc(sizeof(*s->ss) * nr_cpu_ids); + if (s->ss == NULL) + return -1; + + s->es = malloc(sizeof(*s->es) * nr_cpu_ids); + if (s->es == NULL) { + free(s->ss); + return -1; + } + + for (cpu = 0; cpu < nr_cpu_ids; cpu++) { + s->es[cpu].data = NULL; + + if (!global_buffers[cpu].kaddr) + continue; + + if (cpulist && !cpulist[cpu]) + continue; + + if (ring_buffer_per_cpu_stream_init(global_buffers + cpu, + global_pages, s->ss + cpu) < 0) { + __rbs_destroy(s, cpulist, cpu); + return -1; + } + } + + s->ts = 0; + s->popped_cpu = nr_cpu_ids; + s->pushed = 0; + + return 0; +} + +static +void ring_buffer_stream_destroy(struct ring_buffer_stream *s, int *cpulist) +{ + __rbs_destroy(s, cpulist, nr_cpu_ids); +} + +/* make current event be returned again at next pop */ +static void ring_buffer_stream_push_current_event(struct ring_buffer_stream *s) +{ + if ((s->popped_cpu < 0) || (s->popped_cpu == nr_cpu_ids)) + return; + + s->pushed = 1; +} + +/* return the cpu# of this event */ +static int ring_buffer_stream_pop_event(struct ring_buffer_stream *s, + struct ftrace_event *res) +{ + int cpu, min_cpu = -1; + u64 ts, min_ts; + + res->data = NULL; + + if (s->popped_cpu < 0) + return -1; + + if (s->popped_cpu == nr_cpu_ids) { + for (cpu = 0; cpu < nr_cpu_ids; cpu++) { + if (!global_buffers[cpu].kaddr) + continue; + + ring_buffer_per_cpu_stream_pop_event(s->ss + cpu, + s->es + cpu); + + if (s->es[cpu].data == NULL) + continue; + + /* + * We do not have start point of time, + * determine the min_ts with heuristic way. + */ + ts = s->es[cpu].ts; + if (min_cpu < 0 || (s64)(ts - min_ts) < 0) { + min_ts = ts; + min_cpu = cpu; + } + } + + s->pushed = 0; + goto done; + } + + if (s->pushed) { + s->pushed = 0; + *res = s->es[s->popped_cpu]; + return s->popped_cpu; + } + + ring_buffer_per_cpu_stream_pop_event(&s->ss[s->popped_cpu], + &s->es[s->popped_cpu]); + + for (cpu = 0; cpu < nr_cpu_ids; cpu++) { + if (s->es[cpu].data == NULL) + continue; + + /* we have start point of time(s->ts) */ + ts = s->es[cpu].ts - s->ts; + if (min_cpu < 0 || ts < min_ts) { + min_ts = ts; + min_cpu = cpu; + } + } + +done: + s->popped_cpu = min_cpu; + + if (min_cpu < 0) + return -1; + + s->ts = s->es[min_cpu].ts; + *res = s->es[min_cpu]; + + return min_cpu; +} + +static u64 access_error(struct ftrace_field *f, void *data) +{ + return 0; +} + +static u64 access_8(struct ftrace_field *f, void *data) +{ + return *(int8_t *)(data + f->offset); +} + +static u64 access_16(struct ftrace_field *f, void *data) +{ + return *(int16_t *)(data + f->offset); +} + +static u64 access_32(struct ftrace_field *f, void *data) +{ + return *(int32_t *)(data + f->offset); +} + +static u64 access_64(struct ftrace_field *f, void *data) +{ + return *(int64_t *)(data + f->offset); +} + +static u64 access_string_local(struct ftrace_field *f, void *data) +{ + int offset; + + if (f->size == 2) + offset = *(int16_t *)(data + f->offset); + else + offset = *(int32_t *)(data + f->offset) & 0xFFFF; + + return (long)(data + offset); +} + +static u64 access_string(struct ftrace_field *f, void *data) +{ + return (long)(data + f->offset); +} + +static u64 access_other_local(struct ftrace_field *f, void *data) +{ + return access_string_local(f, data); +} + +static u64 access_other(struct ftrace_field *f, void *data) +{ + return (long)(data + f->offset); +} + +static void ftrace_field_access_init(struct ftrace_field *f) +{ + /* guess whether it is string array */ + if (!strncmp(f->type, "__data_loc", sizeof("__data_loc") - 1)) { + if (f->size != 2 && f->size != 4) { + /* kernel side may be changed, need fix here */ + f->op = access_error; + } else if (strstr(f->type, "char")) { + f->op = access_string_local; + } else { + f->op = access_other_local; + } + } else if (strchr(f->type, '[')) { + if (strstr(f->type, "char")) + f->op = access_string; + else + f->op = access_other; + } else { + switch (f->size) { + case 1: f->op = access_8; break; + case 2: f->op = access_16; break; + case 4: f->op = access_32; break; + case 8: f->op = access_64; break; + default: f->op = access_other; break; + } + } +} + +static void show_basic_info(void) +{ + fprintf(fp, "current tracer is %s\n", current_tracer_name); +} + +static int dump_saved_cmdlines(const char *dump_tracing_dir) +{ + char path[PATH_MAX]; + FILE *out; + int i; + struct task_context *tc; + + snprintf(path, sizeof(path), "%s/saved_cmdlines", dump_tracing_dir); + out = fopen(path, "w"); + if (out == NULL) + return -1; + + tc = FIRST_CONTEXT(); + for (i = 0; i < RUNNING_TASKS(); i++) + fprintf(out, "%d %s\n", (int)tc[i].pid, tc[i].comm); + + fclose(out); + return 0; +} + +static void ftrace_dump(int argc, char *argv[]) +{ + int c; + int dump_meta_data = 0; + int dump_symbols = 0; + char *dump_tracing_dir; + char path[PATH_MAX]; + int ret; + + while ((c = getopt(argc, argv, "sm")) != EOF) { + switch(c) + { + case 's': + dump_symbols = 1; + break; + case 'm': + dump_meta_data = 1; + break; + default: + cmd_usage(pc->curcmd, SYNOPSIS); + return; + } + } + + if (argc - optind == 0) { + dump_tracing_dir = "dump_tracing_dir"; + } else if (argc - optind == 1) { + dump_tracing_dir = argv[optind]; + } else { + cmd_usage(pc->curcmd, SYNOPSIS); + return; + } + + ret = mkdir(dump_tracing_dir, 0755); + if (ret < 0) { + if (errno == EEXIST) + error(INFO, "mkdir: %s exists\n", dump_tracing_dir); + return; + } + + snprintf(path, sizeof(path), "%s/per_cpu", dump_tracing_dir); + if (try_mkdir(path, 0755) < 0) + return; + + if (ftrace_dump_buffers(path) < 0) + return; + + if (dump_meta_data) { + /* Dump event types */ + snprintf(path, sizeof(path), "%s/events", dump_tracing_dir); + if (try_mkdir(path, 0755) < 0) + return; + + if (ftrace_dump_event_types(path) < 0) + return; + + /* Dump pids with corresponding cmdlines */ + if (dump_saved_cmdlines(dump_tracing_dir) < 0) + return; + } + + if (dump_symbols) { + /* Dump all symbols of the kernel */ + fprintf(fp, "\n-s option hasn't been implemented.\n"); + fprintf(fp, "symbols is not dumpped.\n"); + fprintf(fp, "You can use `sym -l > %s/kallsyms`\n\n", + dump_tracing_dir); + } +} + +static char show_event_buf[4096]; +static int show_event_pos; + +#define INVALID_ACCESS_FIELD 1 +static jmp_buf show_event_env; + +struct format_context { + struct ring_buffer_stream stream; + struct ftrace_event event; + int cpu; +}; + +static struct format_context format_context; + +/* !!!! @event_type and @field_name should be const for every call */ +#define access_field(event_type, data, field_name) \ +({ \ + static struct ftrace_field *__access_field##_field; \ + \ + if (__access_field##_field == NULL) { \ + __access_field##_field = find_event_field(event_type, \ + field_name); \ + } \ + \ + if (__access_field##_field == NULL) { \ + event_type->printer = event_default_print; \ + ring_buffer_stream_push_current_event(&format_context.stream);\ + longjmp(show_event_env, INVALID_ACCESS_FIELD); \ + } \ + \ + __access_field##_field->op(__access_field##_field, data); \ +}) + +static int ftrace_event_get_id(void *data) +{ + return access_field(event_types[0], data, "common_type"); +} + +static int ftrace_event_get_pid(void *data) +{ + return access_field(event_types[0], data, "common_pid"); +} + +#define event_printf(fmt, args...) \ +do { \ + show_event_pos += snprintf(show_event_buf + show_event_pos, \ + sizeof(show_event_buf) - show_event_pos, \ + fmt, ##args); \ +} while (0) + + +static void event_field_print(struct ftrace_field *f, void *data) +{ + u64 value = f->op(f, data); + + if (f->op == access_error) { + event_printf(""); + } else if (f->op == access_8) { + if (f->is_signed) + event_printf("%d", (int8_t)value); + else + event_printf("%u", (uint8_t)value); + } else if (f->op == access_16) { + if (f->is_signed) + event_printf("%d", (int16_t)value); + else + event_printf("%u", (uint16_t)value); + } else if (f->op == access_32) { + if (f->is_signed) + event_printf("%d", (int32_t)value); + else + event_printf("%u", (uint32_t)value); + } else if (f->op == access_64) { + if (f->is_signed) + event_printf("%lld", (long long)value); + else + event_printf("%llu", (unsigned long long)value); + } else if (f->op == access_string_local) { + int size = 0; + + if (f->size == 4) + size = *(int32_t *)(data + f->offset) >> 16; + + if (size) + event_printf("%.*s", size, (char *)(long)value); + else + event_printf("%s", (char *)(long)value); + } else if (f->op == access_string) { + event_printf("%.*s", f->size, (char *)(long)value); + } else if (f->op == access_other) { + /* TODO */ + } else if (f->op == access_other_local) { + /* TODO */ + } else { + /* TODO */ + } +} + +static void get_comm_from_pid(int pid, char *comm) +{ + int li, hi; + struct task_context *tc; + + if (pid == 0) { + strcpy(comm, ""); + return; + } + + tc = FIRST_CONTEXT(); + + li = 0; + hi = RUNNING_TASKS(); + while (li < hi) { + int mid = (li + hi) / 2; + + if (tc[mid].pid > pid) + hi = mid; + else if (tc[mid].pid < pid) + li = mid + 1; + else { + strcpy(comm, tc[mid].comm); + return; + } + } + + strcpy(comm, "<...>"); +} + +static void event_context_print(struct event_type *t, struct format_context *fc) +{ + u64 time = fc->event.ts / 1000; + ulong sec = time / 1000000; + ulong usec = time % 1000000; + int pid = ftrace_event_get_pid(fc->event.data); + char comm[20]; + + get_comm_from_pid(pid, comm); + event_printf("%16s-%-5d [%03d] %5lu.%06lu: ", + comm, pid, fc->cpu, sec, usec); +} + +static int gopt_context_info; +static int gopt_sym_offset; +static int gopt_sym_addr; + +static int gopt_graph_print_duration; +static int gopt_graph_print_overhead; +static int gopt_graph_print_abstime; +static int gopt_graph_print_cpu; +static int gopt_graph_print_proc; +static int gopt_graph_print_overrun; + +static void set_all_flags_default(void) +{ + gopt_context_info = 1; + gopt_sym_offset = 0; + gopt_sym_addr = 0; + + gopt_graph_print_duration = 1; + gopt_graph_print_overhead = 1; + gopt_graph_print_abstime = 0; + gopt_graph_print_cpu = 1; + gopt_graph_print_proc = 0; + gopt_graph_print_overrun = 0; +} + +static void set_clear_flag(const char *flag_name, int set) +{ + if (!strcmp(flag_name, "context_info")) + gopt_context_info = set; + else if (!strcmp(flag_name, "sym_offset")) + gopt_sym_offset = set; + else if (!strcmp(flag_name, "sym_addr")) + gopt_sym_addr = set; + else if (!strcmp(flag_name, "graph_print_duration")) + gopt_graph_print_duration = set; + else if (!strcmp(flag_name, "graph_print_overhead")) + gopt_graph_print_overhead = set; + else if (!strcmp(flag_name, "graph_print_abstime")) + gopt_graph_print_abstime = set; + else if (!strcmp(flag_name, "graph_print_cpu")) + gopt_graph_print_cpu = set; + else if (!strcmp(flag_name, "graph_print_proc")) + gopt_graph_print_proc = set; + else if (!strcmp(flag_name, "graph_print_overrun")) + gopt_graph_print_overrun = set; + /* invalid flage_name is omitted. */ +} + +static int tracer_no_event_context; + +static void ftrace_show_function_graph_init(void); +static void ftrace_show_function_init(void); +static void ftrace_show_trace_event_init(void); + +static int ftrace_show_init(void) +{ + /* ftrace_event_get_id(), ftrace_event_get_pid() should not failed. */ + if (find_event_field(event_types[0], "common_type") == NULL) + return -1; + + if (find_event_field(event_types[0], "common_pid") == NULL) + return -1; + + ftrace_show_function_init(); + ftrace_show_function_graph_init(); + ftrace_show_trace_event_init(); + + return 0; +} + +void show_event(struct format_context *fc) +{ + struct event_type *etype; + int id; + + id = ftrace_event_get_id(fc->event.data); + etype = find_event_type(id); + + if (etype == NULL) { + event_printf("\n"); + return; + } + + if (!tracer_no_event_context && gopt_context_info) + event_context_print(etype, fc); + if (!etype->plugin) + event_printf("%s: ", etype->name); + etype->printer(etype, fc); +} + +static int parse_cpulist(int *cpulist, const char *cpulist_str, int len) +{ + unsigned a, b; + const char *s = cpulist_str; + + memset(cpulist, 0, sizeof(int) * len); + + do { + if (!isdigit(*s)) + return -1; + b = a = strtoul(s, (char **)&s, 10); + if (*s == '-') { + s++; + if (!isdigit(*s)) + return -1; + b = strtoul(s, (char **)&s, 10); + } + if (!(a <= b)) + return -1; + if (b >= len) + return -1; + while (a <= b) { + cpulist[a] = 1; + a++; + } + if (*s == ',') + s++; + } while (*s != '\0' && *s != '\n'); + + return 0; +} + +static void ftrace_show_function_graph_start(void); + +static void ftrace_show(int argc, char *argv[]) +{ + int c; + int *cpulist = NULL; + + set_all_flags_default(); + ftrace_show_function_graph_start(); + + while ((c = getopt(argc, argv, "f:c:")) != EOF) { + switch(c) + { + case 'f': + if (optarg[0] == 'n' && optarg[1] == 'o') + set_clear_flag(optarg + 2, 0); + else + set_clear_flag(optarg, 1); + break; + case 'c': + if (cpulist) + goto err_arg; + + cpulist = malloc(sizeof(int) * nr_cpu_ids); + if (cpulist == NULL) { + error(INFO, "malloc() fail\n"); + return; + } + + if (parse_cpulist(cpulist, optarg, nr_cpu_ids) < 0) + goto err_arg; + break; + default: + goto err_arg; + } + } + + if (argc - optind != 0) { +err_arg: + cmd_usage(pc->curcmd, SYNOPSIS); + free(cpulist); + return; + } + + ring_buffer_stream_init(&format_context.stream, cpulist); + + /* Ignore setjmp()'s return value, no special things to do. */ + setjmp(show_event_env); + + for (;;) { + show_event_pos = 0; + format_context.cpu = ring_buffer_stream_pop_event( + &format_context.stream, &format_context.event); + if (format_context.cpu < 0) + break; + + show_event(&format_context); + fprintf(fp, "%s", show_event_buf); + } + + ring_buffer_stream_destroy(&format_context.stream, cpulist); + free(cpulist); +} + +static void cmd_ftrace(void) +{ + if (argcnt == 1) + show_basic_info(); + else if (!strcmp(args[1], "dump")) + ftrace_dump(argcnt - 1, args + 1); + else if (!strcmp(args[1], "show")) + ftrace_show(argcnt - 1, args + 1); + else + cmd_usage(pc->curcmd, SYNOPSIS); +} + +static void event_default_print(struct event_type *t, struct format_context *fc) +{ + int i; + + /* Skip the common types */ + for (i = t->nfields - 6; i >= 0; i--) { + struct ftrace_field *f; + + f = &t->fields[i]; + event_printf("%s=", f->name); + event_field_print(f, fc->event.data); + if (i) + event_printf(", "); + } + + event_printf("\n"); +} + +static void sym_print(ulong sym, int opt_offset) +{ + if (!sym) { + event_printf("0"); + } else { + ulong offset; + struct syment *se; + + se = value_search(sym, &offset); + if (se) { + event_printf("%s", se->name); + if (opt_offset) + event_printf("+%lu", offset); + } + } +} + +static void event_fn_print(struct event_type *t, struct format_context *fc) +{ + unsigned long ip = access_field(t, fc->event.data, "ip"); + unsigned long parent_ip = access_field(t, fc->event.data, "parent_ip"); + + sym_print(ip, gopt_sym_offset); + if (gopt_sym_addr) + event_printf("<%lx>", ip); + + event_printf(" <-"); + + sym_print(parent_ip, gopt_sym_offset); + if (gopt_sym_addr) + event_printf("<%lx>", parent_ip); + + event_printf("\n"); +} + +static void ftrace_show_function_init(void) +{ + struct event_type *t = find_event_type_by_name("ftrace", "function"); + + if (t) + t->printer = event_fn_print; +} + +#if 0 +/* simple */ +static void event_fn_entry_print(struct event_type *t, struct format_context *fc) +{ + ulong func = access_field(t, fc->event.data, "graph_ent.func"); + int depth = access_field(t, fc->event.data, "graph_ent.depth"); + + event_printf("%*s", depth, " "); + sym_print(func, gopt_sym_offset); + if (gopt_sym_addr) + event_printf("<%lx>", func); + event_printf("() {"); +} + +static void event_fn_return_print(struct event_type *t, struct format_context *fc) +{ + ulong func = access_field(t, fc->event.data, "ret.func"); + u64 calltime = access_field(t, fc->event.data, "ret.calltime"); + u64 rettime = access_field(t, fc->event.data, "ret.rettime"); + int depth = access_field(t, fc->event.data, "ret.depth"); + + event_printf("%*s} %lluns", depth, " ", + (unsigned long long)(rettime - calltime)); +} + +static void ftrace_show_function_graph_init(void) +{ + struct event_type *t1 = find_event_type_by_name( + "ftrace", "funcgraph_entry"); + struct event_type *t2 = find_event_type_by_name( + "ftrace", "funcgraph_exit"); + + if (t1 == NULL || t2 == NULL) + return; + + t1->printer = event_fn_entry_print; + t2->printer = event_fn_return_print; +} +#endif + + +#define TRACE_GRAPH_PROCINFO_LENGTH 14 +#define TRACE_GRAPH_INDENT 2 + +static int max_bytes_for_cpu; +static int *cpus_prev_pid; + +static int function_graph_entry_id; +static int function_graph_return_id; +static struct event_type *function_graph_entry_type; +static struct event_type *function_graph_return_type; + +static void ftrace_show_function_graph_start(void) +{ + int i; + + if (cpus_prev_pid == NULL) + return; + + for (i = 0; i < nr_cpu_ids; i++) + cpus_prev_pid[i] = -1; +} + +static void fn_graph_proc_print(int pid) +{ + int pid_strlen, comm_strlen; + char pid_str[20]; + char comm[20] = "<...>"; + + pid_strlen = sprintf(pid_str, "%d", pid); + comm_strlen = TRACE_GRAPH_PROCINFO_LENGTH - 1 - pid_strlen; + + get_comm_from_pid(pid, comm); + event_printf("%*.*s-%s", comm_strlen, comm_strlen, comm, pid_str); +} + +/* If the pid changed since the last trace, output this event */ +static void fn_graph_proc_switch_print(int pid, int cpu) +{ + int prev_pid = cpus_prev_pid[cpu]; + + cpus_prev_pid[cpu] = pid; + if ((prev_pid == pid) || (prev_pid == -1)) + return; + +/* + * Context-switch trace line: + + ------------------------------------------ + | 1) migration/0--1 => sshd-1755 + ------------------------------------------ + + */ + + event_printf(" ------------------------------------------\n"); + event_printf(" %*d) ", max_bytes_for_cpu, cpu); + fn_graph_proc_print(prev_pid); + event_printf(" => "); + fn_graph_proc_print(pid); + event_printf("\n ------------------------------------------\n\n"); +} + +/* Signal a overhead of time execution to the output */ +static void fn_graph_overhead_print(unsigned long long duration) +{ + const char *s = " "; + + /* If duration disappear, we don't need anything */ + if (!gopt_graph_print_duration) + return; + + /* duration == -1 is for non nested entry or return */ + if ((duration != -1) && gopt_graph_print_overhead) { + /* Duration exceeded 100 msecs */ + if (duration > 100000ULL) + s = "! "; + /* Duration exceeded 10 msecs */ + else if (duration > 10000ULL) + s = "+ "; + } + + event_printf(s); +} + +static void fn_graph_abstime_print(u64 ts) +{ + u64 time = ts / 1000; + unsigned long sec = time / 1000000; + unsigned long usec = time % 1000000; + + event_printf("%5lu.%06lu | ", sec, usec); +} + +static void fn_graph_irq_print(int type) +{ + /* TODO: implement it. */ +} + +static void fn_graph_duration_print(unsigned long long duration) +{ + /* log10(ULONG_MAX) + '\0' */ + char msecs_str[21]; + char nsecs_str[5]; + int len; + unsigned long nsecs_rem = duration % 1000; + + duration = duration / 1000; + len = sprintf(msecs_str, "%lu", (unsigned long) duration); + + /* Print msecs */ + event_printf("%s", msecs_str); + + /* Print nsecs (we don't want to exceed 7 numbers) */ + if (len < 7) { + snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem); + event_printf(".%s", nsecs_str); + + len += strlen(nsecs_str); + } + + if (len > 7) + len = 7; + + event_printf(" us %*s| ", 7 - len, ""); +} + +/* Case of a leaf function on its call entry */ +static void fn_graph_entry_leaf_print(void *entry_data, void *exit_data) +{ + struct event_type *t = function_graph_return_type; + + u64 calltime = access_field(t, exit_data, "ret.calltime"); + u64 rettime = access_field(t, exit_data, "ret.rettime"); + u64 duration = rettime - calltime; + int depth = access_field(t, exit_data, "ret.depth"); + ulong func = access_field(t, exit_data, "ret.func"); + + fn_graph_overhead_print(duration); + if (gopt_graph_print_duration) + fn_graph_duration_print(duration); + + event_printf("%*s", depth * TRACE_GRAPH_INDENT, ""); + sym_print(func, 0); + event_printf("();\n"); +} + +static void fn_graph_entry_nested_print(struct event_type *t, void *data) +{ + int depth = access_field(t, data, "graph_ent.depth"); + ulong func = access_field(t, data, "graph_ent.func"); + + fn_graph_overhead_print(-1); + + /* No time */ + if (gopt_graph_print_duration) + event_printf(" | "); + + event_printf("%*s", depth * TRACE_GRAPH_INDENT, ""); + sym_print(func, 0); + event_printf("() {\n"); +} + +static void fn_graph_prologue_print(int cpu, u64 ts, int pid, int type) +{ + fn_graph_proc_switch_print(pid, cpu); + + if (type) + fn_graph_irq_print(type); + + if (gopt_graph_print_abstime) + fn_graph_abstime_print(ts); + + if (gopt_graph_print_cpu) + event_printf(" %*d) ", max_bytes_for_cpu, cpu); + + if (gopt_graph_print_proc) { + fn_graph_proc_print(pid); + event_printf(" | "); + } +} + +static void *get_return_for_leaf(struct event_type *t, + struct format_context *fc, void *curr_data) +{ + int cpu; + struct ftrace_event next; + ulong entry_func, exit_func; + + cpu = ring_buffer_stream_pop_event(&fc->stream, &next); + + if (cpu < 0) + goto not_leaf; + + if (ftrace_event_get_id(next.data) != function_graph_return_id) + goto not_leaf; + + if (ftrace_event_get_pid(curr_data) != ftrace_event_get_pid(next.data)) + goto not_leaf; + + entry_func = access_field(t, curr_data, "graph_ent.func"); + exit_func = access_field(function_graph_return_type, next.data, + "ret.func"); + + if (entry_func != exit_func) + goto not_leaf; + + return next.data; + +not_leaf: + ring_buffer_stream_push_current_event(&fc->stream); + return NULL; +} + +static +void event_fn_entry_print(struct event_type *t, struct format_context *fc) +{ + void *leaf_ret_data = NULL, *curr_data = fc->event.data, *data; + int pid = ftrace_event_get_pid(curr_data); + + fn_graph_prologue_print(fc->cpu, fc->event.ts, pid, 1); + + data = alloca(fc->event.length); + if (data) { + memcpy(data, fc->event.data, fc->event.length); + curr_data = data; + leaf_ret_data = get_return_for_leaf(t, fc, curr_data); + } + + if (leaf_ret_data) + return fn_graph_entry_leaf_print(curr_data, leaf_ret_data); + else + return fn_graph_entry_nested_print(t, curr_data); +} + +static +void event_fn_return_print(struct event_type *t, struct format_context *fc) +{ + void *data = fc->event.data; + int pid = ftrace_event_get_pid(data); + + u64 calltime = access_field(t, data, "ret.calltime"); + u64 rettime = access_field(t, data, "ret.rettime"); + u64 duration = rettime - calltime; + int depth = access_field(t, data, "ret.depth"); + + fn_graph_prologue_print(fc->cpu, fc->event.ts, pid, 0); + fn_graph_overhead_print(duration); + + if (gopt_graph_print_duration) + fn_graph_duration_print(duration); + + event_printf("%*s}\n", depth * TRACE_GRAPH_INDENT, ""); + + if (gopt_graph_print_overrun) { + unsigned long overrun = access_field(t, data, "ret.overrun"); + event_printf(" (Overruns: %lu)\n", overrun); + } + + fn_graph_irq_print(0); +} + +static void ftrace_show_function_graph_init(void) +{ + if (strcmp(current_tracer_name, "function_graph")) + return; + + function_graph_entry_type = find_event_type_by_name( + "ftrace", "funcgraph_entry"); + function_graph_return_type = find_event_type_by_name( + "ftrace", "funcgraph_exit"); + + if (!function_graph_entry_type || !function_graph_return_type) + return; + + /* + * Because of get_return_for_leaf(), the exception handling + * of access_field() is not work for function_graph. So we need + * to ensure access_field() will not failed for these fields. + * + * I know these will not failed. I just ensure it. + */ + + if (!find_event_field(function_graph_entry_type, "graph_ent.func")) + return; + + if (!find_event_field(function_graph_entry_type, "graph_ent.depth")) + return; + + if (!find_event_field(function_graph_return_type, "ret.func")) + return; + + if (!find_event_field(function_graph_return_type, "ret.calltime")) + return; + + if (!find_event_field(function_graph_return_type, "ret.rettime")) + return; + + if (!find_event_field(function_graph_return_type, "ret.overrun")) + return; + + if (!find_event_field(function_graph_return_type, "ret.depth")) + return; + + cpus_prev_pid = malloc(sizeof(int) * nr_cpu_ids); + if (!cpus_prev_pid) + return; + + max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); + + function_graph_entry_id = function_graph_entry_type->id; + function_graph_return_id = function_graph_return_type->id; + + /* OK, set the printer for function_graph. */ + tracer_no_event_context = 1; + function_graph_entry_type->printer = event_fn_entry_print; + function_graph_return_type->printer = event_fn_return_print; +} + +static void event_sched_kthread_stop_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("task %s:%d\n", + (char *)(long)access_field(t, fc->event.data, "comm"), + (int)access_field(t, fc->event.data, "pid")); +} + +static void event_sched_kthread_stop_ret_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("ret %d\n", (int)access_field(t, fc->event.data, "ret")); +} + +static void event_sched_wait_task_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("task %s:%d [%d]\n", + (char *)(long)access_field(t, fc->event.data, "comm"), + (int)access_field(t, fc->event.data, "pid"), + (int)access_field(t, fc->event.data, "prio")); +} + +static void event_sched_wakeup_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("task %s:%d [%d] success=%d\n", + (char *)(long)access_field(t, fc->event.data, "comm"), + (int)access_field(t, fc->event.data, "pid"), + (int)access_field(t, fc->event.data, "prio"), + (int)access_field(t, fc->event.data, "success")); +} + +static void event_sched_wakeup_new_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("task %s:%d [%d] success=%d\n", + (char *)(long)access_field(t, fc->event.data, "comm"), + (int)access_field(t, fc->event.data, "pid"), + (int)access_field(t, fc->event.data, "prio"), + (int)access_field(t, fc->event.data, "success")); +} + +static void event_sched_switch_print(struct event_type *t, + struct format_context *fc) +{ + char *prev_comm = (char *)(long)access_field(t, fc->event.data, + "prev_comm"); + int prev_pid = access_field(t, fc->event.data, "prev_pid"); + int prev_prio = access_field(t, fc->event.data, "prev_prio"); + + int prev_state = access_field(t, fc->event.data, "prev_state"); + + char *next_comm = (char *)(long)access_field(t, fc->event.data, + "next_comm"); + int next_pid = access_field(t, fc->event.data, "next_pid"); + int next_prio = access_field(t, fc->event.data, "next_prio"); + + event_printf("task %s:%d [%d] (", prev_comm, prev_pid, prev_prio); + + if (prev_state == 0) { + event_printf("R"); + } else { + if (prev_state & 1) + event_printf("S"); + if (prev_state & 2) + event_printf("D"); + if (prev_state & 4) + event_printf("T"); + if (prev_state & 8) + event_printf("t"); + if (prev_state & 16) + event_printf("Z"); + if (prev_state & 32) + event_printf("X"); + if (prev_state & 64) + event_printf("x"); + if (prev_state & 128) + event_printf("W"); + } + + event_printf(") ==> %s:%d [%d]\n", next_comm, next_pid, next_prio); +} + +static void event_sched_migrate_task_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("task %s:%d [%d] from: %d to: %d\n", + (char *)(long)access_field(t, fc->event.data, "comm"), + (int)access_field(t, fc->event.data, "pid"), + (int)access_field(t, fc->event.data, "prio"), + (int)access_field(t, fc->event.data, "orig_cpu"), + (int)access_field(t, fc->event.data, "dest_cpu")); +} + +static void event_sched_process_free_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("task %s:%d [%d]\n", + (char *)(long)access_field(t, fc->event.data, "comm"), + (int)access_field(t, fc->event.data, "pid"), + (int)access_field(t, fc->event.data, "prio")); +} + +static void event_sched_process_exit_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("task %s:%d [%d]\n", + (char *)(long)access_field(t, fc->event.data, "comm"), + (int)access_field(t, fc->event.data, "pid"), + (int)access_field(t, fc->event.data, "prio")); +} + +static void event_sched_process_wait_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("task %s:%d [%d]\n", + (char *)(long)access_field(t, fc->event.data, "comm"), + (int)access_field(t, fc->event.data, "pid"), + (int)access_field(t, fc->event.data, "prio")); +} + +static void event_sched_process_fork_print(struct event_type *t, + struct format_context *fc) +{ + char *parent_comm = (char *)(long)access_field(t, fc->event.data, + "parent_comm"); + int parent_pid = access_field(t, fc->event.data, "parent_pid"); + + char *child_comm = (char *)(long)access_field(t, fc->event.data, + "child_comm"); + int child_pid = access_field(t, fc->event.data, "child_pid"); + + event_printf("parent %s:%d child %s:%d\n", parent_comm, parent_pid, + child_comm, child_pid); +} + +static void event_sched_signal_send_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("sig: %d task %s:%d\n", + (int)access_field(t, fc->event.data, "sig"), + (char *)(long)access_field(t, fc->event.data, "comm"), + (int)access_field(t, fc->event.data, "pid")); +} + +static void event_kmalloc_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu " + "gfp_flags=%lx\n", + (long)access_field(t, fc->event.data, "call_site"), + (void *)(long)access_field(t, fc->event.data, "ptr"), + (size_t)access_field(t, fc->event.data, "bytes_req"), + (size_t)access_field(t, fc->event.data, "bytes_alloc"), + (long)access_field(t, fc->event.data, "gfp_flags")); +} + +static void event_kmem_cache_alloc_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu " + "gfp_flags=%lx\n", + (long)access_field(t, fc->event.data, "call_site"), + (void *)(long)access_field(t, fc->event.data, "ptr"), + (size_t)access_field(t, fc->event.data, "bytes_req"), + (size_t)access_field(t, fc->event.data, "bytes_alloc"), + (long)access_field(t, fc->event.data, "gfp_flags")); +} + +static void event_kmalloc_node_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu " + "gfp_flags=%lx node=%d\n", + (long)access_field(t, fc->event.data, "call_site"), + (void *)(long)access_field(t, fc->event.data, "ptr"), + (size_t)access_field(t, fc->event.data, "bytes_req"), + (size_t)access_field(t, fc->event.data, "bytes_alloc"), + (long)access_field(t, fc->event.data, "gfp_flags"), + (int)access_field(t, fc->event.data, "node")); +} + +static void event_kmem_cache_alloc_node_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu " + "gfp_flags=%lx node=%d\n", + (long)access_field(t, fc->event.data, "call_site"), + (void *)(long)access_field(t, fc->event.data, "ptr"), + (size_t)access_field(t, fc->event.data, "bytes_req"), + (size_t)access_field(t, fc->event.data, "bytes_alloc"), + (long)access_field(t, fc->event.data, "gfp_flags"), + (int)access_field(t, fc->event.data, "node")); +} + +static void event_kfree_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("call_site=%lx ptr=%p\n", + (long)access_field(t, fc->event.data, "call_site"), + (void *)(long)access_field(t, fc->event.data, "ptr")); +} + +static void event_kmem_cache_free_print(struct event_type *t, + struct format_context *fc) +{ + event_printf("call_site=%lx ptr=%p\n", + (long)access_field(t, fc->event.data, "call_site"), + (void *)(long)access_field(t, fc->event.data, "ptr")); +} + +static void event_workqueue_insertion_print(struct event_type *t, + struct format_context *fc) +{ + char *thread_comm = (char *)(long)access_field(t, fc->event.data, + "thread_comm"); + int thread_pid = access_field(t, fc->event.data, "thread_pid"); + ulong func = access_field(t, fc->event.data, "func"); + + event_printf("thread=%s:%d func=", thread_comm, thread_pid); + sym_print(func, 1); + event_printf("\n"); +} + +static void event_workqueue_execution_print(struct event_type *t, + struct format_context *fc) +{ + char *thread_comm = (char *)(long)access_field(t, fc->event.data, + "thread_comm"); + int thread_pid = access_field(t, fc->event.data, "thread_pid"); + ulong func = access_field(t, fc->event.data, "func"); + + event_printf("thread=%s:%d func=", thread_comm, thread_pid); + sym_print(func, 1); + event_printf("\n"); +} + +static void event_workqueue_creation_print(struct event_type *t, + struct format_context *fc) +{ + char *thread_comm = (char *)(long)access_field(t, fc->event.data, + "thread_comm"); + int thread_pid = access_field(t, fc->event.data, "thread_pid"); + int cpu = access_field(t, fc->event.data, "cpu"); + + event_printf("thread=%s:%d cpu=%d\n", thread_comm, thread_pid, cpu); +} + +static void event_workqueue_destruction_print(struct event_type *t, + struct format_context *fc) +{ + char *thread_comm = (char *)(long)access_field(t, fc->event.data, + "thread_comm"); + int thread_pid = access_field(t, fc->event.data, "thread_pid"); + + event_printf("thread=%s:%d\n", thread_comm, thread_pid); +} + +static void ftrace_show_trace_event_init(void) +{ +#define init_trace_event(system, name) \ +do { \ + struct event_type *t = find_event_type_by_name(#system, #name); \ + if (t) \ + t->printer = event_ ## name ## _print; \ +} while (0) + + init_trace_event(sched, sched_kthread_stop); + init_trace_event(sched, sched_kthread_stop_ret); + init_trace_event(sched, sched_wait_task); + init_trace_event(sched, sched_wakeup); + init_trace_event(sched, sched_wakeup_new); + init_trace_event(sched, sched_switch); + init_trace_event(sched, sched_migrate_task); + init_trace_event(sched, sched_process_free); + init_trace_event(sched, sched_process_exit); + init_trace_event(sched, sched_process_wait); + init_trace_event(sched, sched_process_fork); + init_trace_event(sched, sched_signal_send); + + init_trace_event(kmem, kmalloc); + init_trace_event(kmem, kmem_cache_alloc); + init_trace_event(kmem, kmalloc_node); + init_trace_event(kmem, kmem_cache_alloc_node); + init_trace_event(kmem, kfree); + init_trace_event(kmem, kmem_cache_free); + + init_trace_event(workqueue, workqueue_insertion); + init_trace_event(workqueue, workqueue_execution); + init_trace_event(workqueue, workqueue_creation); + init_trace_event(workqueue, workqueue_destruction); +#undef init_trace_event +} + +static void ftrace_show_destroy(void) +{ + free(cpus_prev_pid); +} + +static char *help_ftrace[] = { +"trace", +"show or dump the tracing info", +"[ ] [-f [no]]> | > ]", +"trace", +" shows the current tracer and other informations.", +"", +"trace show [ -c ] [ -f [no] ]", +" shows all events with readability text(sorted by timestamp)", +" -c: only shows specified CPUs' events.", +" ex. trace show -c 1,2 - only shows cpu#1 and cpu#2 's events.", +" trace show -c 0,2-7 - only shows cpu#0, cpu#2...cpu#7's events.", +" -f: set or clear a flag", +" available flags default", +" context_info true", +" sym_offset false", +" sym_addr false", +" graph_print_duration true", +" graph_print_overhead true", +" graph_print_abstime false", +" graph_print_cpu true", +" graph_print_proc false", +" graph_print_overrun false", +"", +"trace dump [-sm] ", +" dump ring_buffers to dest-dir. Then you can parse it", +" by other tracing tools. The dirs and files are generated", +" the same as debugfs/tracing.", +" -m: also dump metadata of ftrace.", +" -s: also dump symbols of the kernel .", +NULL +}; + +static struct command_table_entry command_table[] = { + { "trace", cmd_ftrace, help_ftrace, 0 }, + { NULL, 0, 0, 0 } +}; + +static int ftrace_initialized; + +int _init(void) +{ + if (ftrace_init() < 0) + return 0; + + ftrace_initialized = 1; + register_extension(command_table); + + return 1; +} + +int _fini(void) +{ + if (ftrace_initialized) + ftrace_destroy(); + + return 1; +} --- crash-4.0.9/extensions/libsial/sial_member.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/extensions/libsial/sial_member.c 2009-09-30 08:32:14.000000000 -0400 @@ -4,6 +4,7 @@ #include #include "sial.h" #include "sial.tab.h" +#include /* these function are used to access and set members in structs */ @@ -236,10 +237,13 @@ } /* bit field gymnastic */ else if(stm->m.nbits) { - ull value=0; + void *target = &value; + + if (__BYTE_ORDER != __LITTLE_ENDIAN) + target = target + (sizeof(value) - stm->m.size); - API_GETMEM(m->mem+stm->m.offset, &value, stm->m.size); + API_GETMEM(m->mem+stm->m.offset, target, stm->m.size); get_bit_value(value, stm->m.nbits, stm->m.fbit, stm->m.size, v); /* no mempos for bit fields ... */ --- crash-4.0.9/extensions/libsial/sial_type.c 2009-10-07 11:39:58.000000000 -0400 +++ crash-4.1.0/extensions/libsial/sial_type.c 2009-09-30 08:32:30.000000000 -0400 @@ -5,6 +5,7 @@ #include "sial.tab.h" #include #include +#include /* This file contains functions that deals with type and type casting operators. @@ -287,7 +288,11 @@ else { mask = ((1 << nbits) - 1); } - val = val >> boff; + + if (__BYTE_ORDER == __LITTLE_ENDIAN) + val = val >> boff; + else + val = val >> (vnbits - boff - nbits); val &= mask; if(issigned(v)) {