From 0cdc2db4c48f5e16f45585fab8ebf72396b51fe6 Mon Sep 17 00:00:00 2001 From: k4lizen <124312252+k4lizen@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:31:56 +0100 Subject: [PATCH] Re-enable archlinux tests (#3478) * reenable arch tests * fix dt and dedup gdb/dt. fix elf * fix 32-bit tests * fix go code (and thus test) --- .github/workflows/docker.yml | 2 +- pwndbg/aglib/godbg.py | 3 ++ setup-dev.sh | 1 + .../library/dbg/tests/test_command_canary.py | 3 ++ tests/library/dbg/tests/test_command_dt.py | 9 ++-- tests/library/dbg/tests/test_commands_elf.py | 6 ++- tests/library/dbg/tests/test_go.py | 35 +++++---------- tests/library/gdb/tests/test_command_dt.py | 43 ------------------- tests/library/gdb/tests/test_go.py | 33 -------------- 9 files changed, 28 insertions(+), 107 deletions(-) delete mode 100644 tests/library/gdb/tests/test_command_dt.py diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 0691f7b06..8ba5264f3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - images: [ubuntu22.04, ubuntu24.04, debian12] # archlinux - tests fail on arch, see #2796 + images: [ubuntu22.04, ubuntu24.04, debian12, archlinux] runs-on: ubuntu-latest timeout-minutes: 30 diff --git a/pwndbg/aglib/godbg.py b/pwndbg/aglib/godbg.py index d77a497d6..cc6466ae5 100644 --- a/pwndbg/aglib/godbg.py +++ b/pwndbg/aglib/godbg.py @@ -336,6 +336,9 @@ def get_go_version() -> Tuple[int, ...] | None: if not version_string.startswith("go"): emit_warning(f"Go version string {version_string!r} doesn't start with 'go'") return None + + # Cleanup a string that looks like "go1.25.5 X:nodwarf5" + version_string = version_string.split(" ")[0] return tuple(int(x) for x in version_string[2:].split(".")) diff --git a/setup-dev.sh b/setup-dev.sh index 8bf113246..a2e5b90b0 100755 --- a/setup-dev.sh +++ b/setup-dev.sh @@ -141,6 +141,7 @@ EOF nasm \ gcc \ glibc-debug \ + lib32-glibc \ curl \ wget \ base-devel \ diff --git a/tests/library/dbg/tests/test_command_canary.py b/tests/library/dbg/tests/test_command_canary.py index 52799f3ab..73fdd5526 100644 --- a/tests/library/dbg/tests/test_command_canary.py +++ b/tests/library/dbg/tests/test_command_canary.py @@ -2,6 +2,7 @@ from __future__ import annotations import pytest +from ....host import Controller from . import get_binary from . import launch_to from . import pwndbg_test @@ -27,6 +28,7 @@ async def test_command_canary(ctrl: Controller, binary: str, reg_name: str, skip import pwndbg import pwndbg.aglib.memory import pwndbg.aglib.regs + import pwndbg.commands.canary await launch_to(ctrl, binary, "main") @@ -44,6 +46,7 @@ async def test_command_canary(ctrl: Controller, binary: str, reg_name: str, skip await ctrl.step_instruction() canary_value, at_random = pwndbg.commands.canary.canary_value() + assert at_random is not None raw = pwndbg.aglib.memory.read_pointer_width(at_random) mask = pwndbg.aglib.arch.ptrmask ^ 0xFF diff --git a/tests/library/dbg/tests/test_command_dt.py b/tests/library/dbg/tests/test_command_dt.py index 31f3c073b..967a6ae34 100644 --- a/tests/library/dbg/tests/test_command_dt.py +++ b/tests/library/dbg/tests/test_command_dt.py @@ -27,10 +27,11 @@ async def test_command_dt_works_with_address(ctrl: Controller) -> None: out = await ctrl.execute_and_capture(f'dt "struct tcache_perthread_struct" {tcache_addr}') + # Accounting for differences between architectures and glibc versions (specifically 2.42) exp_regex = ( "struct tcache_perthread_struct @ 0x[0-9a-f]+\n" - " 0x[0-9a-f]+ \\+0x0000 counts +: +.*\\{([0-9]+, [0-9]+ |(\\s*\\[[0-9]+\\] = [0-9]){20,64}\\s*([.]+\\s*)?)\\}\n" - " 0x[0-9a-f]+ \\+0x[0-9a-f]{4} entries +: +.*\\{(0x[0-9a-f]+, 0x[0-9a-f]+ |(\\s*\\[[0-9]+\\] = (0x[0-9a-f]+|NULL)){20,64}\\s*([.]+\\s*)?)\\}" + " 0x[0-9a-f]+ \\+0x0000 (counts|num_slots) +: +.*\\{([0-9]+, [0-9]+ |(\\s*\\[[0-9]+\\] = [0-9]){20,76}\\s*([.]+\\s*)?)\\}\n" + " 0x[0-9a-f]+ \\+0x[0-9a-f]{4} entries +: +.*\\{(0x[0-9a-f]+, 0x[0-9a-f]+ |(\\s*\\[[0-9]+\\] = (0x[0-9a-f]+|NULL)){20,76}\\s*([.]+\\s*)?)\\}" ) assert re.match(exp_regex, out) @@ -48,7 +49,7 @@ async def test_command_dt_works_with_no_address(ctrl: Controller) -> None: exp_regex = ( "struct tcache_perthread_struct\n" - " \\+0x0000 counts +: +uint16_t ?\\[64\\]\n" - " \\+0x[0-9a-f]{4} entries +: +tcache_entry ?\\*\\[64\\]\n" + " \\+0x0000 (counts|num_slots) +: +uint16_t ?\\[(64|76)\\]\n" + " \\+0x[0-9a-f]{4} entries +: +tcache_entry ?\\*\\[(64|76)\\]\n" ) assert re.match(exp_regex, out) diff --git a/tests/library/dbg/tests/test_commands_elf.py b/tests/library/dbg/tests/test_commands_elf.py index ebe2ba686..4399e2288 100644 --- a/tests/library/dbg/tests/test_commands_elf.py +++ b/tests/library/dbg/tests/test_commands_elf.py @@ -77,7 +77,8 @@ async def test_command_elf(ctrl: Controller, binary_name: str, is_pie: bool) -> pytest.skip("TODO multiarch") out = (await ctrl.execute_and_capture("elf")).splitlines() - assert len(out) == 25 + # Never versions of gcc emit an additional `.sframe` section. + assert len(out) == 25 or len(out) == 26 # test for default for section in out[2:]: @@ -93,7 +94,8 @@ async def test_command_elf(ctrl: Controller, binary_name: str, is_pie: bool) -> # if this is a pie binary, test for --no-rebase if is_pie: out = (await ctrl.execute_and_capture("elf -R")).splitlines() - assert len(out) == 25 + # Never versions of gcc emit an additional `.sframe` section. + assert len(out) == 25 or len(out) == 26 for section in out[2:]: assert re.match( diff --git a/tests/library/dbg/tests/test_go.py b/tests/library/dbg/tests/test_go.py index a933a33fa..8d30085d7 100644 --- a/tests/library/dbg/tests/test_go.py +++ b/tests/library/dbg/tests/test_go.py @@ -10,8 +10,17 @@ GOSAMPLE_X64 = get_binary("gosample.x86-64.out") GOSAMPLE_X86 = get_binary("gosample.i386.out") -async def helper_test_dump(ctrl: Controller, target: str) -> None: - await ctrl.launch(target, env={"GOMAXPROCS": "1"}) +@pwndbg_test +@pytest.mark.parametrize("binary", [GOSAMPLE_X64, GOSAMPLE_X86], ids=["x86-64", "i386"]) +async def test_go_dumping(ctrl: Controller, binary: str) -> None: + import pwndbg + import pwndbg.commands.godbg + from pwndbg.dbg import DebuggerType + + if pwndbg.dbg.name() == DebuggerType.LLDB: + pytest.skip("Go tests are not supported in LLDB") + + await ctrl.launch(binary, env={"GOMAXPROCS": "1"}) await ctrl.execute("b gosample.native.go:6") await ctrl.cont() @@ -33,25 +42,3 @@ async def helper_test_dump(ctrl: Controller, target: str) -> None: dump = await ctrl.execute_and_capture("go-dump -f 1 any &x") assert dump.strip() == """([3]complex64) [(1.1 + 2.2i), (-2.5 - 5.0i), (4.2 - 2.1i)]""" - - -@pwndbg_test -async def test_go_dumping_x64(ctrl: Controller) -> None: - import pwndbg - from pwndbg.dbg import DebuggerType - - if pwndbg.dbg.name() == DebuggerType.LLDB: - pytest.skip("Go tests are not supported in LLDB") - - await helper_test_dump(ctrl, GOSAMPLE_X64) - - -@pwndbg_test -async def test_go_dumping_x86(ctrl: Controller) -> None: - import pwndbg - from pwndbg.dbg import DebuggerType - - if pwndbg.dbg.name() == DebuggerType.LLDB: - pytest.skip("Go tests are not supported in LLDB") - - await helper_test_dump(ctrl, GOSAMPLE_X86) diff --git a/tests/library/gdb/tests/test_command_dt.py b/tests/library/gdb/tests/test_command_dt.py deleted file mode 100644 index 66582051a..000000000 --- a/tests/library/gdb/tests/test_command_dt.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import annotations - -import re - -import gdb - -from . import get_binary - -HEAP_MALLOC_CHUNK = get_binary("heap_malloc_chunk.native.out") - - -def test_command_dt_works_with_address(start_binary): - start_binary(HEAP_MALLOC_CHUNK) - gdb.execute("break break_here") - gdb.execute("continue") - - tcache = gdb.execute("print tcache", to_string=True) - - tcache_addr = tcache.split()[-1] - - out = gdb.execute(f'dt "struct tcache_perthread_struct" {tcache_addr}', to_string=True) - - exp_regex = ( - "struct tcache_perthread_struct @ 0x[0-9a-f]+\n" - " 0x[0-9a-f]+ \\+0x0000 counts : \\{[0-9]+, [0-9]+ \\}\n" - " 0x[0-9a-f]+ \\+0x[0-9a-f]{4} entries : \\{0x[0-9a-f]+, 0x[0-9a-f]+ \\}\n" - ) - assert re.match(exp_regex, out) - - -def test_command_dt_works_with_no_address(start_binary): - start_binary(HEAP_MALLOC_CHUNK) - gdb.execute("break break_here") - gdb.execute("continue") - - out = gdb.execute('dt "struct tcache_perthread_struct"', to_string=True) - - exp_regex = ( - "struct tcache_perthread_struct\n" - " \\+0x0000 counts : uint16_t \\[64\\]\n" - " \\+0x[0-9a-f]{4} entries : tcache_entry \\*\\[64\\]\n" - ) - assert re.match(exp_regex, out) diff --git a/tests/library/gdb/tests/test_go.py b/tests/library/gdb/tests/test_go.py index a43a1c534..a8c807027 100644 --- a/tests/library/gdb/tests/test_go.py +++ b/tests/library/gdb/tests/test_go.py @@ -28,36 +28,3 @@ def test_typeinfo_go_x86(): gdb.execute("file " + GOSAMPLE_X86) start = gdb.execute("start", to_string=True) assert "Python Exception" not in start - - -def helper_test_dump(start_binary, filename): - gdb.execute("set environment GOMAXPROCS=1") - start_binary(filename) - gdb.execute("break gosample.native.go:6", to_string=True) - gdb.execute("continue") - - dump = gdb.execute("go-dump any &x", to_string=True) - assert dump.strip() == """(map[uint8]uint64) &{1: 2, 3: 4, 5: 6}""" - gdb.execute("continue") - - dump = gdb.execute("go-dump any &x", to_string=True) - assert dump.strip() == """(map[string]int) &{"a": 1, "b": 2, "c": 3}""" - gdb.execute("continue") - - dump = gdb.execute("go-dump any &x", to_string=True) - assert ( - dump.strip() - == """([]struct { a int; b string }) [struct {a: 1, b: "first"}, struct {a: 2, b: "second"}]""" - ) - gdb.execute("continue") - - dump = gdb.execute("go-dump -f 1 any &x", to_string=True) - assert dump.strip() == """([3]complex64) [(1.1 + 2.2i), (-2.5 - 5.0i), (4.2 - 2.1i)]""" - - -def test_go_dumping_x64(start_binary): - helper_test_dump(start_binary, GOSAMPLE_X64) - - -def test_go_dumping_x86(start_binary): - helper_test_dump(start_binary, GOSAMPLE_X86)