def setup_slab_caches(slab_caches: gdb.Symbol) -> None: list_caches = slab_caches.value() for cache in list_for_each_entry(list_caches, types.kmem_cache_type, KmemCache.head_name): name = cache["name"].string() kmem_cache = KmemCache(name, cache) kmem_caches[name] = kmem_cache kmem_caches_by_addr[int(cache.address)] = kmem_cache
def setup_xen_m2p(cls, symbol: gdb.Symbol) -> None: xen_domain_type = int(symbol.value()) # XXX: this is quite lazy... if xen_domain_type == 0: return cls.machine_to_phys_nr = int(get_symbol_value("machine_to_phys_nr")) cls.xen_max_p2m_pfn = int(get_symbol_value("xen_max_p2m_pfn")) cls.xen_p2m_addr = get_symbol_value("xen_p2m_addr") cls.xen_m2p_needed = True
def check_task_interface(cls, init_task: gdb.Symbol) -> None: """ Check which interface to iterating over mount structures is in use Meant to be used as a SymbolCallback. Args: init_task: The ``init_task`` symbol. """ cls._init_fs_root = init_task.value()['fs']['root'] if struct_has_member(init_task, 'nsproxy'): cls._for_each_mount = cls._for_each_mount_nsproxy else: raise NotImplementedError("Mount.for_each_mount is unhandled on this kernel version")
def setup_possible_mask(cls, cpu_mask: gdb.Symbol) -> None: """ Translate the ``cpu_possible_mask`` bitmap into a list of possible CPU numbers. Meant to be used as a SymbolCallback. Args: cpu_mask: The symbol for ``cpu_possible_mask`` or ``__cpu_possible_mask``, depending on kernel version. """ cls._cpu_possible_mask = cpu_mask.value() bits = cls._cpu_possible_mask["bits"] cls.cpus_possible = list(for_each_set_bit(bits))
def _setup_flag_names(symbol: gdb.Symbol) -> None: global gfpflag_names, pageflag_names flag_names = list() array = symbol.value() i = 0 val = array[0] while val["mask"] != 0 and val["name"] != 0: flag_names.append((int(val["mask"]), str(val["name"].string()))) i += 1 val = array[i] if symbol.name == "gfpflag_names": gfpflag_names = flag_names elif symbol.name == "pageflag_names": pageflag_names = flag_names else: raise RuntimeError("unknown symbol passed")
def setup_node_states(cls, node_states_sym: gdb.Symbol) -> None: """ Detect names of node states and which nodes are possible and online. Meant to be used as a SymbolCallback. Args: node_states_sym: The ``node_states`` symbol. """ node_states = node_states_sym.value() enum_node_states = gdb.lookup_type("enum node_states") N_POSSIBLE = enum_node_states["N_POSSIBLE"].enumval N_ONLINE = enum_node_states["N_ONLINE"].enumval bits = node_states[N_POSSIBLE]["bits"] cls.nids_possible = list(for_each_set_bit(bits)) bits = node_states[N_ONLINE]["bits"] cls.nids_online = list(for_each_set_bit(bits))
def setup_directmap_base(cls, symbol: gdb.Symbol) -> None: cls.directmap_base = int(symbol.value())
def setup_vmemmap_base(cls, symbol: gdb.Symbol) -> None: cls.vmemmap_base = int(symbol.value()) # setup_page_type() was first and used the hardcoded initial value, # we have to update cls.vmemmap = gdb.Value(cls.vmemmap_base).cast( types.page_type.pointer())
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 callback(self, value: gdb.Symbol) -> None: symval = value.value() if symval.type.code == gdb.TYPE_CODE_FUNC: symval = symval.address self.value = symval