Hi Rongwei,

On Tue, Sep 16, 2025 at 12:39 PM Rongwei Wang <[email protected]> wrote:
>
> 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;

Forget to mention, there is a function which is similar to this one
as: tools.c:pages_to_size(). Basically this function is trying to
convert num of pages to a total of bytes, then convert bytes into
B/KB/MB. Do you think these can be refactored, so format_bytes() and
tools.c:pages_to_size() can share some code of unit converting?

Thanks,
Tao Liu

> +
> +       /* 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

Reply via email to