def check_free_pages(self) -> None: for order in range(array_size(self.gdb_obj["free_area"])): area = self.gdb_obj["free_area"][order] self._check_free_area(area, False, order) for cpu in for_each_online_cpu(): pageset = get_percpu_var(self.gdb_obj["pageset"], cpu) self._check_free_area(pageset["pcp"], True, cpu)
def _get_loadavg_values(self) -> List[float]: metrics = [] for index in range(0, array_size(self.symvals.avenrun)): metrics.append(self._calculate_loadavg( self.symvals.avenrun[index])) return metrics
def task_state_flags_callback(cls, symbol): count = array_size(cls.task_state_array) bit = 0 for i in range(count): state = cls.task_state_array[i].string() state_strings = { '(running)' : 'TASK_RUNNING', '(sleeping)' : 'TASK_INTERRUPTIBLE', '(disk sleep)' : 'TASK_UNINTERRUPTIBLE', '(stopped)' : 'TASK_STOPPED', '(zombie)' : 'TASK_ZOMBIE', #'(dead)' : 'TASK_DEAD', '(swapping)' : 'TASK_SWAPPING', #'(tracing stop)' : 'TASK_TRACING_STOPPED', '(wakekill)' : 'TASK_WAKEKILL', '(waking)' : 'TASK_WAKING', } for key in state_strings: if key in state: try: dv = get_delayed_lookup(cls, state_strings[key]) dv.callback(bit) except KeyError: setattr(cls, state_strings[key], bit) if '(dead)' in state: cls.TASK_DEAD = bit if '(tracing stop)' in state: cls.TASK_TRACING_STOPPED = bit if bit == 0: bit = 1 else: bit <<= 1 cls.check_state_bits()
def task_state_flags_callback(cls, symbol): count = array_size(cls.task_state_array) bit = 0 for i in range(count): state = cls.task_state_array[i].string() state_strings = { '(running)' : 'TASK_RUNNING', '(sleeping)' : 'TASK_INTERRUPTIBLE', '(disk sleep)' : 'TASK_UNINTERRUPTIBLE', '(stopped)' : 'TASK_STOPPED', '(zombie)' : 'TASK_ZOMBIE', #'(dead)' : 'TASK_DEAD', '(swapping)' : 'TASK_SWAPPING', #'(tracing stop)' : 'TASK_TRACING_STOPPED', '(wakekill)' : 'TASK_WAKEKILL', '(waking)' : 'TASK_WAKING', } for key in state_strings: if key in state: try: dv = get_delayed_lookup(cls, state_strings[key]) dv.callback(bit) except KeyError: setattr(cls, state_strings[key], bit) if '(dead)' in state: cls.TASK_DEAD = bit if '(tracing stop)' in state: cls.TASK_TRACING_STOPPED = bit if bit == 0: bit = 1 else: bit <<= 1 cls.check_state_bits()
def _check_free_area(self, area: gdb.Value, is_pcp: bool, order_cpu: int) -> None: nr_free = 0 if is_pcp: list_array_name = "lists" error_desc = "pcplist" order_cpu_desc = f"cpu {order_cpu}" else: list_array_name = "free_list" error_desc = "free area" order_cpu_desc = f"order {order_cpu}" for mt in range(array_size(area[list_array_name])): free_list = area[list_array_name][mt] for reverse in [False, True]: if reverse: print("Retrying list in reverse direction") try: for page_obj in list_for_each_entry(free_list, self.types.page_type, "lru", reverse=reverse): page = crash.types.page.Page.from_obj(page_obj) if not page: print(f"page 0x{int(page_obj.address):x} is not a valid page pointer on " f"{error_desc} of node {self.nid} zone {self.zid}, {order_cpu_desc} mt {mt}") continue nr_free += 1 if is_pcp: errors = page.check_pcplist_page() else: errors = page.check_freelist_page(order_cpu) if errors != "": print(f"page 0x{int(page_obj.address):x} pfn {page.pfn} on {error_desc} of node " f"{self.nid} zone {self.zid}, {order_cpu_desc} mt {mt} had unexpected state: {errors}") if page.get_nid() != self.nid or page.get_zid() != self.zid: print(f"page 0x{int(page_obj.address):x} pfn {page.pfn} misplaced on " f"{error_desc} of node {self.nid} zone {self.zid}, {order_cpu_desc} mt {mt} " f"has flags for node {page.get_nid()} zone {page.get_zid()}") except CorruptListError as e: print(f"Error traversing {error_desc} 0x{int(area.address):x} for {order_cpu_desc} mt {mt}: {e}") continue except BufferError as e: print(f"Error traversing {error_desc} 0x{int(area.address):x} for {order_cpu_desc} mt {mt}: {e}") continue break nr_expected = area["count"] if is_pcp else area["nr_free"] if nr_free != nr_expected: print(f"nr_free mismatch in {error_desc} 0x{int(area.address):x} for {order_cpu_desc}: " f"expected {nr_expected}, counted {nr_free}")
def setup_nr_cpus(cls, unused: gdb.Symbol) -> None: if cls._nr_cpus == 0: cls._nr_cpus = array_size(symvals['__per_cpu_offset']) if cls._last_cpu == -1: cls._last_cpu = cls._nr_cpus
def task_state_flags_callback(cls, symbol: gdb.Symbol) -> None: # pylint: disable=unused-argument """ Detect which task flags this kernel uses. Meant to be used as a SymbolCallback. Different kernels use different task flags or even different values for the same flags. This method tries to determine the flags for the kernel. Args: symbol: The ``task_state_array`` symbol. """ task_state_array = symbol.value() count = array_size(task_state_array) bit = 0 for i in range(count): state = task_state_array[i].string() state_strings = { '(running)' : 'TASK_RUNNING', '(sleeping)' : 'TASK_INTERRUPTIBLE', '(disk sleep)' : 'TASK_UNINTERRUPTIBLE', '(stopped)' : 'TASK_STOPPED', '(zombie)' : 'EXIT_ZOMBIE', 'x (dead)' : 'TASK_DEAD', 'X (dead)' : 'EXIT_DEAD', '(swapping)' : 'TASK_SWAPPING', '(tracing stop)' : 'TASK_TRACING_STOPPED', '(wakekill)' : 'TASK_WAKEKILL', '(waking)' : 'TASK_WAKING', '(parked)' : 'TASK_PARKED', '(idle)' : '__TASK_IDLE', } for key in state_strings: if key in state: setattr(cls, state_strings[key], bit) if bit == 0: bit = 1 else: bit <<= 1 # Linux 4.14 re-introduced TASK_PARKED into task_state_array # which renumbered some bits if cls.has_flag('TASK_PARKED') and not cls.has_flag('TASK_DEAD'): newbits = cls.TASK_PARKED << 1 cls.TASK_DEAD = newbits cls.TASK_WAKEKILL = newbits << 1 cls.TASK_WAKING = newbits << 2 cls.TASK_NOLOAD = newbits << 3 cls.TASK_NEW = newbits << 4 assert cls.TASK_PARKED == 0x0040 assert cls.TASK_DEAD == 0x0080 assert cls.TASK_WAKEKILL == 0x0100 assert cls.TASK_WAKING == 0x0200 # Linux 3.14 removed several elements from task_state_array # so we'll have to make some assumptions. # TASK_NOLOAD wasn't introduced until 4.2 and wasn't added # to task_state_array until v4.14. There's no way to # detect whether the use of the flag is valid for a particular # kernel release. elif cls.has_flag('EXIT_DEAD'): if cls.EXIT_ZOMBIE > cls.EXIT_DEAD: newbits = cls.EXIT_ZOMBIE << 1 else: newbits = cls.EXIT_DEAD << 1 cls.TASK_DEAD = newbits cls.TASK_WAKEKILL = newbits << 1 cls.TASK_WAKING = newbits << 2 cls.TASK_PARKED = newbits << 3 cls.TASK_NOLOAD = newbits << 4 cls.TASK_NEW = newbits << 5 assert cls.TASK_DEAD == 0x0040 assert cls.TASK_WAKEKILL == 0x0080 assert cls.TASK_WAKING == 0x0100 assert cls.TASK_PARKED == 0x0200 else: assert cls.TASK_DEAD == 64 assert cls.TASK_WAKEKILL == 128 assert cls.TASK_WAKING == 256 assert cls.TASK_PARKED == 512 if cls.has_flag('TASK_NOLOAD'): assert cls.TASK_NOLOAD == 1024 cls.TASK_IDLE = cls.TASK_NOLOAD | cls.TASK_UNINTERRUPTIBLE assert cls.TASK_IDLE == 1026 if cls.has_flag('TASK_NEW'): assert cls.TASK_NEW == 2048 cls._check_state_bits()
def _get_rss_stat_field(self) -> int: stat = self.task_struct['mm']['rss_stat']['count'] rss = 0 for i in range(array_size(stat)): rss += int(stat[i]['counter']) return rss
def get_loadavg_values(self): metrics = [] for index in range(0, array_size(self.avenrun)): metrics.append(self.calculate_loadavg(self.avenrun[index])) return metrics
def setup_nr_cpus(cls, ignored): cls.nr_cpus = array_size(cls.__per_cpu_offset) # piggyback on this as it seems those minsymbols at the time of # their callback yield offset of 0 cls.setup_kaslr_offset()
def setup_nr_cpus(cls, ignored): cls.nr_cpus = array_size(cls.__per_cpu_offset)