Skip to content

Commit

Permalink
Merge branch 'main' into hugsy/lint-fmt
Browse files Browse the repository at this point in the history
  • Loading branch information
hugsy authored Nov 2, 2024
2 parents 741ce7c + 5376d78 commit 854912b
Show file tree
Hide file tree
Showing 13 changed files with 138 additions and 73 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
strategy:
fail-fast: false
matrix:
runner: [ubuntu-24.04, ubuntu-22.04, ubuntu-20.04]
runner: [ubuntu-24.04, ubuntu-22.04]

name: "Run Unit tests on ${{ matrix.runner }}"
runs-on: ${{ matrix.runner }}
Expand Down
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ persistent=yes

# Minimum Python version to use for version dependent checks. Will default to
# the version used to run pylint.
py-version=3.6
py-version=3.10

# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
Expand Down
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.10.14
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ from the debugging runtime.

## Instant Setup

Simply make sure you have [GDB 8.0 or higher](https://www.gnu.org/s/gdb) compiled with Python3.6+
Simply make sure you have [GDB 10.0 or higher](https://www.gnu.org/s/gdb) compiled with Python3.10+
bindings, then:

```bash
Expand Down
24 changes: 0 additions & 24 deletions docs/commands/ksymaddr.md

This file was deleted.

20 changes: 15 additions & 5 deletions docs/commands/vmmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,23 @@ differs from one architecture to another (this is one of the main reasons I star
place). For example, you can learn that ELF running on SPARC architectures always have their `.data`
and `heap` sections set as Read/Write/Execute.

`vmmap` accepts one argument, either a pattern to match again mapping names, or an address to
determine which section it belongs to.
`vmmap` can accept multiple arguments, either patterns to match again mapping names, or addresses
to determine which section it belongs to:

![vmmap-grep](https://i.imgur.com/ZFF4QVf.png)
1. `-a` / `--addr`:
- filter by address -> parses the next argument as an integer or asks gdb to interpret the value
2. `-n` / `--name`:
- filter based on section name
3. If nothing is specified, it prints a warning and guesses the type

![vmmap-address](https://i.imgur.com/hfcs1jH.png)
![vmmap-grep](https://github.com/hugsy/gef/assets/11377623/a3dbaa3e-88b0-407f-a0dd-07e65c4a3f73)

![vmmap-address](https://github.com/hugsy/gef/assets/11377623/4dffe491-f927-4f03-b842-4d941140e66c)

The address can be also be given in the form of a register or variable.

![vmmap-register](https://i.imgur.com/RlZA6NU.png)
![vmmap-register](https://github.com/hugsy/gef/assets/11377623/aed7ecdc-7ad9-4ba5-ae03-329e66432731)

And you can do all of them in one command 🙂

![vmmap-all-in-one](https://github.com/hugsy/gef/assets/11377623/b043f61b-48b3-4316-9f84-eb83822149ac)
8 changes: 3 additions & 5 deletions docs/compat.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

This matrix indicates the version of Python and/or GDB

| GEF version | GDB Python compatibility* | Python compatibility** |
| GEF version | GDB Python compatibility | Python compatibility |
|:--:|:--:|:--:|
| [2018.02](https://github.com/hugsy/gef/releases/tag/2018.02) | 7.2 | Python 2.7, Python 3.4+ |
| [2020.03](https://github.com/hugsy/gef/releases/tag/2020.03) | 7.4 | Python 2.7, Python 3.4+ |
| [2022.01](https://github.com/hugsy/gef/releases/tag/2021.01) | 7.7 | Python 3.4+ |
| [Current](https://github.com/hugsy/gef/tree/main) | 8.0+ | Python 3.6+ |

** Up to (included)
| [2022.01](https://github.com/hugsy/gef/releases/tag/2022.01) | 8.0 | Python 3.6+ |
| [2024.09](https://github.com/hugsy/gef/releases/tag/2024.09) | 10.0 | Python 3.10+ |
16 changes: 8 additions & 8 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ new architectures very easily as well!
Also, PEDA development has been quite idle for a few years now, and many new interesting features a
debugger can provide simply do not exist.

## What if my GDB is < 8.0 ?
## What if my GDB is < 10.0 ?

GDB was introduced with its Python support early 2011 with the release of GDB 7. A (very) long way
has gone since and the Python API has been massively improved, and GEF is taking advantage of them
to provide the coolest features with as little performance impact as possible.

Currently, GEF is optimized for running against GDB version 8.0+, and Python 3.6+. This allows for a
best performance and best use of the GDB Python API. However, GEF can run on older versions too,
Currently, GEF is optimized for running against GDB version 10.0+, and Python 3.10+. This allows for
the best performance and use of the GDB Python API. However, GEF can run on older versions too,
check out [the version compatibility matrix](compat.md). For really older versions of GDB, you can
use [`gef-legacy`](https://github.com/hugsy/gef-legacy) which supports a lot of older GDB, and a
Python 2/3 compatibility layer.

Therefore, it is highly recommended to run GEF with the latest version of GDB. However, all
functions should work on a GDB 8.0 and up. If not, send a [bug
report](https://github.com/hugsy/gef/issues) and provide as much details as possible.
functions should work on a GDB 10.0 and up. If not, send a [bug
report](https://github.com/hugsy/gef/issues) and provide as many details as possible.

If you are running an obsolete version, GEF will show a error and message and exit.

Expand All @@ -36,7 +36,7 @@ Some pre-compiled static binaries for both recent GDB and GDBServer can be downl

## I cannot get GEF setup

GEF will work on any GDB 8+ compiled with Python 3.6+ support. You can view that commands that
GEF will work on any GDB 10+ compiled with Python 3.10+ support. You can view that commands that
failed to load using `gef missing`, but this will not affect GEF generally.

If you experience problems setting it up on your host, first go to the [Discord
Expand All @@ -45,8 +45,8 @@ channel](https://discord.gg/HCS8Hg7) for that. You will find great people there
Note that the GitHub issue section is to be used to **report bugs** and **GEF issues** (like
unexpected crash, improper error handling, weird edge case, etc.), not a place to ask for help.

All recent distributions ship packaged GDB that should be ready-to-go, with a GDB >= 8.0 and Python
3.6+. Any version higher or equal will work just fine. So you might actually only need to run `apt
All recent distributions ship packaged GDB that should be ready-to-go, with GDB >= 10.0 and Python
3.10+. Any version higher or equal will work just fine. So you might actually only need to run `apt
install gdb` to get the full-force of GEF.

## I get a SegFault when starting GDB with GEF
Expand Down
7 changes: 3 additions & 4 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ your OS package manager to install them.

### GDB

Only [GDB 8 and higher](https://www.gnu.org/s/gdb) is required. It must be compiled with Python 3.6
Only [GDB 10.0 and higher](https://www.gnu.org/s/gdb) is required. It must be compiled with Python 3.10
or higher support. For most people, simply using your distribution package manager should be enough.

As of January 2020, GEF officially doesn't support Python 2 any longer, due to Python 2 becoming
Expand All @@ -36,8 +36,7 @@ This should display your version of Python compiled with `gdb`.

```bash
$ gdb -nx -ex 'pi print(sys.version)' -ex quit
3.6.9 (default, Nov 7 2019, 10:44:02)
[GCC 8.3.0]
3.12.3 (main, Jul 31 2024, 17:43:48) [GCC 13.2.0]
```

### Python dependencies
Expand All @@ -56,7 +55,7 @@ easily extended via
### Quick install

The quickest way to get started with GEF is through the installation script available. Simply make
sure you have [GDB 8.0 or higher](https://www.gnu.org/s/gdb), compiled with Python 3.6 or higher,
sure you have [GDB 10.0 or higher](https://www.gnu.org/s/gdb), compiled with Python 3.10 or higher,
and run

```bash
Expand Down
86 changes: 65 additions & 21 deletions gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -1936,13 +1936,10 @@ def gef_pybytes(x: str) -> bytes:
@lru_cache()
def which(program: str) -> pathlib.Path:
"""Locate a command on the filesystem."""
for path in os.environ["PATH"].split(os.pathsep):
dirname = pathlib.Path(path)
fpath = dirname / program
if os.access(fpath, os.X_OK):
return fpath

raise FileNotFoundError(f"Missing file `{program}`")
res = shutil.which(program)
if not res:
raise FileNotFoundError(f"Missing file `{program}`")
return pathlib.Path(res)


def style_byte(b: int, color: bool = True) -> str:
Expand Down Expand Up @@ -8897,12 +8894,35 @@ class VMMapCommand(GenericCommand):
_example_ = f"{_cmdline_} libc"

@only_if_gdb_running
def do_invoke(self, argv: list[str]) -> None:
@parse_arguments({"unknown_types": [""]}, {("--addr", "-a"): [""], ("--name", "-n"): [""]})
def do_invoke(self, _: List[str], **kwargs: Any) -> None:
args : argparse.Namespace = kwargs["arguments"]
vmmap = gef.memory.maps
if not vmmap:
err("No address mapping information found")
return

addrs: Dict[str, int] = {x: parse_address(x) for x in args.addr}
names: List[str] = [x for x in args.name]

for arg in args.unknown_types:
if not arg:
continue

if self.is_integer(arg):
addr = int(arg, 0)
else:
addr = safe_parse_and_eval(arg)

if addr is None:
names.append(arg)
warn(f"`{arg}` has no type specified. We guessed it was a name filter.")
else:
addrs[arg] = int(addr)
warn(f"`{arg}` has no type specified. We guessed it was an address filter.")
warn("You can use --name or --addr before the filter value for specifying its type manually.")
gef_print()

if not gef.config["gef.disable_color"]:
self.show_legend()

Expand All @@ -8911,22 +8931,30 @@ def do_invoke(self, argv: list[str]) -> None:
headers = ["Start", "End", "Offset", "Perm", "Path"]
gef_print(Color.colorify("{:<{w}s}{:<{w}s}{:<{w}s}{:<4s} {:s}".format(*headers, w=gef.arch.ptrsize*2+3), color))

last_printed_filter = None

for entry in vmmap:
if not argv:
names_filter = [f"name = '{x}'" for x in names if x in entry.path]
addrs_filter = [f"addr = {self.format_addr_filter(arg, addr)}" for arg, addr in addrs.items()
if entry.page_start <= addr < entry.page_end]
filter_content = f"[{' & '.join([*names_filter, *addrs_filter])}]"

if not names and not addrs:
self.print_entry(entry)
continue
if argv[0] in entry.path:

elif names_filter or addrs_filter:
if filter_content != last_printed_filter:
gef_print() # skip a line between different filters
gef_print(Color.greenify(filter_content))
last_printed_filter = filter_content
self.print_entry(entry)
elif self.is_integer(argv[0]):
addr = int(argv[0], 0)
if addr >= entry.page_start and addr < entry.page_end:
self.print_entry(entry)
else:
addr = safe_parse_and_eval(argv[0])
if addr is not None and addr >= entry.page_start and addr < entry.page_end:
self.print_entry(entry)

gef_print()
return

def format_addr_filter(self, arg: str, addr: int):
return f"`{arg}`" if self.is_integer(arg) else f"`{arg}` ({addr:#x})"

def print_entry(self, entry: Section) -> None:
line_color = ""
if entry.path == "[stack]":
Expand Down Expand Up @@ -10742,8 +10770,24 @@ def read_cstring(self,
try:
res_bytes = self.read(address, length)
except gdb.error:
err(f"Can't read memory at '{address}'")
return ""
current_address = address
res_bytes = b""
while len(res_bytes) < length:
try:
# Calculate how many bytes there are until next page
next_page = current_address + DEFAULT_PAGE_SIZE
page_mask = ~(DEFAULT_PAGE_SIZE - 1)
size = (next_page & page_mask) - current_address

# Read until the end of the current page
res_bytes += self.read(current_address, size)

current_address += size
except gdb.error:
if not res_bytes:
err(f"Can't read memory at '{address:#x}'")
return ""
break
try:
with warnings.catch_warnings():
# ignore DeprecationWarnings (see #735)
Expand Down
1 change: 0 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ nav:
- hexdump: commands/hexdump.md
- highlight: commands/highlight.md
- hijack-fd: commands/hijack-fd.md
- ksymaddr: commands/ksymaddr.md
- memory: commands/memory.md
- name-break: commands/name-break.md
- nop: commands/nop.md
Expand Down
14 changes: 14 additions & 0 deletions tests/api/gef_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,17 @@ def test_func_parse_maps_realpath(self):
"/usr" not in section.realpath):
assert pathlib.Path(section.realpath).is_file()
break

def test_func_read_cstring_oob(self):
gef, gdb = self._gef, self._gdb

gdb.execute("b main")
gdb.execute("start")

section = gef.memory.maps[0]
oob_val = gef.memory.read_cstring(section.page_start, section.page_end -
section.page_start + 0x100)
val = gef.memory.read_cstring(section.page_start, section.page_end -
section.page_start)

assert val == oob_val
28 changes: 26 additions & 2 deletions tests/commands/vmmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,31 @@ def test_cmd_vmmap(self):
self.assertGreater(len(res.splitlines()), 1)

res = gdb.execute("vmmap stack", to_string=True)
self.assertGreater(len(res.splitlines()), 1)
assert "`stack` has no type specified. We guessed it was a name filter." in res
self.assertEqual(len(res.splitlines()), 9)

res = gdb.execute("vmmap $pc", to_string=True)
self.assertEqual(len(res.splitlines()), 2)
assert "`$pc` has no type specified. We guessed it was an address filter." in res
self.assertEqual(len(res.splitlines()), 8)

def test_cmd_vmmap_addr(self):
gef, gdb = self._gef, self._gdb
gdb.execute("start")

pc = gef.arch.register("pc")

res = gdb.execute(f"vmmap -a {pc:#x}", to_string=True)
self.assertEqual(len(res.splitlines()), 5)

res = gdb.execute("vmmap --addr $pc", to_string=True)
self.assertEqual(len(res.splitlines()), 5)

def test_cmd_vmmap_name(self):
gdb = self._gdb
gdb.execute("start")

res = gdb.execute("vmmap -n stack", to_string=True)
self.assertEqual(len(res.splitlines()), 5)

res = gdb.execute("vmmap --name stack", to_string=True)
self.assertEqual(len(res.splitlines()), 5)

0 comments on commit 854912b

Please sign in to comment.