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 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.wrw(a)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