diff --git a/linux-ramdump-parser-v2/mm.py b/linux-ramdump-parser-v2/mm.py index ec55f5d239adc773569afded94fe8eca63e4fbf0..efca724830789ce95123989d4146d72c2f375acb 100644 --- a/linux-ramdump-parser-v2/mm.py +++ b/linux-ramdump-parser-v2/mm.py @@ -19,6 +19,21 @@ def page_buddy(ramdump, page): return val == 0xffffff80 +def page_count(ramdump, page): + """Commit: 0139aa7b7fa12ceef095d99dc36606a5b10ab83a + mm: rename _count, field of the struct page, to _refcount""" + if (ramdump.version < (4, 6, 0)): + count = ramdump.read_structure_field(page, 'struct page', + '_count.counter') + else: + count = ramdump.read_structure_field(page, 'struct page', + '_refcount.counter') + return count + + +def page_ref_count(ramdump, page): + return page_count(ramdump, page) + def get_debug_flags(ramdump, page): debug_flag_offset = ramdump.field_offset('struct page', 'debug_flags') flagval = ramdump.read_word(page + debug_flag_offset) @@ -152,22 +167,27 @@ def get_vmemmap(ramdump): spsize = ramdump.sizeof('struct page') vmemmap_size = bitops.align((1 << (va_bits - page_shift)) * spsize, pud_size) - pfn_offset = (ramdump.phys_offset >> page_shift) - offset = pfn_offset * spsize + + memstart_addr = ramdump.read_s64('memstart_addr') + page_section_mask = ~((1 << 18) - 1) + memstart_offset = (memstart_addr >> page_shift) & page_section_mask + memstart_offset *= spsize + if (ramdump.kernel_version < (3, 18, 31)): - vmalloc_end = ramdump.page_offset - pud_size - vmemmap_size # vmalloc_end = 0xFFFFFFBC00000000 + vmemmap = ramdump.page_offset - pud_size - vmemmap_size elif (ramdump.kernel_version < (4, 9, 0)): # for version >= 3.18.31, # vmemmap is shifted to base addr (0x80000000) pfn. - vmalloc_end = ramdump.page_offset - pud_size - vmemmap_size - offset + vmemmap = (ramdump.page_offset - pud_size - vmemmap_size - + memstart_offset) else: # for version >= 4.9.0, + # vmemmap_size = ( 1 << (39 - 12 - 1 + 6)) struct_page_max_shift = 6 - #vmemmap_size = ( 1 << (39 - 12 - 1 + 6)) vmemmap_size = ( 1 << (va_bits - page_shift - 1 + struct_page_max_shift)) - vmalloc_end = ramdump.page_offset - vmemmap_size - offset - return vmalloc_end + vmemmap = ramdump.page_offset - vmemmap_size - memstart_offset + return vmemmap def page_to_pfn_vmemmap(ramdump, page): @@ -284,3 +304,30 @@ def page_address(ramdump, page): pam = ramdump.read_word(pam + lh_offset) if pam == start: return None + + +def for_each_pfn(ramdump): + """ creates a generator for looping through valid pfn + Example: + for i in for_each_pfn(ramdump): + page = pfn_to_page(i) + """ + page_size = (1 << 12) + cnt = ramdump.read_structure_field('memblock', 'struct memblock', + 'memory.cnt') + region = ramdump.read_structure_field('memblock', 'struct memblock', + 'memory.regions') + memblock_region_size = ramdump.sizeof('struct memblock_region') + for i in range(cnt): + start = ramdump.read_structure_field(region, 'struct memblock_region', + 'base') + end = start + ramdump.read_structure_field( + region, 'struct memblock_region', 'size') + + pfn = start / page_size + end /= page_size + while pfn < end: + yield pfn + pfn += 1 + + region += memblock_region_size diff --git a/linux-ramdump-parser-v2/parsers/ddrcompare.py b/linux-ramdump-parser-v2/parsers/ddrcompare.py index 5a4866ffbdd41deb2f398b27a4d12d3cba8aaaf3..63cefe64b715203838a7b5f5eb218903415e0b97 100644 --- a/linux-ramdump-parser-v2/parsers/ddrcompare.py +++ b/linux-ramdump-parser-v2/parsers/ddrcompare.py @@ -45,7 +45,8 @@ class DDRCompare(RamParser) : bitcheck = virtual & 0x3 if bitcheck: virtual = virtual - bitcheck - physical = self.ramdump.virt_to_phys(virtual) + physical = self.ramdump.virt_to_phys( + virtual + self.ramdump.kaslr_offset) magic = hex(self.ramdump.read_u32(physical, False)).rstrip("L").lstrip("0x").zfill(8) if (m.group(2) != magic): diff --git a/linux-ramdump-parser-v2/parsers/pagetracking.py b/linux-ramdump-parser-v2/parsers/pagetracking.py index e7ec446c273293a1570b1d9c1c97b049eab349cd..c627ac87f9ea7473780c5e2748134d3af8e5e8b1 100644 --- a/linux-ramdump-parser-v2/parsers/pagetracking.py +++ b/linux-ramdump-parser-v2/parsers/pagetracking.py @@ -11,7 +11,7 @@ from print_out import print_out_str from parser_util import register_parser, RamParser -from mm import pfn_to_page, page_buddy +from mm import pfn_to_page, page_buddy, page_count, for_each_pfn @register_parser('--print-pagetracking', 'print page tracking information (if available)') @@ -22,13 +22,6 @@ class PageTracking(RamParser): print_out_str('CONFIG_PAGE_OWNER not defined') return - min_pfn_addr = self.ramdump.address_of('min_low_pfn') - max_pfn_addr = self.ramdump.address_of('max_pfn') - min_pfn = self.ramdump.read_word( - min_pfn_addr) + (self.ramdump.phys_offset >> 12) - max_pfn = self.ramdump.read_word( - max_pfn_addr) + (self.ramdump.phys_offset >> 12) - if (self.ramdump.kernel_version >= (3, 19, 0)): mem_section = self.ramdump.read_word('mem_section') @@ -61,16 +54,20 @@ class PageTracking(RamParser): out_frequency = self.ramdump.open_file('page_frequency.txt') sorted_pages = {} - for pfn in range(min_pfn, max_pfn): + for pfn in for_each_pfn(self.ramdump): page = pfn_to_page(self.ramdump, pfn) + order = 0 - # validate this page is free - if page_buddy(self.ramdump, page): + """must be allocated, and the first pfn of an order > 0 page""" + if (page_buddy(self.ramdump, page) or + page_count(self.ramdump, page) == 0): continue if (self.ramdump.kernel_version <= (3, 19, 0)): nr_trace_entries = self.ramdump.read_int( page + trace_offset + nr_entries_offset) struct_holding_trace_entries = page + order = self.ramdump.read_structure_field( + page, 'struct page', 'order') else: phys = pfn << 12 if phys is None or phys is 0: @@ -85,11 +82,14 @@ class PageTracking(RamParser): nr_trace_entries = self.ramdump.read_int( temp_page_ext + nr_entries_offset) struct_holding_trace_entries = temp_page_ext + order = self.ramdump.read_structure_field( + temp_page_ext, 'struct page_ext', 'order') if nr_trace_entries <= 0 or nr_trace_entries > 16: continue - out_tracking.write('PFN 0x{0:x} page 0x{1:x} \n'.format(pfn, page)) + out_tracking.write('PFN 0x{:x}-0x{:x} page 0x{:x}\n'.format( + pfn, pfn + (1 << order) - 1, page)) alloc_str = '' for i in range(0, nr_trace_entries): diff --git a/linux-ramdump-parser-v2/ramdump.py b/linux-ramdump-parser-v2/ramdump.py index b0d4ecf33aeaff322f104b6137125a72391b8994..e0a379cd4d5c11884d38dfd6e1c1885af2fab48c 100755 --- a/linux-ramdump-parser-v2/ramdump.py +++ b/linux-ramdump-parser-v2/ramdump.py @@ -1318,6 +1318,9 @@ class RamDump(): """reads a 4 or 8 byte field from a structure""" size = self.sizeof("(({0} *)0)->{1}".format(struct_name, field)) virt = self.resolve_virt(addr_or_name) + if virt is None or size is None: + return None + if size == 4: return self.read_u32(virt + self.field_offset(struct_name, field))