def test_by_task_struct(self): pid = fork_and_pause() wait_until(proc_blocked, pid) self.assertIn("pause", str(self.prog.stack_trace(find_task(self.prog, pid)))) os.kill(pid, signal.SIGKILL) os.waitpid(pid, 0)
def setUpClass(cls): # It'd be nice to just use addClassCleanup(), but that was added in # Python 3.8. cls.__cleanups = [] try: super().setUpClass() # Don't enable cgroup2 on systems that aren't already using it (or # don't support it). cgroup2_enabled = False try: with open("/proc/self/cgroup", "rb") as f: for line in f: if line.startswith(b"0::"): cgroup2_enabled = True break except FileNotFoundError: pass if not cgroup2_enabled: raise unittest.SkipTest("cgroup2 not enabled") # It's easier to mount the cgroup2 filesystem than to find it. cgroup2_mount = Path(tempfile.mkdtemp(prefix="drgn-tests-")) cls.__cleanups.append((cgroup2_mount.rmdir, )) mount("cgroup2", cgroup2_mount, "cgroup2", MS_NOSUID | MS_NODEV | MS_NOEXEC) cls.__cleanups.append((umount, cgroup2_mount)) cls.root_cgroup = cls.prog["cgrp_dfl_root"].cgrp.address_of_() pid = fork_and_pause() try: task = find_task(cls.prog, pid) parent_cgroup_dir = Path( tempfile.mkdtemp(prefix="drgn-tests-", dir=cgroup2_mount)) cls.__cleanups.append((parent_cgroup_dir.rmdir, )) cls.parent_cgroup_name = os.fsencode(parent_cgroup_dir.name) cls.parent_cgroup_path = b"/" + cls.parent_cgroup_name (parent_cgroup_dir / "cgroup.procs").write_text(str(pid)) cls.parent_cgroup = task.cgroups.dfl_cgrp.read_() child_cgroup_dir = parent_cgroup_dir / "child" child_cgroup_dir.mkdir() cls.__cleanups.append((child_cgroup_dir.rmdir, )) cls.child_cgroup_name = os.fsencode(child_cgroup_dir.name) cls.child_cgroup_path = (cls.parent_cgroup_path + b"/" + cls.child_cgroup_name) (child_cgroup_dir / "cgroup.procs").write_text(str(pid)) cls.child_cgroup = task.cgroups.dfl_cgrp.read_() finally: os.kill(pid, signal.SIGKILL) os.waitpid(pid, 0) except BaseException: for cleanup in reversed(cls.__cleanups): cleanup[0](*cleanup[1:]) raise
def test_find_user(self): for uid in self.UIDS: pid = fork_and_pause(functools.partial(os.setuid, uid)) try: wait_until(lambda: proc_state(pid) == "S") found_uid = find_user(self.prog, uid).uid.val.value_() finally: os.kill(pid, signal.SIGKILL) self.assertEqual(found_uid, uid)
def test_for_each_user(self): pids = [] try: for uid in self.UIDS: pid = fork_and_pause(functools.partial(os.setuid, uid)) wait_until(lambda: proc_state(pid) == "S") pids.append(pid) found_uids = {user.uid.val.value_() for user in for_each_user(self.prog)} finally: for pid in pids: os.kill(pid, signal.SIGKILL) self.assertTrue(self.UIDS.issubset(found_uids))
def test_registers(self): # Smoke test that we get at least one register and that # StackFrame.registers() agrees with StackFrame.register(). pid = fork_and_pause() wait_until(proc_blocked, pid) trace = self.prog.stack_trace(pid) have_registers = False for frame in trace: for name, value in frame.registers().items(): self.assertEqual(frame.register(name), value) have_registers = True self.assertTrue(have_registers) os.kill(pid, signal.SIGKILL) os.waitpid(pid, 0)
def _test_by_pid(self, orc): old_orc = int(os.environ.get("DRGN_PREFER_ORC_UNWINDER", "0")) != 0 with setenv("DRGN_PREFER_ORC_UNWINDER", "1" if orc else "0"): if orc == old_orc: prog = self.prog else: prog = Program() prog.set_kernel() self._load_debug_info(prog) pid = fork_and_pause() wait_until(proc_blocked, pid) self.assertIn("pause", str(prog.stack_trace(pid))) os.kill(pid, signal.SIGKILL) os.waitpid(pid, 0)
def test_local_variable(self): pid = fork_and_pause() wait_until(proc_blocked, pid) for frame in self.prog.stack_trace(pid): if frame.name in ("context_switch", "__schedule"): try: prev = frame["prev"] except KeyError: continue if not prev.absent_: self.assertEqual(prev.pid, pid) break else: self.skipTest("prev not found in context_switch or __schedule") os.kill(pid, signal.SIGKILL) os.waitpid(pid, 0)
def test_task_state_to_char(self): task = find_task(self.prog, os.getpid()) self.assertEqual(task_state_to_char(task), "R") pid = fork_and_pause() task = find_task(self.prog, pid) wait_until(lambda: proc_state(pid) == "S") self.assertEqual(task_state_to_char(task), "S") os.kill(pid, signal.SIGSTOP) wait_until(lambda: proc_state(pid) == "T") self.assertEqual(task_state_to_char(task), "T") os.kill(pid, signal.SIGKILL) wait_until(lambda: proc_state(pid) == "Z") self.assertEqual(task_state_to_char(task), "Z") os.waitpid(pid, 0)