From: Rongwei Wang <[email protected]> '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, usage likes: crash> help -l Gap Hole: 0xffffffffff7ff001 - 0xffffffffffffffff Size: 8.0 MB Fixmap Area: 0xffffffffff578000 - 0xffffffffff7ff000 Size: 2.5 MB Gap Hole: 0xffffffffff000001 - 0xffffffffff577fff Size: 5.5 MB Module Area: 0xffffffffa0000000 - 0xffffffffff000000 Size: 1.5 GB Gap Hole: 0xffffffff84826001 - 0xffffffff9fffffff Size: 439.9 MB Kernel Image: 0xffffffff81000000 - 0xffffffff84826000 Size: 56.1 MB Gap Hole: 0xffffeb0000000000 - 0xffffffff80ffffff Size: 21.0 TB Vmemmap Area: 0xffffea0000000000 - 0xffffeaffffffffff Size: 1.0 TB Gap Hole: 0xffffe90000000000 - 0xffffe9ffffffffff Size: 1.0 TB Vmalloc Area: 0xffffc90000000000 - 0xffffe8ffffffffff Size: 32.0 TB Gap Hole: 0xffffc88000000000 - 0xffffc8ffffffffff Size: 512.0 GB Linear Mapping: 0xffff888000000000 - 0xffffc87fffffffff Size: 64.0 TB Linear Gap: 0xffff800000000000 - 0xffff887fffffffff Size: 8.5 TB Gap Hole: 0x0000800000000000 - 0xffff7fffffffffff Size: 16776960.0 TB User Space: 0x0000000000000000 - 0x00007fffffffffff Size: 128.0 TB Signed-off-by: Rongwei Wang <[email protected]> --- defs.h | 14 +++- help.c | 7 +- memory.c | 11 +++ x86_64.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 266 insertions(+), 2 deletions(-) diff --git a/defs.h b/defs.h index 4fecb83..a3f00d5 100644 --- a/defs.h +++ b/defs.h @@ -4100,12 +4100,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 @@ -5911,6 +5922,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..bfb53b4 100644 --- a/x86_64.c +++ b/x86_64.c @@ -1151,6 +1151,242 @@ x86_64_dump_machdep_table(ulong arg) fprintf(fp, "excpetion_functions_orig\n"); } +#define MAX_LAYOUT 32 +struct mem_segment { + char name[64]; + char desc[64]; + unsigned long start; + unsigned long end; +}; + +struct mem_layout { + int count; + 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 print_layout(struct mem_layout *layout) +{ + struct mem_segment *segs = layout->segs; + struct mem_segment seg; + int i; + + if (layout == NULL) + return; + + for (i=0; i<layout->count; i++) { + seg = segs[i]; + + fprintf(fp, "%s:\t 0x%016lx - 0x%016lx\t Size: %s\n", seg.name, seg.start, + seg.end, seg.desc); + } +} + +#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)) + +/* + * memory layout: + * + * Gap Area: 0xffffffffff7ff001 - 0xffffffffffffffff Size: 8.0 MB + * Fixmap Area: 0xffffffffff578000 - 0xffffffffff7ff000 Size: 2.5 MB + * Gap Area: 0xffffffffff000001 - 0xffffffffff577fff Size: 5.5 MB + * Module Area: 0xffffffffa0000000 - 0xffffffffff000000 Size: 1.5 GB + * Gap Area: 0xffffffff84826001 - 0xffffffff9fffffff Size: 439.9 MB + * Kernel Image: 0xffffffff81000000 - 0xffffffff84826000 Size: 56.1 MB + * Gap Area: 0xffffeb0000000000 - 0xffffffff80ffffff Size: 21.0 TB + * Vmemmap Area: 0xffffea0000000000 - 0xffffeaffffffffff Size: 1.0 TB + * Gap Area: 0xffffe90000000000 - 0xffffe9ffffffffff Size: 1.0 TB + * Vmalloc Area: 0xffffc90000000000 - 0xffffe8ffffffffff Size: 32.0 TB + * Gap Area: 0xffffc88000000000 - 0xffffc8ffffffffff Size: 512.0 GB + * Linear Mapping: 0xffff888000000000 - 0xffffc87fffffffff Size: 64.0 TB + * Linear Gap: 0xffff800000000000 - 0xffff887fffffffff Size: 8.5 TB + * Gap Area: 0x0000800000000000 - 0xffff7fffffffffff Size:16776960.0 TB + * User Space: 0x0000000000000000 - 0x00007fffffffffff 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 *segments = layout->segs; + if(!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(segments[0].name, 64, "Kernel Image"); + snprintf(segments[0].desc, 64, "%s", + format_bytes(text_end - text_start + 1, size_buf, 20)); + segments[0].start = text_start; + segments[0].end = text_end; + + snprintf(segments[1].name, 64, "Vmemmap Area"); + snprintf(segments[1].desc, 64, "%s", + format_bytes(ms->vmemmap_end - ms->vmemmap_vaddr + 1, size_buf, 20)); + segments[1].start = (ulong)ms->vmemmap_vaddr; + segments[1].end = (ulong)ms->vmemmap_end; + + snprintf(segments[2].name, 64, "Module Area"); + snprintf(segments[2].desc, 64, "%s", + format_bytes(ms->modules_end - ms->modules_vaddr + 1, size_buf, 20)); + segments[2].start = (ulong)ms->modules_vaddr; + segments[2].end = (ulong)ms->modules_end; + + snprintf(segments[3].name, 64, "Vmalloc Area"); + snprintf(segments[3].desc, 64, "%s", + format_bytes(ms->vmalloc_end - ms->vmalloc_start_addr + 1, size_buf, 20)); + segments[3].start = (ulong)ms->vmalloc_start_addr; + segments[3].end = (ulong)ms->vmalloc_end; + + snprintf(segments[4].name, 64, "Linear Mapping"); + segments[4].start = (ulong)ms->page_offset; + segments[4].end = (ulong)ms->page_offset + (1UL << machdep->max_physmem_bits) - 1; + snprintf(segments[4].desc, 64, "%s", + format_bytes(1UL << machdep->max_physmem_bits, size_buf, 20)); + + snprintf(segments[5].name, 64, "User Space"); + snprintf(segments[5].desc, 64, "%s", + format_bytes((ulong)ms->userspace_top, size_buf, 20)); + segments[5].start = 0UL; + segments[5].end = (ulong)ms->userspace_top - 1; + + snprintf(segments[6].name, 64, "Linear Gap"); + segments[6].start = -1UL - (1UL << __VIRTUAL_MASK_SHIFT) + 1; + segments[6].end = (ulong)ms->page_offset - 1; + snprintf(segments[6].desc, 64, "%s", + format_bytes(segments[6].end - segments[6].start + 1, size_buf, 20)); + + layout->count = 7; + if (kernel_symbol_exists("kasan_init")) { + snprintf(segments[7].name, 64, "KASAN"); + segments[7].start = KASAN_SHADOW_START; + segments[7].end = KASAN_SHADOW_END; + snprintf(segments[7].desc, 64, "%s", + format_bytes(segments[7].end - 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(segments[7].name, 64, "Fixmap Area"); + segments[idx].end = round_up(VSYSCALL_START + PAGE_SIZE, 1 << PMD_SHIFT) - PAGE_SIZE; + segments[idx].start = segments[idx].end - fixaddr_size; + + snprintf(segments[idx].desc, 64, "%s", + format_bytes(segments[idx].end - segments[idx].start + 1, size_buf, 20)); + layout->count++; + } + + /* Sort segments from highest address to lowest. */ + qsort(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 = segments[i].end; + + if (i == 0) + prev_start = -1UL; + else + prev_start = segments[i-1].start; + + if (prev_start == (end + 1)) + continue; + + snprintf(segments[next_idx].name, 64, "Gap Hole"); + segments[next_idx].start = end + 1; + segments[next_idx].end = (i == 0) ? prev_start : prev_start - 1; + snprintf(segments[next_idx].desc, 64, "%s", + format_bytes(segments[next_idx].end - segments[next_idx].start + 1, size_buf, 20)); + + next_idx++; + } + + layout->count = next_idx; + qsort(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.43.5 -- Crash-utility mailing list -- [email protected] To unsubscribe send an email to [email protected] https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/ Contribution Guidelines: https://github.com/crash-utility/crash/wiki
