Hi Rongwei, Thanks for your patch.
On Sun, Jul 27, 2025 at 1:57 AM Rongwei Wang <rongwei....@gmail.com> wrote: > > From: Rongwei Wang <rongwei....@gmail.com> > > 'help -m' can show most of variables which > relates to memory layout, e.g. userspace_top, > page_offset, vmalloc_start_addr, etc. They > aren't a visual way to show a memory layout > for kernel space. > > This patch provides 'help -l' to show memory > layout in a table-based way, usage likes: > > crash> help -l > +---------------------------------------------------------+ > |xxxxxxxxxxxxxxxxxxx gap (size: 8.0 MB) xxxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > +---------------------------------------------------------+ > | FIXMAP | > | (0xffffffffff578000 - 0xffffffffff7ff000 size: 2.5 MB) | > +---------------------------------------------------------+ > |xxxxxxxxxxxxxxxxxxx gap (size: 5.5 MB) xxxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > +---------------------------------------------------------+ > | Module Area | > | (0xffffffffa0000000 - 0xffffffffff000000 size: 1.5 GB) | > +---------------------------------------------------------+ > |xxxxxxxxxxxxxxxxxx gap (size: 451.9 MB) xxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > +---------------------------------------------------------+ > | kernel image | > | (0xffffffff81000000 - 0xffffffff83c26000 size: 44.1 MB) | > +---------------------------------------------------------+ > |xxxxxxxxxxxxxxxxxx gap (size: 21.0 TB) xxxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > +---------------------------------------------------------+ > | Vmemmap Area | > | (0xffffea0000000000 - 0xffffeaffffffffff size: 1.0 TB) | > +---------------------------------------------------------+ > |xxxxxxxxxxxxxxxxxxx gap (size: 1.0 TB) xxxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > +---------------------------------------------------------+ > | Vmalloc/Vfree Area | > | (0xffffc90000000000 - 0xffffe8ffffffffff size: 32.0 TB) | > +---------------------------------------------------------+ > |xxxxxxxxxxxxxxxxxx gap (size: 512.0 GB) xxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > +---------------------------------------------------------+ > | Linear Mapping Area | > | (0xffff888000000000 - 0xffffc87fffffffff size: 64.0 TB) | > +---------------------------------------------------------+ > | Kernel Space Offset | > | (0xffff800000000000 - 0xffff887fffffffff size: 8.5 TB) | > +---------------------------------------------------------+ > |xxxxxxxxxxxxxxx gap (size: 16776960.0 TB) xxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > +---------------------------------------------------------+ > | User Space | > | (size: 128.0 TB) | > +---------------------------------------------------------+ > I'm OK with adding a function to present the machine's memory layout, but I'd prefer an easier way. In fact, there are few places in crash to present data in a table. Although the table you showed is good looking, such as frames, edges and fills, but this involves extra code to calculate the table length, and 'X' filling. IMHO, those code are not essential for crash's function and will increase the costs for maintenance. What do you think of the following outputs: crash> help -l FIXMAP: 0xffffffffff578000 - 0xffffffffff7ff000 size: 2.5 MB Module Area: 0xffffffffa0000000 - 0xffffffffff000000 size: 1.5 GB kernel image: 0xffffffff81000000 - 0xffffffff83c26000 size: 44.1 MB .... They are much cleaner, and can give out the major information to users. Also I think the gap (size: 8.0 MB) calculation is not necessary. It is easy for people to calculate when really needed. Again, only give the major information, since your function is only to list the memory layout. > Signed-off-by: Rongwei Wang <rongwei....@gmail.com> > --- > defs.h | 14 +- > help.c | 7 +- > memory.c | 11 ++ > x86_64.c | 388 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 418 insertions(+), 2 deletions(-) > > diff --git a/defs.h b/defs.h > index bbd6d4b..66b1c8e 100644 > --- a/defs.h > +++ b/defs.h > @@ -4097,12 +4097,23 @@ typedef signed int s32; > #define __PHYSICAL_MASK_SHIFT_5LEVEL 52 > #define __PHYSICAL_MASK_SHIFT (machdep->machspec->physical_mask_shift) > #define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1) > -#define __VIRTUAL_MASK_SHIFT 48 > +#define __VIRTUAL_MASK_SHIFT 47 > #define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) > #define PAGE_SHIFT 12 > #define PAGE_SIZE (1UL << PAGE_SHIFT) > #define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & __PHYSICAL_MASK ) > > + > +#define KASAN_SHADOW_OFFSET 0xdffffc0000000000 > +#define KASAN_SHADOW_SCALE_SHIFT 3 > + > +#define KASAN_SHADOW_START (KASAN_SHADOW_OFFSET + \ > + ((-1UL << __VIRTUAL_MASK_SHIFT) >> \ > + KASAN_SHADOW_SCALE_SHIFT)) > +#define KASAN_SHADOW_END (KASAN_SHADOW_START + \ > + (1ULL << (__VIRTUAL_MASK_SHIFT - \ > + KASAN_SHADOW_SCALE_SHIFT))) > + > #define _PAGE_BIT_NX 63 > #define _PAGE_PRESENT 0x001 > #define _PAGE_RW 0x002 > @@ -5908,6 +5919,7 @@ int phys_to_page(physaddr_t, ulong *); > int generic_get_kvaddr_ranges(struct vaddr_range *); > int l1_cache_size(void); > int dumpfile_memory(int); > +void dump_memory_layout(void); > #define DUMPFILE_MEM_USED (1) > #define DUMPFILE_FREE_MEM (2) > #define DUMPFILE_MEM_DUMP (3) > diff --git a/help.c b/help.c > index 5d61e0d..cd54744 100644 > --- a/help.c > +++ b/help.c > @@ -538,7 +538,7 @@ cmd_help(void) > oflag = 0; > > while ((c = getopt(argcnt, args, > - "efNDdmM:ngcaBbHhkKsvVoptTzLOr")) != EOF) { > + "efNDdmM:ngcaBbHhkKsvVoptTzLOrl")) != EOF) { > switch(c) > { > case 'e': > @@ -666,6 +666,7 @@ cmd_help(void) > fprintf(fp, " -v - vm_table\n"); > fprintf(fp, " -V - vm_table (verbose)\n"); > fprintf(fp, " -z - help options\n"); > + fprintf(fp, " -l - show memory layout\n"); > return; > > case 'L': > @@ -676,6 +677,10 @@ cmd_help(void) > dump_registers(); > return; > > + case 'l': > + dump_memory_layout(); > + return; > + > default: > argerrs++; > break; > diff --git a/memory.c b/memory.c > index 400d31a..55ed2f1 100644 > --- a/memory.c > +++ b/memory.c > @@ -17657,6 +17657,17 @@ dumpfile_memory(int cmd) > return retval; > } > > +#ifdef X86_64 > +extern void x86_64_dump_memory_layout(void); > +#endif > + > +void dump_memory_layout(void) > +{ > +#ifdef X86_64 > + x86_64_dump_memory_layout(); > +#endif > +} > + > /* > * Functions for sparse mem support > */ > diff --git a/x86_64.c b/x86_64.c > index d7da536..b4d2821 100644 > --- a/x86_64.c > +++ b/x86_64.c > @@ -1151,6 +1151,394 @@ x86_64_dump_machdep_table(ulong arg) > fprintf(fp, "excpetion_functions_orig\n"); > } > > +#define MAX_LAYOUT 32 > +#define MAX_COL_LAYOUT 60 > +struct mem_segment { > + char name[64]; > + char desc[128]; > + unsigned long start; > + unsigned long end; > + int width; > + char fill_char; > +}; > + > +struct mem_layout { > + int count; > + int capacity; > + struct mem_segment segs[MAX_LAYOUT]; > +}; > + > +char* format_bytes(unsigned long bytes, char* buffer, int buffer_size) > +{ > + const char* units[] = {"B", "KB", "MB", "GB", "TB"}; I think we don't need to distinguish units, all take KB or MB is enough, like in kernel: $ cat /proc/meminfo MemTotal: 56936660 kB MemFree: 42517704 kB MemAvailable: 50075760 kB Buffers: 390476 kB Cached: 7798504 kB ... Like I said, people can do calculations when needed, what we do is to present the major info while keeping the code clean and simple. > + int i = 0; > + double readable_size = (double)bytes; > + > + /* Handle the edge case of zero bytes */ > + if (bytes == 0) { > + snprintf(buffer, buffer_size, "0 B"); > + return buffer; > + } > + > + /* Handle negative values if necessary, though size is typically > non-negative */ > + if (bytes < 0) { > + snprintf(buffer, buffer_size, "Invalid size"); > + return buffer; > + } > + > + while (readable_size >= 1024 && i < (sizeof(units) / sizeof(units[0]) > - 1)) { > + readable_size /= 1024; > + i++; > + } > + > + memset(buffer, '\0', buffer_size); > + snprintf(buffer, buffer_size, "%.1f %s", readable_size, units[i]); > + > + return buffer; > +} > + > +int compare_segments(const void *a, const void *b) > +{ > + const struct mem_segment *seg_a = (const struct mem_segment *)a; > + const struct mem_segment *seg_b = (const struct mem_segment *)b; > + > + if (seg_a->start > seg_b->start) return -1; > + if (seg_a->start < seg_b->start) return 1; > + return 0; > +} > + > +void* make_layout(struct mem_layout *layout, int max_row, int max_col) > +{ > + int col = MAX_COL_LAYOUT; > + int row = max_row + 1; > + char *layout_raw; > + int i,j; > + unsigned int cursor = 0; > + int idx = 0; > + > + if (max_col > col) > + col = max_col; > + > + layout_raw = (char *)malloc(row * col * sizeof(char)); Please use GETBUF/FREEBUF in crash, except there are unavoidable reasons. > + memset(layout_raw, ' ', row * col * sizeof(char)); > + for (i=0; i<layout->count; i++) { > + int center_bias = 0; > + char fill = layout->segs[i].fill_char; > + > + memset(layout_raw+cursor, '-', col); > + layout_raw[cursor] = layout_raw[cursor+col-2] = '+'; > + layout_raw[cursor+col-1] = '\n'; > + cursor += col; /* next row */ These are drawing code, unnessary for maintainance. I belive with these removed, your patch can be much simpler and cleaner. Thanks, Tao Liu > + > + memset(layout_raw+cursor, fill, col); > + layout_raw[cursor] = '|'; > + layout_raw[cursor+col-2] = '|'; > + layout_raw[cursor+col-1] = '\n'; > + center_bias = (col - strlen(layout->segs[i].name)) / 2; > + memcpy(layout_raw + cursor + center_bias, > layout->segs[i].name, > + strlen(layout->segs[i].name)); > + cursor += col; /* next row */ > + > + if (strlen(layout->segs[i].desc) != 0) { > + memset(layout_raw+cursor, fill, col); > + layout_raw[cursor] = '|'; > + layout_raw[cursor+col-2] = '|'; > + layout_raw[cursor+col-1] = '\n'; > + > + center_bias = (col - strlen(layout->segs[i].desc)) / > 2; > + memcpy(layout_raw + cursor + center_bias, > layout->segs[i].desc, > + strlen(layout->segs[i].desc)); > + > + cursor += col; /* next row */ > + } else { > + /* It's a gap area. */ > + int width = layout->segs[i].width; > + > + while(width--) { > + memset(layout_raw+cursor, fill, col); > + layout_raw[cursor] = '|'; > + layout_raw[cursor+col-2] = '|'; > + layout_raw[cursor+col-1] = '\n'; > + cursor += col; /* next row */ > + } > + } > + > + if (i == (layout->count - 1)) { > + /* last line */ > + memset(layout_raw+cursor, '-', col); > + layout_raw[cursor] = layout_raw[cursor+col-2] = '+'; > + layout_raw[cursor+col-1] = '\n'; > + layout_raw[cursor+col] = '\0'; > + } > + } > + > + return layout_raw; > +} > + > +void print_layout(struct mem_layout *layout) > +{ > + int max_col = 0; > + int max_row = 0; > + struct mem_segment *segs = layout->segs; > + struct mem_segment seg; > + int i, j; > + char *layout_raw; > + char *string; > + > + if (layout == NULL) > + return; > + > + /* calculate the max col which can includes all 'desc' */ > + for (i=0; i<layout->count; i++) { > + int col = 0; > + int cursor = 0; > + int row = 1; /* the minimal row */ > + > + seg = segs[i]; > + col = strlen(seg.name); > + > + max_col = (max_col >= col) ?: col; > + /* The gap area has no desc. */ > + if (seg.desc[0] != '\0') { > + col = strlen(seg.desc); > + row += 1; > + max_col = (max_col >= col) ?: col; > + } else > + row += segs[i].width; > + > + max_row += row; > + } > + /* add border line */ > + max_row += layout->count + 1; > + max_col + 3; > + > + layout_raw = make_layout(layout, max_row, max_col); > + fprintf(fp, "%s", layout_raw); > + free(layout_raw); > +} > + > +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) > +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) > +#define round_down(x, y) ((x) & ~__round_mask(x, y)) > + > +/* > + * table-based memory layout: > + * > + * +---------------------------------------------------------+ > + * |xxxxxxxxxxxxxxxxxxx gap (size: 8.0 MB) xxxxxxxxxxxxxxxxxx| > + * +---------------------------------------------------------+ > + * | FIXMAP | > + * | (0xffffffffff578000 - 0xffffffffff7ff000 size: 2.5 MB) | > + * +---------------------------------------------------------+ > + * |xxxxxxxxxxxxxxxxxxx gap (size: 5.5 MB) xxxxxxxxxxxxxxxxxx| > + * +---------------------------------------------------------+ > + * | Module Area | > + * | (0xffffffffa0000000 - 0xffffffffff000000 size: 1.5 GB) | > + * +---------------------------------------------------------+ > + * |xxxxxxxxxxxxxxxxxx gap (size: 451.9 MB) xxxxxxxxxxxxxxxxx| > + * +---------------------------------------------------------+ > + * | kernel image | > + * | (0xffffffff81000000 - 0xffffffff83c26000 size: 44.1 MB) | > + * +---------------------------------------------------------+ > + * |xxxxxxxxxxxxxxxxxx gap (size: 21.0 TB) xxxxxxxxxxxxxxxxxx| > + * |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > + * |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > + * +---------------------------------------------------------+ > + * | Vmemmap Area | > + * | (0xffffea0000000000 - 0xffffeaffffffffff size: 1.0 TB) | > + * +---------------------------------------------------------+ > + * |xxxxxxxxxxxxxxxxxxx gap (size: 1.0 TB) xxxxxxxxxxxxxxxxxx| > + * |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > + * +---------------------------------------------------------+ > + * | Vmalloc/Vfree Area | > + * | (0xffffc90000000000 - 0xffffe8ffffffffff size: 32.0 TB) | > + * +---------------------------------------------------------+ > + * |xxxxxxxxxxxxxxxxxx gap (size: 512.0 GB) xxxxxxxxxxxxxxxxx| > + * +---------------------------------------------------------+ > + * | Linear Mapping Area | > + * | (0xffff888000000000 - 0xffffc87fffffffff size: 64.0 TB) | > + * +---------------------------------------------------------+ > + * | Kernel Space Offset | > + * | (0xffff800000000000 - 0xffff887fffffffff size: 8.5 TB) | > + * +---------------------------------------------------------+ > + * |xxxxxxxxxxxxxxx gap (size: 16776960.0 TB) xxxxxxxxxxxxxxx| > + * |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > + * |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| > + * +---------------------------------------------------------+ > + * | User Space | > + * | (size: 128.0 TB) | > + * +---------------------------------------------------------+ > + * > + * kernel space: > + * _end, _text > + * vmemmap_end: ms->vmemmap_end > + * vmemmap_vaddr: ms->vmemmap_vaddr > + * vmalloc_end: ms->vmalloc_end > + * vmalloc_start_addr: ms->vmalloc_start_addr > + * page_offset_base: ms->page_offset > + * > + * user space: > + * userspace_top: ms->userspace_top > + * > + */ > +void x86_64_dump_memory_layout(void) > +{ > + struct mem_layout *layout = NULL; > + ulong text_start, text_end; > + struct machine_specific *ms = machdep->machspec; > + int i, next_idx; > + char size_buf[20]; > + long value = 0; > + > + layout = malloc(sizeof(struct mem_layout)); > + if (layout == NULL || layout->count == 0) { > + printf("Layout is empty, nothing to print.\n"); > + return; > + } > + > + /* Create a temporary copy to sort for printing, preserving the > original order. */ > + struct mem_segment *sorted_segments = layout->segs; > + if(!sorted_segments) { > + perror("Failed to allocate memory for sorting"); > + return; > + } > + > + if (!symbol_exists("_text")) > + return; > + else > + text_start = symbol_value("_text"); > + > + if (!symbol_exists("_end")) > + return; > + else > + text_end = symbol_value("_end"); > + > + snprintf(sorted_segments[0].name, 64, "kernel image"); > + snprintf(sorted_segments[0].desc, 64, "(0x%lx - 0x%lx size: %s)", > + text_start, text_end, > + format_bytes(text_end - text_start + 1, size_buf, 20)); > + sorted_segments[0].start = text_start; > + sorted_segments[0].end = text_end; > + sorted_segments[0].fill_char = ' '; > + > + snprintf(sorted_segments[1].name, 64, "Vmemmap Area"); > + snprintf(sorted_segments[1].desc, 64, "(0x%lx - 0x%lx size: %s)", > + (ulong)ms->vmemmap_vaddr, (ulong)ms->vmemmap_end, > + format_bytes(ms->vmemmap_end - ms->vmemmap_vaddr + 1, > size_buf, 20)); > + sorted_segments[1].start = (ulong)ms->vmemmap_vaddr; > + sorted_segments[1].end = (ulong)ms->vmemmap_end; > + sorted_segments[1].fill_char = ' '; > + > + snprintf(sorted_segments[2].name, 64, "Module Area"); > + snprintf(sorted_segments[2].desc, 64, "(0x%lx - 0x%lx size: %s)", > + (ulong)ms->modules_vaddr,(ulong)ms->modules_end, > + format_bytes(ms->modules_end - ms->modules_vaddr + 1, > size_buf, 20)); > + sorted_segments[2].start = (ulong)ms->modules_vaddr; > + sorted_segments[2].end = (ulong)ms->modules_end; > + sorted_segments[2].fill_char = ' '; > + > + snprintf(sorted_segments[3].name, 64, "Vmalloc/Vfree Area"); > + snprintf(sorted_segments[3].desc, 64, "(0x%lx - 0x%lx size: %s)", > + (ulong)ms->vmalloc_start_addr, (ulong)ms->vmalloc_end, > + format_bytes(ms->vmalloc_end - ms->vmalloc_start_addr + 1, > size_buf, 20)); > + sorted_segments[3].start = (ulong)ms->vmalloc_start_addr; > + sorted_segments[3].end = (ulong)ms->vmalloc_end; > + sorted_segments[3].fill_char = ' '; > + > + snprintf(sorted_segments[4].name, 64, "Linear Mapping Area"); > + sorted_segments[4].start = (ulong)ms->page_offset; > + sorted_segments[4].end = (ulong)ms->page_offset + (1UL << > machdep->max_physmem_bits) - 1; > + sorted_segments[4].fill_char = ' '; > + snprintf(sorted_segments[4].desc, 64, "(0x%lx - 0x%lx size: %s)", > + sorted_segments[4].start, sorted_segments[4].end, > + format_bytes(1UL << machdep->max_physmem_bits, size_buf, > 20)); > + > + snprintf(sorted_segments[5].name, 64, "User Space"); > + snprintf(sorted_segments[5].desc, 64, "(size: %s)", > + format_bytes((ulong)ms->userspace_top, size_buf, 20)); > + sorted_segments[5].start = 0UL; > + sorted_segments[5].end = (ulong)ms->userspace_top - 1; > + sorted_segments[5].fill_char = ' '; > + > + snprintf(sorted_segments[6].name, 64, "Kernel Space Offset"); > + sorted_segments[6].start = -1UL - (1UL << __VIRTUAL_MASK_SHIFT) + 1; > + sorted_segments[6].end = (ulong)ms->page_offset - 1; > + sorted_segments[6].fill_char = ' '; > + snprintf(sorted_segments[6].desc, 64, "(0x%lx - 0x%lx size: %s)", > + sorted_segments[6].start, sorted_segments[6].end, > + format_bytes(sorted_segments[6].end - > sorted_segments[6].start + 1, size_buf, 20)); > + > + layout->count = 7; > + if (kernel_symbol_exists("kasan_init")) { > + snprintf(sorted_segments[7].name, 64, "KASAN"); > + sorted_segments[7].start = KASAN_SHADOW_START; > + sorted_segments[7].end = KASAN_SHADOW_END; > + sorted_segments[7].fill_char = ' '; > + snprintf(sorted_segments[7].desc, 64, "(0x%lx - 0x%lx size: > %s)", > + sorted_segments[7].start, sorted_segments[7].end, > + format_bytes(sorted_segments[7].end - > sorted_segments[7].start + 1, size_buf, 20)); > + layout->count++; > + } > + > + if (enumerator_value("__end_of_permanent_fixed_addresses", &value)) { > + unsigned fixaddr_size = 0; > + int idx = layout->count; > + > + fixaddr_size = value << PAGE_SHIFT; > + > + snprintf(sorted_segments[7].name, 64, "FIXMAP"); > + sorted_segments[idx].end = round_up(VSYSCALL_START + > PAGE_SIZE, 1 << PMD_SHIFT) - PAGE_SIZE; > + sorted_segments[idx].start = sorted_segments[idx].end - > fixaddr_size; > + > + sorted_segments[idx].fill_char = ' '; > + snprintf(sorted_segments[idx].desc, 64, "(0x%lx - 0x%lx size: > %s)", > + sorted_segments[idx].start, sorted_segments[idx].end, > + format_bytes(sorted_segments[idx].end - > sorted_segments[idx].start + 1, size_buf, 20)); > + layout->count++; > + } > + > + /* Sort segments from highest address to lowest. */ > + qsort(sorted_segments, layout->count, sizeof(struct mem_segment), > compare_segments); > + > + next_idx = layout->count; > + /* Insert gap area */ > + for (i=0; i<layout->count; i++) { > + unsigned long prev_start; > + unsigned long end = sorted_segments[i].end; > + > + if (i == 0) > + prev_start = -1UL; > + else > + prev_start = sorted_segments[i-1].start; > + > + if (prev_start == (end + 1)) > + continue; > + > + if ((prev_start - end) >= (8UL * 1024 * 1024 * 1024 * 1024)) > + sorted_segments[next_idx].width = 3; > + else if ((prev_start - end) >= (1UL * 1024 * 1024 * 1024 * > 1024)) > + sorted_segments[next_idx].width = 2; > + else > + sorted_segments[next_idx].width = 1; > + > + sorted_segments[next_idx].start = end + 1; > + sorted_segments[next_idx].end = (i == 0) ? prev_start : > prev_start - 1; > + sorted_segments[next_idx].fill_char = 'x'; > + snprintf(sorted_segments[next_idx].name, 64, " gap (size: %s) > ", > + format_bytes(sorted_segments[next_idx].end - > sorted_segments[next_idx].start + 1, > + size_buf, 20)); > + sorted_segments[next_idx].desc[0] = '\0'; > + > + next_idx++; > + } > + > + layout->count = next_idx; > + qsort(sorted_segments, layout->count, sizeof(struct mem_segment), > compare_segments); > + > + print_layout(layout); > + free(layout); > +} > + > /* > * Gather the cpu_pda array info, updating any smp-related items that > * were possibly bypassed or improperly initialized in kernel_init(). > -- > 2.39.3 > -- > Crash-utility mailing list -- devel@lists.crash-utility.osci.io > To unsubscribe send an email to devel-le...@lists.crash-utility.osci.io > https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/ > Contribution Guidelines: https://github.com/crash-utility/crash/wiki -- Crash-utility mailing list -- devel@lists.crash-utility.osci.io To unsubscribe send an email to devel-le...@lists.crash-utility.osci.io https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/ Contribution Guidelines: https://github.com/crash-utility/crash/wiki