On Tue, Oct 5, 2021 at 4:51 PM <crash-utility-request@xxxxxxxxxx> wrote: > Date: Mon, 4 Oct 2021 20:15:36 +0300 > From: Sergey Samoylenko <s.samoylenko@xxxxxxxxx> > To: <crash-utility@xxxxxxxxxx> > Cc: Sergey Samoylenko <s.samoylenko@xxxxxxxxx>, linux@xxxxxxxxx > Subject: [PATCH] New sbitmap command > Message-ID: <20211004171536.30971-1-s.samoylenko@xxxxxxxxx> > Content-Type: text/plain > > 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 > Thank you for the patch,Sergey. It is very helpful for parsing sbitmap. But I need some time to understand this patch, please be patient. Thanks. Lianbo > 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