1 # SPDX-License-Identifier: GPL-2.0-only 2 # 3 # gdb helper commands and functions for Linux 4 # 5 # routines to introspect page table 6 # 7 # Authors: 8 # Dmitrii Bundin <dmitrii.bundin.a@gmail.com> 9 # 10 11 import gdb 12 13 from linux import utils 14 15 PHYSICAL_ADDRESS_MASK = gdb.parse_and_eval('0x 16 17 18 def page_mask(level=1): 19 # 4KB 20 if level == 1: 21 return gdb.parse_and_eval('(u64) ~0xff 22 # 2MB 23 elif level == 2: 24 return gdb.parse_and_eval('(u64) ~0x1f 25 # 1GB 26 elif level == 3: 27 return gdb.parse_and_eval('(u64) ~0x3f 28 else: 29 raise Exception(f'Unknown page level: 30 31 32 #page_offset_base in case CONFIG_DYNAMIC_MEMOR 33 POB_NO_DYNAMIC_MEM_LAYOUT = '0xffff88800000000 34 def _page_offset_base(): 35 pob_symbol = gdb.lookup_global_symbol('pag 36 pob = pob_symbol.name if pob_symbol else P 37 return gdb.parse_and_eval(pob) 38 39 40 def is_bit_defined_tupled(data, offset): 41 return offset, bool(data >> offset & 1) 42 43 def content_tupled(data, bit_start, bit_end): 44 return (bit_start, bit_end), data >> bit_s 45 46 def entry_va(level, phys_addr, translating_va) 47 def start_bit(level): 48 if level == 5: 49 return 48 50 elif level == 4: 51 return 39 52 elif level == 3: 53 return 30 54 elif level == 2: 55 return 21 56 elif level == 1: 57 return 12 58 else: 59 raise Exception(f'Unknown leve 60 61 entry_offset = ((translating_va >> st 62 entry_va = _page_offset_base() + phys_ 63 return entry_va 64 65 class Cr3(): 66 def __init__(self, cr3, page_levels): 67 self.cr3 = cr3 68 self.page_levels = page_levels 69 self.page_level_write_through = is_bit 70 self.page_level_cache_disabled = is_bi 71 self.next_entry_physical_address = cr3 72 73 def next_entry(self, va): 74 next_level = self.page_levels 75 return PageHierarchyEntry(entry_va(nex 76 77 def mk_string(self): 78 return f"""\ 79 cr3: 80 {'cr3 binary data': <30} {hex(self.cr3)} 81 {'next entry physical address': <30} {hex( 82 --- 83 {'bit' : <4} {self.page_level_write_throug 84 {'bit' : <4} {self.page_level_cache_disabl 85 """ 86 87 88 class PageHierarchyEntry(): 89 def __init__(self, address, level): 90 data = int.from_bytes( 91 memoryview(gdb.selected_inferior() 92 "little" 93 ) 94 if level == 1: 95 self.is_page = True 96 self.entry_present = is_bit_define 97 self.read_write = is_bit_defined_t 98 self.user_access_allowed = is_bit_ 99 self.page_level_write_through = is 100 self.page_level_cache_disabled = i 101 self.entry_was_accessed = is_bit_d 102 self.dirty = is_bit_defined_tupled 103 self.pat = is_bit_defined_tupled(d 104 self.global_translation = is_bit_d 105 self.page_physical_address = data 106 self.next_entry_physical_address = 107 self.hlat_restart_with_ordinary = 108 self.protection_key = content_tupl 109 self.executed_disable = is_bit_def 110 else: 111 page_size = is_bit_defined_tupled( 112 page_size_bit = page_size[1] 113 self.is_page = page_size_bit 114 self.entry_present = is_bit_define 115 self.read_write = is_bit_defined_t 116 self.user_access_allowed = is_bit_ 117 self.page_level_write_through = is 118 self.page_level_cache_disabled = i 119 self.entry_was_accessed = is_bit_d 120 self.page_size = page_size 121 self.dirty = is_bit_defined_tupled 122 data, 6) if page_size_bit else 123 self.global_translation = is_bit_d 124 data, 8) if page_size_bit else 125 self.pat = is_bit_defined_tupled( 126 data, 12) if page_size_bit els 127 self.page_physical_address = data 128 self.next_entry_physical_address = 129 self.hlat_restart_with_ordinary = 130 self.protection_key = content_tupl 131 self.executed_disable = is_bit_def 132 self.address = address 133 self.page_entry_binary_data = data 134 self.page_hierarchy_level = level 135 136 def next_entry(self, va): 137 if self.is_page or not self.entry_pres 138 return None 139 140 next_level = self.page_hierarchy_level 141 return PageHierarchyEntry(entry_va(nex 142 143 144 def mk_string(self): 145 if not self.entry_present[1]: 146 return f"""\ 147 level {self.page_hierarchy_level}: 148 {'entry address': <30} {hex(self.address)} 149 {'page entry binary data': <30} {hex(self. 150 --- 151 PAGE ENTRY IS NOT PRESENT! 152 """ 153 elif self.is_page: 154 def page_size_line(ps_bit, ps, lev 155 return "" if level == 1 else f 156 157 return f"""\ 158 level {self.page_hierarchy_level}: 159 {'entry address': <30} {hex(self.address)} 160 {'page entry binary data': <30} {hex(self. 161 {'page size': <30} {'1GB' if self.page_hie 162 {'page physical address': <30} {hex(self.p 163 --- 164 {'bit': <4} {self.entry_present[0]: <10} { 165 {'bit': <4} {self.read_write[0]: <10} {'re 166 {'bit': <4} {self.user_access_allowed[0]: 167 {'bit': <4} {self.page_level_write_through 168 {'bit': <4} {self.page_level_cache_disable 169 {'bit': <4} {self.entry_was_accessed[0]: < 170 {"" if self.page_hierarchy_level == 1 else 171 {'bit': <4} {self.dirty[0]: <10} {'page di 172 {'bit': <4} {self.global_translation[0]: < 173 {'bit': <4} {self.hlat_restart_with_ordina 174 {'bit': <4} {self.pat[0]: <10} {'pat': <30 175 {'bits': <4} {str(self.protection_key[0]): 176 {'bit': <4} {self.executed_disable[0]: <10 177 """ 178 else: 179 return f"""\ 180 level {self.page_hierarchy_level}: 181 {'entry address': <30} {hex(self.address)} 182 {'page entry binary data': <30} {hex(self. 183 {'next entry physical address': <30} {hex( 184 --- 185 {'bit': <4} {self.entry_present[0]: <10} { 186 {'bit': <4} {self.read_write[0]: <10} {'re 187 {'bit': <4} {self.user_access_allowed[0]: 188 {'bit': <4} {self.page_level_write_through 189 {'bit': <4} {self.page_level_cache_disable 190 {'bit': <4} {self.entry_was_accessed[0]: < 191 {'bit': <4} {self.page_size[0]: <10} {'pag 192 {'bit': <4} {self.hlat_restart_with_ordina 193 {'bit': <4} {self.executed_disable[0]: <10 194 """ 195 196 197 class TranslateVM(gdb.Command): 198 """Prints the entire paging structure used 199 200 Having an address space of the currently execu 201 and prints detailed information of all paging 202 Currently supported arch: x86""" 203 204 def __init__(self): 205 super(TranslateVM, self).__init__('tra 206 207 def invoke(self, arg, from_tty): 208 if utils.is_target_arch("x86"): 209 vm_address = gdb.parse_and_eval(f' 210 cr3_data = gdb.parse_and_eval('$cr 211 cr4 = gdb.parse_and_eval('$cr4') 212 page_levels = 5 if cr4 & (1 << 12) 213 page_entry = Cr3(cr3_data, page_le 214 while page_entry: 215 gdb.write(page_entry.mk_string 216 page_entry = page_entry.next_e 217 else: 218 gdb.GdbError("Virtual address tran 219 "supported for this a 220 221 222 TranslateVM()
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.