From 9427727485204fac664eec8149ad51e0d15c28ff Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Thu, 20 Oct 2022 10:15:48 -0700 Subject: [PATCH] Update developer docs (#1303) --- DEVELOPING.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/DEVELOPING.md b/DEVELOPING.md index 1afa129da..827e6656c 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -1,3 +1,64 @@ +# Environment setup + +After installing `pwndbg` by running `setup.sh`, you additionally need to run `./setup-test-tools.sh` to install the necessary development dependencies. + +If you would like to use Docker, you can create a Docker image with everything already installed for you. To do this, run the following command: +```bash +docker run -it --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -v `pwd`:/pwndbg pwndbg bash +``` + +If you'd like to use `docker compose`, you can run +```bash +docker compose run -i main +``` + +# Testing + +It's highly recommended you write a new test or update an existing test whenever adding new functionality to `pwndbg`. + +Tests are located in [`tests/gdb-tests`](tests/gdb-tests). `tests/unit-tests` also exists, but the unit testing framework is not complete and so it should not be used. + +To run the tests, run [`./tests.sh`](./tests.sh). You can filter the tests to run by providing an argument to the script, such as `./tests.sh heap`, which will only run tests that contain "heap" in the name. You can also drop into the PDB debugger when a test fails with `./tests.sh --pdb`. + +Our tests are written using [`pytest`](https://docs.pytest.org/en/latest/). It uses some magic so that Python's `assert` can be used for asserting things in tests and it injects dependencies which are called fixtures, into test functions. These fixtures are defined in [`tests/conftest.py`](tests/conftest.py). + +We can take a look at [`tests/gdb-tests/tests/test_hexdump.py`](tests/gdb-tests/tests/test_hexdump.py) for an example of a simple test. Looking at a simplified version of the top-level code, we have this: +```python +import gdb +import tests + +BINARY = tests.binaries.get("reference-binary.out") +``` + +Since these tests run inside GDB, we can import the `gdb` Python library. We also import the `tests` module, which makes it easy to get the path to the test binaries located in [`tests/gdb-tests/tests/binaries`](tests/gdb-tests/tests/binaries). You should be able to reuse the binaries in this folder for most tests, but if not feel free to add a new one. + +Here's a small snippet of the actual test: +```python +def test_hexdump(start_binary): + start_binary(BINARY) + pwndbg.gdblib.config.hexdump_group_width = -1 + + gdb.execute("set hexdump-byte-separator") + stack_addr = pwndbg.gdblib.regs.rsp - 0x100 +``` + +`pytest` will run any function that starts with `test_` as a new test, so there is no need to register your new test anywhere. The `start_binary` argument is a function that will run the binary you give it, and it will set some common options before starting the binary. Using `start_binary` is recommended if you don't need any additional customization to GDB settings before starting the binary, but if you do it's fine to not use it. + +Note that in the test, we can access `pwndbg` library code like `pwndbg.gdblib.regs.rsp` as well as execute GDB commands with `gdb.execute()`. + +# Linting + +The `lint.sh` script runs `isort`, `black`, `flake8`, and `shfmt`. `isort` and `black` are able to automatically fix any issues they detect, and you can enable this by running `./lint.sh -f`. You can find the configuration files for these tools in `setup.cfg` and `pyproject.toml`. + +When submitting a PR, the CI job defined in `.github/workflows/lint.yml` will verify that running `./lint.sh` succeeds, otherwise the job will fail and we won't be able to merge your PR. + +You can optionally set the contents of `.git/hooks/pre-push` to the following if you would like `lint.sh` to automatically be run before every push: +```bash +#!/bin/sh + +./lint.sh || exit 1 +``` + # Random developer notes Feel free to update the list below! @@ -29,9 +90,3 @@ Feel free to update the list below! * Some of pwndbg's functionality - e.g. memory fetching - require us to have an instance of proper `gdb.Type` - the problem with that is that there is no way to define our own types - we have to ask gdb if it detected particular type in this particular binary (that sucks). We do it in `pwndbg/typeinfo.py` and it works most of the time. The known bug with that is that it might not work properly for Golang binaries compiled with debugging symbols. * We would like to add proper tests for pwndbg - see tests framework PR if you want to help on that. - -# Testing - -Our tests are written using [pytest](https://docs.pytest.org/en/latest/). It uses some magic so that Python's `assert` can be used for asserting things in tests and it injects dependencies which are called fixtures, into test functions. - -The fixtures should be defined in [tests/conftest.py](tests/conftest.py). If you need help with writing tests, feel free to reach out on gitub issues/pr or on our irc channel on freenode.