diff --git a/linux-ramdump-parser-v2/parsers/pagetracking.py b/linux-ramdump-parser-v2/parsers/pagetracking.py index d21165cac22949f8769b54ca16c0e298f147077c..c5ddb3967384004817aa22dc14c7dc5e0c455b8b 100644 --- a/linux-ramdump-parser-v2/parsers/pagetracking.py +++ b/linux-ramdump-parser-v2/parsers/pagetracking.py @@ -12,30 +12,52 @@ from print_out import print_out_str from parser_util import register_parser, RamParser from mm import pfn_to_page, page_buddy, page_count, for_each_pfn +from mm import page_to_pfn +import sys @register_parser('--print-pagetracking', 'print page tracking information (if available)') class PageTracking(RamParser): - def parse(self): - if not self.ramdump.is_config_defined('CONFIG_PAGE_OWNER'): - print_out_str('CONFIG_PAGE_OWNER not defined') - return + def __init__(self, *args): + super(PageTracking, self).__init__(*args) + self.trace_entry_size = self.ramdump.sizeof('unsigned long') + if self.ramdump.is_config_defined('CONFIG_SPARSEMEM'): + self.page_ext_offset = self.ramdump.field_offset( + 'struct mem_section', 'page_ext') + else: + self.page_ext_offset = self.ramdump.field_offset( + 'struct pglist_data', 'node_page_ext') - if (self.ramdump.kernel_version >= (3, 19, 0)): - if self.ramdump.is_config_defined('CONFIG_SPARSEMEM'): - mem_section = self.ramdump.read_word('mem_section') - if self.ramdump.kernel_version >= (4, 14): - mem_section = self.ramdump.read_word(mem_section) - else: - mem_section = self.ramdump.address_of('contig_page_data') + if self.ramdump.is_config_defined('CONFIG_SPARSEMEM'): + self.mem_section_size = self.ramdump.sizeof("struct mem_section") + else: + self.mem_section_size = 0 + + ''' + Following based upon definition in include/linux/mmzone.h + + #ifndef CONFIG_FORCE_MAX_ZONEORDER + #define MAX_ORDER 11 + #else + #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER + #endif + ''' + try: + self.max_order = int(self.ramdump.get_config_val( + "CONFIG_FORCE_MAX_ZONEORDER")) + except: + self.max_order = 11 + + self.stack_slabs = self.ramdump.address_of('stack_slabs') + self.stack_slabs_size = self.ramdump.sizeof('void *') + def page_trace(self, pfn, mem_section): trace_offset = 0 nr_entries_offset = 0 trace_entries_offset = 0 offset = 0 struct_holding_trace_entries = 0 - trace_entry_size = self.ramdump.sizeof("unsigned long") if (self.ramdump.kernel_version <= (3, 19, 0)): trace_offset = self.ramdump.field_offset('struct page', 'trace') @@ -43,166 +65,192 @@ class PageTracking(RamParser): 'struct stack_trace', 'nr_entries') trace_entries_offset = self.ramdump.field_offset( 'struct page', 'trace_entries') - else: - if self.ramdump.is_config_defined('CONFIG_SPARSEMEM'): - page_ext_offset = self.ramdump.field_offset( - 'struct mem_section', 'page_ext') - else: - page_ext_offset = self.ramdump.field_offset( - 'struct pglist_data', 'node_page_ext') + else: trace_offset = self.ramdump.field_offset( - 'struct page_ext', 'trace') + 'struct page_ext', 'trace') if self.ramdump.is_config_defined('CONFIG_STACKDEPOT'): trace_entries_offset = self.ramdump.field_offset( - 'struct stack_record', 'entries') + 'struct stack_record', 'entries') else: trace_entries_offset = self.ramdump.field_offset( - 'struct page_ext', 'trace_entries') - + 'struct page_ext', 'trace_entries') nr_entries_offset = self.ramdump.field_offset( - 'struct page_ext', 'nr_entries') - if self.ramdump.is_config_defined('CONFIG_SPARSEMEM'): - mem_section_size = self.ramdump.sizeof("struct mem_section") - else: - mem_section_size = 0; + 'struct page_ext', 'nr_entries') + page_ext_size = self.ramdump.sizeof("struct page_ext") - if self.ramdump.kernel_version >= (4,9,0): + if self.ramdump.kernel_version >= (4, 9, 0): page_owner_size = self.ramdump.sizeof("struct page_owner") page_ext_size = page_ext_size + page_owner_size page_owner_ops_offset = self.ramdump.read_structure_field( 'page_owner_ops', 'struct page_ext_operations', 'offset') + page = pfn_to_page(self.ramdump, pfn) + order = 0 - out_tracking = self.ramdump.open_file('page_tracking.txt') - out_frequency = self.ramdump.open_file('page_frequency.txt') - sorted_pages = {} - - ''' - Following based upon definition in include/linux/mmzone.h + 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 == 0: + return + if self.ramdump.is_config_defined('CONFIG_MEMORY_HOTPLUG'): + section_size_bits = int(self.ramdump.get_config_val( + 'CONFIG_HOTPLUG_SIZE_BITS')) + offset = phys >> section_size_bits + else: + offset = phys >> 30 + if self.ramdump.is_config_defined('CONFIG_SPARSEMEM'): + mem_section_0_offset = ( + mem_section + offset * self.mem_section_size) + page_ext = self.ramdump.read_word( + mem_section_0_offset + self.page_ext_offset) + else: + page_ext = self.ramdump.read_word( + mem_section + self.page_ext_offset) - #ifndef CONFIG_FORCE_MAX_ZONEORDER - #define MAX_ORDER 11 - #else - #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER - #endif - ''' - try: - max_order = int(self.ramdump.get_config_val("CONFIG_FORCE_MAX_ZONEORDER")) - except: - max_order = 11 + if self.ramdump.arm64: + temp_page_ext = page_ext + (pfn * page_ext_size) + else: + pfn_index = pfn - (self.ramdump.phys_offset >> 12) + temp_page_ext = page_ext + (pfn_index * page_ext_size) - for pfn in for_each_pfn(self.ramdump): - page = pfn_to_page(self.ramdump, pfn) - order = 0 + if self.ramdump.kernel_version >= (4, 9, 0): + temp_page_ext = temp_page_ext + page_owner_ops_offset + order = self.ramdump.read_structure_field( + temp_page_ext, 'struct page_owner', 'order') + else: + order = self.ramdump.read_structure_field( + temp_page_ext, 'struct page_ext', 'order') - """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)): + if not self.ramdump.is_config_defined('CONFIG_STACKDEPOT'): 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') + temp_page_ext + nr_entries_offset) + struct_holding_trace_entries = temp_page_ext else: - phys = pfn << 12 - if phys is None or phys is 0: - continue - if self.ramdump.is_config_defined('CONFIG_MEMORY_HOTPLUG'): - section_size_bits = int(self.ramdump.get_config_val( - 'CONFIG_HOTPLUG_SIZE_BITS')) - offset = phys >> section_size_bits + if self.ramdump.kernel_version >= (4, 9, 0): + handle = self.ramdump.read_structure_field( + temp_page_ext, 'struct page_owner', 'handle') else: - offset = phys >> 30 + handle = self.ramdump.read_structure_field( + temp_page_ext, 'struct page_ext', 'handle') - if self.ramdump.is_config_defined('CONFIG_SPARSEMEM'): - mem_section_0_offset = ( - mem_section + (offset * mem_section_size)) - page_ext = self.ramdump.read_word( - mem_section_0_offset + page_ext_offset) - else: - page_ext = self.ramdump.read_word( - mem_section + page_ext_offset) + slabindex = handle & 0x1fffff + handle_offset = (handle >> 0x15) & 0x3ff + handle_offset = handle_offset << 4 + slab = self.ramdump.read_word( + self.stack_slabs + (self.stack_slabs_size * slabindex)) + stack = slab + handle_offset - if self.ramdump.arm64: - temp_page_ext = page_ext + (pfn * page_ext_size) - else: - pfn_index = pfn - (self.ramdump.phys_offset >> 12) - temp_page_ext = page_ext + (pfn_index * page_ext_size) + nr_trace_entries = self.ramdump.read_structure_field( + stack, 'struct stack_record', 'size') - if self.ramdump.kernel_version >= (4,9,0): - temp_page_ext = temp_page_ext + page_owner_ops_offset - order = self.ramdump.read_structure_field( - temp_page_ext, 'struct page_owner', 'order') - else: - order = self.ramdump.read_structure_field( - temp_page_ext, 'struct page_ext', 'order') - if not self.ramdump.is_config_defined('CONFIG_STACKDEPOT'): + struct_holding_trace_entries = stack - nr_trace_entries = self.ramdump.read_int( - temp_page_ext + nr_entries_offset) - struct_holding_trace_entries = temp_page_ext + if nr_trace_entries <= 0 or nr_trace_entries > 16: + return + if order >= self.max_order: + return - else: - if self.ramdump.kernel_version >= (4,9,0): - handle = self.ramdump.read_structure_field( - temp_page_ext, 'struct page_owner', 'handle') - else: - handle = self.ramdump.read_structure_field( - temp_page_ext, 'struct page_ext', 'handle') - - slabindex = handle & 0x1fffff - handle_offset = (handle >> 0x15) & 0x3ff - handle_offset = handle_offset << 4 - - stack_slabs = self.ramdump.address_of('stack_slabs') - stack_slabs_size = self.ramdump.sizeof('void *') - slab = self.ramdump.read_word(stack_slabs + ( stack_slabs_size * slabindex)) - stack = slab + handle_offset - - nr_trace_entries = self.ramdump.read_structure_field( - stack, 'struct stack_record', 'size') - - struct_holding_trace_entries = stack - - - if nr_trace_entries <= 0 or nr_trace_entries > 16: - continue - - if order >= max_order: - out_tracking.write('PFN 0x{:x} page 0x{:x} skip as order 0x{:x}\n'.format( - pfn, page, order)) - continue - - 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): - addr = self.ramdump.read_word( - struct_holding_trace_entries + trace_entries_offset + i * trace_entry_size) - - if addr == 0: - break - look = self.ramdump.unwind_lookup(addr) - if look is None: - break - symname, offset = look - unwind_dat = ' [<{0:x}>] {1}+0x{2:x}\n'.format( - addr, symname, offset) - out_tracking.write(unwind_dat) - alloc_str = alloc_str + unwind_dat - - if alloc_str in sorted_pages: - sorted_pages[alloc_str] = sorted_pages[alloc_str] + 1 + alloc_str = '' + for i in range(0, nr_trace_entries): + addr = self.ramdump.read_word( + struct_holding_trace_entries + trace_entries_offset + i * + self.trace_entry_size) + + if not addr: + break + look = self.ramdump.unwind_lookup(addr) + if look is None: + break + symname, offset = look + unwind_dat = ' [<{0:x}>] {1}+0x{2:x}\n'.format( + addr, symname, offset) + alloc_str = alloc_str + unwind_dat + + return alloc_str, order + + def parse(self): + ranges = None + for arg in sys.argv: + if "ranges=" in arg: + g_optimization = True + k, ranges = arg.split("=") + start, end = ranges.split('-') + start_pfn = int(start, 16) >> 12 + end_pfn = int(end, 16) >> 12 + break + elif "page=" in arg: + g_optimization = True + k, page = arg.split('=') + page = int(page, 16) + start_pfn = page_to_pfn(self.ramdump, page) + end_pfn = start_pfn + 1 + break + else: + g_optimization = False + if not self.ramdump.is_config_defined('CONFIG_PAGE_OWNER'): + print_out_str('CONFIG_PAGE_OWNER not defined') + return + + if (self.ramdump.kernel_version >= (3, 19, 0)): + if self.ramdump.is_config_defined('CONFIG_SPARSEMEM'): + mem_section = self.ramdump.read_word('mem_section') + if self.ramdump.kernel_version >= (4, 14): + mem_section = self.ramdump.read_word(mem_section) else: - sorted_pages[alloc_str] = 1 + mem_section = self.ramdump.address_of('contig_page_data') - out_tracking.write('\n') + out_tracking = self.ramdump.open_file('page_tracking.txt') + out_frequency = self.ramdump.open_file('page_frequency.txt') + sorted_pages = {} + str = "PFN : 0x{0:x}-0x{1:x} Page : 0x{2:x}\n{3}\n" + + if g_optimization is True: + for pfn in range(start_pfn, end_pfn): + page = pfn_to_page(self.ramdump, pfn) + order = 0 + if (page_buddy(self.ramdump, page) or + page_count(self.ramdump, page) == 0): + continue + function_list, order = self.page_trace(pfn, mem_section) + if order >= self.max_order: + out_tracking.write('PFN 0x{:x} page 0x{:x} skip as order ' + '0x{:x}\n'.format(pfn, page, order)) + out_tracking.write(str.format(pfn, pfn + (1 << order) - 1, + page, function_list)) + if function_list in sorted_pages: + sorted_pages[function_list] = sorted_pages[function_list]\ + + 1 + else: + sorted_pages[function_list] = 1 + + else: + for pfn in for_each_pfn(self.ramdump): + page = pfn_to_page(self.ramdump, pfn) + order = 0 + if (page_buddy(self.ramdump, page) or + page_count(self.ramdump, page) == 0): + continue + function_list, order = self.page_trace(pfn, mem_section) + if order >= self.max_order: + out_tracking.write('PFN 0x{:x} page 0x{:x} skip as order ' + '0x{:x}\n'.format(pfn, page, order)) + + out_tracking.write(str.format(pfn, pfn + (1 << order) - 1, + page, function_list)) + + if function_list in sorted_pages: + sorted_pages[function_list] = sorted_pages[function_list]\ + + 1 + else: + sorted_pages[function_list] = 1 sortlist = sorted(sorted_pages.iteritems(), key=lambda(k, v): (v), reverse=True)