diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index ad191da34..ab304ce1c 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -16,7 +16,7 @@ on: - '!*.md' jobs: - check_release_build-x86_64: + check_release_build-gdb-x86_64: runs-on: ubuntu-latest timeout-minutes: 60 steps: @@ -26,7 +26,25 @@ jobs: nix_path: nixpkgs=channel:nixos-unstable - name: build pwndbg - run: nix build '.#pwndbg' -o result-pwndbg + run: nix build '.#pwndbg' -o result1 + + - name: simple run pwndbg + run: ./result1/bin/pwndbg <<< 'exit' + + check_release_build-lldb-x86_64: + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # @v3 + - uses: cachix/install-nix-action@6ed004b9ccb68dbc28e7c85bee15fa93dbd214ac # @v22 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: build pwndbg + run: nix build '.#pwndbg-lldb' -o result2 + + - name: simple run pwndbg + run: ./result2/bin/pwndbg-lldb <<< 'exit' lock_flake: runs-on: ubuntu-latest diff --git a/nix/devshell.nix b/nix/devshell.nix index ade080d01..60e1a5b73 100644 --- a/nix/devshell.nix +++ b/nix/devshell.nix @@ -26,9 +26,13 @@ let ; isDev = true; }; - jemalloc-static = pkgs.jemalloc.overrideAttrs (oldAttrs: { + jemalloc-static = pkgs.jemalloc.overrideAttrs (finalAttrs: previousAttrs: { version = "5.3.0"; # version match setup-dev.sh - configureFlags = (oldAttrs.configureFlags or [ ]) ++ [ + src = pkgs.fetchurl { + url = "https://github.com/jemalloc/jemalloc/releases/download/${finalAttrs.version}/${finalAttrs.pname}-${finalAttrs.version}.tar.bz2"; + sha256 = "sha256-LbgtHnEZ3z5xt2QCGbbf6EeJvAU3mDw7esT3GJrs/qo="; + }; + configureFlags = (previousAttrs.configureFlags or [ ]) ++ [ "--enable-static" "--disable-shared" ]; @@ -37,7 +41,7 @@ let makeFlagsArray+=(CFLAGS="-O0 -g") ''; postInstall = '' - ${oldAttrs.postInstall or ""} + ${previousAttrs.postInstall or ""} cp -v lib/libjemalloc.a $out/lib/ ''; dontStrip = true; # don't strip the debug symbols we added @@ -89,7 +93,6 @@ in shellHook = '' export PWNDBG_VENV_PATH="PWNDBG_PLEASE_SKIP_VENV" export ZIGPATH="${pkgs.lib.getBin pkgs.zig_0_10}/bin/" - export JEMALLOC_PATH="${jemalloc-static}/lib/libjemalloc.a" ''; }; } diff --git a/pwndbg/commands/heap.py b/pwndbg/commands/heap.py index 4899f3f3c..c26edcafb 100644 --- a/pwndbg/commands/heap.py +++ b/pwndbg/commands/heap.py @@ -1639,11 +1639,18 @@ def jemalloc_heap() -> None: print("This command was tested only for jemalloc 5.3.0 and does not support lower versions") print() - rtree = jemalloc.RTree.get_rtree() + try: + rtree = jemalloc.RTree.get_rtree() + except pwndbg.dbg_mod.Error as what: + # Fixes test_commands[jemalloc_heap] test case + print(message.warn(f"{what}")) + return + extents = rtree.extents if len(extents) == 0: print(message.warn("No extents found")) return + for extent in extents: # TODO: refactor so not create copies jemalloc_extent_info(extent.extent_address, header=False) diff --git a/pwndbg/commands/version.py b/pwndbg/commands/version.py index 522d021ba..4a02ae0a7 100644 --- a/pwndbg/commands/version.py +++ b/pwndbg/commands/version.py @@ -175,12 +175,16 @@ If it is somehow unavailable, use: charset_info = sys.getdefaultencoding() current_setup += f"Charset: {charset_info}\n" - # 8. showing width - width_info = os.get_terminal_size().columns - current_setup += f"Width: {width_info}\n" + # 8. showing width, height + try: + width_info = os.get_terminal_size().columns + height_info = os.get_terminal_size().lines + except OSError: + # Terminal size may not be available in non-interactive environments (e.g., scripts, IDEs) + width_info = "no terminal size" + height_info = "no terminal size" - # 9. showing height - height_info = os.get_terminal_size().lines + current_setup += f"Width: {width_info}\n" current_setup += f"Height: {height_info}\n" current_setup += "\n".join(all_info) @@ -248,7 +252,6 @@ If it is somehow unavailable, use: check_call(["gh", "issue", "create", "--body-file", f.name]) except Exception: print(please_please_submit + github_issue_url) - raise elif run_browser: try: check_output(["xdg-open", github_issue_url + github_issue_body]) diff --git a/tests/gdb-tests/tests/binaries/makefile b/tests/gdb-tests/tests/binaries/makefile index 5adf621ca..537a1f411 100644 --- a/tests/gdb-tests/tests/binaries/makefile +++ b/tests/gdb-tests/tests/binaries/makefile @@ -21,10 +21,6 @@ GO = go SOURCES_GO = $(wildcard *.go) COMPILED_GO = $(SOURCES_GO:.go=.x86) $(SOURCES_GO:.go=.x64) -ifndef JEMALLOC_PATH -JEMALLOC_PATH = /usr/local/lib/libjemalloc.a -endif - ifeq ($(TARGET), x86) CFLAGS += -m32 endif @@ -101,13 +97,13 @@ heap_jemalloc_extent_info.out: heap_jemalloc_extent_info.c @echo "[+] Building heap_jemalloc_extent_info.out" ${CC} -g -O0 -Wno-nonnull -Wno-unused-result \ -o heap_jemalloc_extent_info.out heap_jemalloc_extent_info.c \ - -lpthread ${JEMALLOC_PATH} -lm -lstdc++ -pthread -ldl + -Wl,-Bstatic -ljemalloc -Wl,-Bdynamic -lpthread -lm -lstdc++ -pthread -ldl heap_jemalloc_heap.out: heap_jemalloc_heap.c @echo "[+] Building heap_jemalloc_heap.out" ${CC} -g -O0 -Wno-nonnull -Wno-unused-result \ -o heap_jemalloc_heap.out heap_jemalloc_heap.c \ - -lpthread ${JEMALLOC_PATH} \-lm -lstdc++ -pthread -ldl + -Wl,-Bstatic -ljemalloc -Wl,-Bdynamic -lpthread -lm -lstdc++ -pthread -ldl multiple_threads.out: multiple_threads.c diff --git a/tests/gdb-tests/tests/heap/test_find_fake_fast.py b/tests/gdb-tests/tests/heap/test_find_fake_fast.py index 943509b05..fb42bd31c 100644 --- a/tests/gdb-tests/tests/heap/test_find_fake_fast.py +++ b/tests/gdb-tests/tests/heap/test_find_fake_fast.py @@ -4,7 +4,10 @@ import re import gdb -import pwndbg +import pwndbg.aglib.arch +import pwndbg.aglib.heap +import pwndbg.aglib.memory +import pwndbg.dbg import tests HEAP_FIND_FAKE_FAST = tests.binaries.get("heap_find_fake_fast.out") @@ -51,12 +54,12 @@ def test_find_fake_fast_command(start_binary): unmapped_heap_info = pwndbg.aglib.heap.ptmalloc.heap_for_ptr( int(gdb.lookup_global_symbol("fake_chunk").value()) ) - assert pwndbg.gdblib.memory.peek(unmapped_heap_info) is None + assert pwndbg.aglib.memory.peek(unmapped_heap_info) is None # A gdb.MemoryError raised here indicates a regression from PR #1145 gdb.execute("find_fake_fast fake_chunk+0x80") - target_address = pwndbg.gdblib.symbol.address("target_address") + target_address = pwndbg.dbg.selected_inferior().symbol_address_from_name("target_address") assert target_address is not None print(hex(target_address)) diff --git a/tests/gdb-tests/tests/heap/test_heap.py b/tests/gdb-tests/tests/heap/test_heap.py index 35a9cf125..df2b1ffb0 100644 --- a/tests/gdb-tests/tests/heap/test_heap.py +++ b/tests/gdb-tests/tests/heap/test_heap.py @@ -5,11 +5,10 @@ import re import gdb import pytest -import pwndbg import pwndbg.aglib.heap import pwndbg.aglib.memory import pwndbg.aglib.typeinfo -import pwndbg.gdblib.symbol +import pwndbg.dbg import tests from pwndbg.aglib.heap.ptmalloc import SymbolUnresolvableError @@ -158,7 +157,7 @@ def test_malloc_chunk_command(start_binary): gdb.execute("continue") # Print main thread's chunk from another thread - assert gdb.selected_thread().num == 2 + assert pwndbg.dbg.selected_thread().index() == 2 results["large"] = gdb.execute("malloc_chunk large_chunk", to_string=True).splitlines() expected = generate_expected_malloc_chunk_output(chunks) assert results["large"] == expected["large"] @@ -183,7 +182,7 @@ def test_malloc_chunk_command(start_binary): # Print another thread's chunk from the main thread gdb.execute("thread 1") - assert gdb.selected_thread().num == 1 + assert pwndbg.dbg.selected_thread().index() == 1 results["large"] = gdb.execute("malloc_chunk large_chunk", to_string=True).splitlines() assert results["large"] == expected["large"] @@ -211,7 +210,7 @@ def test_malloc_chunk_command_heuristic(start_binary): gdb.execute("continue") # Print main thread's chunk from another thread - assert gdb.selected_thread().num == 2 + assert pwndbg.dbg.selected_thread().index() == 2 results["large"] = gdb.execute("malloc_chunk large_chunk", to_string=True).splitlines() expected = generate_expected_malloc_chunk_output(chunks) assert results["large"] == expected["large"] @@ -235,7 +234,7 @@ def test_malloc_chunk_command_heuristic(start_binary): # Print another thread's chunk from the main thread gdb.execute("thread 1") - assert gdb.selected_thread().num == 1 + assert pwndbg.dbg.selected_thread().index() == 1 results["large"] = gdb.execute("malloc_chunk large_chunk", to_string=True).splitlines() assert results["large"] == expected["large"] @@ -281,14 +280,11 @@ class mock_for_heuristic: mock_symbols # every symbol's address in the list will be mocked to `None` ) self.mock_all = mock_all # all symbols will be mocked to `None` - # Save `pwndbg.gdblib.symbol.address` and `pwndbg.gdblib.symbol.static_linkage_symbol_address` before mocking - self.saved_address_func = pwndbg.gdblib.symbol.address - self.saved_static_linkage_symbol_address_func = ( - pwndbg.gdblib.symbol.static_linkage_symbol_address - ) + # Save `selected_inferior` before mocking + self.saved_func = pwndbg.dbg.selected_inferior def __enter__(self): - def mock(original): + def mock_symbol_address_from_name(original): def _mock(symbol, *args, **kwargs): if self.mock_all: return None @@ -299,18 +295,22 @@ class mock_for_heuristic: return _mock - # Mock `pwndbg.gdblib.symbol.address` and `pwndbg.gdblib.symbol.static_linkage_symbol_address` - pwndbg.gdblib.symbol.address = mock(pwndbg.gdblib.symbol.address) - pwndbg.gdblib.symbol.static_linkage_symbol_address = mock( - pwndbg.gdblib.symbol.static_linkage_symbol_address - ) + def mock_interior(original): + def _mock(*args, **kwargs): + inst = original(*args, **kwargs) + inst.symbol_address_from_name = mock_symbol_address_from_name( + inst.symbol_address_from_name + ) + return inst + + return _mock + + # Mock `symbol_address_from_name` from `selected_inferior` + pwndbg.dbg.selected_inferior = mock_interior(pwndbg.dbg.selected_inferior) def __exit__(self, exc_type, exc_value, traceback): - # Restore `pwndbg.gdblib.symbol.address` and `pwndbg.gdblib.symbol.static_linkage_symbol_address` - pwndbg.gdblib.symbol.address = self.saved_address_func - pwndbg.gdblib.symbol.static_linkage_symbol_address = ( - self.saved_static_linkage_symbol_address_func - ) + # Restore `selected_inferior` + pwndbg.dbg.selected_inferior = self.saved_func def test_main_arena_heuristic(start_binary): @@ -320,9 +320,9 @@ def test_main_arena_heuristic(start_binary): gdb.execute("continue") # Use the debug symbol to get the address of `main_arena` - main_arena_addr_via_debug_symbol = pwndbg.gdblib.symbol.static_linkage_symbol_address( - "main_arena" - ) or pwndbg.gdblib.symbol.address("main_arena") + main_arena_addr_via_debug_symbol = pwndbg.dbg.selected_inferior().symbol_address_from_name( + "main_arena", prefer_static=True + ) # Check if we can get the address of `main_arena` from debug symbols and the struct of `main_arena` is correct assert pwndbg.aglib.heap.current.main_arena is not None @@ -349,9 +349,9 @@ def test_mp_heuristic(start_binary): gdb.execute("continue") # Use the debug symbol to get the address of `mp_` - mp_addr_via_debug_symbol = pwndbg.gdblib.symbol.static_linkage_symbol_address( - "mp_" - ) or pwndbg.gdblib.symbol.address("mp_") + mp_addr_via_debug_symbol = pwndbg.dbg.selected_inferior().symbol_address_from_name( + "mp_", prefer_static=True + ) # Check if we can get the address of `mp_` from debug symbols and the struct of `mp_` is correct assert pwndbg.aglib.heap.current.mp is not None @@ -382,12 +382,12 @@ def test_thread_cache_heuristic(start_binary, is_multi_threaded): gdb.execute("continue") if is_multi_threaded: gdb.execute("continue") - assert gdb.selected_thread().num == 2 + assert pwndbg.dbg.selected_thread().index() == 2 # Use the debug symbol to find the address of `thread_cache` - tcache_addr_via_debug_symbol = pwndbg.gdblib.symbol.static_linkage_symbol_address( - "tcache" - ) or pwndbg.gdblib.symbol.address("tcache") + tcache_addr_via_debug_symbol = pwndbg.dbg.selected_inferior().symbol_address_from_name( + "tcache", prefer_static=True + ) thread_cache_addr_via_debug_symbol = pwndbg.aglib.memory.u(tcache_addr_via_debug_symbol) # Check if we can get the address of `thread_cache` from debug symbols and the struct of `thread_cache` is correct @@ -426,12 +426,12 @@ def test_thread_arena_heuristic(start_binary, is_multi_threaded): gdb.execute("continue") if is_multi_threaded: gdb.execute("continue") - assert gdb.selected_thread().num == 2 + assert pwndbg.dbg.selected_thread().index() == 2 # Use the debug symbol to find the value of `thread_arena` - thread_arena_via_debug_symbol = pwndbg.gdblib.symbol.static_linkage_symbol_address( - "thread_arena" - ) or pwndbg.gdblib.symbol.address("thread_arena") + thread_arena_via_debug_symbol = pwndbg.dbg.selected_inferior().symbol_address_from_name( + "thread_arena", prefer_static=True + ) assert thread_arena_via_debug_symbol is not None thread_arena_via_debug_symbol = pwndbg.aglib.memory.u(thread_arena_via_debug_symbol) assert thread_arena_via_debug_symbol > 0 @@ -459,9 +459,9 @@ def test_global_max_fast_heuristic(start_binary): gdb.execute("continue") # Use the debug symbol to find the address of `global_max_fast` - global_max_fast_addr_via_debug_symbol = pwndbg.gdblib.symbol.static_linkage_symbol_address( - "global_max_fast" - ) or pwndbg.gdblib.symbol.address("global_max_fast") + global_max_fast_addr_via_debug_symbol = pwndbg.dbg.selected_inferior().symbol_address_from_name( + "global_max_fast", prefer_static=True + ) assert global_max_fast_addr_via_debug_symbol is not None # Check if we can get the address of `global_max_fast` from debug symbols and the value of `global_max_fast` is correct @@ -488,7 +488,7 @@ def test_heuristic_fail_gracefully(start_binary, is_multi_threaded): gdb.execute("continue") if is_multi_threaded: gdb.execute("continue") - assert gdb.selected_thread().num == 2 + assert pwndbg.dbg.selected_thread().index() == 2 def _test_heuristic_fail_gracefully(name): try: diff --git a/tests/gdb-tests/tests/heap/test_heap_bins.py b/tests/gdb-tests/tests/heap/test_heap_bins.py index 4664cbaa1..8456d7120 100644 --- a/tests/gdb-tests/tests/heap/test_heap_bins.py +++ b/tests/gdb-tests/tests/heap/test_heap_bins.py @@ -4,9 +4,9 @@ import gdb import pytest import pwndbg.aglib.heap -import pwndbg.gdblib.memory -import pwndbg.gdblib.symbol -import pwndbg.gdblib.vmmap +import pwndbg.aglib.memory +import pwndbg.aglib.vmmap +import pwndbg.dbg import tests from pwndbg.aglib.heap.ptmalloc import BinType @@ -25,22 +25,22 @@ def test_heap_bins(start_binary): gdb.execute("continue") allocator = pwndbg.aglib.heap.current - addr = pwndbg.gdblib.symbol.address("tcache_size") - tcache_size = allocator._request2size(pwndbg.gdblib.memory.u64(addr)) - addr = pwndbg.gdblib.symbol.address("tcache_count") - tcache_count = pwndbg.gdblib.memory.u64(addr) - addr = pwndbg.gdblib.symbol.address("fastbin_size") - fastbin_size = allocator._request2size(pwndbg.gdblib.memory.u64(addr)) - addr = pwndbg.gdblib.symbol.address("fastbin_count") - fastbin_count = pwndbg.gdblib.memory.u64(addr) - addr = pwndbg.gdblib.symbol.address("smallbin_size") - smallbin_size = allocator._request2size(pwndbg.gdblib.memory.u64(addr)) - addr = pwndbg.gdblib.symbol.address("smallbin_count") - smallbin_count = pwndbg.gdblib.memory.u64(addr) - addr = pwndbg.gdblib.symbol.address("largebin_size") - largebin_size = allocator._request2size(pwndbg.gdblib.memory.u64(addr)) - addr = pwndbg.gdblib.symbol.address("largebin_count") - largebin_count = pwndbg.gdblib.memory.u64(addr) + addr = pwndbg.dbg.selected_inferior().symbol_address_from_name("tcache_size") + tcache_size = allocator._request2size(pwndbg.aglib.memory.u64(addr)) + addr = pwndbg.dbg.selected_inferior().symbol_address_from_name("tcache_count") + tcache_count = pwndbg.aglib.memory.u64(addr) + addr = pwndbg.dbg.selected_inferior().symbol_address_from_name("fastbin_size") + fastbin_size = allocator._request2size(pwndbg.aglib.memory.u64(addr)) + addr = pwndbg.dbg.selected_inferior().symbol_address_from_name("fastbin_count") + fastbin_count = pwndbg.aglib.memory.u64(addr) + addr = pwndbg.dbg.selected_inferior().symbol_address_from_name("smallbin_size") + smallbin_size = allocator._request2size(pwndbg.aglib.memory.u64(addr)) + addr = pwndbg.dbg.selected_inferior().symbol_address_from_name("smallbin_count") + smallbin_count = pwndbg.aglib.memory.u64(addr) + addr = pwndbg.dbg.selected_inferior().symbol_address_from_name("largebin_size") + largebin_size = allocator._request2size(pwndbg.aglib.memory.u64(addr)) + addr = pwndbg.dbg.selected_inferior().symbol_address_from_name("largebin_count") + largebin_count = pwndbg.aglib.memory.u64(addr) result = allocator.tcachebins() assert result.bin_type == BinType.TCACHE @@ -87,7 +87,7 @@ def test_heap_bins(start_binary): and len(result.bins[tcache_size].fd_chain) == tcache_count + 1 ) for addr in result.bins[tcache_size].fd_chain[:-1]: - assert pwndbg.gdblib.vmmap.find(addr) + assert pwndbg.aglib.vmmap.find(addr) # check fastbin gdb.execute("continue") @@ -98,7 +98,7 @@ def test_heap_bins(start_binary): len(result.bins[fastbin_size].fd_chain) == fastbin_count + 1 ) for addr in result.bins[fastbin_size].fd_chain[:-1]: - assert pwndbg.gdblib.vmmap.find(addr) + assert pwndbg.aglib.vmmap.find(addr) # check unsortedbin gdb.execute("continue") @@ -111,9 +111,9 @@ def test_heap_bins(start_binary): ) assert not result.bins["all"].is_corrupted for addr in result.bins["all"].fd_chain[:-1]: - assert pwndbg.gdblib.vmmap.find(addr) + assert pwndbg.aglib.vmmap.find(addr) for addr in result.bins["all"].bk_chain[:-1]: - assert pwndbg.gdblib.vmmap.find(addr) + assert pwndbg.aglib.vmmap.find(addr) # check smallbins gdb.execute("continue") @@ -126,9 +126,9 @@ def test_heap_bins(start_binary): ) assert not result.bins[smallbin_size].is_corrupted for addr in result.bins[smallbin_size].fd_chain[:-1]: - assert pwndbg.gdblib.vmmap.find(addr) + assert pwndbg.aglib.vmmap.find(addr) for addr in result.bins[smallbin_size].bk_chain[:-1]: - assert pwndbg.gdblib.vmmap.find(addr) + assert pwndbg.aglib.vmmap.find(addr) # check largebins gdb.execute("continue") @@ -141,9 +141,9 @@ def test_heap_bins(start_binary): ) assert not result.bins[largebin_size].is_corrupted for addr in result.bins[largebin_size].fd_chain[:-1]: - assert pwndbg.gdblib.vmmap.find(addr) + assert pwndbg.aglib.vmmap.find(addr) for addr in result.bins[largebin_size].bk_chain[:-1]: - assert pwndbg.gdblib.vmmap.find(addr) + assert pwndbg.aglib.vmmap.find(addr) # check corrupted gdb.execute("continue") diff --git a/tests/gdb-tests/tests/heap/test_try_free.py b/tests/gdb-tests/tests/heap/test_try_free.py index 3e710f7eb..9664d167a 100644 --- a/tests/gdb-tests/tests/heap/test_try_free.py +++ b/tests/gdb-tests/tests/heap/test_try_free.py @@ -6,7 +6,8 @@ import tempfile import gdb import pytest -import pwndbg +import pwndbg.aglib.arch +import pwndbg.aglib.heap import tests HEAP_BINARY = tests.binaries.get("heap_bugs.out") diff --git a/tests/gdb-tests/tests/heap/test_vis_heap_chunks.py b/tests/gdb-tests/tests/heap/test_vis_heap_chunks.py index 757723960..b2dbbc5bf 100644 --- a/tests/gdb-tests/tests/heap/test_vis_heap_chunks.py +++ b/tests/gdb-tests/tests/heap/test_vis_heap_chunks.py @@ -2,7 +2,9 @@ from __future__ import annotations import gdb -import pwndbg +import pwndbg.aglib.arch +import pwndbg.aglib.memory +import pwndbg.aglib.vmmap import tests HEAP_VIS = tests.binaries.get("heap_vis.out") @@ -15,9 +17,9 @@ def test_vis_heap_chunk_command(start_binary): # TODO/FIXME: Shall we have a standard method to do this kind of filtering? # Note that we have `pages_filter` in pwndbg/pwndbg/commands/vmmap.py heh - heap_page = next(page for page in pwndbg.gdblib.vmmap.get() if page.objfile == "[heap]") + heap_page = next(page for page in pwndbg.aglib.vmmap.get() if page.objfile == "[heap]") - first_chunk_size = pwndbg.gdblib.memory.u64(heap_page.start + pwndbg.aglib.arch.ptrsize) + first_chunk_size = pwndbg.aglib.memory.u64(heap_page.start + pwndbg.aglib.arch.ptrsize) # Just a sanity check... assert (heap_page.start & 0xFFF) == 0 @@ -50,7 +52,7 @@ def test_vis_heap_chunk_command(start_binary): hexdump = hexdump_16B(addr) nonlocal dq2 - dq1, dq2 = map(pwndbg.gdblib.memory.u64, (addr, addr + 8)) + dq1, dq2 = map(pwndbg.aglib.memory.u64, (addr, addr + 8)) formatted = f"{addr:#x}\t{dq1:#018x}\t{dq2:#018x}\t{hexdump}" formatted += suffix diff --git a/tests/gdb-tests/tests/test_callstack.py b/tests/gdb-tests/tests/test_callstack.py index bc877d1f7..88d53419e 100644 --- a/tests/gdb-tests/tests/test_callstack.py +++ b/tests/gdb-tests/tests/test_callstack.py @@ -2,8 +2,8 @@ from __future__ import annotations import gdb -import pwndbg.gdblib.memory -import pwndbg.gdblib.stack +import pwndbg.aglib.memory +import pwndbg.aglib.stack import tests REFERENCE_BINARY = tests.binaries.get("reference-binary.out") @@ -14,7 +14,7 @@ def test_callstack_readable(start_binary): gdb.execute("b break_here") gdb.execute("r") - addresses = pwndbg.gdblib.stack.callstack() + addresses = pwndbg.aglib.stack.callstack() assert len(addresses) > 0 - assert all(pwndbg.gdblib.memory.is_readable_address(address) for address in addresses) + assert all(pwndbg.aglib.memory.is_readable_address(address) for address in addresses) diff --git a/tests/gdb-tests/tests/test_command_branch.py b/tests/gdb-tests/tests/test_command_branch.py index d3c2878ca..bffa888b9 100644 --- a/tests/gdb-tests/tests/test_command_branch.py +++ b/tests/gdb-tests/tests/test_command_branch.py @@ -3,7 +3,7 @@ from __future__ import annotations import gdb import pytest -import pwndbg.gdblib +import pwndbg.aglib.regs import tests CONDBR_X64_BINARY = tests.binaries.get("conditional_branch_breakpoints_x64.out") @@ -35,4 +35,4 @@ def test_command_break_if_x64(start_binary, binary): def continue_and_test_pc(stop_label): gdb.execute("continue") address = int(gdb.parse_and_eval(f"&{stop_label}")) - assert pwndbg.gdblib.regs.pc == address + assert pwndbg.aglib.regs.pc == address diff --git a/tests/gdb-tests/tests/test_command_cyclic.py b/tests/gdb-tests/tests/test_command_cyclic.py index 0078836d5..d93e642a8 100644 --- a/tests/gdb-tests/tests/test_command_cyclic.py +++ b/tests/gdb-tests/tests/test_command_cyclic.py @@ -4,8 +4,8 @@ import gdb from pwnlib.util.cyclic import cyclic import pwndbg.aglib.arch -import pwndbg.gdblib.memory -import pwndbg.gdblib.regs +import pwndbg.aglib.memory +import pwndbg.aglib.regs import tests REFERENCE_BINARY = tests.binaries.get("reference-binary.out") @@ -38,7 +38,7 @@ def test_command_cyclic_register(start_binary): ptr_size = pwndbg.aglib.arch.ptrsize test_offset = 45 pattern = cyclic(length=80, n=ptr_size) - pwndbg.gdblib.regs.rdi = int.from_bytes( + pwndbg.aglib.regs.rdi = int.from_bytes( pattern[test_offset : test_offset + ptr_size], pwndbg.aglib.arch.endian ) out = gdb.execute("cyclic -l $rdi", to_string=True) @@ -55,11 +55,11 @@ def test_command_cyclic_address(start_binary): """ start_binary(REFERENCE_BINARY) - addr = pwndbg.gdblib.regs.rsp + addr = pwndbg.aglib.regs.rsp ptr_size = pwndbg.aglib.arch.ptrsize test_offset = 48 pattern = cyclic(length=80, n=ptr_size) - pwndbg.gdblib.memory.write(addr, pattern) + pwndbg.aglib.memory.write(addr, pattern) out = gdb.execute(f"cyclic -l '{{unsigned long}}{hex(addr + test_offset)}'", to_string=True) assert out == ( diff --git a/tests/gdb-tests/tests/test_command_distance.py b/tests/gdb-tests/tests/test_command_distance.py index d92443ef2..aee841eb9 100644 --- a/tests/gdb-tests/tests/test_command_distance.py +++ b/tests/gdb-tests/tests/test_command_distance.py @@ -2,7 +2,7 @@ from __future__ import annotations import gdb -import pwndbg.gdblib.regs +import pwndbg.aglib.regs import tests REFERENCE_BINARY = tests.binaries.get("reference-binary.out") @@ -11,7 +11,7 @@ REFERENCE_BINARY = tests.binaries.get("reference-binary.out") def test_command_distance(start_binary): start_binary(REFERENCE_BINARY) - rsp = pwndbg.gdblib.regs.rsp + rsp = pwndbg.aglib.regs.rsp result = gdb.execute("distance $rsp $rsp+0x10", to_string=True) assert result == f"{rsp:#x}->{rsp + 0x10:#x} is 0x10 bytes (0x2 words)\n" diff --git a/tests/gdb-tests/tests/test_command_flags.py b/tests/gdb-tests/tests/test_command_flags.py index ddf919e1d..31d44541e 100644 --- a/tests/gdb-tests/tests/test_command_flags.py +++ b/tests/gdb-tests/tests/test_command_flags.py @@ -2,7 +2,7 @@ from __future__ import annotations import gdb -import pwndbg.gdblib.regs +import pwndbg.aglib.regs import tests REFERENCE_BINARY = tests.binaries.get("reference-binary.out") @@ -11,7 +11,7 @@ REFERENCE_BINARY = tests.binaries.get("reference-binary.out") def test_flags_command(start_binary): start_binary(REFERENCE_BINARY) - old_eflags = pwndbg.gdblib.regs.eflags + old_eflags = pwndbg.aglib.regs.eflags # Verify CF is not set assert old_eflags & 0x1 == 0 @@ -19,15 +19,15 @@ def test_flags_command(start_binary): gdb.execute("setflag cf 1") # Verify CF is set and no other flags have changed - assert (old_eflags | 1) == pwndbg.gdblib.regs.eflags + assert (old_eflags | 1) == pwndbg.aglib.regs.eflags gdb.execute("setflag cf 0") # Verify CF is not set and no other flags have changed - assert old_eflags == pwndbg.gdblib.regs.eflags + assert old_eflags == pwndbg.aglib.regs.eflags # Test setting an invalid value gdb.execute("setflag cf 2") # Verify no flags have changed - assert old_eflags == pwndbg.gdblib.regs.eflags + assert old_eflags == pwndbg.aglib.regs.eflags diff --git a/tests/gdb-tests/tests/test_command_ignore.py b/tests/gdb-tests/tests/test_command_ignore.py index db7131f93..4ccc66349 100644 --- a/tests/gdb-tests/tests/test_command_ignore.py +++ b/tests/gdb-tests/tests/test_command_ignore.py @@ -2,7 +2,7 @@ from __future__ import annotations import gdb -import pwndbg +import pwndbg.aglib.proc import tests REFERENCE_BINARY = tests.binaries.get("reference-binary.out") @@ -37,10 +37,10 @@ def test_command_ignore_breakpoint_last_found_one(): assert out == "Will ignore next 1 crossings of breakpoint 1.\n" gdb.execute("run") - assert not pwndbg.gdblib.proc.alive + assert not pwndbg.aglib.proc.alive gdb.execute("run") - assert pwndbg.gdblib.proc.alive + assert pwndbg.aglib.proc.alive def test_command_ignore_breakpoint_last_found_two(): diff --git a/tests/gdb-tests/tests/test_command_killthreads.py b/tests/gdb-tests/tests/test_command_killthreads.py index 9b1f5ca0c..02e28cfdd 100644 --- a/tests/gdb-tests/tests/test_command_killthreads.py +++ b/tests/gdb-tests/tests/test_command_killthreads.py @@ -4,6 +4,7 @@ import time import gdb +import pwndbg.dbg import tests REFERENCE_BINARY_THREADS = tests.binaries.get("multiple_threads.out") @@ -28,12 +29,12 @@ def test_command_killthreads_kills_all_threads_except_current(start_binary): gdb.execute("break break_here") gdb.execute("run") - wait_until(lambda: len(gdb.selected_inferior().threads()) == 3) + wait_until(lambda: len(pwndbg.dbg.selected_inferior().threads()) == 3) gdb.execute("killthreads --all") # check if only one thread is left - wait_until(lambda: len(gdb.selected_inferior().threads()) == 1) + wait_until(lambda: len(pwndbg.dbg.selected_inferior().threads()) == 1) def test_command_killthreads_kills_specific_thread(start_binary): @@ -41,19 +42,23 @@ def test_command_killthreads_kills_specific_thread(start_binary): gdb.execute("break break_here") gdb.execute("run") - initial_thread_count = len(gdb.selected_inferior().threads()) + initial_thread_count = len(pwndbg.dbg.selected_inferior().threads()) # check if thread with id 3 exists wait_until( - lambda: len([thread for thread in gdb.selected_inferior().threads() if thread.num == 3]) + lambda: len( + [thread for thread in pwndbg.dbg.selected_inferior().threads() if thread.index() == 3] + ) == 1 ) gdb.execute("killthreads 3") # check if the thread was killed, and no other thread was killed wait_until( - lambda: len([thread for thread in gdb.selected_inferior().threads() if thread.num == 3]) + lambda: len( + [thread for thread in pwndbg.dbg.selected_inferior().threads() if thread.index() == 3] + ) == 0 ) - assert len(gdb.selected_inferior().threads()) == initial_thread_count - 1 + assert len(pwndbg.dbg.selected_inferior().threads()) == initial_thread_count - 1 gdb.execute("kill") @@ -64,7 +69,10 @@ def test_command_killthreads_produces_error_when_unknown_thread_passed(start_bin gdb.execute("break break_here") gdb.execute("run") # check if thread with id 3 exists - assert len([thread for thread in gdb.selected_inferior().threads() if thread.num == 3]) == 1 + assert ( + len([thread for thread in pwndbg.dbg.selected_inferior().threads() if thread.index() == 3]) + == 1 + ) out = gdb.execute("killthreads 999", to_string=True) assert "Thread ID 999 does not exist" in out diff --git a/tests/gdb-tests/tests/test_command_onegadget.py b/tests/gdb-tests/tests/test_command_onegadget.py index 4b9d9a0c0..5dafc4a13 100644 --- a/tests/gdb-tests/tests/test_command_onegadget.py +++ b/tests/gdb-tests/tests/test_command_onegadget.py @@ -5,7 +5,6 @@ from unittest.mock import patch import gdb import pytest -import pwndbg.gdblib.onegadget import pwndbg.glibc import tests diff --git a/tests/gdb-tests/tests/test_command_procinfo.py b/tests/gdb-tests/tests/test_command_procinfo.py index a30ef29ae..36f25e41b 100644 --- a/tests/gdb-tests/tests/test_command_procinfo.py +++ b/tests/gdb-tests/tests/test_command_procinfo.py @@ -7,6 +7,7 @@ import subprocess import gdb +import pwndbg.aglib.proc import tests REFERENCE_BINARY_NET = tests.binaries.get("reference-binary-net.out") @@ -28,8 +29,8 @@ def test_command_procinfo(start_binary): start_new_session=True, ) - bin_path = gdb.execute("pi pwndbg.gdblib.proc.exe", to_string=True).strip("\n") - pid = gdb.execute("pi pwndbg.gdblib.proc.pid", to_string=True).strip("\n") + bin_path = pwndbg.aglib.proc.exe + pid = str(pwndbg.aglib.proc.pid) gdb.execute("break break_here") gdb.execute("continue") diff --git a/tests/gdb-tests/tests/test_command_stepuntilasm.py b/tests/gdb-tests/tests/test_command_stepuntilasm.py index 3d2c39ce2..131c328f5 100644 --- a/tests/gdb-tests/tests/test_command_stepuntilasm.py +++ b/tests/gdb-tests/tests/test_command_stepuntilasm.py @@ -2,7 +2,7 @@ from __future__ import annotations import gdb -import pwndbg.gdblib +import pwndbg.aglib.regs import tests STEPUNTILASM_X64_BINARY = tests.binaries.get("stepuntilasm_x64.out") @@ -22,4 +22,4 @@ def test_command_untilasm_x64(start_binary): def run_and_verify(stop_label, asm): gdb.execute(f"stepuntilasm {asm}") address = int(gdb.parse_and_eval(f"&{stop_label}")) - assert pwndbg.gdblib.regs.pc == address + assert pwndbg.aglib.regs.pc == address diff --git a/tests/gdb-tests/tests/test_command_telescope.py b/tests/gdb-tests/tests/test_command_telescope.py index 089908721..88f24be82 100644 --- a/tests/gdb-tests/tests/test_command_telescope.py +++ b/tests/gdb-tests/tests/test_command_telescope.py @@ -4,7 +4,10 @@ import re import gdb -import pwndbg.gdblib +import pwndbg.aglib.memory +import pwndbg.aglib.proc +import pwndbg.aglib.regs +import pwndbg.aglib.vmmap import tests TELESCOPE_BINARY = tests.binaries.get("telescope_binary.out") @@ -68,12 +71,12 @@ def test_telescope_command_with_address_as_count(start_binary): start_binary(TELESCOPE_BINARY) out = gdb.execute("telescope 2", to_string=True).splitlines() - rsp = pwndbg.gdblib.regs.rsp + rsp = pwndbg.aglib.regs.rsp assert len(out) == 2 assert out[0] == "00:0000│ rsp %#x ◂— 1" % rsp - expected = rf"01:0008│ {rsp + 8:#x} —▸ 0x[0-9a-f]+ ◂— '{pwndbg.gdblib.proc.exe}'" + expected = rf"01:0008│ {rsp + 8:#x} —▸ 0x[0-9a-f]+ ◂— '{pwndbg.aglib.proc.exe}'" assert re.search(expected, out[1]) @@ -81,7 +84,7 @@ def test_telescope_command_with_address_as_count_and_reversed_flag(start_binary) start_binary(TELESCOPE_BINARY) out = gdb.execute("telescope -r 2", to_string=True).splitlines() - rsp = pwndbg.gdblib.regs.rsp + rsp = pwndbg.aglib.regs.rsp assert out == ["00:0000│ %#x ◂— 0" % (rsp - 8), "01:0008│ rsp %#x ◂— 1" % rsp] @@ -95,9 +98,9 @@ def test_command_telescope_reverse_skipped_records_shows_input_address(start_bin gdb.execute("break break_here") gdb.execute("run") gdb.execute("up") - pwndbg.gdblib.memory.write(pwndbg.gdblib.regs.rsp - 8 * 3, b"\x00" * 8 * 4) + pwndbg.aglib.memory.write(pwndbg.aglib.regs.rsp - 8 * 3, b"\x00" * 8 * 4) - expected_value = hex(pwndbg.gdblib.regs.rsp) + expected_value = hex(pwndbg.aglib.regs.rsp) result_str = gdb.execute("telescope -r $rsp", to_string=True) result_lines = result_str.strip("\n").split("\n") @@ -113,8 +116,8 @@ def test_command_telescope_frame(start_binary): gdb.execute("break break_here") gdb.execute("run") - rsp = hex(pwndbg.gdblib.regs.sp) - rbp = hex(pwndbg.gdblib.regs[pwndbg.gdblib.regs.frame]) + rsp = hex(pwndbg.aglib.regs.sp) + rbp = hex(pwndbg.aglib.regs[pwndbg.aglib.regs.frame]) result_str = gdb.execute("telescope --frame", to_string=True) result_lines = result_str.strip().split("\n") @@ -133,7 +136,7 @@ def test_command_telescope_frame_bp_below_sp(start_binary): gdb.execute("run") gdb.execute("memoize") # turn off cache - pwndbg.gdblib.regs.sp = pwndbg.gdblib.regs[pwndbg.gdblib.regs.frame] + 1 + pwndbg.aglib.regs.sp = pwndbg.aglib.regs[pwndbg.aglib.regs.frame] + 1 result_str = gdb.execute("telescope --frame", to_string=True) @@ -150,10 +153,10 @@ def test_command_telescope_frame_bp_sp_different_vmmaps(start_binary): gdb.execute("run") gdb.execute("memoize") # turn off cache - pages = pwndbg.gdblib.vmmap.get() + pages = pwndbg.aglib.vmmap.get() - pwndbg.gdblib.regs.sp = pages[0].start - pwndbg.gdblib.regs.bp = pages[1].start + pwndbg.aglib.regs.sp = pages[0].start + pwndbg.aglib.regs.bp = pages[1].start result_str = gdb.execute("telescope --frame", to_string=True) diff --git a/tests/gdb-tests/tests/test_command_tls.py b/tests/gdb-tests/tests/test_command_tls.py index 069e65a65..3b3ddcee6 100644 --- a/tests/gdb-tests/tests/test_command_tls.py +++ b/tests/gdb-tests/tests/test_command_tls.py @@ -3,8 +3,8 @@ from __future__ import annotations import gdb import pytest -import pwndbg.gdblib.tls -import pwndbg.gdblib.vmmap +import pwndbg.aglib.tls +import pwndbg.aglib.vmmap import tests TLS_X86_64_BINARY = tests.binaries.get("tls.x86-64.out") @@ -23,20 +23,20 @@ def test_tls_address_and_command(start_binary, binary): expected_tls_address = int(gdb.parse_and_eval("(void *)tls_address")) - assert pwndbg.gdblib.tls.find_address_with_register() == expected_tls_address + assert pwndbg.aglib.tls.find_address_with_register() == expected_tls_address - assert pwndbg.gdblib.tls.find_address_with_pthread_self() == expected_tls_address + assert pwndbg.aglib.tls.find_address_with_pthread_self() == expected_tls_address assert ( gdb.execute("tls", to_string=True) == f"""Thread Local Storage (TLS) base: {expected_tls_address:#x} TLS is located at: -{pwndbg.gdblib.vmmap.find(expected_tls_address)}\n""" +{pwndbg.aglib.vmmap.find(expected_tls_address)}\n""" ) assert ( gdb.execute("tls --pthread-self", to_string=True) == f"""Thread Local Storage (TLS) base: {expected_tls_address:#x} TLS is located at: -{pwndbg.gdblib.vmmap.find(expected_tls_address)}\n""" +{pwndbg.aglib.vmmap.find(expected_tls_address)}\n""" ) diff --git a/tests/gdb-tests/tests/test_command_vmmap.py b/tests/gdb-tests/tests/test_command_vmmap.py index 7da2952b3..2c9463fd6 100644 --- a/tests/gdb-tests/tests/test_command_vmmap.py +++ b/tests/gdb-tests/tests/test_command_vmmap.py @@ -5,7 +5,7 @@ import tempfile import gdb import pytest -import pwndbg +import pwndbg.aglib.proc import tests GAPS_MAP_BINARY = tests.binaries.get("mmap_gaps.out") @@ -32,7 +32,7 @@ def get_proc_maps(): # Note: info proc mappings may not have permissions information, # so we get it here and fill from `perms` - with open("/proc/%d/maps" % pwndbg.gdblib.proc.pid) as f: + with open("/proc/%d/maps" % pwndbg.aglib.proc.pid) as f: for line in f.read().splitlines(): addrs, perms, offset, _inode, size, objfile = line.split(maxsplit=6) start, end = (int(v, 16) for v in addrs.split("-")) diff --git a/tests/gdb-tests/tests/test_command_xor.py b/tests/gdb-tests/tests/test_command_xor.py index b329c9dfd..9d4754f38 100644 --- a/tests/gdb-tests/tests/test_command_xor.py +++ b/tests/gdb-tests/tests/test_command_xor.py @@ -2,8 +2,8 @@ from __future__ import annotations import gdb -import pwndbg.gdblib.memory -import pwndbg.gdblib.regs +import pwndbg.aglib.memory +import pwndbg.aglib.regs import tests from pwndbg.commands.xor import memfrob @@ -16,10 +16,10 @@ def test_command_xor_with_gdb_execute(start_binary): """ start_binary(REFERENCE_BINARY) - before = pwndbg.gdblib.regs.rsp - pwndbg.gdblib.memory.write(before, b"aaaaaaaa") + before = pwndbg.aglib.regs.rsp + pwndbg.aglib.memory.write(before, b"aaaaaaaa") gdb.execute("xor $rsp ' ' 4") - after = pwndbg.gdblib.memory.read(before, 8) + after = pwndbg.aglib.memory.read(before, 8) assert after == b"AAAAaaaa" @@ -29,11 +29,11 @@ def test_command_xor_with_int(start_binary): """ start_binary(REFERENCE_BINARY) - before = pwndbg.gdblib.regs.rsp + before = pwndbg.aglib.regs.rsp assert isinstance(before, int) - pwndbg.gdblib.memory.write(before, b"aaaaaaaa") + pwndbg.aglib.memory.write(before, b"aaaaaaaa") gdb.execute(f"xor {before} ' ' 4") - after = pwndbg.gdblib.memory.read(before, 8) + after = pwndbg.aglib.memory.read(before, 8) assert after == b"AAAAaaaa" @@ -43,20 +43,20 @@ def test_command_xor_with_hex(start_binary): """ start_binary(REFERENCE_BINARY) - before = pwndbg.gdblib.regs.rsp + before = pwndbg.aglib.regs.rsp before_hex = hex(before) assert isinstance(before_hex, str) - pwndbg.gdblib.memory.write(before, b"aaaaaaaa") + pwndbg.aglib.memory.write(before, b"aaaaaaaa") gdb.execute(f"xor {before_hex} ' ' 4") - after = pwndbg.gdblib.memory.read(before, 8) + after = pwndbg.aglib.memory.read(before, 8) assert after == b"AAAAaaaa" def test_command_memfrob(start_binary): start_binary(REFERENCE_BINARY) - before = pwndbg.gdblib.regs.rsp - pwndbg.gdblib.memory.write(before, b"aaaaaaaa") + before = pwndbg.aglib.regs.rsp + pwndbg.aglib.memory.write(before, b"aaaaaaaa") memfrob(before, 4) - after = pwndbg.gdblib.memory.read(before, 8) + after = pwndbg.aglib.memory.read(before, 8) assert after == b"KKKKaaaa" diff --git a/tests/gdb-tests/tests/test_commands.py b/tests/gdb-tests/tests/test_commands.py index eec516bb7..08fef5b48 100644 --- a/tests/gdb-tests/tests/test_commands.py +++ b/tests/gdb-tests/tests/test_commands.py @@ -50,8 +50,8 @@ if should_skip_test: @pytest.mark.xfail(reason="flaky test") def test_commands(start_binary, name): print("Running command", name) + start_binary(BINARY) try: - start_binary(BINARY) gdb.execute(name) except gdb.error as e: ignore = False diff --git a/tests/gdb-tests/tests/test_commands_next.py b/tests/gdb-tests/tests/test_commands_next.py index 4682a2f5e..d80c4123b 100644 --- a/tests/gdb-tests/tests/test_commands_next.py +++ b/tests/gdb-tests/tests/test_commands_next.py @@ -3,7 +3,9 @@ from __future__ import annotations import gdb import pytest -import pwndbg.gdblib.regs +import pwndbg.aglib.proc +import pwndbg.aglib.regs +import pwndbg.aglib.vmmap import tests REFERENCE_BINARY = tests.binaries.get("reference-binary.out") @@ -26,20 +28,20 @@ def test_command_nextproginstr(start_binary): # Sanity check exec_bin_pages = [ - p for p in pwndbg.gdblib.vmmap.get() if p.objfile == pwndbg.gdblib.proc.exe and p.execute + p for p in pwndbg.aglib.vmmap.get() if p.objfile == pwndbg.aglib.proc.exe and p.execute ] - assert any(pwndbg.gdblib.regs.pc in p for p in exec_bin_pages) - main_page = pwndbg.gdblib.vmmap.find(pwndbg.gdblib.regs.pc) + assert any(pwndbg.aglib.regs.pc in p for p in exec_bin_pages) + main_page = pwndbg.aglib.vmmap.find(pwndbg.aglib.regs.pc) gdb.execute("break puts") gdb.execute("continue") # Sanity check that we are in libc - assert "libc" in pwndbg.gdblib.vmmap.find(pwndbg.gdblib.regs.rip).objfile + assert "libc" in pwndbg.aglib.vmmap.find(pwndbg.aglib.regs.rip).objfile # Execute nextproginstr and see if we came back to the same vmmap page gdb.execute("nextproginstr") - assert pwndbg.gdblib.regs.pc in main_page + assert pwndbg.aglib.regs.pc in main_page # Ensure that nextproginstr won't jump now out = gdb.execute("nextproginstr", to_string=True) @@ -56,7 +58,7 @@ def test_next_command_doesnt_freeze_crashed_binary(start_binary, command): # The nextproginstr won't step if we are already on the binary address # and interestingly, other commands won't step if the address can't be disassemblied if command == "nextproginstr": - pwndbg.gdblib.regs.pc = 0x1234 + pwndbg.aglib.regs.pc = 0x1234 # This should not halt/freeze the program gdb.execute(command, to_string=True) diff --git a/tests/gdb-tests/tests/test_context_commands.py b/tests/gdb-tests/tests/test_context_commands.py index ed74b8ebe..a3785ff9b 100644 --- a/tests/gdb-tests/tests/test_context_commands.py +++ b/tests/gdb-tests/tests/test_context_commands.py @@ -5,6 +5,8 @@ import re import gdb import pytest +import pwndbg.aglib.memory +import pwndbg.aglib.regs import pwndbg.commands import pwndbg.commands.canary import tests @@ -326,7 +328,7 @@ def test_context_disasm_proper_render_on_mem_change_issue_1818(start_binary, pat gdb.execute("patch $rip nop;nop;nop;nop;nop", to_string=True) else: # Do the same, but through write API - pwndbg.gdblib.memory.write(pwndbg.gdblib.regs.rip, b"\x90" * 5) + pwndbg.aglib.memory.write(pwndbg.aglib.regs.rip, b"\x90" * 5) # Actual test: we expect the read memory to be different now ;) # (and not e.g. returned incorrectly from a not cleared cache) diff --git a/tests/gdb-tests/tests/test_cymbol.py b/tests/gdb-tests/tests/test_cymbol.py index 5751664f3..376ff9d59 100644 --- a/tests/gdb-tests/tests/test_cymbol.py +++ b/tests/gdb-tests/tests/test_cymbol.py @@ -2,8 +2,12 @@ from __future__ import annotations import os -import pwndbg.commands.cymbol -import pwndbg.gdblib.dt +import pwndbg.dbg + +if pwndbg.dbg.is_gdblib_available(): + import pwndbg.commands.cymbol + import pwndbg.gdblib.dt + import tests REFERENCE_BINARY = tests.binaries.get("reference-binary.out") diff --git a/tests/gdb-tests/tests/test_emulate.py b/tests/gdb-tests/tests/test_emulate.py index 4c7549e1a..bb907da37 100644 --- a/tests/gdb-tests/tests/test_emulate.py +++ b/tests/gdb-tests/tests/test_emulate.py @@ -1,8 +1,8 @@ from __future__ import annotations -import pwndbg.gdblib.regs +import pwndbg.aglib.regs import tests -from pwndbg.gdblib.nearpc import nearpc +from pwndbg.aglib.nearpc import nearpc EMULATE_DISASM_BINARY = tests.binaries.get("emulate_disasm.out") EMULATE_DISASM_LOOP_BINARY = tests.binaries.get("emulate_disasm_loop.out") @@ -53,7 +53,7 @@ def test_emulate_disasm_loop(start_binary): disasm_with_emu_0x400080 = [ " ► 0x400080 <_start> movabs rsi, string RSI => 0x400094 (string) ◂— xor dword ptr [rdx], esi /* '12345' */", - f" 0x40008a <_start+10> mov rdi, rsp RDI => {hex(pwndbg.gdblib.regs.rsp)} ◂— 1", + f" 0x40008a <_start+10> mov rdi, rsp RDI => {hex(pwndbg.aglib.regs.rsp)} ◂— 1", " 0x40008d <_start+13> mov ecx, 3 ECX => 3", " 0x400092 <_start+18> rep movsb byte ptr [rdi], byte ptr [rsi]", " ↓", diff --git a/tests/gdb-tests/tests/test_gdblib_parameter.py b/tests/gdb-tests/tests/test_gdblib_parameter.py index feb8d13f6..2fefd2298 100644 --- a/tests/gdb-tests/tests/test_gdblib_parameter.py +++ b/tests/gdb-tests/tests/test_gdblib_parameter.py @@ -3,7 +3,7 @@ from __future__ import annotations import gdb import pytest -import pwndbg +import pwndbg.dbg import pwndbg.lib.config @@ -73,7 +73,10 @@ def test_gdb_parameter_default_value_works(start_binary, params): ) # Initialize and register param in GDB as if it would be done by gdblib.config.init_params - pwndbg.gdblib.config_mod.Parameter(param) + if pwndbg.dbg.is_gdblib_available(): + from pwndbg.gdblib import config_mod as gdblib_config_mod + + gdblib_config_mod.Parameter(param) out = gdb.execute(f"show {param_name}", to_string=True) assert ( diff --git a/tests/gdb-tests/tests/test_glibc.py b/tests/gdb-tests/tests/test_glibc.py index 9cb5ae6a9..ee0035773 100644 --- a/tests/gdb-tests/tests/test_glibc.py +++ b/tests/gdb-tests/tests/test_glibc.py @@ -7,7 +7,6 @@ import tempfile import gdb import pytest -import pwndbg.gdblib.info import pwndbg.glibc import tests @@ -27,7 +26,7 @@ def test_parsing_info_sharedlibrary_to_find_libc_filename(start_binary, have_deb gdb.execute("break break_here") gdb.execute("continue") if not have_debugging_information: - assert "(*)" in pwndbg.gdblib.info.sharedlibrary() + assert "(*)" in gdb.execute("info sharedlibrary", to_string=True) libc_path = pwndbg.glibc.get_libc_filename_from_info_sharedlibrary() assert libc_path is not None @@ -44,7 +43,7 @@ def test_parsing_info_sharedlibrary_to_find_libc_filename(start_binary, have_deb gdb.execute("continue") # Check if we can find the libc loaded by LD_PRELOAD if not have_debugging_information: - assert "(*)" in pwndbg.gdblib.info.sharedlibrary() + assert "(*)" in gdb.execute("info sharedlibrary", to_string=True) assert pwndbg.glibc.get_libc_filename_from_info_sharedlibrary() == test_libc_path # Unfortunatly, if we used LD_PRELOAD to load libc, we might cannot find the libc's filename diff --git a/tests/gdb-tests/tests/test_hexdump.py b/tests/gdb-tests/tests/test_hexdump.py index f86d1e0e1..5b8bfbba4 100644 --- a/tests/gdb-tests/tests/test_hexdump.py +++ b/tests/gdb-tests/tests/test_hexdump.py @@ -4,9 +4,9 @@ import gdb from pwnlib.util.cyclic import cyclic import pwndbg -import pwndbg.gdblib.memory -import pwndbg.gdblib.regs -import pwndbg.gdblib.vmmap +import pwndbg.aglib.memory +import pwndbg.aglib.regs +import pwndbg.aglib.vmmap import tests BINARY = tests.binaries.get("reference-binary.out") @@ -16,7 +16,7 @@ def run_tests(stack, use_big_endian, expected): pwndbg.config.hexdump_group_use_big_endian = use_big_endian # Put some data onto the stack - pwndbg.gdblib.memory.write(stack, cyclic(0x100)) + pwndbg.aglib.memory.write(stack, cyclic(0x100)) # Test empty hexdump result = gdb.execute("hexdump 0", to_string=True) @@ -39,7 +39,7 @@ def test_hexdump(start_binary): # TODO: Setting theme options with Python isn't working gdb.execute("set hexdump-byte-separator") - stack_addr = pwndbg.gdblib.regs.rsp - 0x100 + stack_addr = pwndbg.aglib.regs.rsp - 0x100 expected = [ f"""+0000 0x{stack_addr:x} 6161616261616161 6161616461616163 │aaaabaaa│caaadaaa│ @@ -62,9 +62,9 @@ def test_hexdump(start_binary): def test_hexdump_collapse_lines(start_binary): start_binary(BINARY) - sp = pwndbg.gdblib.regs.rsp + sp = pwndbg.aglib.regs.rsp - pwndbg.gdblib.memory.write(sp, b"abcdefgh\x01\x02\x03\x04\x05\x06\x07\x08" * 16) + pwndbg.aglib.memory.write(sp, b"abcdefgh\x01\x02\x03\x04\x05\x06\x07\x08" * 16) def hexdump_lines(lines): offset = (lines - 1) * 0x10 # last line offset @@ -88,11 +88,11 @@ def test_hexdump_saved_address_and_offset(start_binary): # TODO There is no way to verify repetition: the last_address and offset are reset # before each command start_binary(BINARY) - sp = pwndbg.gdblib.regs.rsp + sp = pwndbg.aglib.regs.rsp SIZE = 21 - pwndbg.gdblib.memory.write(sp, b"abcdefgh\x01\x02\x03\x04\x05\x06\x07\x08" * 16) + pwndbg.aglib.memory.write(sp, b"abcdefgh\x01\x02\x03\x04\x05\x06\x07\x08" * 16) out1 = gdb.execute(f"hexdump $rsp {SIZE}", to_string=True) out2 = ( diff --git a/tests/gdb-tests/tests/test_memory.py b/tests/gdb-tests/tests/test_memory.py index 77fd3eb63..72aa0cc8a 100644 --- a/tests/gdb-tests/tests/test_memory.py +++ b/tests/gdb-tests/tests/test_memory.py @@ -2,8 +2,9 @@ from __future__ import annotations import gdb -import pwndbg.gdblib.memory -import pwndbg.gdblib.stack +import pwndbg.aglib.memory +import pwndbg.aglib.stack +import pwndbg.dbg import tests REFERENCE_BINARY = tests.binaries.get("reference-binary.out") @@ -15,24 +16,22 @@ def test_memory_read_write(start_binary): Tests simple pwndbg's memory read/write operations with different argument types """ start_binary(REFERENCE_BINARY) - stack_addr = next(iter(pwndbg.gdblib.stack.get().values())).vaddr + stack_addr = next(iter(pwndbg.aglib.stack.get().values())).vaddr # Testing write(addr, str) val = "X" * 50 - pwndbg.gdblib.memory.write(stack_addr, val) - assert pwndbg.gdblib.memory.read(stack_addr, len(val) + 1) == bytearray(b"X" * 50 + b"\x00") + pwndbg.aglib.memory.write(stack_addr, val) + assert pwndbg.aglib.memory.read(stack_addr, len(val) + 1) == bytearray(b"X" * 50 + b"\x00") # Testing write(addr, bytearray) val = bytearray("Y" * 10, "utf8") - pwndbg.gdblib.memory.write(stack_addr, val) - assert pwndbg.gdblib.memory.read(stack_addr, len(val) + 4) == val + bytearray(b"XXXX") + pwndbg.aglib.memory.write(stack_addr, val) + assert pwndbg.aglib.memory.read(stack_addr, len(val) + 4) == val + bytearray(b"XXXX") # Testing write(addr, bytes) val = bytes("Z" * 8, "utf8") - pwndbg.gdblib.memory.write(stack_addr, val) - assert pwndbg.gdblib.memory.read(stack_addr, len(val) + 4) == bytearray( - "Z" * 8 + "YYXX", "utf8" - ) + pwndbg.aglib.memory.write(stack_addr, val) + assert pwndbg.aglib.memory.read(stack_addr, len(val) + 4) == bytearray("Z" * 8 + "YYXX", "utf8") def test_memory_peek_poke(start_binary): @@ -46,23 +45,23 @@ def test_memory_peek_poke(start_binary): # Address 0 is not mapped, so peek should return None # and poke should fail - assert pwndbg.gdblib.memory.poke(0) is False - assert pwndbg.gdblib.memory.peek(0) is None + assert pwndbg.aglib.memory.poke(0) is False + assert pwndbg.aglib.memory.peek(0) is None - stack_addr = pwndbg.gdblib.regs.rsp + stack_addr = pwndbg.aglib.regs.rsp for v in range(256): data = bytearray([v, 0, 0, 0]) - pwndbg.gdblib.memory.write(stack_addr, data) + pwndbg.aglib.memory.write(stack_addr, data) # peek should return the first byte - assert pwndbg.gdblib.memory.peek(stack_addr) == bytearray([v]) + assert pwndbg.aglib.memory.peek(stack_addr) == bytearray([v]) # Now poke it! - assert pwndbg.gdblib.memory.poke(stack_addr) is True + assert pwndbg.aglib.memory.poke(stack_addr) is True # Now make sure poke did not change the underlying bytes - assert pwndbg.gdblib.memory.read(stack_addr, 4) == data + assert pwndbg.aglib.memory.read(stack_addr, 4) == data # TODO/FIXME: Fix peek/poke exception handling and uncomment this! """ @@ -70,23 +69,23 @@ def test_memory_peek_poke(start_binary): # when incorrect argument type is passed for not_parsable_as_int in (b"asdf", "asdf"): with pytest.raises(ValueError): - pwndbg.gdblib.memory.peek(not_parsable_as_int) + pwndbg.aglib.memory.peek(not_parsable_as_int) for not_parsable_as_int in (b"asdf", "asdf"): with pytest.raises(ValueError): - pwndbg.gdblib.memory.poke(not_parsable_as_int) + pwndbg.aglib.memory.poke(not_parsable_as_int) """ # Acceptable inputs (not great; maybe we should ban them?) # Note: they return 0 because the address 0 is not mapped - assert pwndbg.gdblib.memory.peek(0.0) is None - assert pwndbg.gdblib.memory.peek("0") is None - assert pwndbg.gdblib.memory.peek(b"0") is None + assert pwndbg.aglib.memory.peek(0.0) is None + assert pwndbg.aglib.memory.peek("0") is None + assert pwndbg.aglib.memory.peek(b"0") is None def test_fetch_struct_as_dictionary(start_binary): """ - Test pwndbg.gdblib.memory.fetch_struct_as_dictionary() + Test pwndbg.aglib.memory.fetch_struct_as_dictionary() Ensure it can handle nested structs, anonymous structs & nested typedefs. """ start_binary(NESTED_STRUCTS_BINARY) @@ -103,17 +102,17 @@ def test_fetch_struct_as_dictionary(start_binary): "outer_z": 5, } - struct_address = pwndbg.gdblib.symbol.address("outer") + struct_address = pwndbg.dbg.selected_inferior().symbol_address_from_name("outer") assert struct_address is not None - result = pwndbg.gdblib.memory.fetch_struct_as_dictionary("outer_struct", struct_address) + result = pwndbg.aglib.memory.fetch_struct_as_dictionary("outer_struct", struct_address) assert result == expected_result def test_fetch_struct_as_dictionary_include_filter(start_binary): """ - Test pwndbg.gdblib.memory.fetch_struct_as_dictionary() + Test pwndbg.aglib.memory.fetch_struct_as_dictionary() Ensure its include_only_fields filter works. """ start_binary(NESTED_STRUCTS_BINARY) @@ -127,10 +126,10 @@ def test_fetch_struct_as_dictionary_include_filter(start_binary): "anonymous_nested": 100, } - struct_address = pwndbg.gdblib.symbol.address("outer") + struct_address = pwndbg.dbg.selected_inferior().symbol_address_from_name("outer") assert struct_address is not None - result = pwndbg.gdblib.memory.fetch_struct_as_dictionary( + result = pwndbg.aglib.memory.fetch_struct_as_dictionary( "outer_struct", struct_address, include_only_fields={"outer_x", "inner", "anonymous_k", "anonymous_nested"}, @@ -141,7 +140,7 @@ def test_fetch_struct_as_dictionary_include_filter(start_binary): def test_fetch_struct_as_dictionary_exclude_filter(start_binary): """ - Test pwndbg.gdblib.memory.fetch_struct_as_dictionary() + Test pwndbg.aglib.memory.fetch_struct_as_dictionary() Ensure its exclude_fields filter works. Note that the exclude filter cannot filter fields of anonymous structs. """ @@ -156,10 +155,10 @@ def test_fetch_struct_as_dictionary_exclude_filter(start_binary): "anonymous_nested": 100, } - struct_address = pwndbg.gdblib.symbol.address("outer") + struct_address = pwndbg.dbg.selected_inferior().symbol_address_from_name("outer") assert struct_address is not None - result = pwndbg.gdblib.memory.fetch_struct_as_dictionary( + result = pwndbg.aglib.memory.fetch_struct_as_dictionary( "outer_struct", struct_address, exclude_fields={"outer_x", "inner", "outer_z"}, diff --git a/tests/gdb-tests/tests/test_mmap.py b/tests/gdb-tests/tests/test_mmap.py index 9b437c3e9..5bc608436 100644 --- a/tests/gdb-tests/tests/test_mmap.py +++ b/tests/gdb-tests/tests/test_mmap.py @@ -2,7 +2,10 @@ from __future__ import annotations import gdb -import pwndbg +import pwndbg.aglib.arch +import pwndbg.aglib.memory +import pwndbg.aglib.vmmap +import pwndbg.lib.memory import tests USE_FDS_BINARY = tests.binaries.get("use-fds.out") @@ -29,7 +32,7 @@ def test_mmap_executes_properly(start_binary): # Checks whether permissions match. def has_correct_perms(ptr, perm): - page = pwndbg.gdblib.vmmap.find(ptr) + page = pwndbg.aglib.vmmap.find(ptr) return ( not (page.read ^ ("r" in perm)) and not (page.write ^ ("w" in perm)) @@ -46,7 +49,7 @@ def test_mmap_executes_properly(start_binary): # Check basic fixed mapping. base_addr = 0xDEADBEEF & pwndbg.lib.memory.PAGE_MASK while True: - page = pwndbg.gdblib.vmmap.find(base_addr) + page = pwndbg.aglib.vmmap.find(base_addr) if page is None: break base_addr = page.end @@ -75,8 +78,8 @@ def test_mmap_executes_properly(start_binary): # the first 16 bytes present in our newly created memory map, and compare # them. data_ptr = int(gdb.newest_frame().read_var("buf").address) - data_local = pwndbg.gdblib.memory.read(data_ptr, 16) - data_mapped = pwndbg.gdblib.memory.read(ptr, 16) + data_local = pwndbg.aglib.memory.read(data_ptr, 16) + data_mapped = pwndbg.aglib.memory.read(ptr, 16) assert data_local == data_mapped diff --git a/tests/gdb-tests/tests/test_mprotect.py b/tests/gdb-tests/tests/test_mprotect.py index 8c4d1fe03..888c28661 100644 --- a/tests/gdb-tests/tests/test_mprotect.py +++ b/tests/gdb-tests/tests/test_mprotect.py @@ -2,7 +2,8 @@ from __future__ import annotations import gdb -import pwndbg +import pwndbg.aglib.regs +import pwndbg.aglib.vmmap import tests SMALL_BINARY = tests.binaries.get("crash_simple.out.hardcoded") @@ -14,18 +15,18 @@ def test_mprotect_executes_properly(start_binary): """ start_binary(SMALL_BINARY) - pc = pwndbg.gdblib.regs.pc + pc = pwndbg.aglib.regs.pc # Check if we can use mprotect with address provided as value # and to set page permissions to RWX gdb.execute("mprotect %d 4096 PROT_EXEC|PROT_READ|PROT_WRITE" % pc) - vm = pwndbg.gdblib.vmmap.find(pc) + vm = pwndbg.aglib.vmmap.find(pc) assert vm.read and vm.write and vm.execute # Check if we can use mprotect with address provided as register # and to set page permissions to none gdb.execute("mprotect $pc 0x1000 PROT_NONE") - vm = pwndbg.gdblib.vmmap.find(pc) + vm = pwndbg.aglib.vmmap.find(pc) assert not (vm.read and vm.write and vm.execute) diff --git a/tests/gdb-tests/tests/test_prompt_recolor.py b/tests/gdb-tests/tests/test_prompt_recolor.py index 0dfcb7c9c..8ba002fa6 100644 --- a/tests/gdb-tests/tests/test_prompt_recolor.py +++ b/tests/gdb-tests/tests/test_prompt_recolor.py @@ -2,9 +2,7 @@ from __future__ import annotations import gdb -import pwndbg import pwndbg.color.message -import pwndbg.gdblib.proc import tests BINARY = tests.binaries.get("reference-binary.out") diff --git a/tests/gdb-tests/tests/test_symbol.py b/tests/gdb-tests/tests/test_symbol.py index 1dd7d47f2..7794ffe6c 100644 --- a/tests/gdb-tests/tests/test_symbol.py +++ b/tests/gdb-tests/tests/test_symbol.py @@ -2,7 +2,7 @@ from __future__ import annotations import gdb -import pwndbg +import pwndbg.dbg import tests MANGLING_BINARY = tests.binaries.get("symbol_1600_and_752.out") @@ -20,7 +20,7 @@ def test_symbol_get(start_binary): # (we pass `to_string=True` to suppress the context output) gdb.execute("nextret", to_string=True) p = int(gdb.parse_and_eval("p")) - return pwndbg.gdblib.symbol.get(p) + return pwndbg.dbg.selected_inferior().symbol_name_at_address(p) assert get_next_ptr() == "main" @@ -42,7 +42,7 @@ def test_symbol_duplicated_symbols_issue_1610(): # Sanity checks assert gdb.execute("info symbol main", to_string=True) == "main in section .text\n" - assert pwndbg.gdblib.symbol.get(main_addr) == "main" + assert pwndbg.dbg.selected_inferior().symbol_name_at_address(main_addr) == "main" # This causes some confusion, see below :) # Note: {addr} argument is needed for old GDB (e.g. on Ubuntu 18.04) @@ -60,10 +60,13 @@ def test_symbol_duplicated_symbols_issue_1610(): assert out[2] == "" # Make sure to clear cache! - pwndbg.gdblib.symbol.get.cache.clear() + if pwndbg.dbg.is_gdblib_available(): + from pwndbg.gdblib.symbol import get as symbol_get + + symbol_get.cache.clear() # Real test assert - this should not crash! - assert pwndbg.gdblib.symbol.get(main_addr) == "main" + assert pwndbg.dbg.selected_inferior().symbol_name_at_address(main_addr) == "main" def _get_section_addr(sect): diff --git a/tests/gdb-tests/tests/test_windbg.py b/tests/gdb-tests/tests/test_windbg.py index 6b4fa89a1..4d2642264 100644 --- a/tests/gdb-tests/tests/test_windbg.py +++ b/tests/gdb-tests/tests/test_windbg.py @@ -2,7 +2,9 @@ from __future__ import annotations import gdb -import pwndbg +import pwndbg.aglib.memory +import pwndbg.aglib.regs +import pwndbg.aglib.vmmap import tests MEMORY_BINARY = tests.binaries.get("memory.out") @@ -287,8 +289,8 @@ def test_windbg_eX_commands(start_binary): ### Test write & output on partial write ######################################### # e.g. when we make a write to the last stack address - stack_ea = pwndbg.gdblib.regs[pwndbg.gdblib.regs.stack] - stack_page = pwndbg.gdblib.vmmap.find(stack_ea) + stack_ea = pwndbg.aglib.regs[pwndbg.aglib.regs.stack] + stack_page = pwndbg.aglib.vmmap.find(stack_ea) # Last possible address on stack where we can perform an 8-byte write stack_last_qword_ea = stack_page.end - 8 @@ -300,7 +302,7 @@ def test_windbg_eX_commands(start_binary): assert gdb_result[1] == "(Made 1 writes to memory; skipping further writes)" # Check if the write actually occurred - assert pwndbg.gdblib.memory.read(stack_last_qword_ea, 8) == b"\xef\xbe\xad\xde\xbe\xba\xfe\xca" + assert pwndbg.aglib.memory.read(stack_last_qword_ea, 8) == b"\xef\xbe\xad\xde\xbe\xba\xfe\xca" def test_windbg_commands_x86(start_binary): @@ -311,59 +313,57 @@ def test_windbg_commands_x86(start_binary): start_binary(X86_BINARY) # Prepare memory - pwndbg.gdblib.memory.write(pwndbg.gdblib.regs.esp, b"1234567890abcdef_") - pwndbg.gdblib.memory.write(pwndbg.gdblib.regs.esp + 16, b"\x00" * 16) - pwndbg.gdblib.memory.write(pwndbg.gdblib.regs.esp + 32, bytes(range(16))) - pwndbg.gdblib.memory.write(pwndbg.gdblib.regs.esp + 48, b"Z" * 16) + pwndbg.aglib.memory.write(pwndbg.aglib.regs.esp, b"1234567890abcdef_") + pwndbg.aglib.memory.write(pwndbg.aglib.regs.esp + 16, b"\x00" * 16) + pwndbg.aglib.memory.write(pwndbg.aglib.regs.esp + 32, bytes(range(16))) + pwndbg.aglib.memory.write(pwndbg.aglib.regs.esp + 48, b"Z" * 16) ################################################# #### dX command tests ################################################# db = gdb.execute("db $esp", to_string=True).splitlines() assert db == [ - "%x 31 32 33 34 35 36 37 38 39 30 61 62 63 64 65 66" % pwndbg.gdblib.regs.esp, - "%x 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" % (pwndbg.gdblib.regs.esp + 16), - "%x 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" % (pwndbg.gdblib.regs.esp + 32), - "%x 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a" % (pwndbg.gdblib.regs.esp + 48), + "%x 31 32 33 34 35 36 37 38 39 30 61 62 63 64 65 66" % pwndbg.aglib.regs.esp, + "%x 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" % (pwndbg.aglib.regs.esp + 16), + "%x 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" % (pwndbg.aglib.regs.esp + 32), + "%x 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a" % (pwndbg.aglib.regs.esp + 48), ] dw = gdb.execute("dw $esp", to_string=True).splitlines() assert dw == [ - "%x 3231 3433 3635 3837 3039 6261 6463 6665" % pwndbg.gdblib.regs.esp, - "%x 0000 0000 0000 0000 0000 0000 0000 0000" % (pwndbg.gdblib.regs.esp + 16), - "%x 0100 0302 0504 0706 0908 0b0a 0d0c 0f0e" % (pwndbg.gdblib.regs.esp + 32), - "%x 5a5a 5a5a 5a5a 5a5a 5a5a 5a5a 5a5a 5a5a" % (pwndbg.gdblib.regs.esp + 48), + "%x 3231 3433 3635 3837 3039 6261 6463 6665" % pwndbg.aglib.regs.esp, + "%x 0000 0000 0000 0000 0000 0000 0000 0000" % (pwndbg.aglib.regs.esp + 16), + "%x 0100 0302 0504 0706 0908 0b0a 0d0c 0f0e" % (pwndbg.aglib.regs.esp + 32), + "%x 5a5a 5a5a 5a5a 5a5a 5a5a 5a5a 5a5a 5a5a" % (pwndbg.aglib.regs.esp + 48), ] dd = gdb.execute("dd $esp", to_string=True).splitlines() assert dd == [ - "%x 34333231 38373635 62613039 66656463" % pwndbg.gdblib.regs.esp, - "%x 00000000 00000000 00000000 00000000" % (pwndbg.gdblib.regs.esp + 16), - "%x 03020100 07060504 0b0a0908 0f0e0d0c" % (pwndbg.gdblib.regs.esp + 32), - "%x 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a" % (pwndbg.gdblib.regs.esp + 48), + "%x 34333231 38373635 62613039 66656463" % pwndbg.aglib.regs.esp, + "%x 00000000 00000000 00000000 00000000" % (pwndbg.aglib.regs.esp + 16), + "%x 03020100 07060504 0b0a0908 0f0e0d0c" % (pwndbg.aglib.regs.esp + 32), + "%x 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a" % (pwndbg.aglib.regs.esp + 48), ] dq = gdb.execute("dq $esp", to_string=True).splitlines() assert dq == [ - "%x 3837363534333231 6665646362613039" % pwndbg.gdblib.regs.esp, - "%x 0000000000000000 0000000000000000" % (pwndbg.gdblib.regs.esp + 16), - "%x 0706050403020100 0f0e0d0c0b0a0908" % (pwndbg.gdblib.regs.esp + 32), - "%x 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a" % (pwndbg.gdblib.regs.esp + 48), + "%x 3837363534333231 6665646362613039" % pwndbg.aglib.regs.esp, + "%x 0000000000000000 0000000000000000" % (pwndbg.aglib.regs.esp + 16), + "%x 0706050403020100 0f0e0d0c0b0a0908" % (pwndbg.aglib.regs.esp + 32), + "%x 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a" % (pwndbg.aglib.regs.esp + 48), ] ################################################# #### eX command tests ################################################# gdb.execute("eb $esp 00") - assert pwndbg.gdblib.memory.read(pwndbg.gdblib.regs.esp, 1) == b"\x00" + assert pwndbg.aglib.memory.read(pwndbg.aglib.regs.esp, 1) == b"\x00" gdb.execute("ew $esp 4141") - assert pwndbg.gdblib.memory.read(pwndbg.gdblib.regs.esp, 2) == b"\x41\x41" + assert pwndbg.aglib.memory.read(pwndbg.aglib.regs.esp, 2) == b"\x41\x41" gdb.execute("ed $esp 5252525252") - assert pwndbg.gdblib.memory.read(pwndbg.gdblib.regs.esp, 4) == b"\x52" * 4 + assert pwndbg.aglib.memory.read(pwndbg.aglib.regs.esp, 4) == b"\x52" * 4 gdb.execute("eq $esp 1122334455667788") - assert ( - pwndbg.gdblib.memory.read(pwndbg.gdblib.regs.esp, 8) == b"\x88\x77\x66\x55\x44\x33\x22\x11" - ) + assert pwndbg.aglib.memory.read(pwndbg.aglib.regs.esp, 8) == b"\x88\x77\x66\x55\x44\x33\x22\x11" diff --git a/tests/qemu-tests/tests/system/__init__.py b/tests/qemu-tests/tests/system/__init__.py new file mode 100644 index 000000000..9d48db4f9 --- /dev/null +++ b/tests/qemu-tests/tests/system/__init__.py @@ -0,0 +1 @@ +from __future__ import annotations diff --git a/tests/qemu-tests/tests/system/test_callstack.py b/tests/qemu-tests/tests/system/test_callstack.py index 3efdebed1..2d52ab33f 100644 --- a/tests/qemu-tests/tests/system/test_callstack.py +++ b/tests/qemu-tests/tests/system/test_callstack.py @@ -1,11 +1,11 @@ from __future__ import annotations -import pwndbg.gdblib.memory -import pwndbg.gdblib.stack +import pwndbg.aglib.memory +import pwndbg.aglib.stack def test_callstack_readable(): - addresses = pwndbg.gdblib.stack.callstack() + addresses = pwndbg.aglib.stack.callstack() assert len(addresses) > 0 - assert all(pwndbg.gdblib.memory.is_readable_address(address) for address in addresses) + assert all(pwndbg.aglib.memory.is_readable_address(address) for address in addresses) diff --git a/tests/qemu-tests/tests/system/test_commands_kernel.py b/tests/qemu-tests/tests/system/test_commands_kernel.py index f63c8089e..ed8b034e4 100644 --- a/tests/qemu-tests/tests/system/test_commands_kernel.py +++ b/tests/qemu-tests/tests/system/test_commands_kernel.py @@ -2,7 +2,11 @@ from __future__ import annotations import gdb -import pwndbg +import pwndbg.dbg + +if pwndbg.dbg.is_gdblib_available(): + import pwndbg.gdblib.kernel + import pwndbg.gdblib.kernel.slab def test_command_kchecksec(): diff --git a/tests/qemu-tests/tests/system/test_gdblib_kernel.py b/tests/qemu-tests/tests/system/test_gdblib_kernel.py index 5f5900aa0..8f6bfd45d 100644 --- a/tests/qemu-tests/tests/system/test_gdblib_kernel.py +++ b/tests/qemu-tests/tests/system/test_gdblib_kernel.py @@ -4,21 +4,29 @@ import os import pytest -import pwndbg -from pwndbg.gdblib import kernel +import pwndbg.dbg + +is_gdblib = pwndbg.dbg.is_gdblib_available() +if is_gdblib: + import pwndbg.gdblib.kernel + import pwndbg.gdblib.kernel.kallsyms + import pwndbg.gdblib.symbol ARCH = os.getenv("PWNDBG_ARCH") KERNEL_TYPE = os.getenv("PWNDBG_KERNEL_TYPE") KERNEL_VERSION = os.getenv("PWNDBG_KERNEL_VERSION") -@pytest.mark.skipif(not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols") +@pytest.mark.skipif( + is_gdblib and not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols" +) def test_gdblib_kernel_archops_address_translation(): # test address translation functions for LowMem min_low_pfn = int(pwndbg.gdblib.symbol.parse_and_eval("(long)min_low_pfn")) max_low_pfn = int(pwndbg.gdblib.symbol.parse_and_eval("(long)max_low_pfn")) pfns = [min_low_pfn, max_low_pfn] + kernel = pwndbg.gdblib.kernel for pfn in pfns: assert kernel.virt_to_pfn(kernel.pfn_to_virt(pfn)) == pfn assert kernel.phys_to_pfn(kernel.pfn_to_phys(pfn)) == pfn @@ -30,7 +38,9 @@ def test_gdblib_kernel_archops_address_translation(): assert kernel.page_to_phys(kernel.phys_to_page(phys)) == phys -@pytest.mark.skipif(not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols") +@pytest.mark.skipif( + is_gdblib and not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols" +) def test_gdblib_kernel_krelease(): release_ver = pwndbg.gdblib.kernel.krelease() # release should be int tuple of form (major, minor, patch) or (major, minor) @@ -39,18 +49,24 @@ def test_gdblib_kernel_krelease(): assert release_str in pwndbg.gdblib.kernel.kversion() -@pytest.mark.skipif(not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols") +@pytest.mark.skipif( + is_gdblib and not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols" +) def test_gdblib_kernel_is_kaslr_enabled(): pwndbg.gdblib.kernel.is_kaslr_enabled() -@pytest.mark.skipif(not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols") +@pytest.mark.skipif( + is_gdblib and not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols" +) def test_gdblib_kernel_nproc(): # make sure no exception occurs pwndbg.gdblib.kernel.nproc() -@pytest.mark.skipif(not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols") +@pytest.mark.skipif( + is_gdblib and not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols" +) def test_gdblib_kernel_kbase(): # newer arm/arm64 kernels reserve (_stext, _end] and other kernels reserve [_text, _end) # https://elixir.bootlin.com/linux/v6.8.4/source/arch/arm64/mm/init.c#L306 @@ -60,7 +76,9 @@ def test_gdblib_kernel_kbase(): ) -@pytest.mark.skipif(not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols") +@pytest.mark.skipif( + is_gdblib and not pwndbg.gdblib.kernel.has_debug_syms(), reason="test requires debug symbols" +) def test_gdblib_kernel_kallsyms(): ks = pwndbg.gdblib.kernel.kallsyms.get() assert ks["commit_creds"][0] == pwndbg.gdblib.symbol.address("commit_creds") diff --git a/tests/qemu-tests/tests/user/test_aarch64.py b/tests/qemu-tests/tests/user/test_aarch64.py index 8c9f3dd01..94251b2fd 100644 --- a/tests/qemu-tests/tests/user/test_aarch64.py +++ b/tests/qemu-tests/tests/user/test_aarch64.py @@ -5,8 +5,8 @@ import user from capstone.arm64_const import ARM64_INS_BL import pwndbg.aglib.disasm -import pwndbg.gdblib.nearpc -import pwndbg.gdblib.symbol +import pwndbg.aglib.nearpc +import pwndbg.dbg from pwndbg.aglib.disasm.instruction import InstructionCondition AARCH64_GRACEFUL_EXIT = """ @@ -89,7 +89,7 @@ def test_aarch64_syscall_annotation(qemu_assembly_run): qemu_assembly_run(AARCH64_GRACEFUL_EXIT, "aarch64") instructions = pwndbg.aglib.disasm.near( - address=pwndbg.gdblib.regs.pc, instructions=3, emulate=True + address=pwndbg.aglib.regs.pc, instructions=3, emulate=True )[0] future_syscall_ins = instructions[2] @@ -436,7 +436,7 @@ REFERENCE_BINARY = user.binaries.get("reference-binary.aarch64.out") def test_aarch64_reference(qemu_start_binary): qemu_start_binary(REFERENCE_BINARY, "aarch64") gdb.execute("break break_here") - assert pwndbg.gdblib.symbol.address("main") is not None + assert pwndbg.dbg.selected_inferior().symbol_address_from_name("main") is not None gdb.execute("continue") gdb.execute("argv", to_string=True) diff --git a/tests/qemu-tests/tests/user/test_arm.py b/tests/qemu-tests/tests/user/test_arm.py index 21bee3b6d..63f20ef86 100644 --- a/tests/qemu-tests/tests/user/test_arm.py +++ b/tests/qemu-tests/tests/user/test_arm.py @@ -2,7 +2,7 @@ from __future__ import annotations import gdb -import pwndbg +import pwndbg.color ARM_GRACEFUL_EXIT = """ mov r0, 0 diff --git a/tests/qemu-tests/tests/user/test_mips.py b/tests/qemu-tests/tests/user/test_mips.py index bfef54b58..026ca87dd 100644 --- a/tests/qemu-tests/tests/user/test_mips.py +++ b/tests/qemu-tests/tests/user/test_mips.py @@ -2,7 +2,7 @@ from __future__ import annotations import gdb -import pwndbg +import pwndbg.color MIPS_GRACEFUL_EXIT = """ li $v0, 0xfa1 diff --git a/tests/qemu-tests/tests/user/test_riscv64.py b/tests/qemu-tests/tests/user/test_riscv64.py index 46f9c38b1..f67af6166 100644 --- a/tests/qemu-tests/tests/user/test_riscv64.py +++ b/tests/qemu-tests/tests/user/test_riscv64.py @@ -3,7 +3,8 @@ from __future__ import annotations import gdb import user -import pwndbg.gdblib.symbol +import pwndbg.color +import pwndbg.dbg RISCV64_GRACEFUL_EXIT = """ li a2, 30 @@ -296,7 +297,7 @@ REFERENCE_BINARY = user.binaries.get("reference-binary.riscv64.out") def test_riscv64_reference(qemu_start_binary): qemu_start_binary(REFERENCE_BINARY, "riscv64") gdb.execute("break 4") - assert pwndbg.gdblib.symbol.address("main") is not None + assert pwndbg.dbg.selected_inferior().symbol_address_from_name("main") is not None gdb.execute("continue") gdb.execute("stepuntilasm jalr") diff --git a/tests/tests.py b/tests/tests.py index cd6f8d977..222e199d5 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -3,11 +3,11 @@ from __future__ import annotations import argparse import concurrent.futures import os -import random import re import subprocess import sys import time +from pathlib import Path from subprocess import CompletedProcess from typing import List from typing import Tuple @@ -15,7 +15,56 @@ from typing import Tuple root_dir = os.path.realpath("../") -def ensureZigPath(): +def reserve_port(ip="127.0.0.1", port=0): + """ + https://github.com/Yelp/ephemeral-port-reserve/blob/master/ephemeral_port_reserve.py + + Bind to an ephemeral port, force it into the TIME_WAIT state, and unbind it. + + This means that further ephemeral port alloctions won't pick this "reserved" port, + but subprocesses can still bind to it explicitly, given that they use SO_REUSEADDR. + By default on linux you have a grace period of 60 seconds to reuse this port. + To check your own particular value: + $ cat /proc/sys/net/ipv4/tcp_fin_timeout + 60 + + By default, the port will be reserved for localhost (aka 127.0.0.1). + To reserve a port for a different ip, provide the ip as the first argument. + Note that IP 0.0.0.0 is interpreted as localhost. + """ + import contextlib + import errno + from socket import SO_REUSEADDR + from socket import SOL_SOCKET + from socket import error as SocketError + from socket import socket + + port = int(port) + with contextlib.closing(socket()) as s: + s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) + try: + s.bind((ip, port)) + except SocketError as e: + # socket.error: EADDRINUSE Address already in use + if e.errno == errno.EADDRINUSE and port != 0: + s.bind((ip, 0)) + else: + raise + + # the connect below deadlocks on kernel >= 4.4.0 unless this arg is greater than zero + s.listen(1) + + sockname = s.getsockname() + + # these three are necessary just to get the port into a TIME_WAIT state + with contextlib.closing(socket()) as s2: + s2.connect(sockname) + sock, _ = s.accept() + with contextlib.closing(sock): + return sockname[1] + + +def ensure_zig_path(): if "ZIGPATH" not in os.environ: # If ZIGPATH is not set, set it to $pwd/.zig # In Docker environment this should by default be set to /opt/zig @@ -23,41 +72,17 @@ def ensureZigPath(): print(f'ZIGPATH set to {os.environ["ZIGPATH"]}') -def makeBinaries(): - try: - subprocess.check_call(["make", "all"], cwd="./gdb-tests/tests/binaries") - except subprocess.CalledProcessError: - exit(1) - +def make_binaries(test_dir: str): + dir_binaries = Path(test_dir) / "binaries" + if not dir_binaries.exists(): + return -def makeCrossArchBinaries(): try: - subprocess.check_call(["make", "all"], cwd="./qemu-tests/tests/user/binaries") + subprocess.check_call(["make", "all"], cwd=str(dir_binaries)) except subprocess.CalledProcessError: exit(1) -def open_ports(n: int) -> List[int]: - """ - Returns a list of `n` open ports - """ - try: - result = subprocess.run( - ["netstat", "-tuln"], stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - if result.returncode != 0: - # If netstat not found, try ss - raise FileNotFoundError - except FileNotFoundError: - result = subprocess.run(["ss", "-tuln"], stdout=subprocess.PIPE) - - used_ports = set(re.findall(r":(\d+)", result.stdout.decode())) - used_ports = set(map(int, used_ports)) - - available_ports = [port for port in range(1024, 65536) if port not in used_ports] - return random.sample(available_ports, n) - - def run_gdb( gdb_binary: str, gdb_args: List[str], env=None, capture_output=True ) -> CompletedProcess[str]: @@ -70,7 +95,7 @@ def run_gdb( ) -def getTestsList( +def get_tests_list( collect_only: bool, test_name_filter: str, gdb_binary: str, @@ -174,12 +199,9 @@ def run_tests_and_print_stats( test_results: List[Tuple[CompletedProcess[str], str]] = [] stats = TestStats() - port_iterator = iter(ports) - if args.serial: test_results = [ - run_test(test, args, gdb_binary, gdbinit_path, next(port_iterator, None)) - for test in tests_list + run_test(test, args, gdb_binary, gdbinit_path, reserve_port()) for test in tests_list ] else: print("") @@ -187,7 +209,7 @@ def run_tests_and_print_stats( with concurrent.futures.ThreadPoolExecutor(max_workers=os.cpu_count()) as executor: for test in tests_list: executor.submit( - run_test, test, args, gdb_binary, gdbinit_path, next(port_iterator, None) + run_test, test, args, gdb_binary, gdbinit_path, reserve_port() ).add_done_callback( lambda future: stats.handle_test_result(future.result(), args, test_dir_path) ) @@ -253,9 +275,13 @@ def parse_args(): return parser.parse_args() -TEST_FOLDER_NAME = {"gdb": "gdb-tests/tests", "cross-arch": "qemu-tests/tests/user"} +TEST_FOLDER_NAME = { + "gdb": "gdb-tests/tests", + "cross-arch": "qemu-tests/tests/user", +} -if __name__ == "__main__": + +def main(): args = parse_args() if args.cov: print("Will run codecov") @@ -271,18 +297,23 @@ if __name__ == "__main__": else: gdbinit_path = os.path.join(root_dir, "gdbinit.py") - gdb_binary = "gdb" + test_dir_path = TEST_FOLDER_NAME[args.type] if args.type == "gdb": - ensureZigPath() - makeBinaries() - else: - makeCrossArchBinaries() + gdb_binary = "gdb" + ensure_zig_path() + make_binaries(test_dir_path) + elif args.type == "cross-arch": gdb_binary = "gdb-multiarch" + make_binaries(test_dir_path) + else: + raise NotImplementedError(args.type) - test_dir_path = TEST_FOLDER_NAME[args.type] - tests_list = getTestsList( + tests_list = get_tests_list( args.collect_only, args.test_name_filter, gdb_binary, gdbinit_path, test_dir_path ) - ports = open_ports(len(tests_list)) - run_tests_and_print_stats(tests_list, args, gdb_binary, gdbinit_path, test_dir_path, ports) + run_tests_and_print_stats(tests_list, args, gdb_binary, gdbinit_path, test_dir_path) + + +if __name__ == "__main__": + main()