Patch adds new 'sbitmap' command. This command dumps the contents of the sbitmap_queue structure and the used bits in the bitmap. Also, it shows the dump of a structure array associated with the sbitmap_queue. Signed-off-by: Sergey Samoylenko <s.samoylenko@xxxxxxxxx> --- Makefile | 7 +- defs.h | 2 + global_data.c | 1 + help.c | 89 ++++++++ sbitmap.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 688 insertions(+), 2 deletions(-) create mode 100644 sbitmap.c diff --git a/Makefile b/Makefile index ece1306..c116177 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \ xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \ xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c \ ramdump.c vmware_vmss.c vmware_guestdump.c \ - xen_dom0.c kaslr_helper.c + xen_dom0.c kaslr_helper.c sbitmap.c SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \ ${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \ @@ -92,7 +92,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \ xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \ xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o \ ramdump.o vmware_vmss.o vmware_guestdump.o \ - xen_dom0.o kaslr_helper.o + xen_dom0.o kaslr_helper.o sbitmap.o MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README @@ -346,6 +346,9 @@ cmdline.o: ${GENERIC_HFILES} cmdline.c tools.o: ${GENERIC_HFILES} tools.c ${CC} -c ${CRASH_CFLAGS} tools.c ${WARNING_OPTIONS} ${WARNING_ERROR} +sbitmap.o: ${GENERIC_HFILES} sbitmap.c + ${CC} -c ${CRASH_CFLAGS} sbitmap.c ${WARNING_OPTIONS} ${WARNING_ERROR} + global_data.o: ${GENERIC_HFILES} global_data.c ${CC} -c ${CRASH_CFLAGS} global_data.c ${WARNING_OPTIONS} ${WARNING_ERROR} diff --git a/defs.h b/defs.h index eb1c71b..1fa5c21 100644 --- a/defs.h +++ b/defs.h @@ -4956,6 +4956,7 @@ void cmd_mach(void); /* main.c */ void cmd_help(void); /* help.c */ void cmd_test(void); /* test.c */ void cmd_ascii(void); /* tools.c */ +void cmd_sbitmap(void); /* sbitmap.c */ void cmd_bpf(void); /* bfp.c */ void cmd_set(void); /* tools.c */ void cmd_eval(void); /* tools.c */ @@ -5543,6 +5544,7 @@ void display_help_screen(char *); extern char *help_pointer[]; extern char *help_alias[]; extern char *help_ascii[]; +extern char *help_sbitmap[]; extern char *help_bpf[]; extern char *help_bt[]; extern char *help_btop[]; diff --git a/global_data.c b/global_data.c index a316d1c..55524e3 100644 --- a/global_data.c +++ b/global_data.c @@ -105,6 +105,7 @@ struct command_table_entry linux_command_table[] = { {"rd", cmd_rd, help_rd, MINIMAL}, {"repeat", cmd_repeat, help_repeat, 0}, {"runq", cmd_runq, help_runq, REFRESH_TASK_TABLE}, + {"sbitmap", cmd_sbitmap, help_sbitmap, 0}, {"search", cmd_search, help_search, 0}, {"set", cmd_set, help_set, REFRESH_TASK_TABLE | MINIMAL}, {"sig", cmd_sig, help_sig, REFRESH_TASK_TABLE}, diff --git a/help.c b/help.c index 6c262a3..b946745 100644 --- a/help.c +++ b/help.c @@ -967,6 +967,95 @@ char *help_ascii[] = { NULL }; +char *help_sbitmap[] = { +"sbitmap", +"sbitmap_queue struct contents", +"[-s struct[.member[,member]] -p address [-v]] address", +" This command dumps the contents of the sbitmap_queue structure and", +" the used bits in the bitmap. Also, it shows the dump of a structure", +" array associated with the sbitmap_queue.", +"", +" The arguments are as follows:", +"", +" -s struct - name of a C-code structure, that is stored in an array", +" sssociated with sbitmap_queue structure. Use the", +" \"struct.member\" format in order to display a particular", +" member of the structure. -s option requires -p option", +"", +" -p address - address of a structure array associated with sbitmap_queue", +" structure. The set bits in sbitmap are used for the index", +" in an associated array.", +"", +" -x - override default output format with hexadecimal format.", +"", +" -d - override default output format with decimal format.", +"", +" -v - By default, the sbitmap command shows only a used sbitmap", +" index and a structure address in the associated array.", +" This flag says to print of a formatted display of the", +" contents of a structure in an associated array. -v option", +" requires of -s.", +"", +"EXAMPLES", +"", +" Display the common sbitmap information:", +"", +" %s> sbitmap ffffffffc06b9420", +" depth = 256", +" busy = 15", +" cleared = 1", +" bits_per_word = 64", +" map_nr = 4", +" alloc_hint = {193, 78}", +" wake_batch = 8", +" wake_index = 0", +" ws_active = 0", +" ws = {", +" { .wait_cnt = 8, .wait = inactive },", +" { .wait_cnt = 8, .wait = inactive },", +" { .wait_cnt = 8, .wait = inactive },", +" { .wait_cnt = 8, .wait = inactive },", +" { .wait_cnt = 8, .wait = inactive },", +" { .wait_cnt = 8, .wait = inactive },", +" { .wait_cnt = 8, .wait = inactive },", +" { .wait_cnt = 8, .wait = inactive },", +" }", +" round_robin = 0", +" min_shallow_depth = 4294967295", +"", +" 00000000: 0000 0000 0000 0000 ffbf 0000 0000 0000", +" 00000010: 0000 0000 0000 0000 0000 0000 0000 0000", +"", +" Display the structure address is associated with sbitmap_queue:", +"", +" %s> sbitmap -s test_data -p ffff973422dac000 ffffffffc06b9420", +" 64: 0xffff973422dac200", +" 65: 0xffff973422dac208", +" 66: 0xffff973422dac210", +" ...", +"", +" Display a formatted content of a structures:", +"", +" %s> sbitmap -s test_data -p ffff973422dac000 -v ffffffffc06b9420", +" 64 (0xffff973422dac200):", +" struct test_data {", +" tag = 64,", +" cpu = 1", +" }", +" 65 (0xffff973422dac208):", +" struct test_data {", +" tag = 65,", +" cpu = 1", +" }", +" 66 (0xffff973422dac210):", +" struct test_data {", +" tag = 66,", +" cpu = 1", +" }", +" ...", +NULL +}; + char *help_quit[] = { "quit", "exit this session", diff --git a/sbitmap.c b/sbitmap.c new file mode 100644 index 0000000..71522f8 --- /dev/null +++ b/sbitmap.c @@ -0,0 +1,591 @@ +/* sbitmap.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. + * Copyright (C) 2002-2020 David Anderson + * Copyright (C) 2002-2020 Red Hat, Inc. All rights reserved. + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "defs.h" +#include <stdbool.h> + +#define SBQ_WAIT_QUEUES 8 + +static inline unsigned int __const_hweight8(unsigned long w) +{ + return + (!!((w) & (1ULL << 0))) + + (!!((w) & (1ULL << 1))) + + (!!((w) & (1ULL << 2))) + + (!!((w) & (1ULL << 3))) + + (!!((w) & (1ULL << 4))) + + (!!((w) & (1ULL << 5))) + + (!!((w) & (1ULL << 6))) + + (!!((w) & (1ULL << 7))); +} + +#define __const_hweight16(w) (__const_hweight8(w) + __const_hweight8((w) >> 8)) +#define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16)) +#define __const_hweight64(w) (__const_hweight32(w) + __const_hweight32((w) >> 32)) + +#define hweight32(w) __const_hweight32(w) +#define hweight64(w) __const_hweight64(w) + +#define BIT(nr) (1UL << (nr)) + +/* sbitmap and sbitmap_word structs context */ +struct sbitmap_context { + unsigned sb_depth; + unsigned sb_shift; + unsigned sb_map_nr; + ulong sb_map_addr; + unsigned sb_map_size; + + int w_depth_off; + int w_word_off; + int w_cleared_off; +}; + +/* sbitmap_queue struct context */ +struct sbitmap_queue_context { + ulong sb_addr; + ulong alloc_hint; + unsigned int wake_batch; + int wake_index; + ulong ws_addr; + int ws_active; + bool round_robin; + unsigned int min_shallow_depth; + +}; + +struct sbitmap_data { +#define SD_FLAG_STRUCT_NAME (VERBOSE << 1) +#define SD_FLAG_STRUCT_ADDR (VERBOSE << 2) +#define SD_FLAG_STRUCT_MEMBER (VERBOSE << 3) + ulong flags; + int radix; + /* sbitmap_queue info */ + ulong addr; + /* data array info */ + char *data_name; + ulong data_addr; + + struct sbitmap_queue_context sqc; + struct sbitmap_context sc; +}; + +static inline unsigned long min(unsigned long a, unsigned long b) +{ + return (a < b) ? a : b; +} + +static void __readmem(ulong addr, void *buffer, size_t size) +{ + ulong flag = FAULT_ON_ERROR; + + if (!readmem(addr, KVADDR, buffer, size, "__readmem", flag)) + error(FATAL, "failed read memory: 0x%x\n", addr); +} + +static ulong __read_ulong(ulong addr) +{ + ulong value; + + __readmem(addr, &value, sizeof(value)); + return value; +} + +static long __struct_size(char *name) +{ + long size; + + size = STRUCT_SIZE(name); + if (size < 0) + error(FATAL, "Invalid struct size: %s\n", name); + + return size; +} + +static long __member_offset(char *name, char *member) +{ + long offset; + + offset = MEMBER_OFFSET(name, member); + if (offset == INVALID_OFFSET) + offset = ANON_MEMBER_OFFSET(name, member); + if (offset == INVALID_OFFSET) + error(FATAL, "Can't get offset of '%s.%s'\n", name, member); + + return offset; +} + +static unsigned long __last_word_mask(unsigned long nbits) +{ + return ~0UL >> (-(nbits) & (BITS_PER_LONG - 1)); +} + +static unsigned long bitmap_hweight_long(unsigned long w) +{ + return sizeof(w) == 4 ? hweight32(w) : hweight64(w); +} + +static unsigned long bitmap_weight(unsigned long bitmap, unsigned int bits) +{ + unsigned long w = 0; + + w += bitmap_hweight_long(bitmap); + if (bits % BITS_PER_LONG) + w += bitmap_hweight_long(bitmap & __last_word_mask(bits)); + + return w; +} + +static unsigned int __sbitmap_weight(const struct sbitmap_context *sc, bool set) +{ + unsigned int weight = 0; + ulong addr = sc->sb_map_addr; + unsigned long depth, word, cleared; + int i; + + for (i = 0; i < sc->sb_map_nr; i++) { + depth = __read_ulong(addr + sc->w_depth_off); + + if (set) { + word = __read_ulong(addr + sc->w_word_off); + weight += bitmap_weight(word, depth); + } else { + cleared = __read_ulong(addr + sc->w_cleared_off); + weight += bitmap_weight(cleared, depth); + } + + addr += sc->sb_map_size; + } + + return weight; +} + +static unsigned int sbitmap_weight(const struct sbitmap_context *sc) +{ + return __sbitmap_weight(sc, true); +} + +static unsigned int sbitmap_cleared(const struct sbitmap_context *sc) +{ + return __sbitmap_weight(sc, false); +} + +static void sbitmap_queue_show(const struct sbitmap_queue_context *sqc, + const struct sbitmap_context *sc) +{ + int cpus = get_cpus_possible(); + int sbq_wait_state_size, wait_cnt_off, wait_off, list_head_off; + bool first; + int i; + + fprintf(fp, "depth = %u\n", sc->sb_depth); + fprintf(fp, "busy = %u\n", sbitmap_weight(sc) - sbitmap_cleared(sc)); + fprintf(fp, "cleared = %u\n", sbitmap_cleared(sc)); + fprintf(fp, "bits_per_word = %u\n", 1U << sc->sb_shift); + fprintf(fp, "map_nr = %u\n", sc->sb_map_nr); + + fputs("alloc_hint = {", fp); + first = true; + for (i = 0; i < cpus; i++) { + if (!first) + fprintf(fp, ", "); + first = false; + + ulong ptr = kt->__per_cpu_offset[i] + sqc->alloc_hint; + fprintf(fp, "%lu", __read_ulong(ptr)); + } + fputs("}\n", fp); + + fprintf(fp, "wake_batch = %u\n", sqc->wake_batch); + fprintf(fp, "wake_index = %d\n", sqc->wake_index); + fprintf(fp, "ws_active = %d\n", sqc->ws_active); + + sbq_wait_state_size = __struct_size("sbq_wait_state"); + wait_cnt_off = __member_offset("sbq_wait_state", "wait_cnt"); + wait_off = __member_offset("sbq_wait_state", "wait"); + list_head_off = __member_offset("wait_queue_head", "head"); + + fputs("ws = {\n", fp); + for (i = 0; i < SBQ_WAIT_QUEUES; i++) { + ulong ws_addr = sqc->ws_addr + (sbq_wait_state_size * i); + struct kernel_list_head lh; + ulong wait_cnt_addr, list_head_addr; + ulong wait_cnt; + + wait_cnt_addr = ws_addr + wait_cnt_off; + __readmem(wait_cnt_addr, &wait_cnt, sizeof(wait_cnt)); + + list_head_addr = ws_addr + wait_off + list_head_off; + __readmem(list_head_addr, &lh, sizeof(lh)); + + fprintf(fp, "\t{ .wait_cnt = %lu, .wait = %s },\n", + wait_cnt, (lh.next == lh.prev) ? "inactive" : "active"); + } + fputs("}\n", fp); + + fprintf(fp, "round_robin = %d\n", sqc->round_robin); + fprintf(fp, "min_shallow_depth = %u\n", sqc->min_shallow_depth); +} + +static void sbitmap_emit_byte(unsigned int offset, uint8_t byte) +{ + if ((offset &0xf) == 0) { + if (offset != 0) + fputc('\n', fp); + fprintf(fp, "%08x:", offset); + } + if ((offset & 0x1) == 0) + fputc(' ', fp); + fprintf(fp, "%02x", byte); +} + +static void sbitmap_bitmap_show(const struct sbitmap_context *sc) +{ + uint8_t byte = 0; + unsigned int byte_bits = 0; + unsigned int offset = 0; + int i; + + for (i = 0; i < sc->sb_map_nr; i++) { + ulong addr = sc->sb_map_addr + (sc->sb_map_size * i); + unsigned long word = __read_ulong(addr + sc->w_word_off); + unsigned long cleared = __read_ulong(addr + sc->w_cleared_off); + unsigned long word_bits = __read_ulong(addr + sc->w_depth_off); + + word &= ~cleared; + + while (word_bits > 0) { + unsigned int bits = min(8 - byte_bits, word_bits); + + byte |= (word & (BIT(bits) - 1)) << byte_bits; + byte_bits += bits; + if (byte_bits == 8) { + sbitmap_emit_byte(offset, byte); + byte = 0; + byte_bits = 0; + offset++; + } + word >>= bits; + word_bits -= bits; + } + + } + if (byte_bits) { + sbitmap_emit_byte(offset, byte); + offset++; + } + if (offset) + fputc('\n', fp); +} + +static void sbitmap_queue_dump(const struct sbitmap_data *sd) +{ + sbitmap_queue_show(&sd->sqc, &sd->sc); + fputc('\n', fp); + sbitmap_bitmap_show(&sd->sc); +} + +static unsigned long sbitmap_find_next_bit(unsigned long word, + unsigned long size, unsigned long offset) +{ + if (size > BITS_PER_LONG) + error(FATAL, "%s: word size isn't correct\n", __func__); + + for (; offset < size; offset++) + if (word & (1UL << offset)) + return offset; + + return size; +} + +typedef bool (*sb_for_each_fn)(unsigned int, void *); + +static void __sbitmap_for_each_set(const struct sbitmap_context *sc, + unsigned int start, sb_for_each_fn fn, void *data) +{ + unsigned int index; + unsigned int nr; + unsigned int scanned = 0; + + if (start >= sc->sb_map_nr) + start = 0; + + index = start >> sc->sb_shift; + nr = start & ((1U << sc->sb_shift) - 1U); + + while (scanned < sc->sb_depth) { + unsigned long w_addr = sc->sb_map_addr + (sc->sb_map_size * index); + + unsigned long w_depth = __read_ulong(w_addr + sc->w_depth_off); + unsigned long w_word = __read_ulong(w_addr + sc->w_word_off); + unsigned long w_cleared = __read_ulong(w_addr + sc->w_cleared_off); + + unsigned long word; + unsigned int depth = min(w_depth - nr, sc->sb_depth - scanned); + + scanned += depth; + word = w_word & ~w_cleared; + if (!word) + goto next; + + /* + * On the first iteration of the outer loop, we need to add the + * bit offset back to the size of the word for find_next_bit(). + * On all other iterations, nr is zero, so this is a noop. + */ + depth += nr; + while (1) { + nr = sbitmap_find_next_bit(word, depth, nr); + if (nr >= depth) + break; + if (!fn((index << sc->sb_shift) + nr, data)) + return; + + nr++; + } +next: + nr = 0; + if (++index >= sc->sb_map_nr) + index = 0; + } +} + +static void sbitmap_for_each_set(const struct sbitmap_context *sc, + sb_for_each_fn fn, void *data) +{ + __sbitmap_for_each_set(sc, 0, fn, data); +} + +static void sbitmap_dump_struct_members(const char *s, ulong addr, unsigned radix) +{ + int i, argc; + char *p1, *p2; + char *structname, *members; + char *arglist[MAXARGS]; + + structname = GETBUF(strlen(s) + 1); + members = GETBUF(strlen(s) + 1); + + strcpy(structname, s); + p1 = strstr(structname, ".") + 1; + + p2 = strstr(s, ".") + 1; + strcpy(members, p2); + replace_string(members, ",", ' '); + argc = parse_line(members, arglist); + + for (i = 0; i < argc; i++) { + *p1 = NULLCHAR; + strcat(structname, arglist[i]); + dump_struct_member(structname, addr, radix); + } + + FREEBUF(structname); + FREEBUF(members); +} + +struct data_info { + ulong addr; + int size; + char *name; + unsigned radix; + bool verbose; + bool members; +}; + +static bool sbitmap_data_print(unsigned int idx, void *data) +{ + const struct data_info *d = data; + ulong addr = d->addr + (d->size * idx); + + if (d->verbose) { + fprintf(fp, "%d (0x%08lx):\n", idx, addr); + if (d->members) + sbitmap_dump_struct_members(d->name, addr, d->radix); + else + dump_struct(d->name, addr, d->radix); + } else + fprintf(fp, "%d: 0x%08lx\n", idx, addr); + + return true; +} + +static char *__get_struct_name(const char *s) +{ + char *name, *p; + + name = GETBUF(strlen(s) + 1); + strcpy(name, s); + + p = strstr(name, "."); + *p = NULLCHAR; + + return name; +} + +static void sbitmap_data_dump(const struct sbitmap_data *sd) +{ + struct data_info d = {0}; + + d.addr = sd->data_addr; + d.name = sd->data_name; + d.radix = sd->radix; + d.verbose = !!(sd->flags & VERBOSE); + d.members = !!(sd->flags & SD_FLAG_STRUCT_MEMBER); + + if (d.members) { + char *name = __get_struct_name(d.name); + d.size = __struct_size(name); + FREEBUF(name); + } else + d.size = __struct_size(d.name); + + sbitmap_for_each_set(&sd->sc, sbitmap_data_print, &d); +} + +static void load_sbitmap_queue_context(ulong addr, struct sbitmap_queue_context *sqc) +{ + char *sb_q = "sbitmap_queue"; + + sqc->sb_addr = addr + __member_offset(sb_q, "sb"); + __readmem(addr + __member_offset(sb_q, "alloc_hint"), &sqc->alloc_hint, sizeof(sqc->alloc_hint)); + __readmem(addr + __member_offset(sb_q, "wake_batch"), &sqc->wake_batch, sizeof(sqc->wake_batch)); + __readmem(addr + __member_offset(sb_q, "wake_index"), &sqc->wake_index, sizeof(sqc->wake_index)); + __readmem(addr + __member_offset(sb_q, "ws"), &sqc->ws_addr, sizeof(sqc->ws_addr)); + __readmem(addr + __member_offset(sb_q, "ws_active"), &sqc->ws_active, sizeof(sqc->ws_active)); + __readmem(addr + __member_offset(sb_q, "round_robin"), &sqc->round_robin, sizeof(sqc->round_robin)); + __readmem(addr + __member_offset(sb_q, "min_shallow_depth"), &sqc->min_shallow_depth, sizeof(sqc->min_shallow_depth)); +} + +static void load_sbitmap_context(ulong addr, struct sbitmap_context *sc) +{ + char *sb = "sbitmap"; + char *map = "sbitmap_word"; + + __readmem(addr + __member_offset(sb, "depth"), &sc->sb_depth, sizeof(sc->sb_depth)); + __readmem(addr + __member_offset(sb, "shift"), &sc->sb_shift, sizeof(sc->sb_shift)); + __readmem(addr + __member_offset(sb, "map_nr"), &sc->sb_map_nr, sizeof(sc->sb_map_nr)); + __readmem(addr + __member_offset(sb, "map"), &sc->sb_map_addr, sizeof(sc->sb_map_addr)); + sc->sb_map_size = __struct_size(map); + sc->w_depth_off = __member_offset(map, "depth"); + sc->w_word_off = __member_offset(map, "word"); + sc->w_cleared_off = __member_offset(map, "cleared"); +} + +void cmd_sbitmap(void) +{ + struct sbitmap_data sd = {0}; + int c; + + while ((c = getopt(argcnt, args, "s:p:xdv")) != EOF) { + switch (c) { + case 's': + if (sd.flags & SD_FLAG_STRUCT_NAME) + error(FATAL, "-s option (%s) already entered\n", sd.data_name); + + sd.data_name = optarg; + sd.flags |= SD_FLAG_STRUCT_NAME; + + break; + + case 'p': + if (sd.flags & SD_FLAG_STRUCT_ADDR) + error(FATAL, "-m option (0x%lx) already entered\n", sd.data_addr); + else if (!IS_A_NUMBER(optarg)) + error(FATAL, "invalid -m option: %s\n", optarg); + + sd.data_addr = htol(optarg, FAULT_ON_ERROR, NULL); + if (!IS_KVADDR(sd.data_addr)) + error(FATAL, "invalid kernel virtual address: %s\n", optarg); + sd.flags |= SD_FLAG_STRUCT_ADDR; + + break; + + case 'v': + sd.flags |= VERBOSE; + break; + + case 'x': + if (sd.radix == 10) + error(FATAL, "-d and -x are mutually exclusive\n"); + sd.radix = 16; + break; + + case 'd': + if (sd.radix == 16) + error(FATAL, "-d and -x are mutually exclusive\n"); + sd.radix = 10; + break; + + default: + argerrs++; + break; + } + } + + if (argerrs) + cmd_usage(pc->curcmd, SYNOPSIS); + + if (!args[optind]) { + error(INFO, "command argument is required\n"); + cmd_usage(pc->curcmd, SYNOPSIS); + } else if (args[optind] && args[optind + 1]) { + error(INFO, "too many arguments\n"); + cmd_usage(pc->curcmd, SYNOPSIS); + } else if (!IS_A_NUMBER(args[optind])) { + error(FATAL, "invalid command argument: %s\n", args[optind]); + } + + sd.addr = htol(args[optind], FAULT_ON_ERROR, NULL); + if (!IS_KVADDR(sd.addr)) + error(FATAL, "invalid kernel virtual address: %s\n", args[optind]); + + if ((sd.flags & SD_FLAG_STRUCT_NAME) && !(sd.flags & SD_FLAG_STRUCT_ADDR)) { + error(INFO, "-s option requires -m option"); + cmd_usage(pc->curcmd, SYNOPSIS); + } else if ((sd.flags & SD_FLAG_STRUCT_ADDR) && !(sd.flags & SD_FLAG_STRUCT_NAME)) { + error(FATAL, "-m option is used with -s option only\n"); + cmd_usage(pc->curcmd, SYNOPSIS); + } + + if (sd.flags & SD_FLAG_STRUCT_NAME) { + bool error_flag = false; + + if (count_chars(sd.data_name, '.') > 0) + sd.flags |= SD_FLAG_STRUCT_MEMBER; + + if (sd.flags & SD_FLAG_STRUCT_MEMBER) { + char *data_name = __get_struct_name(sd.data_name); + if (!STRUCT_EXISTS(data_name)) + error_flag = true; + FREEBUF(data_name); + } else { + if (!STRUCT_EXISTS(sd.data_name)) + error_flag = true; + } + if (error_flag) + error(FATAL, "invalid data structure reference: %s\n", sd.data_name); + } + + load_sbitmap_queue_context(sd.addr, &sd.sqc); + load_sbitmap_context(sd.sqc.sb_addr, &sd.sc); + + if (sd.flags & SD_FLAG_STRUCT_NAME) + sbitmap_data_dump(&sd); + else + sbitmap_queue_dump(&sd); +} -- 2.25.1 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/crash-utility