From: Rongwei Wang <rongwei.wrw(a)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, 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 <rongwei.wrw(a)gmail.com>
---
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