17.12.2.1.3. pagemap_dump.out

Dump the physical address of all pages mapped to a given process using /proc/<pid>/maps and /proc/<pid>/pagemap.

First launch linux/virt_to_phys_user.out as described at Userland physical address experiments. Suppose that the output was:

# ./posix/virt_to_phys_test.out &
vaddr 0x601048
pid 63
# ./linux/virt_to_phys_user.out 63 0x601048
0x1a61048

Now obtain the page map for the process:

./linux/pagemap_dump.out 63

Sample output excerpt:

vaddr pfn soft-dirty file/shared swapped present library
400000 1ede 0 1 0 1 ./posix/virt_to_phys_test.out
600000 1a6f 0 0 0 1 ./posix/virt_to_phys_test.out
601000 1a61 0 0 0 1 ./posix/virt_to_phys_test.out
602000 2208 0 0 0 1 [heap]
603000 220b 0 0 0 1 [heap]
7ffff78ec000 1fd4 0 1 0 1 /lib/libuClibc-1.0.30.so

Source:

Meaning of the flags:

  • vaddr: first virtual address of a page the belongs to the process. Notably:

    ./run-toolchain readelf -- -l "$(./getvar userland_build_dir)/posix/virt_to_phys_test.out"

    contains:

      Type           Offset             VirtAddr           PhysAddr
                     FileSiz            MemSiz              Flags  Align
    ...
      LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                     0x000000000000075c 0x000000000000075c  R E    0x200000
      LOAD           0x0000000000000e98 0x0000000000600e98 0x0000000000600e98
                     0x00000000000001b4 0x0000000000000218  RW     0x200000
    
     Section to Segment mapping:
      Segment Sections...
    ...
       02     .interp .hash .dynsym .dynstr .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
       03     .ctors .dtors .jcr .dynamic .got.plt .data .bss

    from which we deduce that:

    • 400000 is the text segment

    • 600000 is the data segment

  • pfn: add three zeroes to it, and you have the physical address.

    Three zeroes is 12 bits which is 4kB, which is the size of a page.

    For example, the virtual address 0x601000 has pfn of 0x1a61, which means that its physical address is 0x1a61000

    This is consistent with what linux/virt_to_phys_user.out told us: the virtual address 0x601048 has physical address 0x1a61048.

    048 corresponds to the three last zeroes, and is the offset within the page.

    Also, this value falls inside 0x601000, which as previously analyzed is the data section, which is the normal location for global variables such as ours.

  • soft-dirty: TODO

  • file/shared: TODO. 1 seems to indicate that the page can be shared across processes, possibly for read-only pages? E.g. the text segment has 1, but the data has 0.

  • swapped: TODO swapped to disk?

  • present: TODO vs swapped?

  • library: which executable owns that page

This program works in two steps:

  • parse the human readable lines lines from /proc/<pid>/maps. This files contains lines of form:

    7ffff7b6d000-7ffff7bdd000 r-xp 00000000 fe:00 658                        /lib/libuClibc-1.0.22.so

    which tells us that:

    • 7f8af99f8000-7f8af99ff000 is a virtual address range that belong to the process, possibly containing multiple pages.

    • /lib/libuClibc-1.0.22.so is the name of the library that owns that memory

  • loop over each page of each address range, and ask /proc/<pid>/pagemap for more information about that page, including the physical address