From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 71AE4C4167B for ; Fri, 30 Dec 2022 20:07:05 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id E3C888E0002; Fri, 30 Dec 2022 15:07:04 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id DEC768E0001; Fri, 30 Dec 2022 15:07:04 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id CDBA58E0002; Fri, 30 Dec 2022 15:07:04 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id BF7B28E0001 for ; Fri, 30 Dec 2022 15:07:04 -0500 (EST) Received: from smtpin08.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 8C53C40831 for ; Fri, 30 Dec 2022 20:07:04 +0000 (UTC) X-FDA: 80300056368.08.B403DAE Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by imf23.hostedemail.com (Postfix) with ESMTP id C7421140005 for ; Fri, 30 Dec 2022 20:07:02 +0000 (UTC) Authentication-Results: imf23.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=TKq3zOov; spf=pass (imf23.hostedemail.com: domain of rppt@kernel.org designates 145.40.68.75 as permitted sender) smtp.mailfrom=rppt@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1672430823; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=5jtYvSf40kAtNrQeoIlmSe+bF9yuTRxK5oamx7pbOx0=; b=Q5UVDdeZ/21Y2DnnnLfUA81YAN1fFQjV2IqJ6xRMxNz+BcVte8Z1Bgu3ifzcgPBl0uB9i8 fGUWAkb+049DywALwDIrmb132feDOfhe7K49XD1TVenCiklnhxfhIv0UfR9NhtPSDVRiy+ vBjuLSLJuqQ+NhBkqqlgwuarPVoXUCE= ARC-Authentication-Results: i=1; imf23.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=TKq3zOov; spf=pass (imf23.hostedemail.com: domain of rppt@kernel.org designates 145.40.68.75 as permitted sender) smtp.mailfrom=rppt@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1672430823; a=rsa-sha256; cv=none; b=iu46z762dBMh/hb/ttplp9bCgoAXIAcU+dA4wngamvPAlnFx3kHpcrICJcTpeN3YlIOu73 uFQoagXKpAjx1CboBKeHyQC9GzVFVsp6NExF6foNFoi4udAgJs/3vUeLfGTChGXnTOn3Ue GXAmraAk3jULgnG9rMKJglKYAor03a0= Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id DC6B3B81C24; Fri, 30 Dec 2022 20:07:00 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5D650C433EF; Fri, 30 Dec 2022 20:06:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672430819; bh=yMfmMH1jzs1567jiXoyHPShvjpYvp6CVpm66CnnU34A=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=TKq3zOov0qD+YUgVczWfQ1BNVXT8J4sx/9YqbGUsvUMXlFwA1HogL/MJbSgrxh1Ck kMotFLlxfKRFPjyNgtLtOAux9ZF0R0H0LYx8FH4GSgJsXQUiMLeQZMhdUXSjMBoygp 24k2pAb69BS11fACrLc2dJG315rOLRnEyYI0rRjUdtFxplbF6AXz/eYQEDdomthGrc o4wZRWQiezzPdWyN8KQwDGVoRxi62FPCOYpygQo8mcahqZOOskrXZVC0Hu7SaWlMGs SRmpCprNjpDffA5Me726P8EcDQ/mvXMiUeRtpRi+el9bhG9RslTkuc4EYbTPrtMtQ4 5V9VBxicUl31g== Date: Fri, 30 Dec 2022 22:06:41 +0200 From: Mike Rapoport To: Dmitrii Bundin Cc: jan.kiszka@siemens.com, kbingham@kernel.org, akpm@linux-foundation.org, gregkh@linuxfoundation.org, mingo@redhat.com, x86@kernel.org, linux-mm@kvack.org, linux-kernel@vger.kernel.org, vbabka@suse.cz Subject: Re: [PATCH] scripts/gdb: add mm introspection utils Message-ID: References: <20221230163512.23736-1-dmitrii.bundin.a@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20221230163512.23736-1-dmitrii.bundin.a@gmail.com> X-Rspam-User: X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: C7421140005 X-Stat-Signature: q6c79m3o9nt41yfcg1841pf6iwjtitpd X-HE-Tag: 1672430822-700843 X-HE-Meta: U2FsdGVkX18Z0RTcOkbtBBTd5rZUaXF7bbLdmX6VwKdbp10t04sjjYVbDpJysjaEQl63yEyhJzBqazZtLPmAjq75L7TjqTbOA5adu9kp5Q+Xvovv+Wz/xyRncdIjmNCvy1gJGXOuof2gz7W9em30Ct0jTw7/hvdjQbC/1Yl0F0dWKdq+uqdgUElFg8vEdCuQsrOmlEwjCyO6rxdx/9gQ0qe2NRGnDoWA27voGbdTNlQkZz/W2R6uV49gXqjbOJhTDaySMIs36Now5q17GoMHZidO7KZ81Xq9KC1OFZXoSw5kAFBgATrHsY+7ohISkU/FWv9Q11noj/Y0gtxwtfSvai8KdQiGK2x8OMeGJnIwS9wokA41hw5LjOUotbJy8CI10t5Cb7ntyh+gdQt9IzwCzQ4lDylpxa5SktrHQ12s1JqIC/+lGuHSZRF33N0PNGrAJbJ/69JARQ8TLKySjrYxFJgEBFUfvZ2j0gl8cMWcSJEtMp3SjkJXL4X0kfS50plQ2AOvaLJfk8NffGXeiWHNmOiAQSmu1eo+cK9haPS0M/sug8yUdXlTKxXPGnDeqHMoUdK2HCGBs/wIfjb2LoCivFbS6trXi2kIJlVEi7jl1PUm8tYb4iQdaeyQDKn2Rfj3BjPlAqABQKAQp19iFITu9Tlt9bAD2tHF+3Js7pSTwQE4r6tUC+t7qz+o0b3JhxlCm+eVvQSuAhq9kDalwUB5C81HjlRhP1qg6Dh+MeS9iSGgPu+4CT38dG/5xeKDWctNrPVH3rFYKl0oGcl/CqVmo5cvzr6HFODvBUsoG4IL51LLBn2w9e8sqKXO93cF1hH2cHS1qNUnYSvRnKnIAsZaSB4O1ryuzadOhVllfDbn56MEPCp4295R6cvDw20EQBatAFGzYayC2eI3YoBxBczylr956R08YVm0rTb1l68t6EhRAeMHwxUKvNgspHkmwyvsrO1MP8e9DSJD0ug8TJg jd2DR0ay drRg+CAz/S65qT2riO/14HQUC3BJNu8lr+TUb4ed2Gw8bt3+rn0RIbf+mcxEHc/dkjQua2s6xaxRIAb8Q3JJjxLn8/B4eKXEdPv2m1ywkj1qHGpY= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: On Fri, Dec 30, 2022 at 07:35:12PM +0300, Dmitrii Bundin wrote: > This command provides a way to traverse the entire page hierarchy by a > given virtual address. In addition to qemu's commands info tlb/info mem > it provides the complete information about the paging structure for an > arbitrary virtual address. It supports 4Kb/2MB/1GB and 5 level paging. The commit message does not mention it's x86-specific. Not sure how gdb scripts handle per-arch functionality, but at the very least this should be stated in the commit message. > Here is an example output for 2MB success translation: > > CR3: > CR3 BINARY DATA: 0x10c1d2002 > NEXT ENTRY PHYSICALL ADDRESS: 0x10c1d2000 > --- > PAGE LEVEL WRITE THROUGH(bit 3): False > PAGE LEVEL CACHE DISABLED(bit 4): False Any particular reason to make it ALL CAPS? > LEVEL 4: > ENTRY ADDRESS: 0xffff88810c1d27f0 > PAGE ENTRY BINARY DATA: 0x8000000105dca067 > NEXT ENTRY PHYSICALL ADDRESS: 0x105dca000 > --- > ENTRY PRESENT(bit 0): True > READ/WRITE ACCESS ALLOWED(bit 1): True > USER ACCESS ALLOWED(bit 2): True > PAGE LEVEL WRITE THROUGH(bit 3): False > PAGE LEVEL CACHE DISABLED(bit 4): False > ENTRY HAS BEEN ACCESSED(bit 5): True > PAGE SIZE(bit 7): False > RESTART TO ORDINARY(bit 11): False > EXECUTE DISABLE(bit 63): True > LEVEL 3: > ENTRY ADDRESS: 0xffff888105dca9d0 > PAGE ENTRY BINARY DATA: 0x105c87067 > NEXT ENTRY PHYSICALL ADDRESS: 0x105c87000 > --- > ENTRY PRESENT(bit 0): True > READ/WRITE ACCESS ALLOWED(bit 1): True > USER ACCESS ALLOWED(bit 2): True > PAGE LEVEL WRITE THROUGH(bit 3): False > PAGE LEVEL CACHE DISABLED(bit 4): False > ENTRY HAS BEEN ACCESSED(bit 5): True > PAGE SIZE(bit 7): False > RESTART TO ORDINARY(bit 11): False > EXECUTE DISABLE(bit 63): False > LEVEL 2: > ENTRY ADDRESS: 0xffff888105c87698 > PAGE ENTRY BINARY DATA: 0x80000001622008e7 > PAGE SIZE: 2MB > PAGE PHYSICALL ADDRESS: 0x162200000 > --- > ENTRY PRESENT(bit 0): True > READ/WRITE ACCESS ALLOWED(bit 1): True > USER ACCESS ALLOWED(bit 2): True > PAGE LEVEL WRITE THROUGH(bit 3): False > PAGE LEVEL CACHE DISABLED(bit 4): False > ENTRY HAS BEEN ACCESSED(bit 5): True > PAGE DIRTY(bit 6): True > PAGE SIZE(bit 7): True > GLOBAL TRANSLATION(bit 8): False > RESTART TO ORDINARY(bit 11): True > PAT(bit 12): False > PROTECTION KEY(bits (62, 59)): 0 > EXECUTE DISABLE(bit 63): True > > Signed-off-by: Dmitrii Bundin > --- > scripts/gdb/linux/mm.py | 220 +++++++++++++++++++++++++++++++++++++ > scripts/gdb/vmlinux-gdb.py | 1 + > 2 files changed, 221 insertions(+) > create mode 100644 scripts/gdb/linux/mm.py > > diff --git a/scripts/gdb/linux/mm.py b/scripts/gdb/linux/mm.py > new file mode 100644 > index 000000000000..c6f04e74edbd > --- /dev/null > +++ b/scripts/gdb/linux/mm.py > @@ -0,0 +1,220 @@ > +# > +# gdb helper commands and functions for Linux kernel debugging > +# > +# routines to introspect virtual memory These routines introspect page tables rather than virtual memory > +# > +# Authors: > +# Dmitrii Bundin > +# > +# This work is licensed under the terms of the GNU GPL version 2. > +# > + > +import gdb > + > +from linux import utils > + > +PHYSICAL_ADDRESS_MASK = gdb.parse_and_eval('0xfffffffffffff') > + > + > +def page_mask(level=1): > + # 4KB > + if level == 1: > + return gdb.parse_and_eval('(u64) ~0xfff') > + # 2MB > + elif level == 2: > + return gdb.parse_and_eval('(u64) ~0x1fffff') > + # 1GB > + elif level == 3: > + return gdb.parse_and_eval('(u64) ~0x3fffffff') What will happen here with 5-level paging? > + else: > + raise Exception(f'Unknown page level: {level}') > + > + > +def _page_offset_base(): > + pob_symbol = gdb.lookup_global_symbol('page_offset_base') > + pob = pob_symbol.name if pob_symbol else '0xffff888000000000' Please don't use magic numbers. > + return gdb.parse_and_eval(pob) > + > + > +def is_bit_defined_tupled(data, offset): > + return offset, bool(data >> offset & 1) > + > +def content_tupled(data, bit_start, bit_end): > + return (bit_end, bit_start), data >> bit_start & ((1 << (1 + bit_end - bit_start)) - 1) > + > +def entry_va(level, phys_addr, translating_va): > + def start_bit(level): > + if level == 5: > + return 48 > + elif level == 4: > + return 39 > + elif level == 3: > + return 30 > + elif level == 2: > + return 21 > + elif level == 1: > + return 12 > + else: > + raise Exception(f'Unknown level {level}') > + > + entry_offset = ((translating_va >> start_bit(level)) & 511) * 8 > + entry_va = _page_offset_base() + phys_addr + entry_offset > + return entry_va > + > +class Cr3(): > + def __init__(self, cr3, page_levels): > + self.cr3 = cr3 > + self.page_levels = page_levels > + self.page_level_write_through = is_bit_defined_tupled(cr3, 3) > + self.page_level_cache_disabled = is_bit_defined_tupled(cr3, 4) > + self.next_entry_physical_address = cr3 & PHYSICAL_ADDRESS_MASK & page_mask() > + > + def next_entry(self, va): > + next_level = self.page_levels > + return PageHierarchyEntry(entry_va(next_level, self.next_entry_physical_address, va), next_level) > + > + def mk_string(self): > + return f"""\ > +CR3: > + CR3 BINARY DATA: {hex(self.cr3)} > + NEXT ENTRY PHYSICALL ADDRESS: {hex(self.next_entry_physical_address)} > + --- > + PAGE LEVEL WRITE THROUGH(bit {self.page_level_write_through[0]}): {self.page_level_write_through[1]} > + PAGE LEVEL CACHE DISABLED(bit {self.page_level_cache_disabled[0]}): {self.page_level_cache_disabled[1]} > +""" > + > + > +class PageHierarchyEntry(): > + def __init__(self, address, level): > + data = int.from_bytes( > + memoryview(gdb.selected_inferior().read_memory(address, 8)), > + "little" > + ) > + if level == 1: > + self.is_page = True > + self.entry_present = is_bit_defined_tupled(data, 0) > + self.read_write = is_bit_defined_tupled(data, 1) > + self.user_access_allowed = is_bit_defined_tupled(data, 2) > + self.page_level_write_through = is_bit_defined_tupled(data, 3) > + self.page_level_cache_disabled = is_bit_defined_tupled(data, 4) > + self.entry_was_accessed = is_bit_defined_tupled(data, 5) > + self.dirty = is_bit_defined_tupled(data, 6) > + self.pat = is_bit_defined_tupled(data, 7) > + self.global_translation = is_bit_defined_tupled(data, 8) > + self.page_physical_address = data & PHYSICAL_ADDRESS_MASK & page_mask(level) > + self.next_entry_physical_address = None > + self.hlat_restart_with_ordinary = is_bit_defined_tupled(data, 11) > + self.protection_key = content_tupled(data, 59, 62) > + self.executed_disable = is_bit_defined_tupled(data, 63) > + else: > + page_size = is_bit_defined_tupled(data, 7) > + page_size_bit = page_size[1] > + self.is_page = page_size_bit > + self.entry_present = is_bit_defined_tupled(data, 0) > + self.read_write = is_bit_defined_tupled(data, 1) > + self.user_access_allowed = is_bit_defined_tupled(data, 2) > + self.page_level_write_through = is_bit_defined_tupled(data, 3) > + self.page_level_cache_disabled = is_bit_defined_tupled(data, 4) > + self.entry_was_accessed = is_bit_defined_tupled(data, 5) > + self.page_size = page_size > + self.dirty = is_bit_defined_tupled( > + data, 6) if page_size_bit else None > + self.global_translation = is_bit_defined_tupled( > + data, 8) if page_size_bit else None > + self.pat = is_bit_defined_tupled( > + data, 12) if page_size_bit else None > + self.page_physical_address = data & PHYSICAL_ADDRESS_MASK & page_mask(level) if page_size_bit else None > + self.next_entry_physical_address = None if page_size_bit else data & PHYSICAL_ADDRESS_MASK & page_mask() > + self.hlat_restart_with_ordinary = is_bit_defined_tupled(data, 11) > + self.protection_key = content_tupled(data, 59, 62) if page_size_bit else None > + self.executed_disable = is_bit_defined_tupled(data, 63) > + self.address = address > + self.page_entry_binary_data = data > + self.page_hierarchy_level = level > + > + def next_entry(self, va): > + if self.is_page or not self.entry_present[1]: > + return None > + > + next_level = self.page_hierarchy_level - 1 > + return PageHierarchyEntry(entry_va(next_level, self.next_entry_physical_address, va), next_level) > + > + > + def mk_string(self): > + if not self.entry_present[1]: > + return f"""\ > +LEVEL {self.page_hierarchy_level}: > + ENTRY ADDRESS: {hex(self.address)} > + PAGE ENTRY BINARY DATA: {hex(self.page_entry_binary_data)} > + --- > + PAGE ENTRY IS NOT PRESENT! > +""" > + elif self.is_page: > + return f"""\ > +LEVEL {self.page_hierarchy_level}: > + ENTRY ADDRESS: {hex(self.address)} > + PAGE ENTRY BINARY DATA: {hex(self.page_entry_binary_data)} > + PAGE SIZE: {'1GB' if self.page_hierarchy_level == 3 else '2MB' if self.page_hierarchy_level == 2 else '4KB' if self.page_hierarchy_level == 1 else 'Unknown page size for level:' + self.page_hierarchy_level} > + PAGE PHYSICALL ADDRESS: {hex(self.page_physical_address)} > + --- > + ENTRY PRESENT(bit {self.entry_present[0]}): {self.entry_present[1]} > + READ/WRITE ACCESS ALLOWED(bit {self.read_write[0]}): {self.read_write[1]} > + USER ACCESS ALLOWED(bit {self.user_access_allowed[0]}): {self.user_access_allowed[1]} > + PAGE LEVEL WRITE THROUGH(bit {self.page_level_write_through[0]}): {self.page_level_write_through[1]} > + PAGE LEVEL CACHE DISABLED(bit {self.page_level_cache_disabled[0]}): {self.page_level_cache_disabled[1]} > + ENTRY HAS BEEN ACCESSED(bit {self.entry_was_accessed[0]}): {self.entry_was_accessed[1]} > + PAGE DIRTY(bit {self.dirty[0]}): {self.dirty[1]} > + """ + \ > + ("" if self.page_hierarchy_level == 1 else f"""PAGE SIZE(bit {self.page_size[0]}): {self.page_size[1]} > + """) + \ > + f"""GLOBAL TRANSLATION(bit {self.global_translation[0]}): {self.global_translation[1]} > + RESTART TO ORDINARY(bit {self.hlat_restart_with_ordinary[0]}): {self.hlat_restart_with_ordinary[1]} > + PAT(bit {self.pat[0]}): {self.pat[1]} > + PROTECTION KEY(bits {self.protection_key[0]}): {self.protection_key[1]} > + EXECUTE DISABLE(bit {self.executed_disable[0]}): {self.executed_disable[1]} > +""" > + else: > + return f"""\ > +LEVEL {self.page_hierarchy_level}: > + ENTRY ADDRESS: {hex(self.address)} > + PAGE ENTRY BINARY DATA: {hex(self.page_entry_binary_data)} > + NEXT ENTRY PHYSICALL ADDRESS: {hex(self.next_entry_physical_address)} > + --- > + ENTRY PRESENT(bit {self.entry_present[0]}): {self.entry_present[1]} > + READ/WRITE ACCESS ALLOWED(bit {self.read_write[0]}): {self.read_write[1]} > + USER ACCESS ALLOWED(bit {self.user_access_allowed[0]}): {self.user_access_allowed[1]} > + PAGE LEVEL WRITE THROUGH(bit {self.page_level_write_through[0]}): {self.page_level_write_through[1]} > + PAGE LEVEL CACHE DISABLED(bit {self.page_level_cache_disabled[0]}): {self.page_level_cache_disabled[1]} > + ENTRY HAS BEEN ACCESSED(bit {self.entry_was_accessed[0]}): {self.entry_was_accessed[1]} > + PAGE SIZE(bit {self.page_size[0]}): {self.page_size[1]} > + RESTART TO ORDINARY(bit {self.hlat_restart_with_ordinary[0]}): {self.hlat_restart_with_ordinary[1]} > + EXECUTE DISABLE(bit {self.executed_disable[0]}): {self.executed_disable[1]} > +""" > + > + > +class TranslateVM(gdb.Command): > + """Prints the entire paging structure used to translate a given virtual address. > + > +Having an address space of the currently executed process translates the virtual address > +and prints detailed information of all paging structure levels used for the transaltion.""" > + > + def __init__(self): > + super(TranslateVM, self).__init__('translate-vm', gdb.COMMAND_USER) > + > + def invoke(self, arg, from_tty): > + if utils.is_target_arch("x86"): > + vm_address = gdb.parse_and_eval(f'{arg}') > + cr3_data = gdb.parse_and_eval('$cr3') > + cr4 = gdb.parse_and_eval('$cr4') > + page_levels = 5 if cr4 & (1 << 12) else 4 > + page_entry = Cr3(cr3_data, page_levels) > + while page_entry: > + gdb.write(page_entry.mk_string()) > + page_entry = page_entry.next_entry(vm_address) > + else: > + gdb.GdbError("Virtual address translation is not" > + "supported for this arch") > + > + > + > +TranslateVM() > diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py > index 4136dc2c59df..27bd7339bccc 100644 > --- a/scripts/gdb/vmlinux-gdb.py > +++ b/scripts/gdb/vmlinux-gdb.py > @@ -37,3 +37,4 @@ else: > import linux.clk > import linux.genpd > import linux.device > + import linux.mm > -- > 2.17.1 > > -- Sincerely yours, Mike.