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) | +---------------------------------------------------------+ 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"}; + 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)); + 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 */ + + 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