osandov / drgn

Programmable debugger
Other
1.78k stars 165 forks source link

Fix s390x virtual address translation on Linux 6.10+ #433

Closed osandov closed 1 month ago

osandov commented 2 months ago

Before Linux 6.10, on s390x, kernel virtual addresses in the direct mapping were equal to physical addresses. This was changed in torvalds/linux@c98d2ecae08f02bd2dccd24e7e485e9f0211db65. This broke drgn's virtual address translation support for s390x. To reproduce (using emulation, so very slow):

$ python3 -m vmtest.rootfsbuild -a s390x --build-drgn
...
$ python3 -m vmtest -a s390x -k 6.11.\*default
...
FAILED tests/linux_kernel/helpers/test_common.py::TestIdentifyAddress::test_identify_slab_cache - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_common.py::TestIdentifyAddress::test_identify_unrecognized - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_common.py::TestIdentifyAddress::test_identify_vmap - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_common.py::TestIdentifyAddress::test_identify_vmap_stack - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_common.py::TestPrintAnnotatedMemory::test_print_annotated_memory - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_common.py::TestPrintAnnotatedStack::test_print_annotated_stack - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_access_remote_vm_init_mm - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_follow_page - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_follow_pfn_init_mm - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_follow_phys - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_page_to_virt - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_pfn_to_virt - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_phys_to_virt - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_virt_to_page - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_virt_to_pfn - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_virt_to_phys - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_vmalloc_to_page - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_mm.py::TestMm::test_vmalloc_to_pfn - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_slab.py::TestSlab::test_find_containing_slab_cache - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_slab.py::TestSlab::test_find_containing_slab_cache_invalid - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000
FAILED tests/linux_kernel/helpers/test_slab.py::TestSlab::test_slab_object_info - _drgn.FaultError: could not find physical memory segment: 0x3fffff84000

If you have access to an s390x machine that you're willing to test on, something like this should reproduce it:

$ make -C "/lib/modules/$(uname -r)/build" M="$PWD/tests/linux_kernel/kmod"
...
$ export DRGN_TEST_KMOD="$PWD/tests/linux_kernel/kmod/drgn_test.ko"
$ python3 setup.py build_ext -i
...
$ python3 -m unittest discover -v

Here is the relevant code that needs to be updated: https://github.com/osandov/drgn/blob/7bbb7e6a9627c6e6f184d659b3fc88b33ddf5dd9/libdrgn/arch_s390x.c#L239-L465

osandov commented 2 months ago

@svens-s390 are you available to take a look at this? No rush at all and no worries if not.

svenschnelle commented 1 month ago

The problem seems to be that drgn is trying to find swapper_pg_dir in the physical mappings - changing linux_kernel_pgtable_iterator_next_s390x() to read the page tables via the virtual address fixes this for me.

osandov commented 1 month ago

That was a much easier fix than I expected. Thanks for taking a look!