-
-
Notifications
You must be signed in to change notification settings - Fork 51
Add ARM Cortex-M OpenOCD arch, command, and session manager #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
4e582bf
Add ARMOpenOCD arch
Grazfather 3f591fe
cleanup
Grazfather d48613e
wip
Grazfather 6d9b3fa
Add docs
Grazfather bbeb202
review
Grazfather fbf9727
review comments
Grazfather 81a36f7
fixes
Grazfather 61db76f
List->list
Grazfather File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| """ | ||
| ARM through OpenOCD support for GEF | ||
|
|
||
| To use, source this file *after* gef | ||
|
|
||
| Author: Grazfather | ||
| """ | ||
|
|
||
| from typing import Optional | ||
| from pathlib import Path | ||
|
|
||
| import gdb | ||
|
|
||
| assert 'gef' in globals(), "This file must be source after gef.py" | ||
|
|
||
|
|
||
| class ARMOpenOCD(ARM): | ||
| arch = "ARMOpenOCD" | ||
| aliases = ("ARMOpenOCD",) | ||
| all_registers = ("$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", | ||
| "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$sp", | ||
| "$lr", "$pc", "$xPSR") | ||
| flag_register = "$xPSR" | ||
| @staticmethod | ||
| def supports_gdb_arch(arch: str) -> Optional[bool]: | ||
| if "arm" in arch and arch.endswith("-m"): | ||
hugsy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return True | ||
| return None | ||
|
|
||
| @staticmethod | ||
| def maps(): | ||
| yield from GefMemoryManager.parse_info_mem() | ||
Grazfather marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| @register | ||
| class OpenOCDRemoteCommand(GenericCommand): | ||
| """This command is intended to replace `gef-remote` to connect to an | ||
| OpenOCD-hosted gdbserver. It uses a special session manager that knows how | ||
| to connect and manage the server.""" | ||
|
|
||
| _cmdline_ = "gef-openocd-remote" | ||
| _syntax_ = f"{_cmdline_} [OPTIONS] HOST PORT" | ||
| _example_ = [f"{_cmdline_} --file /path/to/binary.elf localhost 3333", | ||
| f"{_cmdline_} localhost 3333"] | ||
|
|
||
| def __init__(self) -> None: | ||
| super().__init__(prefix=False) | ||
| return | ||
|
|
||
| @parse_arguments({"host": "", "port": 0}, {"--file": ""}) | ||
| def do_invoke(self, _: list[str], **kwargs: Any) -> None: | ||
| if gef.session.remote is not None: | ||
| err("You're already in a remote session. Close it first before opening a new one...") | ||
| return | ||
|
|
||
| # argument check | ||
| args: argparse.Namespace = kwargs["arguments"] | ||
| if not args.host or not args.port: | ||
| err("Missing parameters") | ||
| return | ||
|
|
||
| # Try to establish the remote session, throw on error | ||
| # Set `.remote_initializing` to True here - `GefRemoteSessionManager` invokes code which | ||
| # calls `is_remote_debug` which checks if `remote_initializing` is True or `.remote` is None | ||
| # This prevents some spurious errors being thrown during startup | ||
| gef.session.remote_initializing = True | ||
| session = GefOpenOCDRemoteSessionManager(args.host, args.port, args.file) | ||
|
|
||
| dbg(f"[remote] initializing remote session with {session.target} under {session.root}") | ||
|
|
||
| # Connect can return false if it wants us to disconnect | ||
| if not session.connect(): | ||
| gef.session.remote = None | ||
| gef.session.remote_initializing = False | ||
| return | ||
| if not session.setup(): | ||
| gef.session.remote = None | ||
| gef.session.remote_initializing = False | ||
| raise EnvironmentError("Failed to setup remote target") | ||
|
|
||
| gef.session.remote_initializing = False | ||
| gef.session.remote = session | ||
| reset_all_caches() | ||
| gdb.execute("context") | ||
| return | ||
|
|
||
|
|
||
| # We CANNOT use the normal session manager because it assumes we have a PID | ||
| class GefOpenOCDRemoteSessionManager(GefRemoteSessionManager): | ||
| """This subclass of GefRemoteSessionManager specially handles the | ||
| intricacies involved with connecting to an OpenOCD-hosted GDB server. | ||
| Specifically, it does not have the concept of PIDs which we need to work | ||
| around.""" | ||
| def __init__(self, host: str, port: str, file: str="") -> None: | ||
| self.__host = host | ||
| self.__port = port | ||
| self.__file = file | ||
| self.__local_root_fd = tempfile.TemporaryDirectory() | ||
| self.__local_root_path = Path(self.__local_root_fd.name) | ||
| class OpenOCDMode(): | ||
| def prompt_string(self) -> str: | ||
| return Color.boldify("(OpenOCD) ") | ||
|
|
||
| self._mode = OpenOCDMode() | ||
|
|
||
| def __str__(self) -> str: | ||
| return f"OpenOCDRemoteSessionManager(='{self.__tty}', file='{self.__file}', attach={self.__attach})" | ||
|
|
||
| def close(self) -> None: | ||
| self.__local_root_fd.cleanup() | ||
| try: | ||
| gef_on_new_unhook(self.remote_objfile_event_handler) | ||
| gef_on_new_hook(new_objfile_handler) | ||
| except Exception as e: | ||
| warn(f"Exception while restoring local context: {str(e)}") | ||
| return | ||
|
|
||
| @property | ||
| def target(self) -> str: | ||
| return f"{self.__host}:{self.__port}" | ||
|
|
||
| @property | ||
| def root(self) -> Path: | ||
| return self.__local_root_path.absolute() | ||
|
|
||
| def sync(self, src: str, dst: Optional[str] = None) -> bool: | ||
| # We cannot sync from this target | ||
| return None | ||
|
|
||
| @property | ||
| def file(self) -> Optional[Path]: | ||
| if self.__file: | ||
| return Path(self.__file).expanduser() | ||
| return None | ||
|
|
||
| def connect(self) -> bool: | ||
| """Connect to remote target. If in extended mode, also attach to the given PID.""" | ||
| # before anything, register our new hook to download files from the remote target | ||
| dbg(f"[remote] Installing new objfile handlers") | ||
| try: | ||
| gef_on_new_unhook(new_objfile_handler) | ||
| except SystemError: | ||
| # the default objfile handler might already have been removed, ignore failure | ||
| pass | ||
|
|
||
| gef_on_new_hook(self.remote_objfile_event_handler) | ||
|
|
||
| # Connect | ||
| with DisableContextOutputContext(): | ||
| self._gdb_execute(f"target extended-remote {self.target}") | ||
|
|
||
| try: | ||
| with DisableContextOutputContext(): | ||
| if self.file: | ||
| self._gdb_execute(f"file '{self.file}'") | ||
| except Exception as e: | ||
| err(f"Failed to connect to {self.target}: {e}") | ||
| # a failure will trigger the cleanup, deleting our hook | ||
| return False | ||
|
|
||
| return True | ||
|
|
||
| def setup(self) -> bool: | ||
| dbg(f"Setting up as remote session") | ||
|
|
||
| # refresh gef to consider the binary | ||
| reset_all_caches() | ||
| if self.file: | ||
| gef.binary = Elf(self.file) | ||
| # We'd like to set this earlier, but we can't because of this bug | ||
| # https://sourceware.org/bugzilla/show_bug.cgi?id=31303 | ||
| reset_architecture("ARMOpenOCD") | ||
| return True | ||
|
|
||
| def _gdb_execute(self, cmd): | ||
| dbg(f"[remote] Executing '{cmd}'") | ||
| gdb.execute(cmd) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| ## ARMOpenOCD | ||
|
|
||
| The ARM OpenOCD architecture is a special arcthtecture used with the `gef-openocd-remote` command. | ||
| Please read the [documentation](../commands/gef-openocd-remote.md) for the command. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| ## Command gef-openocd-remote | ||
|
|
||
| The `gef-openocd-command` is used with the [`ARMOpenOCD`](../../archs/arm-openocd.py] architecture. | ||
|
|
||
| The [arm-openocd.py](../../archs/arm-openocd.py) script adds an easy way to extend the `gef-remote` | ||
| functionality to easily debug ARM targets using a OpenOCD gdbserver. It creates a custom ARM-derived | ||
| `Architecture`, as well as the `gef-openocd-remote` command, which lets you easily connect to the | ||
| target, optionally loading the accompanying ELF binary. | ||
|
|
||
| ### Usage | ||
|
|
||
| ```bash | ||
| gef-openocd-remote localhost 3333 --file /path/to/elf | ||
| ``` |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.