Skip to content

Implement file download from the remote machine in GDB protocol#6576

Open
moste00 wants to merge 3 commits into
rizinorg:devfrom
moste00:feature/gdb_download_remote_exec
Open

Implement file download from the remote machine in GDB protocol#6576
moste00 wants to merge 3 commits into
rizinorg:devfrom
moste00:feature/gdb_download_remote_exec

Conversation

@moste00

@moste00 moste00 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Your checklist for this pull request

  • I've read the guidelines for contributing to this repository.
  • I made sure to follow the project's coding style.
  • I've documented every RZ_API function and struct this PR changes.
  • I've added tests that prove my changes are effective (required for changes to RZ_API).
  • I've updated the Rizin book with the relevant information (if needed).
  • I've used AI tools to generate fully or partially these code changes and I'm sure the changes are not copyrighted by somebody else.

Detailed description

There is an issue to download binary files from a remote machine during a GDB remote session #3975, this file is a simple implementation of that addresses the simplest case.

Implementation as follows:

(1) An existing gdbr_read_file that implemented a bounded read of a remote file into a caller-provided buffer was refactored, it now takes an additional argument start_offset, and starts reading from the remote file at this offset. The more general logic is named gdbr_pread_file, and the behaviour of gdbr_read_file is recovered by calling it with a start_offset of 0.

(2) Using gdbr_pread_file as a generic primitive, file downloading is then implemented as an outer loop repeatedly calling it with increasing offsets until a zero-length or shorter-than-expected read (indicating the remote file is complete).

(3) A sub-command download_file was added where the user controls both the remote source and the local destination

(4) A convenience was added to the main function so that if the user runs rizin -D gdb gdb://..., it offers to download the remote executable being deubugged if any of the following is true (a) the remote host is NOT localhost (b) the file doesn't exist by its full path locally, even if the remote host is localhost.

Note: the localhost check is intentionally conservative, it checks for a literal "gdb://localhost:" in the prefix of the URI, so (e.g.) it rejects 127.0.0.1 and considers it "not local". This is because parsing IP addresses doesn't have any well-established utilities in Rizin AFAICT, and I don't want to implement a half-baked buggy and slow implementation of half of an IP parser in the main function. Note that 127.0.0.1 is not unique as a loopback address anyway, and sometimes it can be behind container/namespace routing that make its filesystem not identical to the local filesystem Rizin is running on.

So for now, localhost is treated as a magic escape when the user knows the file doesn't need to be downloaded, and any other remote address is treated as remote.

Test plan

There are no automated tests, sorry, it would be awkward to test network code like this.

Here's a concrete UX difference:

1- First, run a gdb server with a binary that is inaccessible to Rizin, this can be done with VMs or SSH, but a much simpler way to do it with bwrap is:

sudo bwrap --ro-bind / / --dev-bind /dev /dev --proc /proc --tmpfs /tmp --bind "$tmp/remote-sleep" /tmp/remote-sleep gdbserver :2345 /tmp/remote-sleep 1000

(bwrap is only a convience wrapper over namespaces here, so this is doable on any modern linux without bwrap as well.)

2- Run Rizin without this PR (or with this PR but select no when the prompt for downloading the remote file appears)

3- run is, the reasonable expectation is: symbols should appear. But the error ERROR: No binary object currently selected. appears instead.

4- Even after running a full aaaa analysis pass, a simple debug command like dcu main doesn't actually stop at main. The error WARNING: Breakpoint won't be placed since it's not in a valid map. You can bypass this check by setting dbg.bpinmaps to false. appears instead, and the sleep command appears to run to completion before control is handed back to Rizin.

With this PR, choosing y at the prompt will make (3) and (4) work as expected.

Closing issues

Closes #3975 but might need extra features.

Future/RFC

The following concerns are reasonably too big/unknown to handle in this PR, but arguably should:

1- If the binary being debugged in the remote machine loads .so objects, does the current prompt in main naturally extend to download them as well ? should it ? what if loading is lazy and happens mid-execution? Do we need a new prompt for every one ?

2- If the file is not downloaded by the prompt or manually by the user, should other triggers (e.g. the is command) re-prompt the user or should we treat user refusal as final, given that the manual command is always available in case user changes their mind ?

3- Right now, for simplicity, the convenience prompt generates a new temp file on every download and deletes it on exit, should we make any attempt to build a hash-keyed persistent local database ?

4- Instead of downloading to the filesystem for simplicity, maybe it's better to download to memory instead.

Almost all of those problems/nitpicks are around the triggers and UX of downloading, downloading itself once the decision is made is straightforward enough and uses existing code for the most part.

@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 19.73684% with 61 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.92%. Comparing base (d8413d7) to head (d64c082).
⚠️ Report is 26 commits behind head on dev.

Files with missing lines Patch % Lines
librz/main/rizin.c 2.77% 34 Missing and 1 partial ⚠️
librz/io/p/io_gdb.c 34.37% 13 Missing and 8 partials ⚠️
librz/io/io_desc.c 0.00% 4 Missing ⚠️
subprojects/rzgdb/src/gdbclient/core.c 75.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
librz/include/rz_io.h 25.00% <ø> (ø)
subprojects/rzgdb/src/gdbclient/core.c 27.94% <75.00%> (+0.16%) ⬆️
librz/io/io_desc.c 47.75% <0.00%> (-0.80%) ⬇️
librz/io/p/io_gdb.c 28.00% <34.37%> (+11.33%) ⬆️
librz/main/rizin.c 48.24% <2.77%> (-1.56%) ⬇️

... and 62 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 328bca3...d64c082. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread librz/io/p/io_gdb.c Outdated

@notxvilka notxvilka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, would be great to test it with our mock gdbserver Python script like we do already for some other stuff.

@moste00

moste00 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

@notxvilka Hey, added a test and did some neat-ing up of the code.

One slighlty hack-ish thing I had to do is adding a download_file callback to an IO plugin, only GDB implements it for now. This is so librz/main/rizin.c can download the file after user prompt without resorting to abusing the system callback.

If it's a deal breaker then if we remove it, we can't have the prompt-user-to-download feature, I personally like this feature though, it saves an extra R! download_file command (which a new user might not even know exists).

@moste00

moste00 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

I know I need to document this in the rizin book and I already located the section where I need to edit, I'm just waiting for this PR to be approved so that the feature behaviour is fixed and then I can document it.

@moste00

moste00 commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

@wargio @notxvilka ping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Download file and symbols via GDB remote protocol

3 participants