diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-ttd.bat b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-ttd.bat index a6aa5b0f3e..37cfc06fbb 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-ttd.bat +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-ttd.bat @@ -9,7 +9,7 @@ ::@desc ::@menu-group local ::@icon icon.debugger -::@help TraceRmiLauncherServicePlugin#dbgeng +::@help TraceRmiLauncherServicePlugin#dbgeng_ttd ::@env OPT_PYTHON_EXE:str="python" "Path to python" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." :: Use env instead of args, because "all args except first" is terrible to implement in batch ::@env OPT_TARGET_IMG:str="" "Trace (.run)" "A trace associated with the target binary executable" diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.sh index 3878ab9c38..74a4099743 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.sh @@ -28,7 +28,7 @@ #@arg :str "Image" "The target binary executable image" #@args "Arguments" "Command-line arguments to pass to the target" #@env OPT_GDB_PATH:str="gdb" "Path to gdb" "The path to gdb. Omit the full path to resolve using the system PATH." -#@env OPT_START_CMD:StartCmd="start" "Run command" "The gdb command to actually run the target." +#@env OPT_START_CMD:StartCmd="starti" "Run command" "The gdb command to actually run the target." #@env OPT_EXTRA_TTY:bool=false "Inferior TTY" "Provide a separate terminal emulator for the target." #@tty TTY_TARGET if env:OPT_EXTRA_TTY diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh index 16e6f5eb78..ed48419357 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh @@ -25,8 +25,7 @@ #@desc #@menu-group cross #@icon icon.debugger -#@help TraceRmiLauncherServicePlugin#gdb -#@enum StartCmd:str run start starti +#@help TraceRmiLauncherServicePlugin#gdb_qemu #@arg :str "Image" "The target binary executable image" #@args "Arguments" "Command-line arguments to pass to the target" #@env GHIDRA_LANG_EXTTOOL_qemu:str="" "Path to qemu" "The path to qemu for the target architecture." @@ -53,9 +52,9 @@ target_image="$1" if [ -z "$TTY_TARGET" ] then - "$GHIDRA_LANG_EXTTOOL_qemu" $@ & + "$GHIDRA_LANG_EXTTOOL_qemu" $OPT_EXTRA_QEMU_ARGS $@ & else - "$GHIDRA_LANG_EXTTOOL_qemu" $@ <$TTY_TARGET >$TTY_TARGET 2>&1 & + "$GHIDRA_LANG_EXTTOOL_qemu" $OPT_EXTRA_QEMU_ARGS $@ <$TTY_TARGET >$TTY_TARGET 2>&1 & fi # Give QEMU a moment to open the socket diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/raw-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/raw-gdb.sh index 3a2b8224ec..37779af3e3 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/raw-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/raw-gdb.sh @@ -26,7 +26,7 @@ #@desc #@menu-group raw #@icon icon.debugger -#@help TraceRmiLauncherServicePlugin#gdb +#@help TraceRmiLauncherServicePlugin#gdb_raw #@env OPT_GDB_PATH:str="gdb" "Path to gdb" "The path to gdb. Omit the full path to resolve using the system PATH." #@env OPT_ARCH:str="i386:x86-64" "Architecture" "Target architecture" diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.sh index 7dd2a94142..76af6bdcfd 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.sh @@ -15,6 +15,7 @@ # limitations under the License. ## #@title remote gdb +#@no-image #@desc #@desc

Launch with local gdb and connect to a stub (e.g., gdbserver)

#@desc

This will start gdb on the local system and then use it to connect to the remote system. diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh index ee10af08ef..6ccb89e34b 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh @@ -34,7 +34,7 @@ #@desc #@menu-group remote #@icon icon.debugger -#@help TraceRmiLauncherServicePlugin#gdb +#@help TraceRmiLauncherServicePlugin#gdb_ssh #@enum StartCmd:str run start starti #@arg :str "Image" "The target binary executable image on the remote system" #@args "Arguments" "Command-line arguments to pass to the target" diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.sh index b4e62b8a8a..4185dac8c0 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.sh @@ -31,7 +31,7 @@ #@desc #@menu-group remote #@icon icon.debugger -#@help TraceRmiLauncherServicePlugin#gdb +#@help TraceRmiLauncherServicePlugin#gdb_gdbserver_ssh #@arg :str "Image" "The target binary executable image on the remote system" #@args "Arguments" "Command-line arguments to pass to the target" #@env OPT_HOST:str="localhost" "[User@]Host" "The hostname or user@host" diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/wine-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/wine-gdb.sh index f21c4bd5e6..f1eaf81905 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/wine-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/wine-gdb.sh @@ -26,14 +26,14 @@ #@desc file, and most copies of GDB for UNIX will support only ELF. Nevertheless, Ghidra should #@desc recognize the target and map it, giving you symbols and debug info in the front end, even #@desc if not in the GDB CLI.

-#@desc

You will need to locate the wine executable on your system, not the script. To +#@desc

You will need to locate the wine executable, not the script, on your system. To #@desc find it, either dissect the wine script or consult online documentation for your #@desc distribution of Wine. There are often two executables, one for 32-bit targets and one for #@desc 64-bit targets. You must select the correct one.

#@desc #@menu-group cross #@icon icon.debugger -#@help TraceRmiLauncherServicePlugin#gdb +#@help TraceRmiLauncherServicePlugin#gdb_wine #@arg :str "Image" "The target binary executable image" #@args "Arguments" "Command-line arguments to pass to the target" #@env OPT_WINE_PATH:str="/usr/lib/wine/wine64" "Path to wine binary" "The path to the wine executable for your target architecture." diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.sh b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.sh index 8ab749e8ea..84d0b3f94a 100755 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.sh +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.sh @@ -15,6 +15,7 @@ # limitations under the License. ## #@title remote lldb +#@no-image #@desc #@desc

Launch with local lldb and connect to a stub (e.g., gdbserver)

#@desc

This will start lldb on the local system and then use it to connect to the remote system. @@ -29,7 +30,7 @@ #@desc #@menu-group remote #@icon icon.debugger -#@help TraceRmiLauncherServicePlugin#lldb +#@help TraceRmiLauncherServicePlugin#lldb_remote #@env OPT_HOST:str="localhost" "Host" "The hostname of the target" #@env OPT_PORT:str="9999" "Port" "The host's listening port" #@env OPT_ARCH:str="" "Architecture" "Target architecture override" diff --git a/Ghidra/Debug/Debugger-rmi-trace/build.gradle b/Ghidra/Debug/Debugger-rmi-trace/build.gradle index 40fbc17ab0..2c9cf5fc22 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/build.gradle +++ b/Ghidra/Debug/Debugger-rmi-trace/build.gradle @@ -15,6 +15,7 @@ */ apply from: "${rootProject.projectDir}/gradle/javaProject.gradle" +apply from: "${rootProject.projectDir}/gradle/helpProject.gradle" apply from: "${rootProject.projectDir}/gradle/jacocoProject.gradle" apply from: "${rootProject.projectDir}/gradle/javaTestProject.gradle" apply from: "${rootProject.projectDir}/gradle/distributableGhidraModule.gradle" diff --git a/Ghidra/Debug/Debugger-rmi-trace/certification.manifest b/Ghidra/Debug/Debugger-rmi-trace/certification.manifest index 6a41f8216c..bdc45f52b2 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/certification.manifest +++ b/Ghidra/Debug/Debugger-rmi-trace/certification.manifest @@ -2,6 +2,13 @@ DEVNOTES.txt||GHIDRA||||END| Module.manifest||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||||END| +src/main/help/help/TOC_Source.xml||GHIDRA||||END| +src/main/help/help/topics/TraceRmiConnectionManagerPlugin/TraceRmiConnectionManagerPlugin.html||GHIDRA||||END| +src/main/help/help/topics/TraceRmiConnectionManagerPlugin/images/ConnectDialog.png||GHIDRA||||END| +src/main/help/help/topics/TraceRmiConnectionManagerPlugin/images/TraceRmiConnectionManagerPlugin.png||GHIDRA||||END| +src/main/help/help/topics/TraceRmiLauncherServicePlugin/TraceRmiLauncherServicePlugin.html||GHIDRA||||END| +src/main/help/help/topics/TraceRmiLauncherServicePlugin/images/GdbLauncher.png||GHIDRA||||END| +src/main/help/help/topics/TraceRmiLauncherServicePlugin/images/GdbTerminal.png||GHIDRA||||END| src/main/py/LICENSE||GHIDRA||||END| src/main/py/README.md||GHIDRA||||END| src/main/py/pyproject.toml||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger-rmi-trace/data/debugger-launchers/raw-python3.sh b/Ghidra/Debug/Debugger-rmi-trace/data/debugger-launchers/raw-python3.sh index 2290d7fb4a..823881931d 100755 --- a/Ghidra/Debug/Debugger-rmi-trace/data/debugger-launchers/raw-python3.sh +++ b/Ghidra/Debug/Debugger-rmi-trace/data/debugger-launchers/raw-python3.sh @@ -25,7 +25,7 @@ #@desc #@menu-group raw #@icon icon.debugger -#@help TraceRmiLauncherServicePlugin#gdb +#@help TraceRmiLauncherServicePlugin#python_raw #@env OPT_PYTHON_EXE:str="python" "Path to python" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." #@env OPT_LANG:str="DATA:LE:64:default" "Ghidra Language" "The Ghidra LanguageID for the trace" #@env OPT_COMP:str="pointer64" "Ghidra Compiler" "The Ghidra CompilerSpecID for the trace" diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/TOC_Source.xml b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/TOC_Source.xml new file mode 100644 index 0000000000..3d7af5fccb --- /dev/null +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/TOC_Source.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiConnectionManagerPlugin/TraceRmiConnectionManagerPlugin.html b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiConnectionManagerPlugin/TraceRmiConnectionManagerPlugin.html new file mode 100644 index 0000000000..72bc23dcc1 --- /dev/null +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiConnectionManagerPlugin/TraceRmiConnectionManagerPlugin.html @@ -0,0 +1,107 @@ + + + + + + + Debugger: Connections + + + + + +

Debugger: Connections

+ +
+ +
+ +

The Connections window manages connections to live debuggers and, at a high level, their + targets. Each item is a Trace RMI connection (or a step toward one) to a back-end debugger. + Usually, the back end is a native debugger with a plugin that communicates with Ghidra via + Trace RMI. These connections are typically established using a launcher script, invoked from + the Launcher + Menu, though there are actions here for establishing connections manually or to remote back + ends. There are different kinds of items displayed in the connection list.

+ + + +

Actions

+ +

Connect + Outbound

+ +

Connect to a back end. The back end plays the role of TCP server while Ghidra plays the TCP + client. The dialog prompts for the (possibly remote) back end's host and port. Once the + connection is established, the back end takes the role of Trace RMI client, despite being the + TCP server. Check the command documentation for your back end's plugin to figure out how to + have it listen first.

+ +
+ +
+ +

Connect by + Accept

+ +

Accept a single connection from a back end. Ghidra plays the role of TCP server, and the + back end is the TCP client. The dialog prompts for the host/interface and port on which to + listen. Check the command documentation for your back end's plugin to figure out how to have it + connect to a listening Ghidra. Once the connection is established, the listening port is + closed. The back end plays the role of Trace RMI client.

+ +

Close

+ +

Right-click a connection or acceptor to access this action. For an acceptor, this will + cancel it. For an established connection, this will tear it down, rendering its target traces + dead. Note that the back end may retain its live targets, despite losing its connection to + Ghidra.

+ +

Close All

+ +

Burn it all to the ground and start over. This closes the server, cancels all acceptors, and + tears down all connections. Any live trace in the Debugger will be rendered dead, which often + causes the trace manager to close them. Note that the back ends may retain their live targets, + despite losting their connections to Ghidra.

+ +

Start Server

+ +

Start a persistent server, able to accept many back-end connections. Ghidra plays the role + of TCP server, and each back end is a TCP client. The dialog prompts for the host/interface and + port on which to listen. Check the command documentation for your back end's plugin to figure + out how to have it connect to a listening Ghidra. The listening port remains open no matter how + many connections it has accepted. It is still possible to connect by other means while the + server is active.

+ +

Stop Server

+ +

Stop the server. This closes the persistent server. This does not affect pending acceptors + or established connections.

+ + diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiConnectionManagerPlugin/images/ConnectDialog.png b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiConnectionManagerPlugin/images/ConnectDialog.png new file mode 100644 index 0000000000..ae21ac3c4e Binary files /dev/null and b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiConnectionManagerPlugin/images/ConnectDialog.png differ diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiConnectionManagerPlugin/images/TraceRmiConnectionManagerPlugin.png b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiConnectionManagerPlugin/images/TraceRmiConnectionManagerPlugin.png new file mode 100644 index 0000000000..defda68d43 Binary files /dev/null and b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiConnectionManagerPlugin/images/TraceRmiConnectionManagerPlugin.png differ diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiLauncherServicePlugin/TraceRmiLauncherServicePlugin.html b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiLauncherServicePlugin/TraceRmiLauncherServicePlugin.html new file mode 100644 index 0000000000..cc90ae864a --- /dev/null +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiLauncherServicePlugin/TraceRmiLauncherServicePlugin.html @@ -0,0 +1,598 @@ + + + + + + + Debugger: Launchers + + + + + +

Debugger: Launchers

+ +

The Debugger has an updated and simplified launcher system. A nice collection of basic + launchers for our supported platforms are provided out of the box. For Linux, we provide a + suite of GDB-based launchers. For macOS, we provide a suite of LLDB-based launchers (though, + these work on Linux, too). For Windows, we provide a launcher based on the Windows Debugger + (dbgeng.dll and dbgmodel.dll).

+ +

Each launcher automates the creation of a Trace RMI acceptor, + executes the back-end shell script in a Terminal, then waits for the resulting target trace. In + contrast to the previous system, the Terminal is the first and most basic interface presented. + Even if just about everything else goes wrong, the terminal should still be faithfully + operational:

+ +
+ +
+ +

The Terminal is fully integrated into Ghidra's UI and so can be docked or undocked just like + the rest of Ghidra's windows. It provides fairly robust VT-100 emulation. Thus, the user + experience from the Terminal is nearly identical to using the same debugger outside of Ghidra. + This terminal-first approach also ensures that you interact with the target application's + standard I/O. This was not possible in the previous system, as we re-implemented the CLI using + the back end's execute method. The debugger's (and so also the target's) actual I/O + streams were hidden away within a GDB/MI wrapper.

+ +

Each launcher script sets up a — usually Python — environment, launches the + actual debugger, and provides a sequence of commands for it to load the Trace RMI plugin, + connect back to Ghidra, launch the actual target process, and start the target trace. At this + point, the plugin generally takes over, reacting to user and target events, accepting front-end + requests, and generally keeping Ghidra and the back end synchronized.

+ +

The list of launchers can be accessed in either of two places: + 1) In the Debugger → Configure and Launch ... menu or more conveniently from the + Launch button in the main toolbar. This is the blue bug + button near the top center. The Configure and Launch ... menu lists all available + launchers. Selecting one will prompt for its options then launch. To re-launch quickly, use the + Launch button. Clicking it will re-launch using the most recent launcher and + configuration for the current program. If this is the first launch of the given program, the + button will instead activate its drop-down menu. The drop-down is also accessible by clicking + the down arrow next to the Launch button. The drop-down lists all launchers that have + been previously configured for the current program. Clicking one will immediately launch the + program without prompting. The Configure and Launch ... sub-menu of the drop-down + functions exactly like in the Debugger menu.

+ +

The Terminal provides some fairly standard actions. Other keyboard control sequences, + notably CTRL-C, are interpreted by the terminal, rather than Ghidra's action system, to + achieve their expected behavior, e.g., interrupt.

+ +

Copy

+ +

This is accessed using the toolbar button or the key sequence CTRL-SHIFT-C. As + expected, it copies the current selection to the system clipboard.

+ +

Paste

+ +

This is accessed using the toolbar button or the key sequence CTRL-SHIFT-V. As + expected, it pastes the text contents of the system clipboard into the terminal, as if + typed.

+ +

Find

+ +

This is accessed using the local drop-down menu or the key sequence CTRL-SHIFT-F. It + displays a dialog for searching the terminal's scrollback buffer.

+ +

Find Next/Previous

+ +

These actions are accessed using the local drop-down menu or the key sequence + CTRL-SHIFT-H or CTRL-SHIFT-G, respectively. They repeat the last search in the + forward or backward direction.

+ +

Terminate

+ +

This action is accessed using the local drop-down menu. It will terminate the Terminal's + current session. Exactly what that means is determined by the Terminal's creator. In general, + it means to destroy the full debugging session associated with the Terminal. That may cause + related terminals, e.g., a secondary terminal for target I/O and associated target traces, to + be terminated as well. NOTE: This action is not implied by closing the Terminal + window. Closing the window with an active session merely hides it. It can be recalled using the + Window → Terminals menu. If the session has already been terminated (indicated by + an orange border) then closing the window will, in fact, destroy the Terminal.

+ +

Stock GDB Launchers

+ +

The following launchers based on GDB (GNU Debugger) are included out of the box:

+ +

GDB

+ +

This launcher is a Python plugin for GDB, and so is best suited for debugging Linux + user-space targets as well as many embedded systems. Please note you may need to obtain a + properly-configured build of GDB for your target. If you are working with an embedded system, + it is probably safest to install the "multiarch" build of GDB from your package manager.

+ +

Once running, you are presented with GDB's command-line interface in Ghidra's Terminal. This + is the bona fide GDB command-line interface, so it has all the functionality you would + expect. If you command GDB from this shell, the plugin will keep Ghidra in sync. The terminal + can also be used to interact with the target application when it is running. The plugin + provides an additional set of commands for managing the connection to Ghidra, as well as + controlling trace synchronization. These are all in the "ghidra" command prefix. You + can use tab completion to enumerate the available commands and GDB's "help" command to + examine their documentation.

+ +
+ +
+ +

Options

+ + + +

GDB via SSH

+ +

This works the same as the GDB launcher, but runs gdb on a remote system via + ssh. In contrast to the previous system, which used an SSH library for Java, this + launcher uses the ssh command on the local system. Thus, it should have broader + compatibility with remote systems, and it should use the same configuration files as you are + accustomed to. That said, we developed it using OpenSSH, so your experience will be best if + your copy understands the same command-line arguments. It will need to be capable of port + forwarding. The remote server must permit remote port forwarding (-R option) and terminal + allocation (-t option). You will also need to manually install the required Python + packages on the target host, comprising our plugin for GDB and its dependencies.

+ +

Options

+ + + +

GDB + gdbserver via SSH

+ +

This works similarly to the GDB via SSH launcher, but instead of tunneling the Trace RMI + connection, tunnels the RSP (gdbserver) connection. There is actually a fairly elegant method + of doing this straight from within gdb, which is exactly what this launcher does:

+ + + +

This has some advantages compared to running gdb on the remote target:

+ +
    +
  1. GDB may not be available on the remote target.
  2. + +
  3. There is no need to install our plugin for GDB on the target.
  4. +
+ +

But, it also has some drawbacks:

+ +
    +
  1. gdbserver must be installed on the remote system, and the local gdb + must be compatible with it.
  2. + +
  3. It may be slightly more annoying to map modules from the remote system, because of the + way GDB reports these modules.
  4. + +
  5. The memory map may be absent. Though this is overcome by creating an entry for the entire + address space, if the map is of interest to your analysis, it may not be available.
  6. +
+ +

Options

+ + + +

QEMU + GDB

+ +

This launcher orchestrates a QEMU user-mode target and connects to it using our Python + plugin for GDB. You will almost certainly need the "multiarch" build of GDB, and by default, + the launcher will try to use gdb-multiarch. You must also install the appropriate + build of QEMU for your target architecture. Ghidra will inspect the current program and attempt + to map its language to the appropriate QEMU command, but this may fail, or be subtly + incorrect.

+ +

Options

+ + + +

Wine + GDB

+ +

This launchers runs wine in a gdb session on Linux and directs it to a + target Windows executable. There are other ways to rig a Windows target in GDB on Linux, but + this is the method we have chosen: You will need to install Wine on your system and locate the + actual wine executable. These are often in some library directory and named + "wine32" or "wine64." To find them, either examine the file list of the + installed package, or dissect the wrapper wine script, usually on your path:

+ + + +

The locations are usually given in variables at the top of the script, e.g., + "/usr/lib/wine/wine64". One is for 64-bit Windows targets and another is for 32-bit + Windows targets. Unlike native Windows, Wine does not (yet) implement WoW64 (Windows on Windows + 64). Instead, the 32-bit target is loaded using a 32-bit copy of Wine, and so is serviced by + Linux's 32-bit system calls. NOTE: Careful attention must be given to + select the correct wine executable for the target program's architecture! Even + though the wine executable is smart enough to correct this mistake, it results in + calls to exec, which confuse this launcher. If GDB complains that it cannot place + breakpoints because of memory access, it is probably because of this mistake.

+ +

The launcher loads some additional support packages in our plugin for GDB, e.g., to scan the + memory map for PE files and amend the module list. Thus, Ghidra can display both Windows and + Linux modules, and map them to its program databases accordingly, despite GDB's inability to + process PE files. There are perhaps other configurations of GDB for Linux that can process ELFs + as well as PEs loaded by Wine, but they do not seem to be readily available in any popular + package repositories.

+ +

Options

+ + + +

Remote GDB

+ +

This launcher can target any TCP-based GDB stub that is compatible with a local copy of + gdb. Essentially, it just starts gdb and then enters

+ + + +

into it. It is best to test this command outside of Ghidra to be sure everything is + compatible before using this launcher. This launcher does not require an image, nor does it + create your target. Thus, it can be used without a current program.

+ +

Options

+ + + +

Raw GDB

+ +

This is hardly a launcher at all. It simply starts gdb, gets it connected to + Ghidra, and starts a trace. This allows you to create or connect to whatever target your copy + of GDB supports. While perhaps the most flexible, it is also the least convenient. It requires + no image, so it can be used without a current program. That also means it will make no effort + to ensure your target maps to the current program, if you happen to have one. You may have to + do it manually.

+ +

Options

+ + + +

Stock LLDB Launchers

+ +

The following launchers based on the LLDB Debugger are included out of the box:

+ +

LLDB

+ +

This launcher is a Python plugin for LLDB, and so is well suited for debugging user-space + targets on a variety of platforms. It is the de facto debugger for macOS. It can be + obtained by installing XCode from the App Store. Though it may require a bit more careful + configuration, it can also be obtained from other repositories like brew.

+ +

Once running, you are presented with LLDB's command-line interface in Ghidra's Terminal. + This is the bona fide LLDB command-line interface, so it has all the functionality you + would expect. If you command LLDB from this shell, the plugin will keep Ghidra in sync. The + terminal can be used to interact with the target application when it is running. The plugin + provides an additional set of commands for managing the connection to Ghidra, as well as + controlling trace synchronization. These are all in the "ghidra" category. You can use + tab completion to enumerate the available commands and LLDB's "help" command to + examine their documentation.

+ +

Options

+ + + +

Remote LLDB

+ +

This launcher can target any TCP-based GDB stub that is compatible with a local copy of + lldb. Essentially, it just starts lldb and then enters

+ + + +

into it. It is best to test this command outside of Ghidra to be sure everything is + compatible before using this launcher. This launcher does not require an image, nor does it + create your target. Thus, it can be used without a current program.

+ +

Options

+ + + +

Stock Windows Debugger (WinDbg) Launchers

+ +

The following launchers based on Microsoft's dbgeng.dll are included out of the + box:

+ +

dbgeng

+ +

This launcher is actually a Python implementation of a console debugger based on + dbgeng.dll. This DLL represents the Microsoft Windows Debugger engine, and so is best + suited for debugging Windows user-space targets. Windows kernel targets are not yet supported. + This DLL also backs WinDbg and several other debuggers on Windows. By default, the launcher + will search for this DLL in an installation of the Windows Debugging Kits version 10. If it + does not find it there, it will fall back to the one provided with Windows, which is + substantially less capable. Installing WinDbg is highly recommended. Please note on some system + configurations, one of the debugger's dependencies dbghelp.dll may get loaded from the + system directory instead of from the WinDbg installation, usually because a security product + has pre-loaded it into the Python process. You might work around this by copying the affected + DLLs from your WinDbg installation into your Python installation.

+ +

Once running, you are presented with a command-line interface in Ghidra's Terminal. This CLI + accepts your usual WinDbg (kd) commands. You can escape from this CLI and enter a Python 3 REPL + by entering ".exit". This is not an actual kd command, but our implementation + understands this to mean exit the kd REPL. From the Python 3 REPL, you can access the + underlying Python-based API pybag. This is an uncommon need, but may be useful for + diagnostics and/or workarounds. To re-enter the kd REPL, enter "repl()". + Alternatively, if you are trying to quit, but typed ".exit", just type + "quit()" to terminate the session.

+ +

Options

+ + + +

TTD (Time-Travel Debugging)

+ +

This is a nascent extension to our launcher for the Windows Debugger. The launcher itself + functions well, but lacks full integration. It is not yet properly packaged for the Ghidra + distribution, but is available in development environments. It also needs some additional + protocol support, namely to integrate its notion of time travel with Ghidra's notion. For the + time being, we map our time specifications as follows. MS TTD uses a tuple for its time specs, + both displayed in hexadecimal, e.g., "B5:1A". The first is the "major," which we believe counts + the events that warrant a snapshot. The second is the "minor," which we believe counts + instructions executed since the major event. Thus, we would like to map the major to a Ghidra + trace snapshot and the minor to steps of p-code emulation. For example, the "B5:1A" notation + would map to "181:26". It should be no surprise the notations are similar, since both MS TTD + and Ghidra (as well as several other "timeless" debuggers) use a snapshot-replay strategy to + recover past machine states. However, we have not yet worked out how to have Ghidra cooperate + with a back end in the replay part of this strategy. Currently, Ghidra will always apply p-code + emulation, despite having a perfectly good and performant back end available. So, for the time + being, we multiply the major number by 1000, thus reserving that many Ghidra snapshots between + major events for MS TTD minor steps. Thus, the notation "B5:1A" will actually map to "181026", + that is snapshot 181026 with no steps of p-code emulation. This hack will fall short if you + visit a time where the minor number exceeds 999.

+ +

Furthermore, if you use the Ghidra Debugger UI to visit a past snapshot, the back end is not + yet informed of your intent. You will probably only see stale records of the machine state. + Instead, please use the kd commands from the Terminal to navigate through time. The back end + (MS TTD) will perform the replay, record the snapshot, and command Ghidra to navigate + there.

+ +

Options

+ +

This launcher has the same options as the WinDbg launcher, except that the DLL path must + contain dbgmodel.dll and the scripts that implement TTD. These are most easily + obtained by installing WinDbg Preview or later.

+ +

Development and Diagnostic Launchers

+ +

We currently provide one launcher for Trace RMI API exploration and development:

+ +

Raw Python

+ +

This launcher runs Python in a Terminal window, connects a Trace RMI client back to Ghidra, + then starts a blank trace. Once running, it presents the Python interpreter, with the + ghidratrace and ghidratrace.client packages imported into the local + namespace. Thus, a developer can explore the API, invoke methods, and observer how Ghidra + reacts.

+ +

Options

+ + + + diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiLauncherServicePlugin/images/GdbLauncher.png b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiLauncherServicePlugin/images/GdbLauncher.png new file mode 100644 index 0000000000..85b71b483b Binary files /dev/null and b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiLauncherServicePlugin/images/GdbLauncher.png differ diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiLauncherServicePlugin/images/GdbTerminal.png b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiLauncherServicePlugin/images/GdbTerminal.png new file mode 100644 index 0000000000..9e6c3ab8cb Binary files /dev/null and b/Ghidra/Debug/Debugger-rmi-trace/src/main/help/help/topics/TraceRmiLauncherServicePlugin/images/GdbTerminal.png differ diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java index 9346064010..b05a06f34f 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java @@ -441,9 +441,11 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer PtyParent parent = pty.getParent(); PtyChild child = pty.getChild(); - Terminal terminal = terminalService.createWithStreams(Charset.forName("UTF-8"), + Terminal terminal = terminalService.createWithStreams(plugin, Charset.forName("UTF-8"), parent.getInputStream(), parent.getOutputStream()); - terminal.setSubTitle(ShellUtils.generateLine(commandLine)); + + List withoutPath = ShellUtils.removePath(commandLine); + terminal.setSubTitle(ShellUtils.generateLine(withoutPath)); TerminalListener resizeListener = new TerminalListener() { @Override public void resized(short cols, short rows) { @@ -491,7 +493,7 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer PtyParent parent = pty.getParent(); PtyChild child = pty.getChild(); - Terminal terminal = terminalService.createWithStreams(Charset.forName("UTF-8"), + Terminal terminal = terminalService.createWithStreams(plugin, Charset.forName("UTF-8"), parent.getInputStream(), parent.getOutputStream()); TerminalListener resizeListener = new TerminalListener() { @Override diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java index 92766db32e..49bd096cd9 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java @@ -481,6 +481,14 @@ public class TraceRmiHandler implements TraceRmiConnection { private interface Dispatcher { RootMessage.Builder dispatch(RootMessage req, RootMessage.Builder rep) throws Exception; + default String exceptionMessage(Throwable exc) { + String msg = exc.getMessage(); + if (msg == null) { + return exc.getClass().getCanonicalName(); + } + return exc.getClass().getCanonicalName() + ": " + msg; + } + default RootMessage handle(RootMessage req) { String desc = toString(req); if (desc != null) { @@ -494,7 +502,7 @@ public class TraceRmiHandler implements TraceRmiConnection { catch (Throwable e) { Msg.error(this, "Exception caused by back end", e); return rep.setError(ReplyError.newBuilder() - .setMessage(e.getMessage())) + .setMessage(exceptionMessage(e))) .build(); } } diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/screen/java/ghidra/app/plugin/core/debug/gui/tracermi/connection/TraceRmiConnectionManagerPluginScreenShots.java b/Ghidra/Debug/Debugger-rmi-trace/src/screen/java/ghidra/app/plugin/core/debug/gui/tracermi/connection/TraceRmiConnectionManagerPluginScreenShots.java new file mode 100644 index 0000000000..c740d85948 --- /dev/null +++ b/Ghidra/Debug/Debugger-rmi-trace/src/screen/java/ghidra/app/plugin/core/debug/gui/tracermi/connection/TraceRmiConnectionManagerPluginScreenShots.java @@ -0,0 +1,75 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.debug.gui.tracermi.connection; + +import java.net.InetSocketAddress; + +import org.junit.Test; + +import ghidra.app.plugin.core.debug.gui.objects.components.DebuggerMethodInvocationDialog; +import ghidra.app.plugin.core.debug.gui.tracermi.connection.TraceRmiConnectionManagerProviderTest.Cx; +import ghidra.app.plugin.core.debug.gui.tracermi.connection.tree.TraceRmiConnectionNode; +import ghidra.app.plugin.core.debug.gui.tracermi.connection.tree.TraceRmiConnectionTreeHelper; +import ghidra.app.plugin.core.debug.service.tracermi.DefaultTraceRmiAcceptor; +import ghidra.app.plugin.core.debug.service.tracermi.TraceRmiPlugin; +import help.screenshot.GhidraScreenShotGenerator; + +public class TraceRmiConnectionManagerPluginScreenShots extends GhidraScreenShotGenerator { + private TraceRmiPlugin servicePlugin; + private TraceRmiConnectionManagerPlugin managerPlugin; + + @Test + public void testCaptureTraceRmiConnectionManagerPlugin() throws Throwable { + servicePlugin = addPlugin(tool, TraceRmiPlugin.class); + managerPlugin = addPlugin(tool, TraceRmiConnectionManagerPlugin.class); + + TraceRmiConnectionManagerProvider provider = + waitForComponentProvider(TraceRmiConnectionManagerProvider.class); + + servicePlugin.startServer(); + DefaultTraceRmiAcceptor acceptor = + servicePlugin.acceptOne(new InetSocketAddress("localhost", 0)); + DefaultTraceRmiAcceptor forCx = + servicePlugin.acceptOne(new InetSocketAddress("localhost", 0)); + try (Cx cx = Cx.complete(forCx, "demo-dbg")) { + cx.client().createTrace(0, "bash"); + + TraceRmiConnectionNode node = + TraceRmiConnectionTreeHelper.getConnectionNodeMap(provider.rootNode) + .get(cx.connection()); + provider.tree.expandTree(node); + waitForTasks(); + + captureIsolatedProvider(provider, 400, 300); + } + finally { + acceptor.cancel(); + } + } + + @Test + public void testCaptureConnectDialog() throws Throwable { + servicePlugin = addPlugin(tool, TraceRmiPlugin.class); + managerPlugin = addPlugin(tool, TraceRmiConnectionManagerPlugin.class); + + TraceRmiConnectionManagerProvider provider = + waitForComponentProvider(TraceRmiConnectionManagerProvider.class); + + performAction(provider.actionConnectOutbound, provider, false); + + captureDialog(DebuggerMethodInvocationDialog.class); + } +} diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/gui/tracermi/connection/TraceRmiConnectionManagerProviderTest.java b/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/gui/tracermi/connection/TraceRmiConnectionManagerProviderTest.java index b499c1b8ff..fbcd3d62f8 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/gui/tracermi/connection/TraceRmiConnectionManagerProviderTest.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/gui/tracermi/connection/TraceRmiConnectionManagerProviderTest.java @@ -208,7 +208,7 @@ public class TraceRmiConnectionManagerProviderTest extends AbstractGhidraHeadedD TraceRmiConnectionTreeHelper.getAcceptorNodeMap(provider.rootNode).get(acceptor)); } - record Cx(SocketChannel channel, TestTraceRmiClient client, + public record Cx(SocketChannel channel, TestTraceRmiClient client, TraceRmiConnection connection) implements AutoCloseable { public static Cx complete(TraceRmiAcceptor acceptor, String description) diff --git a/Ghidra/Debug/Debugger/certification.manifest b/Ghidra/Debug/Debugger/certification.manifest index 659589c6fa..9d341db90b 100644 --- a/Ghidra/Debug/Debugger/certification.manifest +++ b/Ghidra/Debug/Debugger/certification.manifest @@ -33,6 +33,8 @@ src/main/help/help/topics/DebuggerMemoryBytesPlugin/DebuggerMemoryBytesPlugin.ht src/main/help/help/topics/DebuggerMemoryBytesPlugin/images/DebuggerMemoryBytesPlugin.png||GHIDRA||||END| src/main/help/help/topics/DebuggerMemviewPlugin/DebuggerMemviewPlugin.html||GHIDRA||||END| src/main/help/help/topics/DebuggerMemviewPlugin/images/DebuggerMemviewPlugin.png||GHIDRA||||END| +src/main/help/help/topics/DebuggerModelPlugin/DebuggerModelPlugin.html||GHIDRA||||END| +src/main/help/help/topics/DebuggerModelPlugin/images/DebuggerModelPlugin.png||GHIDRA||||END| src/main/help/help/topics/DebuggerModelServicePlugin/DebuggerModelServicePlugin.html||GHIDRA||||END| src/main/help/help/topics/DebuggerModulesPlugin/DebuggerModulesPlugin.html||GHIDRA||||END| src/main/help/help/topics/DebuggerModulesPlugin/images/DebuggerModuleMapProposalDialog.png||GHIDRA||||END| @@ -42,20 +44,6 @@ src/main/help/help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html||GHID src/main/help/help/topics/DebuggerObjectsPlugin/images/DebuggerBreakpointDialog.png||GHIDRA||||END| src/main/help/help/topics/DebuggerObjectsPlugin/images/DebuggerMethodInvocationDialog_ForLaunch.png||GHIDRA||||END| src/main/help/help/topics/DebuggerObjectsPlugin/images/DebuggerObjectsPlugin.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/breakpoint-set.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_graph.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_table.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_tree.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_xml.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_graph.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_table.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_tree.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_xml.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/export_as_facts.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/export_as_xml.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/import_from_facts.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/import_from_xml.png||GHIDRA||||END| -src/main/help/help/topics/DebuggerObjectsPlugin/images/stop.png||GHIDRA||||END| src/main/help/help/topics/DebuggerPcodeStepperPlugin/DebuggerPcodeStepperPlugin.html||GHIDRA||||END| src/main/help/help/topics/DebuggerPcodeStepperPlugin/images/DebuggerPcodeStepperPlugin.png||GHIDRA||||END| src/main/help/help/topics/DebuggerPlatformPlugin/DebuggerPlatformPlugin.html||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger/data/debugger.theme.properties b/Ghidra/Debug/Debugger/data/debugger.theme.properties index dd36191376..03d71281da 100644 --- a/Ghidra/Debug/Debugger/data/debugger.theme.properties +++ b/Ghidra/Debug/Debugger/data/debugger.theme.properties @@ -134,6 +134,7 @@ icon.debugger.provider.registers = registers.png icon.debugger.provider.stack = stack.png icon.debugger.provider.breakpoints = breakpoint-mixed.png icon.debugger.provider.modules = modules.png +icon.debugger.provider.mappings = icon.content.handler.program icon.debugger.provider.pcode = stepinto.png icon.debugger.provider.regions = memory16.gif icon.debugger.provider.time = time.png @@ -157,6 +158,8 @@ icon.debugger.map.identically = doubleArrow.png icon.debugger.map.modules = modules.png icon.debugger.map.sections = icon.debugger.map.modules icon.debugger.map.regions = icon.debugger.map.modules +icon.debugger.map.auto = icon.debugger.config +icon.debugger.map.manual = icon.debugger.provider.mappings icon.debugger.block = icon.debugger.map.sections icon.debugger.select.addresses = text_align_justify.png icon.debugger.data.types = dataTypes.png diff --git a/Ghidra/Debug/Debugger/src/main/help/help/TOC_Source.xml b/Ghidra/Debug/Debugger/src/main/help/help/TOC_Source.xml index 0e27f90481..992d5f9500 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/TOC_Source.xml +++ b/Ghidra/Debug/Debugger/src/main/help/help/TOC_Source.xml @@ -54,7 +54,7 @@ target="help/topics/Debugger/Debugger.html" > + + - diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/Debugger.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/Debugger.html index 3f1569a122..8bb0bc0473 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/Debugger.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/Debugger.html @@ -15,38 +15,37 @@

The Debugger is a collection of plugins comprising Ghidra's Dynamic Analysis Framework. This includes a platform for connecting to and controlling debuggers. Ghidra is not a debugger in - itself, but rather, it relies on existing 3rd-party debuggers, their APIs, wire protocols, - and/or command-line interfaces. Such connectors are pluggable, allowing Ghidra to be extended - and integrated with additional debuggers.

+ itself, but rather, it relies on existing 3rd-party ("back end") debuggers, their APIs, wire + protocols, and/or command-line interfaces. Such back ends are pluggable, allowing Ghidra to be + extended and integrated with additional debuggers.

-

When Ghidra recognizes the platform of a target in a connected debugger, it can record that - target into a local database and display the target state. Without recording, the UI will at - least allow interaction through a generic model and/or the debugger's command-line interface. - The recording, called a Trace in Ghidra, logs all the observations made by the framework or the - user. The user can rewind this recording at any point and the UI will recall those - observations, displaying the recorded machine state instead of the present machine state. These - traces can also be saved, loaded, and analyzed after a target has terminated or been - disconnected. Furthermore, they can be committed to a Ghidra Server for sharing and revision - control; however, conflicting changes cannot be merged.

+

Once a target is launched in the back end, the debugger can record that target into a Ghidra + Trace database, and the UI will display the target state. The user can command the debugger + using it's command-line interface (CLI) or the actions provided in Ghidra's Debugger UI. The + trace logs all the observations made by the framework or the user. The user can rewind this + recording during or after a session, and the UI will recall those observations, displaying the + recorded machine state instead of the present machine state. These traces can also be saved, + loaded, and analyzed after a target has terminated or been disconnected. Furthermore, they can + be committed to a Ghidra Server for sharing and revision control; however, conflicting changes + cannot be merged.

A system of mappings, which is usually populated automatically, tracks the relationship of - imported Ghidra programs to modules recorded in a trace. By default, Ghidra will synchronize - the cursor in the dynamic listing with that in the static listing, and encourage the user to - import missing modules. In this way, existing static analysis is readily at hand during a - dynamic analysis session, and the user can further populate program databases during a + imported Ghidra Program databases to modules recorded in a trace. By default, Ghidra will + synchronize the cursor in the dynamic listing with that in the static listing, and encourage + the user to import missing modules. In this way, existing static analysis is readily at hand + during a dynamic analysis session, and the user can further populate program databases during a debugging session. However, target memories contain more spaces than program images, e.g., stack and heap space, and some of those spaces are modified at runtime, e.g., .bss or .data. This information, if observed, is dutifully recorded into the trace for immediate or offline analysis.

-

A variety of plugins allow the user to interact with the target directly, view and - manipulate machine state, set breakpoints, view recordings, etc. See the table of contents for - a comprehensive list of current plugins. Plugins generally fall into one of these - categories:

+

A variety of plugins allow the user to interact with the target, view and manipulate machine + state, set breakpoints, view recordings, etc. See the table of contents for a comprehensive + list of current plugins. Plugins generally fall into one of these categories:

    -
  1. Target manipulation - those used for managing connections and interacting with targets, - regardless of tracing
  2. +
  3. Target manipulation - those used for managing connections and interacting with + targets.
  4. Trace manipulation - those used for viewing and manipulating the trace database, including machine state inspection. Most of these behave differently when the view is "at the diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/GettingStarted.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/GettingStarted.html index cacfe49fff..4eb7e1b4ef 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/GettingStarted.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/GettingStarted.html @@ -13,156 +13,133 @@

    Debugger: Getting Started

    -

    The debugger is poised to support debugging native user-mode applications for Windows and - Linux on 64-bit x86. This is accomplished by "connecting" to the respective debugger for each - platform: MS dbgeng.dll on Windows, and GDB/MI on Linux. A variety of configurations are - possible, and we are already developing more connectors, but native desktop applications are - the target for this release.

    +

    The debugger supports debugging native user-mode applications for Linux, macOS, and Windows + on 64-bit x86 and often arm64, e.g., when on "Apple Silicon." While not official, it also + supports a variety of other platforms, so long as Ghidra can connect to a debugger that + supports it. Launching is accomplished by connecting to the respective debugger for the target + platform: GDB on Linux, LLDB on macOS, and the Windows Debugger (dbgeng.dll) on + Windows. Several launch configurations are already included, and new launchers are fairly + easily added by writing shell scripts.

    Pay Attention to Errors

    Many actions are taken automatically on behalf of the user, e.g., reading registers when a - target is paused. In most cases, errors on automatic actions are dropped to the Debug Console, - as displaying them in a dialog could become a pest. That said, if things still don't seem - right, please check the application log messages.

    + target is paused. In most cases, errors on automatic actions are dropped to the Debug Console, as displaying + them in a dialog could become a pest. That said, if things still don't seem right, please check + the terminal or Ghidra's application log.

    Launching a Target

    -

    Starting up the Ghidra Debugger for the simplest use case, user-mode debugging of a local - process, entails two steps:

    +

    Starting up the Ghidra Debugger for user-mode debugging of a local process usually entails + just two steps:

    1. Open (or import) your program into the Debugger tool
    2. -
    3. Click the "Debug" button ("bug" icon) in the main toolbar
    4. +
    5. Click the Launch (bug icon) button in the main + toolbar
    -

    To load the default Debugger tool, from the main Ghidra application window select Tools → Import Default Tools... from the menus. Select - "defaultTools/Debugger.tool", and hit "OK". The Debugger tool will be added to the Tool +

    The first time you launch a given program, you may be asked to select and configure a + specific launcher. To load the default Debugger tool, from the main Ghidra application window + select Tools → Import Default Tools... from the menus. Select + "defaultTools/Debugger.tool", and hit OK. The Debugger tool will be added to the Tool Chest.

    To launch the tool, you have several options, identical to those you might use to launch the CodeBrowser tool. You can click the Debugger icon to launch an empty Debugger tool. You can drag a program that you have already imported from the Active Project window onto the tool icon - in the Tool Chest, or you can right-click on one of the project programs and pick Open With → Debugger. If you open an empty Debugger tool, you can add - programs to it later in the usual ways, e.g. via File → Import - File... or by dragging-and-dropping programs onto the running tool.

    + in the Tool Chest, or you can right-click on one of the programs in the project and pick + Open With → Debugger. If you open an empty Debugger tool, you can add programs to + it later in the usual ways, e.g. via File → Import File... or by + dragging-and-dropping programs onto the running tool.

    -

    The default tool is pre-configured with a collection of plugins relevant for the Listing and - for Debugger-related operations. As always, there is some chance that the tool will launch with - some portion of the plugins not displayed or with a less-than-optimal layout. To verify which - plugins you have, you can select File → Configure. "Debugger" - should already be selected. Choosing "Configure All Plugins" (the plug icon near the top - right), should show the full list of pre-selected plugins. Debugger-related plugins all begin - with "Debugger". At a bare minimum, you will need the "DebuggerTargetsPlugin" and the - "DebuggerObjectsPlugin", and the plugins on which they depend.

    +

    The default tool is pre-configured with a collection of plugins relevant to both dynamic and + static analysis. As always, there is some chance that the tool will launch with some portion of + the plugins not displayed or with a less-than-optimal layout. To verify which plugins you have, + you can select File → Configure. "Debugger" should already be selected. Choosing + Configure All Plugins (the plug icon) near + the top right should show the full list of pre-selected plugins. Debugger-related plugins all + begin with "Debugger" or "TraceRmi."

    -

    For the "Debug" button to work, you must (a) have the program you wish to run visible and - selected in the static Listing window, and (b) have imported the program from the place it +

    For the Launch button to work, you must (a) have the program you wish to run visible + and selected in the static Listing window, and (b) have imported the program from the place it lives on the local system. In other words, the file path associated with the program should be - the path to the executable for the current file system. You can verify this using the Help → About my_program menu item in the main tool bar. For example, - on a Linux system, if you've imported "xclock", Help → About - xclock... should have an entry at the bottom of the page for "Executable Location: - /usr/bin/xclock".

    - -

    Alternative launch options may be available using the dropdown next to the "Debug" button. - Furthermore, to access additional configuration options, use the Debugger - → Debug program → ... menu options. The options selected here are saved and - applied for later launches, whether from the button or the menu.

    + the path to the executable for the current file system. You can verify this using the Help + → About my_program menu item in the main tool bar. For example, on a Linux system, if + you've imported "xclock", Help → About xclock... should have an entry at the bottom + of the page for "Executable Location: /usr/bin/xclock".

    When you launch the target by this method, a number of changes should be evident in the GUI. - A blank "Agent" window may appear, indicating the agent status and connection port (if GADP was - selected). An interpreter console will appear, potentially including various information about - the launch. A connection will be added to the Targets window. A new tree + A Terminal should appear, containing the actual back end debugger, likely including some + initialization messages and diagnostics. A new trace will appears in the Listing. A new tree structure will be populated within the Objects window. The - remaining windows will be populated with current trace information. Please be patient, on some - platforms it may still take some time for things to populate and settle. The Debug Console - should provide some hints as to ongoing activity.

    + "help/topics/DebuggerModelPlugin/DebuggerModelPlugin.html">Model window. The remaining + windows will be populated with current trace information. Please be patient, on some platforms + it may still take some time for things to populate and settle. The Debug Console should provide + some hints as to ongoing activity.

    Debugger Components

    -

    Some of the more commonly-access components are explained below. Many also have their own +

    Some of the more commonly accessed components are explained below. They also have their own help pages.

    -

    Debugging Agent

    +

    Terminal

    -

    An "agent" is a process running on the local system, which acts as a mediator between the - Ghidra GUI and the native debugger. For systems such as Linux that support GDB, the agent wraps - the native GDB functionality via a Java container that implements the GDB machine interface - (GDB/MI). For Windows, the agent wraps the native dbgeng.dll functionality in a similar - fashion. The blank "Agent" window allows you to see the current status of the agent. If the - agent dies or is killed, the debugging session will be terminated. Of particular note, the - protocol used to communicate between the GUI and the agent is the Ghidra Asynchronous Debug - Protocol (GADP). It is not the native protocol associated with the debugger. Direct - communication with a native target is not currently supported, although that functionality may - be added in the future. If you choose an IN-VM connector, Ghidra will access the native - debugger directly, so no agent window will appear. This may be faster, but it also introduces - the risk of crashing Ghidra and losing data.

    +

    The terminal window allows a user command-line access to the native debugger. For Linux, + this means the standard GDB command line interface; for macOS, the LLDB command line interface; + and for Windows, the WinDbg/kd command set. While basic tasks may not require using the command + line interface, more complicated debugging scenarios invariably require commands specific to + the target which have not or cannot be implemented generically in the GUI. Additionally, if for + some reason the connection to Ghidra fails, the terminal will still provide command-line access + for diagnostics and/or manual recovery.

    -

    Interpreter

    +

    Model

    -

    The interpreter window allows a user command-line access to the native debugger. For Linux, - this means the standard GDB command line interface; for Windows, the WinDbg/kd command set. - While basic tasks may not require using the command line interface, more complicated debugging - scenarios invariably require commands specific to the target which have not or cannot be - implemented generically in the GUI.

    +

    The Model window + displays a directory of objects in a 3d-party debugging session using a structure determined by + its back-end plugin. In some cases, e.g., when the back end does not recognize the target's + architecture, other displays may struggle to display meaningful information. Even then, this + window should provide a good overview of the debugger's and its target's current state. It may + also provide some useful commands for diagnostics, but the terminal may be a better choice.

    -

    Targets / Connections

    +

    Listing

    -

    The "Debugger Targets" window adds an entry for every new debugger connection. These may be - added directly from this window using the "Connect" button. This allows the user to select - non-default connection options and/or to initiate a connection without launching or attaching - to a target. Using this method of starting a connection requires the additional step of - launching or attaching to a specific target.

    +

    The back end uses its connection to Ghidra to create a trace and record target information + into it. The Debugger's various windows all derive their contents from the current trace. + Perhaps the most important of these is the Listing window. Analogous to + the static listing, it displays the raw bytes in the target's memory and allows the user to + mark them up, e.g., disassemble, place data types, comment. Unlike the static listing, this + window shows live bytes in all valid memory, including stacks and heaps. When it can, the + Ghidra debugger keeps the cursor locations in the Static and Dynamic Listings synchronized.

    -

    Objects

    +

    Controls and Miscellany

    -

    To launch or attach to a target without using the "Debug" button, you will need to use the - "Objects" window. The "Objects" window provides a default tree-structured list of everything - the debugger knows about the target. On its tool bar are buttons for "Quick Launch', "Launch", - and "Attach". "Quick Launch", like the "Debug" button on the main tool bar, runs the executable - associated with the active program in the Listing view. "Launch" allows you to specify a target - and its parameters, typically, in the form of a command line. This target can be any executable - on the system and need not be associated with an imported program. The "Attach" button - populates a list with potential targets from the running process list for the system, which the - user may select and attach to.

    +

    The main toolbar provides your standard debugging controls, e.g., resume, step, interrupt. + They apply to the current thread or frame as defined by the back end's command set. For + details, see the Control plugin. During or + after a session, the user can examine trace history or emulate by changing control mode.

    -

    Traces and Threads

    - -

    The Targets, Objects, and Interpreter windows are the only windows populated directly using - information gleaned directly from the target. All other windows derive information from the - current trace. Once triggered, Ghidra captures information from the current debugging session - and uses this information to fill the other windows. The most important of these is the - "Threads" provider. The Threads window has two parts: one on the left listing the set of traced - target threads and one on the right indicating the current position in the trace by thread. If - no process is being traced or no thread is selected, all of the remaining windows will be - empty. If the current position (indicated by the draggable caret at the top of the right - display) lies outside the bounds of the current trace, all of the remaining windows will be - empty. Selecting a thread and a position causes the trace-based windows to display information - for that thread and time. From this window, the "step" buttons can be used to simulate target - execution to some extent.

    - -

    Commands / Miscellany

    - -

    The control buttons in the Objects window or commands issued in the Interpreter cause the - target to advance in the usual ways. (The control buttons in the Thread window, by contrast, - cause the trace to move forward or backward without affecting the target.) Breakpoints can be - set from either the "Breakpoints" window or the listing. The "Registers" and "Stack" display - reflect the state of the selected thread from the "Threads" window. Typically, the thread - selected for the trace in the Threads display is kept in sync with the active thread for the - debugger selected in the Objects view, but this need not be the case. Similarly, the "Dynamic - Listing" shows the bytes from the target's actual memory, which may or may not match the bytes - from the imported executable in the primary "Listing". When it can, the Ghidra debugger keeps - the Static and Dynamic Listings synchronized.

    +

    Breakpoints can be set from either the Breakpoints window + or the Listing. + The Registers + and Stack windows + reflect the state of the current thread, which can be selected in the Threads window. Typically, + the thread selected for the trace in the Threads window is kept in sync with the + active/selected/focused thread in the back-end debugger, but not always.

    Console

    -

    This console is a central place for reporting activity, errors, and suggesting actions. This - is the first place to look when troubleshooting.

    +

    The Debug Console + is a central place for reporting activity, errors, and suggesting actions. This and the + Terminal are the first places to look when troubleshooting.

    diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/Troubleshooting.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/Troubleshooting.html index 8617d48425..c646dfda9c 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/Troubleshooting.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/Debugger/Troubleshooting.html @@ -15,68 +15,79 @@

    Often, it's a good idea to troubleshoot by using the target platform's recommended debugger without connecting it to Ghidra. If it doesn't work there, it's not likely to work in Ghidra, - since it relies on that debugger. For Linux, use gdb; for Windows, use WinDbg; for macOS, use - LLDB.

    + since it relies on that debugger. For Linux, use gdb; for macOS, use LLDB; for Windows, use + WinDbg.

    + +

    Terminal

    + +

    The first place to look when you're having trouble is the debugger's terminal. If you do not + see one, check the Window → Terminals menu. If there is not one there, then there + is no back-end debugger running — unless, perhaps, you are trying to use a Recorder-based + target. See Plugin Configuration if you suspect this is the + case.

    + +

    If you already have the correct set of TraceRmi-based plugins enabled, but there is still no + terminal after attempting to launch, then the launcher is sorely mis-configured, or your system + or installation is broken. Use Debugger → Configure and Launch ... in the menus to + examine and modify your configuration and try again. This menu is also avaible in the drop-down + next to the Launch button.

    + +

    If you do have a terminal, then examine it, starting at the very top, for errors and + warnings.

    Error Console

    -

    The first place to look when you're having trouble is the Debug Console. Second, if you're - running from Eclipse, you can check its "Console" window. Often, Ghidra's Debug Console will - offer actions to help you resolve a well-known issue or configuration problem. It also - duplicates the error log when those messages are emitted from a debugger-related component. - These typically offer clues to exactly what has gone wrong.

    +

    The next place to look is the Debug Console. Launchers and + plugins for the Debugger often direct their diagnostic messages to this console, and sometimes + offer remedies.

    -

    Settings and Toggles

    +

    Application Log

    -

    This list is not exhaustive, but here are some options to examine if you're having trouble. - In the FrontEnd tool, under Edit → Tool Options, select - "Debugger.Workflow."

    +

    The next place to look is Ghidra's application log. From the main project window (not the + Debugger tool window), select Help → Show Log in the menus. This is Ghidra's full + application log, so you may need to sift through it for debugger-related entries. Usually + searching for "debugger", "launch", "tracermi", or the name of your platform's debugger, etc., + will help. If you're running from Eclipse, you can check its "Console" window.

    + +

    Plugin Configuration

    + +

    It is possible you have an old Debugger tool still configured for Recorder-based targets. + Recorder-based targets are being replaced by TraceRmi-based targets. Try re-importing the + default Debugger tool.

    + +

    Alternatively, use File → Configure then click the plug icon near the top right to check your tool configuration. The + following should be enabled:

      -
    • "Map modules..." and "Map sections..." control how the debugger attempts to map static - and dynamic memory.
    • +
    • TraceRmiPlugin
    • -
    • "Disassemble..." triggers automatic disassembly in the dynamic view.
    • +
    • TraceRmiLauncherServicePlugin
    • -
    • "Show debugger interpreter..." automatically provides access to the command line.
    • +
    • TraceRmiConnectionManagerPlugin
    • + +
    • DebuggerModelPlugin
    -

    In the Dynamic Listing:

    +

    The following should be disabled:

      -
    • "Sync to Static Listing" controls the tracking of the Static listing.
    • +
    • DebuggerModelServicePlugin
    • + +
    • DebuggerModelServiceProxyPlugin
    • + +
    • DebuggerInterpretersPlugin
    • + +
    • DebuggerObjectsPlugin
    • + +
    • DebuggerTargetsPlugin
    -

    In the Objects provider:

    +

    It is possible to leave both sets of plugins enabled, but this is by all means NOT + recommended.

    -
      -
    • "Record Automatically" causes a trace to be started when a Process object comes into - view. If the process object is not exposed automatically, you may have to expand the tree to - trigger the trace. If auto-record is toggled off, you'll need to hit "Record (R)" with the - process selected to start a trace.
    • - -
    • "Subscribe to..." causes a particular object to be tracked by the trace. Processes, - threads, registers, memory, stack, and so forth are tracked automatically, but you may wish - to add other objects ad hoc.
    • -
    - -

    In the Threads provider:

    - -
      -
    • The "Track the tool to the latest snap" toggle determines whether the caret (and all - resulting information) should track the current thread position as it updates.
    • - -
    • The "Synchronize trace activation..." toggle attempts to maintain synchronization between - the Object provider (i.e. the active target information) and the trace.
    • -
    - -

    In the Debugger menu:

    - -
      -
    • The "Save Traces By Default" toggle causes traces to be saved into the Ghidra project - database at the end of a session. (Open sessions will be re-opened with the tool in the - Threads window, reflected in the thin tabs at its top.)
    • -
    +

    Tutorial

    Additional troubleshooting recommendations are given in the Debugger course materials.

    diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html index e23b219d47..76d6fffe76 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html @@ -13,14 +13,9 @@

    Debugger: Breakpoints in the Listings

    - - - - - - -
    +
    + +

    For a description of how breakpoints are managed logically in Ghidra, please read about the Breakpoints @@ -37,14 +32,9 @@

    In the Function Graph

    - - - - - - -
    +
    + +

    When active in the Debugger, the Function Graph will display @@ -55,14 +45,9 @@

    In the Decompiler

    - - - - - - -
    +
    + +

    When active in the Debugger, the Decompiler will display breakpoints in @@ -86,8 +71,8 @@ other address-based contexts, but not all of those contexts include visual breakpoint indicators.

    -

    Toggle - Breakpoint (K)

    +

    + Toggle Breakpoint (K)

    This action is always available, and it is suitable for almost all cases. If there is a breakpoint at the cursor, this simply toggles its state. If there is no breakpoint at the @@ -99,7 +84,7 @@ actions to force specific commands. NOTE: The default parameters are not guaranteed to be accepted by the connected debugger.

    -

    Set +

    Set Breakpoint

    This menu is available on the dynamic listing when the target supports at least one @@ -107,18 +92,12 @@ breakpoint actions for each reasonable combination of kinds supported by the target. In the static listing, all reasonable combinations are available, regardless of target support; however, only those kinds supported by the target will be included in the resulting command. - NOTE: Breakpoints in the static listing can only be mapped to targets which are recorded - into a trace. Selecting one of the actions will display a prompt allowing adjustments to the - parameters before issuing the command.

    + Selecting one of the actions will display a prompt allowing adjustments to the parameters + before issuing the command.

    - - - - - - -
    +
    + +
    • Address - the address of the breakpoint. It defaults to the address of the instruction or @@ -136,19 +115,19 @@ static location, if applicable.
    -

    Enable +

    Enable Breakpoint

    This action is available when there is at least one disabled breakpoint at the cursor. It enables those logical breakpoints.

    -

    Disable - Breakpoint

    +

    + Disable Breakpoint

    This action is available when there is at least one enabled breakpoint at the cursor. It disables those logical breakpoints.

    -

    Clear +

    Clear (Delete) Breakpoint

    This action is available when there is at least one breakpoint (in any state) at the cursor. diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html index 40912e874d..d4681846f3 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html @@ -13,154 +13,147 @@

    Debugger: Breakpoints

    - - - - - - -
    +
    + +

    The breakpoints window tabulates and manipulates breakpoints among all traces, including live targets. Only address-based breakpoints are tabulated. For other traps, e.g., "break on exception," see the Objects Window. Breakpoints - can also be manipulated from address-based views, especially the disassembly listings. See Model window. Breakpoints can + also be manipulated from address-based views, especially the disassembly listings. See Breakpoints in the Listings.

    Individual breakpoint locations from among the traces are consolidated into logical - breakpoints, based on their addresses in the static listing. The static locations are typically - stored as bookmarks in their respective Ghidra programs, comprising the current breakpoint set. - See the Static Mappings - window for the finer details of address mapping. A breakpoint which cannot be mapped to a - static address becomes its own logical breakpoint at its dynamic address. The top table of the - provider displays logical breakpoints; the bottom table displays individual trace breakpoint - locations. NOTE: The breakpoints window cannot display or manipulate breakpoints from a - live target until that target is recorded into a trace. Only those breakpoints visible at the - current snapshot of each trace are included. For live targets, this is typically the latest - snapshot, i.e., the present.

    + breakpoints, based on their addresses in the static listing. The current breakpoint set + comprises the static locations, stored as bookmarks in their respective program databases. See + the Static + Mappings window for the finer details of address mapping. A breakpoint which cannot be + mapped to a static address becomes its own logical breakpoint at its dynamic address. The top + table of the provider displays logical breakpoints; the bottom table displays individual + breakpoint locations. NOTE: Only those breakpoints visible at the current snapshot of + each trace are included. For live targets, this is typically the latest snapshot, i.e., the + present.

    Depending on what is supported by the connected debugger, breakpoints can trap a target when an address or range is executed, read, or written; using software or hardware mechanisms. In - the case of "read" or "write" breakpoints, debuggers may differ in terminology. For example, - GDB might call them "watchpoints," but Ghidra still calls these "breakpoints." Some debuggers - allow the user to specify a breakpoint location other than by address, but ultimately each - specification is realized by 0 or more addressable locations. To accommodate this, the Objects window will - typically display a list of specifications, each listing its locations as children. However, - the grouping of breakpoint locations into logical breakpoints by Ghidra's breakpoint manager is - done without respect to the debugger's specifications. A specification may be at a - higher stratum than Ghidra natively understands, e.g., the source filename and line number, and - so such specifications are not relevant. Also note that the debugger might not permit locations - to be manipulated independently of their specifications. This may limit how Ghidra can operate, - since in that case, it must configure the specification, which may affect more locations than + the case of read or write breakpoints, debuggers may differ in terminology. + For example, GDB might call them watchpoints, but Ghidra still calls these + breakpoints. Some debuggers allow the user to specify a breakpoint location other than + by address, but ultimately each specification is realized by 0 or more addressable locations. + To accommodate this, the Model window will typically + display a list of specifications, each listing its locations as children. However, the grouping + of breakpoint locations into logical breakpoints by Ghidra's breakpoint manager is done + without respect to the debugger's specifications. A specification may be at a higher + stratum than Ghidra natively understands, e.g., the source filename and line number, and so + such specifications are not relevant. Also note that the debugger might not permit locations to + be toggled independently of their specifications. This may limit how Ghidra can operate, since + in that case, it must toggle the specification, which may affect more locations than intended.

    When the control - mode is set to "trace" or "emulator," it is possible to rewind the trace to past snapshots - and examine old breakpoints. You may also emulate from those snapshots, even if the target is - no longer alive. By default, those historical breakpoints are disabled in the integrated - emulator, but they can be toggled in the usual ways. In addition, the locations can be - manipulated independently, since the emulator has its own breakpoint set. Emulated breakpoints - can be configured with conditions expressed in Sleigh using the Set - Condition action, or configured to replace the instruction's semantics altogether using the - Set Injection action.

    + mode is set to Trace or Emulator, it is possible to rewind the trace to past + snapshots and examine old breakpoints. You may also emulate from those snapshots, even if the + target is no longer alive. By default, those historical breakpoints are disabled in the + integrated emulator, but they can be toggled in the usual ways. In addition, the locations can + be manipulated independently, since the emulator has its own breakpoint set. Emulated + breakpoints can be configured with conditions expressed in Sleigh using the Set Condition action, or configured to replace the instruction's semantics + altogether using the Set Injection action.

    Because of the logical grouping of breakpoints, it is possible for a breakpoint to be in a mixed or inconsistent state. This happens quite commonly, e.g., when a breakpoint is placed in - a Ghidra program before that program is mapped to any trace. Once mapped, the location of that - breakpoint in the trace is computed and noted as missing. A logical breakpoint without any - location in a trace is called ineffective and is drawn in grey, e.g.: . An enabled logical breakpoint having a disabled location - is called inconsistent and its icon will include an exclamation mark: . A disabled logical breakpoint having an enabled - location is similarly inconsistent. Toggling an ineffective or inconsistent logical breakpoint - enables and/or places all its mapped locations, aiming for a consistent enabled state. Toggling - it again disables all locations.

    + the Static Listing before that program is mapped to any trace. Once mapped, the dynamic + location of that breakpoint is computed and noted as missing. A logical breakpoint without any + location in a target is called ineffective and is drawn in grey, e.g.: . An enabled logical breakpoint + having a disabled location is called inconsistent and its icon will include an + exclamation mark: . A disabled + logical breakpoint having an enabled location is similarly inconsistent. Toggling an + ineffective or inconsistent logical breakpoint enables and/or places all its mapped locations, + aiming for a consistent enabled state. Toggling it again disables all locations.

    Tables and Columns

    The top table, which lists logical breakpoints, has the following columns:

      -
    • State: displays an icon indicating the state of the breakpoint. If rendered in - grey, the breakpoint has no locations, i.e., it is ineffective. If rendered with an - exclamation mark overlay, the breakpoint is inconsistent. Clicking the icon toggles the - breakpoint.
    • +
    • State - displays an icon indicating the state of the breakpoint. If rendered in grey, the + breakpoint has no locations, i.e., it is ineffective. If rendered with an exclamation mark + overlay, the breakpoint is inconsistent. Clicking the icon toggles the breakpoint.
      • -
      • Enabled: The logical - breakpoint, including all its locations, is enabled.
      • +
      • Enabled: The + logical breakpoint, including all its locations, is enabled.
      • -
      • Disabled: The logical - breakpoint, including all its locations, is disabled.
      • +
      • Disabled: The + logical breakpoint, including all its locations, is disabled.
      • -
      • Mixed: (Listing only) Two - logical breakpoints at the same address have different states.
      • +
      • Mixed: (Listing + only) Two logical breakpoints at the same address have different states.
      -
    • Name: gives the user-defined name of the breakpoint. This cell is only populated - and modifiable when the breakpoint is bookmarked in a program, since the name is associated - with the static location.
    • +
    • Name - gives the user-defined name of the breakpoint. This cell is only populated and + modifiable when the breakpoint is bookmarked in a program, since the name is associated with + the static location.
    • -
    • Address: gives the address of the breakpoint. This is typically the static - address. If the breakpoint cannot be mapped to a static address, this is its dynamic - address.
    • +
    • Address - gives the address of the breakpoint. This is typically the static address. If + the breakpoint cannot be mapped to a static address, this is its dynamic address.
    • -
    • Image: gives the name of the static image, i.e., Ghidra program. If the breakpoint +
    • Image - gives the name of the static image, i.e., Ghidra program. If the breakpoint cannot be mapped to a static location, this is blank.
    • -
    • Length: usually 1. For access breakpoints, this is the length in bytes of the - address range.
    • +
    • Length - usually 1. For access breakpoints, this is the length in bytes of the address + range.
    • -
    • Kinds: indicates the kind(s) of breakpoint: SW_EXECUTE, HW_EXECUTE, READ, and/or +
    • Kinds - indicates the kind(s) of breakpoint: SW_EXECUTE, HW_EXECUTE, READ, and/or WRITE.
    • -
    • Locations: counts the number of locations included in this logical breakpoint, - applying the trace filter if active. Note that a logical breakpoint with 0 locations is +
    • Locations - counts the number of locations included in this logical breakpoint, applying + the trace filter if active. Note that a logical breakpoint with 0 locations is ineffective.
    • -
    • Sleigh: indicates whether or not the breakpoint has a customized Sleigh - configuration. This is only relevant for emulation.
    • +
    • Sleigh - indicates whether or not the breakpoint has a customized Sleigh configuration. + This is only relevant for emulation.

    The bottom table, which lists breakpoint locations, has the following columns:

      -
    • State: displays an icon indicating the state of the location. If rendered with an +
    • State - displays an icon indicating the state of the location. If rendered with an exclamation mark overlay, the location does not agree with its logical breakpoint, or it cannot be bookmarked. Clicking the icon toggles the location.
      • -
      • Enabled: The location is - enabled.
      • +
      • Enabled: The + location is enabled.
      • -
      • Disabled: The location is - disabled.
      • +
      • Disabled: The + location is disabled.
      • -
      • Mixed: (Listing only) Two - locations at the same address have different states.
      • +
      • Mixed: (Listing + only) Two locations at the same address have different states.
      -
    • Name: displays the name given to the location by the connected debugger. This +
    • Name - displays the name given to the location by the connected debugger. This field is + user modifiable.
    • + +
    • Address - gives the dynamic address of this location.
    • + +
    • Trace - gives the name of the location's trace.
    • + +
    • Threads - (hidden by default) if the breakpoint applies to a limited set of threads, + gives the list of threads.
    • + +
    • Comment - gives a user comment — the specification's expression by default. This field is user modifiable.
    • -
    • Address: gives the dynamic address of this location.
    • - -
    • Trace: gives the name of the location's trace.
    • - -
    • Threads: (hidden by default) if the breakpoint applies to a limited set of - threads, gives the list of threads.
    • - -
    • Comment: gives a user comment — the specification's expression by default. - This field is user modifiable.
    • - -
    • Sleigh: (hidden by default) indicates whether or not the location has a customized - Sleigh configuration. This is only relevant for emulation.
    • +
    • Sleigh - indicates whether or not the location has a customized Sleigh configuration. + This is only relevant for emulation.

    Breakpoint Actions

    @@ -170,44 +163,45 @@ "help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html">Breakpoint Marker Actions in the listings.

    -

    +

    Enable

    This action is available when one or more breakpoints or locations are selected. It enables each selected breakpoint. For any breakpoint that is already enabled, no action is taken.

    -

    +

    Enable All Breakpoints

    This action is always available. It enables every breakpoint. For any breakpoint that is already enabled, no action is taken.

    -

    +

    Disable

    This action is available when one or more breakpoints or locations are selected. It disables each selected breakpoint. For any breakpoint that is already disabled, no action is taken.

    -

    - Disable All Breakpoints

    +

    Disable All Breakpoints

    This action is always available. It disables every breakpoint. For any breakpoint that is already disabled, no action is taken.

    Make Breakpoints Effective

    + "icon.debugger.breakpoint.make.effective"> Make Breakpoints Effective

    This action is available whenever there are mapped breakpoints with 0 locations, i.e., it corresponds to a target location where the breakpoint is still missing. It places such breakpoints where possible. This action is also offered as a resolution in the console. It appears in the log any time this action is available.

    -

    Clear

    +

    + Clear

    This action is available when one or more breakpoints or locations are selected. It clears (deletes) each selected breakpoint.

    -

    +

    Clear All Breakpoints

    This action is always available. Use with caution! It deletes every @@ -335,14 +329,14 @@ emu_skip_decoded();

    For organizing breakpoints the manager provides the following actions:

    -

    Filter to +

    Filter to Current Trace

    This toggle is always available. It filters the bottom table to those locations in the current trace only. Additionally, the "Locations" column of the top table will only count those in the current trace.

    -

    Filter to +

    Filter to Breakpoint Selection

    This action is always available. It filters the bottom table to those locations belonging to diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/images/DebuggerBreakpointsPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/images/DebuggerBreakpointsPlugin.png index 46fcfafe1e..4188c674e0 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/images/DebuggerBreakpointsPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/images/DebuggerBreakpointsPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html index a01c5b64af..70f0a05958 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html @@ -13,31 +13,26 @@

    Debugger: Console

    - - - - - - -
    +
    + +
    -

    The console logs messages from Ghidra related to the debugger. Depending on the exact - configuration, this can comprise a wide range of components, including all GUI views, active - connectors, and running agents. Soon, it may also provide a command-line interface to control - Ghidra's debugging sessions and interact with traces.

    - -

    Some log messages include an action context, allowing plug-ins to offer actions on that - message. These are said to be "actionable" messages. A noteworthy example is when navigating to - a module that could not be automatically mapped from the current project. Instead of displaying - a prompt, it will log a message and suggest actions to resolve the issue. A successful - resolution typically removes the message from the log. Note that additional actions may be - available from the context menu.

    +

    The console logs messages from Ghidra related to the debugger. This no longer includes + messages sent to the application log, but only messages that plug-ins deliberately deliver to + this console. Some log messages include an action context, allowing plug-ins to offer actions + on that message. These are said to be "actionable" messages. A noteworthy example is when + navigating to a module that could not be automatically mapped from the current project. Instead + of displaying a prompt, it will log a message and suggest actions to resolve the issue. A + successful resolution typically removes the message from the log. Note that additional actions + may be available from the context menu. Some messages communicate progress of a background + task. These may have a progress bar, and the associated message may change over time. These + entries may offer a cancel action.

    By default, the log is sorted so that actionable messages appear at the top. Then, it is sorted by descending date, so that the most recent messages appear at the top. Like any other Ghidra table, it can customized and filtered. Note that the filter box is at the top, because - we anticipate a command-line input in the future, which we'd like to place at the bottom.

    + we anticipate a command-line input in the future, which we would like to place at the + bottom.

    Table Columns

    @@ -55,8 +50,7 @@

    Actions

    -

    Not considering extension actions from other plugins, the console provides the - following:

    +

    Not considering actions for "actionable" messages, the console provides the following:

    Clear

    @@ -68,7 +62,7 @@

    Cancel

    -

    Some experimental features may display progress entries in the log for background tasks they - run. This action is displayed in the Actions column and will cancel the task.

    +

    For a tasks displaying a progress message in the console, this action will cancel the + task.

    diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerConsolePlugin/images/DebuggerConsolePlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerConsolePlugin/images/DebuggerConsolePlugin.png index fb80f86668..da192195c2 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerConsolePlugin/images/DebuggerConsolePlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerConsolePlugin/images/DebuggerConsolePlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerControlPlugin/DebuggerControlPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerControlPlugin/DebuggerControlPlugin.html index 05ebc6adf4..6e4c3283c2 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerControlPlugin/DebuggerControlPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerControlPlugin/DebuggerControlPlugin.html @@ -31,32 +31,32 @@ are:

      -
    • Control Target w/Edits Disabled: The default, - this presents actions for controlling the live target but rejects all machine-state edits. - Breakpoint commands are directed to the live target. When active, the UI automatically - follows the latest snapshot recorded. If the target is terminated, the mode is automatically +
    • Control Target w/Edits + Disabled: The default, this presents actions for controlling the live target but rejects + all machine-state edits. Breakpoint commands are directed to the live target. When active, + the UI automatically follows the latest snapshot recorded, and navigating back in time is not + permitted. If the target is terminated and the trace remains open, the mode is automatically switched to Control Trace.
    • -
    • Control Target: This presents actions - for controlling the live target and directs edits to the live target. Breakpoint commands are - directed to the live target. To accept edits, the UI must be "live and at the present." If - the trace has no associated target, i.e., it is dead; or if the current view is in the past - or includes any steps of emulation, i.e., it is not at the present; then edits are rejected. - When active, the UI automatically follows the latest snapshot recorded. If the target is - terminated, the mode is automatically switched to Control Emulator.
    • +
    • Control Target: This + presents actions for controlling the live target and directs edits to the live target. + Breakpoint commands are directed to the live target. When active, the UI automatically + follows the latest snapshot recorded, an navigating back in time is not permitted. If the + target is terminated and the trace remains open, the mode is automatically switched to + Control Emulator.
    • -
    • Control Trace w/Edits Disabled: - This presents actions for navigating trace snapshots but rejects all machine-state edits. - Breakpoint commands are directed to the emulator.
    • +
    • Control Trace w/Edits + Disabled: This presents actions for navigating trace snapshots but rejects all + machine-state edits. Breakpoint commands are directed to the emulator.
    • -
    • Control Trace: This presents actions for - navigating trace snapshots. It directs all edits to the trace database. Edits are generally - always accepted, and they are applied directly to the trace. Breakpoint commands are directed - to the emulator.
    • +
    • Control Trace: This + presents actions for navigating trace snapshots. It directs all edits to the trace database. + Edits are generally always accepted, and they are applied directly to the trace. Breakpoint + commands are directed to the emulator.
    • -
    • Control Emulator: This presents - actions for controlling the integrated emulator. Breakpoint commands are directed to the - emulator. This can be used for interpolating and extrapolating execution from the current +
    • Control Emulator: This + presents actions for controlling the integrated emulator. Breakpoint commands are directed to + the emulator. This can be used for interpolating and extrapolating execution from the current snapshot, without affecting the live target. It directs edits to the integrated emulator by generating patch steps and appending them to the emulation schedule. See the Go To Time action. @@ -71,67 +71,67 @@ only when the current trace has an associated live target. Commands are directed to the focused object or a suitable substitute.

      -

      Resume

      +

      Resume

      Allow the current target to resume execution. Other debuggers may call this "continue" or - "go." If successful, the target enters the "running" state until/if it is interrupted or + "go." If successful, the target enters the "running" state until it is interrupted or terminated. This is available when the target is currently stopped.

      -

      Interrupt

      +

      Interrupt

      Interrupt the current target's execution. Other debuggers may call this "break," "suspend," or "stop." If successful, the target enters the "stopped" state. This is available when the target is currently running.

      -

      Kill

      +

      Kill

      -

      Kill the current target. Other debuggers may call this "terminate" or "stop." By default, - this will consequently close the current trace. If successful, the target enters the - "terminated" state. This is always available for a live target.

      +

      Kill the current target. Other debuggers may call this "terminate" or "stop." This may + consequently close the current trace. If successful, the target enters the "terminated" state. + This is always available for a live target.

      -

      Disconnect

      +

      Disconnect

      Disconnect from the current target's debugger. This usually causes the connected debugger to - terminate and likely kill its targets. By default, this will consequently close the trace for - all affected targets. This is always available for a live target.

      + terminate and likely kill its targets. This may consequently close the current trace (and + perhaps others). This is always available for a live target.

      -

      Step Into

      +

      Step Into

      Step the current target to the next instruction. This is available when the target is currently stopped. If successful the target may briefly enter the "running" state.

      -

      Step Over

      +

      Step Over

      Step the current target to the next instruction in the current subroutine. This is available when the target is currently stopped. If successful the target may briefly enter the "running" state.

      -

      Step Out

      +

      Step Out

      Allow the current target to finish the current subroutine, pausing after. This is available when the target is currently stopped. If successful the target may briefly enter the "running" state.

      -

      Step Repeat Last / - Extended

      +

      Step Extended (Repeat Last)

      -

      Perform a target-defined step, often the last (possibly custom or extended) step. This is - available when the target is currently stopped. If successful the target may briefly enter the - "running" state.

      +

      Perform a target-defined step, perhaps the last (possibly custom) step. This is available + when the target is currently stopped. If successful the target may briefly enter the "running" + state.

      Trace Navigation Actions

      These actions are visible when a Control Trace mode is selected. They are available when there is an active trace.

      -

      +

      Snapshot Backward

      This activates the previous snapshot. All windows displaying machine state will show that recorded in the activated snapshot. This is available only when there exists a snapshot previous to the current.

      -

      +

      Snapshot Forward

      This activates the next snapshot. All windows displaying machine state will show that @@ -144,7 +144,7 @@ available when there is an active trace. Commands are directed to the integrated emulator for the current trace.

      -

      Resume

      +

      Resume

      Allow the emulator to resume execution. This is available when no other integrated emulator is running. A monitor dialog is presented during execution, but the GUI remains responsive. @@ -154,14 +154,14 @@ system calls are not yet supported. It could also start executing from unmapped memory or enter an infinite loop. If it seems to carry on too long, interrupt it and examine.

      -

      Interrupt

      +

      Interrupt

      Interrupt the currently-running emulator. This is available when any integrated emulator is running. In most cases, this is the emulator for the current trace, but it may not be. Canceling the dialog for an emulation task will also interrupt the emulator. Upon interruption, the emulation schedule is noted and the snapshot displayed in the GUI.

      -

      Step Back

      +

      Step Back

      Steps the emulator to the previous instruction, by flow. This is available when the current snapshot includes emulated steps. This operates by repeating the current emulation schedule @@ -169,7 +169,7 @@ not common, if emulation to the current snapshot took a good bit of time, then stepping backward will likely take about the same amount of time.

      -

      Step Into

      +

      Step Into

      Steps the emulator to the next instruction, by flow. This is available when there is an active thread. At worst, this operates by repeating the current emulation schedule with one @@ -177,7 +177,7 @@ current snapshot and advance it a single step. Note that "Step Over" is not currently supported by the emulator.

      -

      Skip Over

      +

      Skip Over

      Skips the emulator over the current instruction, ignoring flow. This is available when there is an active thread. At worst, this operates by repeating the current emulation schedule with diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerCopyActionsPlugin/DebuggerCopyActionsPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerCopyActionsPlugin/DebuggerCopyActionsPlugin.html index 49a7fa961f..1e4968c50d 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerCopyActionsPlugin/DebuggerCopyActionsPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerCopyActionsPlugin/DebuggerCopyActionsPlugin.html @@ -16,8 +16,8 @@

      In the course of debugging, the user may want to capture certain state and annotations from the dynamic context into the static. This might include the contents of the stack, the heap, or example data stored in uninitialized memory. The copy actions allow for the easy movement of - data and annotations from traces into programs. The actions are all accessed via the Debugger menu.

      + data and annotations from traces into programs. The actions are all accessed via the + Debugger menu.

      Actions

      @@ -46,14 +46,9 @@

      The Copy Into... actions both present the same dialog: (The Export Trace View action uses a different dialog.)

      - - - - - - -
      +
      + +

      The dialog consists of several options, followed by a table that displays the proposed ranges to copy. For selected ranges not contained in the destination program's memory, new diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerCopyActionsPlugin/images/DebuggerCopyIntoProgramDialog.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerCopyActionsPlugin/images/DebuggerCopyIntoProgramDialog.png index f3c51f59ff..2f9c4d60fe 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerCopyActionsPlugin/images/DebuggerCopyIntoProgramDialog.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerCopyActionsPlugin/images/DebuggerCopyIntoProgramDialog.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerInterpreterPlugin/DebuggerInterpreterPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerInterpreterPlugin/DebuggerInterpreterPlugin.html index 25805ceb04..0134999ec1 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerInterpreterPlugin/DebuggerInterpreterPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerInterpreterPlugin/DebuggerInterpreterPlugin.html @@ -13,10 +13,14 @@

      Debugger: Interpreters

      +

      This window only supports the older "Recorder-based" + targets. For newer "TraceRmi-based" targets, the actual debugger runs in an integrated VT-100 + terminal emulator.

      +

      For debuggers which have built-in interpreters (many do), and whose connectors expose that interpreter in the model, the interpreters plugin can provide user access to it via a graphical - console emulator. The plugin leverages the existing interpreter console framework in Ghidra, so - the interface should be relatively familiar. Typically, the console is accessed via the Objects + console. The plugin leverages the existing interpreter console framework in Ghidra, so the + interface should be relatively familiar. Typically, the console is accessed via the Objects window's Console action. Output is displayed in a large text field, and user input is taken via a small text field at diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html index 327c910ad9..0e14c7435a 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html @@ -13,14 +13,9 @@

      Debugger: Dynamic Listing

      - - - - - - -
      +
      + +

      The dynamic listing is analogous to Ghidra's listing for static analysis, but in the dynamic context. It displays annotated memory contents from a target. More @@ -55,8 +50,8 @@ which have not been read at the current time, are displayed with a darker background. Where that memory is marked "read-only" and has been successfully read previously, that coloring is subdued, since the contents are not likely to have changed. Where a read was attempted but - failed, the first address in the failed range is displayed with a pink background. Otherwise, - up-to-date contents are displayed with the default background color.

      + failed, the entire failed range is displayed with a pink background. Otherwise, up-to-date + contents are displayed with the default background color.

      The dynamic listing supports editing memory. See Control and Machine State. @@ -64,6 +59,26 @@ "help/topics/AssemblerPlugin/Assembler.htm">Patch actions, or by pasting byte strings. These edits may be directed toward a live target, the trace, or the emulator.

      +

      Trace Tabs

      + +

      The trace tab bar is displayed when at least one trace is open. It displays the name of each + open trace in a tab, where the "current" or "focused" trace is selected. Clicking a tab will + select its trace and focus the tool onto it. A trace associated with a live target has a red + "recording" icon at its left. If that icon is not + present, or has disappeared, the trace is dead or terminated. A "dead" trace can still be + manipulated and marked up, but it will not record any new target information.

      + +

      Close Trace / All / Other / Dead + Traces

      + +

      In most cases, a trace is ephemeral, but occasionally, interesting behavior is observed that + is difficult to store as static mark-up. When traces are no longer needed, they can be closed. + Several can be closed at once by right-clicking a tab and selecting one of the actions. See Trace + Management for details of each action.

      +

      Actions

      The listing provides a variety of actions, some for managing and configuring listings, and @@ -71,16 +86,16 @@

      New Dynamic Listing

      -

      This action is always available in the Window → Debugger - menu. It creates a new listing window with the same configuration as the primary dynamic - listing. It is equivalent to cloning the primary dynamic listing.

      +

      This action is always available in the Window → Debugger menu. It creates a new + listing window with the same configuration as the primary dynamic listing. It is equivalent to + cloning the primary dynamic listing.

      Export Trace View

      -

      This action is available whenever there is a trace open in the listing. It is analogous to - "Export Program," but for the current trace at the current time. This provides a mechanism for - capturing a particular point in time from a trace as a static image. The exported image can be - analyzed in Ghidra or another tool.

      +

      This action is available in the Debugger menu whenever there is a trace open in the + listing. It is analogous to "Export Program," but for the current trace at the current time. + This provides a mechanism for capturing a particular point in time from a trace as a static + image. The exported image can be analyzed in Ghidra or another tool.

      Follows Selected Thread

      @@ -141,13 +156,9 @@ of labels, registers, and constants. Labels may come from the current trace or a program mapped into the trace. Ambiguities are resolved arbitrarily.

      - - - - - - -
      +
      + +

      Some examples:

      @@ -231,30 +242,36 @@

      Read Memory

      -

      This action is available when the current trace is "at the present" with a live target, and - there is a selection of addresses in the dynamic listing. It will instruct the recorder to read - and record the contents of memory for the selected range(s). Typically, the viewable addresses - are automatically read, anyway — see the Auto-Read action.

      +

      This action is available when the current trace is "at the present" with a live target. It + will instruct the target to read the contents of memory for the selected or visible addresses. + Typically, the visible addresses are automatically read — see the Auto-Read action + — so this action is for refreshing or for reading large selections.

      Auto-Read Memory

      This action is always available on all dynamic listings. It configures whether or not the - memory range(s) displayed in the listing are automatically read and recorded. Like the Read - Memory action, it is only permitted when the current trace is "at the present" with a live - target. It occurs when the user scrolls the listing, or when the listing is otherwise navigated - to a new location. Note that other components may read memory, regardless of this listing's - configuration. For example, the recorder typically reads the page of memory pointed to by the + memory range(s) displayed in the listing are automatically read. Like the Read Memory action, + it is only permitted when the current trace is "at the present" with a live target. It occurs + when the user scrolls the listing, or when the listing is otherwise navigated to a new + location. Note that other components may read memory, regardless of this listing's + configuration. For example, the target typically reads the page of memory pointed to by the program counter. In other words, this action cannot "disable all memory reads." The options are pluggable, but currently consist of:

        -
      • Do Not Read Memory - disables automatic memory reads for this listing only.
      • +
      • Do Not Read Memory - disables automatic memory + reads for this listing only.
      • -
      • Read Visible Memory - automatically reads stale ranges that enter this listing's - view.
      • +
      • Read Visible Memory - automatically + reads stale ranges that enter this listing's view.
      • -
      • Read Visible Memory, RO Once - (default) behaves like Read Visible Memory, except it will - neglect read-only ranges that have been read previously.
      • +
      • Read Visible Memory, RO Once - + (default) behaves like Read Visible Memory, except it will neglect read-only ranges that have + been read previously.
      • + +
      • Load Emulator from Programs - populates the + trace database using mapped program databases. This is often preferred during "pure + emulation," so that the dynamic listing's contents match those of the static listing.
      diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerGoToDialog.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerGoToDialog.png index bfc2dca48c..8118722273 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerGoToDialog.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerGoToDialog.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerListingPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerListingPlugin.png index ebe1c9b18e..d8d7e04dc7 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerListingPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerListingPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemoryBytesPlugin/DebuggerMemoryBytesPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemoryBytesPlugin/DebuggerMemoryBytesPlugin.html index fc78637adb..fad66b181c 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemoryBytesPlugin/DebuggerMemoryBytesPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemoryBytesPlugin/DebuggerMemoryBytesPlugin.html @@ -13,14 +13,9 @@

      Debugger: Memory (Dynamic Bytes)

      - - - - - - -
      +
      + +

      The memory, or dynamic bytes, window is analogous to Ghidra's bytes window for static analysis, but in the dynamic context. It displays memory contents from @@ -36,13 +31,13 @@ use clones to display different points in time for the same trace.

      Because not all memory is recorded, some background coloring is used to indicate the state - of attempted memory reads. Regardless of state, the most-recent contents, as recorded in the - trace, are displayed in the window, defaulting to 00. "Stale" memory, that is ranges of memory - which have not been read at the current time, are displayed with a darker background. Where - that memory is marked "read-only" and has been successfully read previously, that coloring is + of attempted memory reads. Regardless of state, the most-recent contents recorded in the trace + are displayed in the window, defaulting to 00. "Stale" memory, that is ranges of memory which + have not been read at the current time, are displayed with a darker background. Where that + memory is marked "read-only" and has been successfully read previously, that coloring is subdued, since the contents are not likely to have changed. Where a read was attempted but - failed, the first address in the failed range is displayed with a pink background. Otherwise, - up-to-date contents are displayed with the default background color.

      + failed, the entire range is displayed with a pink background. Otherwise, up-to-date contents + are displayed with the default background color.

      The dynamic bytes viewer supports editing memory. See Control and Machine State. @@ -72,52 +67,32 @@

      Track Location

      -

      This action is equivalent to the same action in the Dynamic - Listing window. NOTE: This feature is disabled when the edit toggle is on.

      +

      This action is equivalent to the same action + in the Dynamic Listing window. NOTE: This feature is disabled when the edit toggle is + on.

      Go To (G)

      -

      This action is equivalent to the same action in the Dynamic Listing - window.

      +

      This action is equivalent to the same action in the + Dynamic Listing window.

      - - - - - - -
      +
      + +

      Read Memory

      -

      This action is available when the current trace is "at the present" with a live target, and - there is a selection of addresses in the memory window. It will instruct the recorder to read - and record the contents of memory for the selected range(s). Typically, the viewable addresses - are automatically read — see the Auto-Read action.

      +

      This action is equivalent to the same action in + the Dynamic Listing window.

      Auto-Read Memory

      -

      This action is always available on all memory windows. It configures whether or not the - memory range(s) displayed in the window are automatically read and recorded. Like the Read - Memory action, it is only permitted when the current trace is "at the present" with a live - target. It occurs when the user scrolls the window, or when the window is otherwise navigated - to a new location. Note that other components may read memory, regardless of this windows's - configuration. For example, the recorder typically reads the page of memory pointed to by the - program counter. In other words, this action cannot "disable all memory reads." The - options are pluggable, but currently consist of:

      - -
        -
      • Do Not Read Memory - disables automatic memory reads for this window only.
      • - -
      • Read Visible Memory - automatically reads stale ranges that enter this window's - view.
      • - -
      • Read Visible Memory, RO Once - (default) behaves like Read Visible Memory, except it will - neglect read-only ranges that have been read previously.
      • -
      +

      This action is equivalent to the same action in + the Dynamic Listing window.

      Byte Viewer Options

      @@ -126,8 +101,9 @@

      Toggle Editing

      This action does the same as it does for the static context. Edits may be rejected if the - trace's editing mode is set to Read-Only in the tool. NOTE: This toggle also disables - automatic navigation in order to prevent the cursor from being moved unexpectedly while typing - edits.

      + trace control mode is + set to Read-Only in the tool. NOTE: This toggle also disables automatic navigation in + order to prevent the cursor from being moved unexpectedly while typing edits.

      diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemoryBytesPlugin/images/DebuggerMemoryBytesPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemoryBytesPlugin/images/DebuggerMemoryBytesPlugin.png index feebf9768f..0378a6ccaa 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemoryBytesPlugin/images/DebuggerMemoryBytesPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemoryBytesPlugin/images/DebuggerMemoryBytesPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemviewPlugin/DebuggerMemviewPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemviewPlugin/DebuggerMemviewPlugin.html index 90bd80ccd8..b1edac8cc4 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemviewPlugin/DebuggerMemviewPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerMemviewPlugin/DebuggerMemviewPlugin.html @@ -13,14 +13,9 @@

      Debugger: Memory View

      - - - - - - -
      +
      + +

      As in the Threads view, you may wish to follow the evolution of various objects over time. The memory viewer window provides a generic time vs. address (or address vs. time) plot of @@ -60,22 +55,22 @@

      Navigation

      -

      Zoom

      +

      Zoom

      The four zoom buttons either contract or expand the view along the time or address axes.

      -

      Toggle Layout

      +

      Toggle Layout

      The default panel view is time vs. address. The toggle button serves as both the way to switch views and to refresh the display.

      -

      Toggle Process +

      Toggle Process Trace

      By default, as new objects are added to a debugger trace, they appear in the table and panel. The behavior can be toggled on or off at the user's discretion.

      -

      Toggle Apply +

      Toggle Apply Filter

      This button determines whether the table filter affects the plot panel. When toggled on, diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModelPlugin/DebuggerModelPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModelPlugin/DebuggerModelPlugin.html new file mode 100644 index 0000000000..92ab871d9c --- /dev/null +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModelPlugin/DebuggerModelPlugin.html @@ -0,0 +1,308 @@ + + + + + + + Debugger: Model Objects + + + + + +

      Debugger: Model Objects

      + +
      + +
      + +

      The Model window permits the user to inspect the trace's object database. It also provides + access to some target-defined actions that might not otherwise be accessible from the rest of + the Debugger UI. The object database is a generic description of everything present on the + target and their states. Many of the other windows, e.g., Modules, Regions, Threads, are just + specialized versions of this window.

      + +

      The target describes the structure of its object directory using a model schema. + The Debugger UI uses the schema to navigate this directory and find relevant objects. For most + mundane targets, the Model window is not necessary, but may still be preferred by some users. + For targets implementing features not natively built into the Debugger, the Model and/or + Terminal windows are essential.

      + +

      The model window consists of three togglable panes: Objects + Tree, Elements Table, and Attributes Table. At the top is a path entry field, which identifies + the current object. Each pane can be hidden, and the whole window can be cloned, allowing users + to customize multiple views. When docked to the side of the Debugger UI, it is common to hide + both tables, so that the Object tree is not obscured. Users who like to see register values in + the tree should enable Show Primitives in Tree.

      + +

      Objects Tree Pane

      + +

      The Tree pane on the left displays the complete object directory. The back-end debugger may + name its Root node to better describe itself. All nodes below that are defined by the target, + but some common nodes are: Available, Processes, Breakpoints, Memory, Modules, Threads, Stack, + and Registers.

      + +
        +
      • Available: This node typically lists running processes on the debugger's host to + which it may attach.
      • + +
      • Processes: This node lists all current target processes to which the debugger is + currently attached. Most often, there is only one.
      • + +
      • Breakpoints: This node may appear as a child of the root or of each target + process. It lists the breakpoints for the entire session (in the former case) or for the + target process (in the latter case) or some combination of both. Some targets distinguish + between a breakpoint specification and its locations. If that is the case, the locations + should be children of their specification. If breakpoints are specified for the entire + session, then each target process should also have a Breakpoints node whose children are + links to the locations within that target.
      • + +
      • Memory: This should always appear as a child of a target. It lists the memory + regions, if known, in that target. For processes, this is the memory map. Only those + addresses in a listed region are valid. For targets where the memory map is not known or + cannot be retrieved, there may be a single region covering the entire address space, simply + to ensure the Dynamic Listing and Byte viewers are populated.
      • + +
      • Modules: This should always appear as a child of a target process. It lists + modules known to be loaded into its memory. Some back ends may also present a Sections + node for each module, which lists the sections of that module. Reporting sections for all + modules is often expensive, so each Sections node may be empty until explicitly loaded or + refreshed.
      • + +
      • Threads: This should always appear as a child of the target. It lists all the + threads executing in the target. Even if the target's platform does not support + multi-threading, this node is typically still present, but will list only the one + thread.
      • + +
      • Stack: This node is not always present, depending on whether the back-end debugger + supports unwinding the stack. Most do. It should always appear as a child of a thread. It + lists the stack frames for that thread, where the topmost, i.e., current or innermost, frame + is numbered 0. Each successive unwound frame is numbered 1 and counting up.
      • + +
      • Registers: This node may appear as a child of a thread or frame. It lists the + registers and their values. In contrast to the Registers window, the values displayed here + have not been mapped into the trace's Sleigh language. The names and values are + determined entirely by the back end. As the child of a thread, the values are the current + register values for that thread. The PC value may be adjusted by the debugger to reflect its + logical value instead of its actual value. As the child of a frame, then frame 0's values are + the current register values for the containing thread. The values for each successive frame + are those recovered by the debugger unwinding the stack. Please see the back-end debugger's + documentation for any caveats that may apply. Unwinding is often an imperfect science. + NOTE: Because targets often record register values as primitive attributes, they may + not appear in the tree pane by default. Use the Attributes pane, or toggle Show Primitives in Tree in the local drop-down menu.
      • +
      + +

      Node Display and Selection

      + +

      Most often, each node is displayed by its name. A target may specify the display text, + usually to make it match what appears in its terminal or to present a useful summary of that + object. When a child is a link, the tree displays its key followed by its value in italics. + When a child is a primitive, it is not displayed in the tree by default. This can be toggled + using Show Primitives in Tree, in which case, it displays the + key followed by the primitive value. Clicking an object will select it and cause the other two + panes to display the detailed contents of that node, including its primitive values, if any. + Double-clicking an object may have one of 3 effects, in order of precedence:

      + +
        +
      1. If the object is activatable, i.e., focusable or selectable, the object will be + activated. This is typically the case for sessions, targets, processes, threads, and frames. + The back-end may further refine the selection. E.g., when activating a process, it may choose + a thread and select its top frame. This becomes the current context throughout the Debugger + UI, often including the back end's command-line interface.
      2. + +
      3. If the object is togglable, the object will be toggled. This is typically the case + for breakpoints and maybe their locations. NOTE: The Breakpoint manager, which is + otherwise responsible for all breakpoint interactions in the Debugger UI, prefers to toggle + breakpoint locations rather than specifications. Beware that toggling a specification via the + Model window may put the UI in an unexpected state. The Breakpoint manager will attempt to + toggle the location, despite its specification being disabled, which may prevent it from + having any effect. If you seem to be having trouble toggling a breakpoint elsewhere in the + UI, check and enable the breakpoint specification here or in the command-line interface.
      4. + +
      5. If the object represents an address or range, this will go to that address + in the Dynamic Listing. If it's a range, it will go to the minimum address and select the + range. This is typically the case for memory regions, modules, sections, and breakpoint + locations; however, breakpoint locations are often togglable, which supersedes go-to.
      6. +
      + +

      Right-clicking an object may present a context menu of target-defined actions. Expanding an + object will display its children. If the target provides a refresh method for the + object, expanding it will invoke that method. To suppress the refresh, hold SHIFT when + expanding.

      + +

      Elements Table Pane

      + +

      The Elements pane on the top right displays the elements of the current object. Typically, + this is the object selected in the Tree pane. Each element is displayed in a row. In most + cases, these are canonical values. That is the parent's path plus the value's key + gives the child object's path. If not, then the value is a link. Links are fairly rare, but may + happen, e.g., to list a target's breakpoint locations when the specifications are kept in a + per-session container. (GDB's model exhibits this schema.) In rarer cases, elements may be + primitive values. There are 4 standard columns plus any number of target-defined columns:

      + +
        +
      • Key - This is the index used to access the element from its parent.
      • + +
      • Value - This is the value of the element.
      • + +
      • Life - This is the "life" of the object. Trace databases record changes to the object + model over a timeline of snapshots. Many objects, especially containers, have a life from 0 + to infinity. Others, e.g., threads will have lives indicating their first and last + observations. Rarely, an object may have multiple disjoint lifespans.
      • + +
      • Plot - This is a visual plot of the "life" of the object. It is hidden by default. The + header for this column contains a caret that shows the Debugger UI's current snapshot within + this plot. Clicking or dragging in that header while in Control Trace or Control + Emulator mode will + activate the clicked snapshot, allowing quick navigation through time. To suppress this + behavior, i.e., so that you can reposition or sort the column, hold SHIFT while + clicking or dragging.
      • + +
      • [Attribute] - Each relevant attribute described in the schema generates a column. + The target determines which are visible and hidden by default. Right-click the table header + to view all available columns. The available columns will vary depending on the current + object.
      • +
      + +

      Row, Cells, and Selection

      + +

      Clicking a row selects it and causes the Attributes pane to display the selected object's + attributes. Double-clicking a row behaves similarly to the Tree pane. A key difference is when + double-clicking a specific cell. If it is an address or range, the UI will go to that address + or range. If it is an object (or a link), then the UI will activate, toggle, or go to that + object. If no such per-cell action is applicable, then the UI will activate, toggle, or go to + the object represented by the row. Right-clicking may present a context menu of target-defined + actions.

      + +

      Attributes Table Pane

      + +

      The attributes pane on the bottom right displays the attributes of the current object, or + the selected element. If the Object tree's selection changed last, this displays the attributes + of the object selected in the tree. Likewise, if the Elements table's selection changed last, + this displays the attributes of the selected element. Each attribute, whether or not described + in the schema, is displayed in a row, unless marked as hidden by the target. For canonical + values, the parent's path plus the value's key gives the child object's path. Linked objects + are also possible, but primitive values are most common. The columns are:

      + +
        +
      • Key - This is the name used to access the attribute from its parent.
      • + +
      • Path - This is the full path to the attribute. It is hidden by default.
      • + +
      • Value - This is the value of the attribute.
      • + +
      • Life - This is the "life" of the attribute entry. This differs slightly from the Life + column of the Elements table. Disjoint entries having the same key are not merged. Thus, the + column displays a single span for each row.
      • + +
      • Plot - This is a visual plot of the "life" of the attribute. It is hidden by default. The + header for this column behaves the same as it does in the Elements table.
      • +
      + +

      Row Selection

      + +

      Clicking a row selects it, but otherwise has no effect. Double-clicking a row behaves + similarly to the Object tree pane. Right-clicking may present a context menu of target-defined + actions.

      + +

      Typography

      + +

      This window and most of the Debugger UI adheres to the following typography:

      + +
        +
      • Bold face is used when the displayed item is (or is an ancestor of) the Debugger's + current object. Note that the Model window's current object, i.e., that selected in the tree, + is not necessarily the same as the Debugger's.
      • + +
      • Red color is used when the displayed value has changed. Since + when? The value is compared between the current and previous trace-snapshot pairs. "Previous" + meaning the pair that were current immediately before the current pair were activated. The + overall result is: 1) When controlling a live target, the values changed since the last + event, e.g., step completed, are displayed in red. 2) When controlling a trace, the values + between the last two visited snapshots are displayed in red. 3) When controlling an emulator, + it depends whether the last action was navigation or stepping.
      • + +
      • Primitive values are displayed as strings. In particular, numbers are displayed in + decimal.
      • + +
      • Addresses and ranges are displayed in hex, possibly prefixed with a space name.
      • + +
      • Primitive arrays are displayed as colon-separated hex, except boolean arrays, which are + displayed as colon-separated Ts and Fs.
      • + +
      • Objects are displayed as their canonical paths, in some cases using italics for + links.
      • +
      + +

      Actions

      + +

      See the specific launcher and/or back end's documentation for target-defined actions. Those + actions are only available when the current trace has a live target. Several other actions are + available for navigating and configuring the Model window.

      + +

      Follow Link

      + +

      When right-clicking a node or row that represents a link to another object, this action will + make that object this window's current object. That is, it will select it in the tree and cause + the tables to display its contents.

      + +

      Show Objects Tree

      + +

      This button toggles the display of the Objects tree pane.

      + +

      + Show Elements Table

      + +

      This button toggles the display of the Elements table.

      + +

      + Show Attributes Table

      + +

      This button toggles the display of the Attributes table.

      + +

      Limit to Current Snap

      + +

      By default, all panes will only display values that are effective for the Debugger's current + snapshot. For diagnostics, or to scrutinize a target's history, enabling this toggle will cause + the panes to display all values recorded in the trace regardless of the current snapshot. Be + careful using this when selecting or expanding objects whose contents are volatile, since this + will try to render all values ever contained by that object.

      + +

      Show Methods in Tree

      + +

      Some targets have their own notion of an object model, e.g., dbgmodel.dll. These + models may present methods, that by their nature, are not suitable for registration at + connection time. Instead, they are reflected and invoked using generic methods. This is an + uncommon case, and even then, users may not be interested in seeing such methods enumerated in + the tree. This toggle allows users to have them displayed in the tree.

      + +

      Show Primitives in Tree

      + +

      This button toggles the display of primitive values in the tree. When the tables are active, + the tree typically serves only to navigate among objects, and so it need not display primitive + values. If you prefer to have only the tree, then consider displaying primitives in the + tree.

      + +

      Show Hidden

      + +

      Targets specify a schema for the object model. The schema describes the expected objects, + types, attributes and locations for various components of the session. When describing an + attribute, the target can specify whether or not it is hidden. Hidden attributes are not + displayed in any pane by default. This toggle forces hidden attributes to be visible. For all + panes, new nodes and rows are added for any hidden items. For the elements table, this may also + add a multitude of new columns.

      + +

      Clone Window

      + +

      This copies the Model window in its current configuration to a new Model window. The cloned + Model window is disconnected from the rest of the Debugger UI. The main windows is the + only connected window. When an object or snapshot is activated in the Debugger, the + connected window tracks along, setting its current object and/or snapshot to match the + Debugger's. Any disconnected windows remain unaffected, but changes to the model itself are + still displayed.

      + + diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModelPlugin/images/DebuggerModelPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModelPlugin/images/DebuggerModelPlugin.png new file mode 100644 index 0000000000..ac2463aa89 Binary files /dev/null and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModelPlugin/images/DebuggerModelPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModelServicePlugin/DebuggerModelServicePlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModelServicePlugin/DebuggerModelServicePlugin.html index b57f9fe05c..f646d504e3 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModelServicePlugin/DebuggerModelServicePlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModelServicePlugin/DebuggerModelServicePlugin.html @@ -13,6 +13,11 @@

      Debugger: Model Service

      +

      This service is the source of older "Recorder-based" + targets. Recorders are being replaced with a system we call Trace RMI. The other + topics in Help have been updated accordingly. See Getting Started.

      +

      This service plugin backs the Targets window. It maintains all debugger connections across the entire Ghidra session, that is, they're shared across all diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModulesPlugin/DebuggerModulesPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModulesPlugin/DebuggerModulesPlugin.html index 4cfb3fbb6e..4902cf2d02 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModulesPlugin/DebuggerModulesPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModulesPlugin/DebuggerModulesPlugin.html @@ -13,21 +13,16 @@

      Debugger: Modules and Sections

      - - - - - - -
      +
      + +

      The concept of a module may vary from platform to platform, but in most cases, it refers to a binary image which is loaded or mapped into memory comprising some portion of the target's executable code. Likely, these are the same files that Ghidra can import for static analysis. Similarly, the concept of a section may vary, but in most cases, it refers to a portion of a module, possibly backed by its binary image. This window displays information about modules, - and sometimes their sections, known to the connected debugger. Information in this window + and sometimes their sections, known to the back-end debugger. Information in this window reflects what has been recorded into the current trace, which in turn comes from a target. The top table displays module information, while the bottom table displays section information.

      @@ -36,39 +31,45 @@

      The top table, which lists modules, has the following columns:

        -
      • Base Address - if available, the minimum address where the module is mapped in the - target's memory. Double-clicking this field navigates to the address.
      • +
      • Base - if available, the minimum address where the module is mapped in the target's + memory. Double-clicking this field navigates to the address.
      • -
      • Max Address - if available, the maximum address where the module is mapped in the - target's memory. Double-clicking this field navigates to the address.
      • +
      • Max - if available, the maximum address where the module is mapped in the target's + memory. Double-clicking this field navigates to the address.
      • Name - a short name for the module, typically its file name.
      • -
      • Module Name - the name of the module, ideally its full path on the target's - filesystem.
      • - -
      • Lifespan - denotes the recorded load and unload times of the module, i.e., the span of - time for which the module record is applicable.
      • +
      • Mapping - if mapped to a Ghidra program database, the name of that program. An asterisk + is appended if the mapping only covers the module partially. If multiple mappings cover the + module, they are all listed.
      • Length - the length from base address to max address, inclusive. Note that not every page in the range is necessarily mapped.
      • + +
      • Path - the path of the module object in the target's model. This is hidden by default. + See the Model + window.

      The bottom table, which lists sections, has the following columns:

        -
      • Start Address - the minimum virtual memory address of the section. Double-clicking this - field navigates to the address.
      • +
      • Start - the minimum memory address of the section. Double-clicking this field navigates + to the address.
      • -
      • End Address - the maximum virtual memory address of the section. Double-clicking this - field navigates to the address.
      • +
      • End - the maximum memory address of the section. Double-clicking this field navigates to + the address.
      • -
      • Section Name - the name of the section given by the debugger, usually the same as the - name given in the module's header.
      • +
      • Name - the name of the section given by the debugger, usually the name given in the + module binary's header.
      • Module Name - the name of the module containing this section.
      • Length - the number of bytes in the section.
      • + +
      • Path - the path of the section object in the target's model. This is hidden by default. + See the Model + window.

      Actions

      @@ -81,7 +82,7 @@

      This action is available from a module's or section's pop-up menu. It prompts the user to import the module from the local file system into Ghidra as a static image.

      -

      Auto-Map

      +

      Auto-Map

      This action is always available. It automatically maps trace memory to static images, using Module, Section, or Region information. See the Map Modules, -

      Map Identically

      +

      Map + Identically

      This action is available when both a trace and a program are opened. It maps the current trace to the current program using identical addresses. This action ignores the module list. It is a suitable mapping when the current program is loaded in the trace without relocation. It is also a fallback worth trying in the absence of a module list.

      -

      Map Manually

      +

      Map Manually

      This action is always available. It simply displays the Static Mappings @@ -114,14 +116,9 @@ the user can cause the mapper to re-use the memorized mapping in future sessions. The memorized module name is saved to the program database.

      - - - - - - -
      +
      + +

      Map Module to Current Program

      @@ -136,14 +133,9 @@ blocks matching the selected sections and proposes new mappings. Users who prefer this to Map Modules should also consider setting Auto-Map to use Sections.

      - - - - - - -
      +
      + +

      Map Sections to Current Program

      @@ -157,34 +149,39 @@ It behaves like Map Sections, except that it will propose the selected section be mapped to the block containing the cursor in the static listing.

      -

      Import Missing Module

      +

      Import Missing + Module

      This action is offered to resolve a "missing module" console message. It is equivalent to Import From File System on the missing module.

      -

      Map Missing Module

      +

      Map Missing + Module

      This action is offered to resolve a "missing module" console message. It is equivalent to Map Module To on the missing module.

      -

      Show Sections Table

      +

      + Show Sections Table

      This actions is always available. By default the sections table (bottom) is showing. Some debuggers do not offer section information, and even for those that do, it can be expensive to retrieve it. The visibility of the section table is controlled by toggling this action.

      -

      Filter Sections by Module

      +

      Filter Sections by + Module

      This action is always available. By default the bottom table displays all sections in the current trace. When this toggle is enabled, and at least one module is selected, the bottom table will only include sections contained by a selected module.

      -

      Select Addresses

      +

      Select + Addresses

      This action is available when at least one module or section is selected. It selects all addresses in the dynamic listing contained by the selected modules or sections.

      -

      Select Rows

      +

      Select Rows

      This action is available when the dynamic listing's cursor is at a valid location. It selects the module and section, if applicable, containing that cursor. If the dynamic listing diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModulesPlugin/images/DebuggerModulesPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModulesPlugin/images/DebuggerModulesPlugin.png index 2d1b78b3d7..3be618c43a 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModulesPlugin/images/DebuggerModulesPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerModulesPlugin/images/DebuggerModulesPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html index 0a8d020d9b..19ae48ac6b 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html @@ -13,13 +13,13 @@

      Debugger: Commands and Objects

      - - - - - - -
      +
      + +
      + +

      This window only supports the older "Recorder-based" + targets. For newer "TraceRmi-based" targets, see the Model window.

      The Objects window permits the user to interact directly with a connected debugger and its targets. Along with the command-line interpreter, it is the primary mechanism for issuing @@ -70,7 +70,7 @@

      Actions for Target Management

      -

      Quick Launch

      +

      Quick Launch

      Launches a new target using the current program. This action is the fastest and probably most common way of starting a debugger target on an existing connection. The action attempts to @@ -79,7 +79,7 @@ local system. The value associated with the program may, of course, be checked using the About Program File function.

      -

      Launch

      +

      Launch

      Launch a new target. Sometimes you may wish to launch a program which has not been imported, to launch a program with various configuration options, or to pass arguments to the program. @@ -93,21 +93,16 @@ the command line, the program used to start the virtual machine (java), the path to where it's installed, and fields for the name of the class and any user options you might supply:

      - - - - - - -
      +
      + +

      The options displayed by the Launch command are, for some targets, connected to the currently selected item under Connectors. For example, the dbgmodel.dll connector offers several launchers: one for command-line launch, one for attach, open for kernel-mode debugging, and one for opening previously-generated dump or TTD trace files.

      -

      Attach

      +

      Attach

      Attach to a running target. If the debugger has available a list of running targets for the local system, the attach action provides a convenient way to select and attach to an existing @@ -116,60 +111,57 @@ displayed in the tree under Session/Available. Bear in mind it often takes time to populate the Available list, which may need to be manually refreshed.

      -

      Detach

      +

      Detach

      Detach from the selected target, usually allowing it to resume execution. As a consequence, this action terminates the trace for the current target, if applicable.

      -

      Re-attach

      +

      Re-attach

      Re-attaches to the selected target. (Some targets require a separate action for re-attaching vs. attaching for the first time. If so, this action provides that capability.)

      -

      Kill

      +

      Kill

      Kill the current target. As a consequence, this action terminates the trace for the current target, if applicable.

      Actions for Execution Management

      -

      Interrupt (Pause, Suspend, - Break)

      +

      Interrupt (Pause, + Suspend, Break)

      Interrupt the current target's execution.

      -

      Resume (Continue, Go)

      +

      Resume (Continue, Go)

      Allow the current target to resume execution.

      -

      Step Into

      +

      Step Into

      Step the current target to the next instruction.

      -

      Step Over

      +

      Step Over

      Step the current target to the next instruction in the current subroutine.

      -

      Finish

      +

      Finish

      Allow the current target to finish the current subroutine, pausing after.

      -

      Step Last / Extended

      +

      Step Last / + Extended

      Perform a target-defined step, often the last (possibly custom or extended) step.

      -

      Set +

      Set Breakpoint

      Set a breakpoint, which will trap target execution under certain conditions.

      - - - - - - -
      +
      + +

      The given expression can follow any form accepted by the connected debugger, although most often this will be an address. Compare this to the listing, which can only set breakpoints on @@ -182,8 +174,7 @@ "help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html">Breakpoint Marker actions from the disassembly listings.

      -

      Toggle - Option

      +

      Toggle Option

      Toggle an object. This may apply to a breakpoint or to configuration options provided in the model tree.

      @@ -193,13 +184,13 @@

      The following actions manage target tracing. Note that many other windows are not usable until a target is recorded into a trace.

      -

      Record

      +

      Record

      Record the current target, if its platform is recognized, and open its trace. If Ghidra cannot uniquely identify the platform, it may prompt the user to select from a list of possibilities.

      -

      Record +

      Record Automatically

      Automatically record and open recognized targets. If Ghidra cannot uniquely identify the @@ -209,13 +200,13 @@

      The following actions can create additional displays of portions of the debugger model.

      -

      Display As +

      Display As Tree

      Constructs a new tree using the selection as the new root, synchronized with the current provider.

      -

      Display As +

      Display As Table

      Constructs a table from the current object, synchronized with the current provider. If the @@ -223,84 +214,86 @@ columns. If not, the attributes will be rows and their name, kind, value, and type will be columns.

      -

      Display As +

      Display As Graph

      Constructs and displays a graph from the selection and its visible descendants. NOTE: The graph does not currently maintain synchronization.

      -

      Display As +

      Display As XML

      Encodes the selected object and its visible descendants in XML and prints the result to the console. NOTE: Various characters not allowed in XML may be converted, typically to underscores, in the result.

      -

      - Display Filtered Tree

      +

      Display + Filtered Tree

      Constructs a static snapshot of the selection and its visible descendants as a tree, applying a filter to the selection.

      -

      - Display Filtered Table

      +

      Display + Filtered Table

      Constructs a static snapshot of the selection and its visible descendants as a table, applying a filter to the selection.

      -

      +

      Display Filtered Graph

      Constructs a static snapshot of the selection and its visible descendants as a graph, applying a filter to the selection.

      -

      +

      Display Filtered XML

      Constructs a static snapshot of the selection and its visible descendants as XML, applying a filter to the selection.

      -

      Display Methods

      +

      Display Methods

      Displays a list of the methods available for the selection, which may be applied and combined in a filter.

      Actions for Data Management

      -

      Export as XML

      +

      Export as + XML

      Converts the selection and its visible descendants to XML and exports the result to a file of the user's choosing.

      -

      Import from - XML

      +

      Import + from XML

      Imports "facts" from a file of the user's choosing and renders it as a tree.

      -

      Export as - Facts

      +

      Export + as Facts

      Converts the selection and its visible descendants to "fact" files and exports the result to a directory of the user's choosing. Currently, "fact" files itemize the path, name, value, type, and children for each object.

      -

      Import from - Facts

      +

      + Import from Facts

      Imports XML from a directory of the user's choosing and renders them as a tree.

      -

      Import from trace

      +

      Import from + trace

      Import from trace is roughly equivalent to using the open dump/trace connector.

      Miscellaneous Actions

      -

      Console

      +

      Console

      Shows the console for the selected context, usually the debugger's command-line interpreter. Some models may also present a target's standard I/O via a console.

      -

      Refresh Node

      +

      Refresh Node

      Queries the model for the current object's children and rebuilds that portion of the display.

      diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/breakpoint-set.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/breakpoint-set.png deleted file mode 100644 index e12b41d306..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/breakpoint-set.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_graph.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_graph.png deleted file mode 100644 index 201d4a298d..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_graph.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_table.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_table.png deleted file mode 100644 index abcd93689a..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_table.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_tree.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_tree.png deleted file mode 100644 index 6386998ebc..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_tree.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_xml.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_xml.png deleted file mode 100644 index 17e15df100..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_as_xml.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_graph.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_graph.png deleted file mode 100644 index 201d4a298d..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_graph.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_table.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_table.png deleted file mode 100644 index abcd93689a..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_table.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_tree.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_tree.png deleted file mode 100644 index 6386998ebc..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_tree.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_xml.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_xml.png deleted file mode 100644 index 17e15df100..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/display_filtered_xml.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/export_as_facts.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/export_as_facts.png deleted file mode 100644 index f3f1ee447d..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/export_as_facts.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/export_as_xml.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/export_as_xml.png deleted file mode 100644 index 17e15df100..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/export_as_xml.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/import_from_facts.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/import_from_facts.png deleted file mode 100644 index f3f1ee447d..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/import_from_facts.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/import_from_xml.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/import_from_xml.png deleted file mode 100644 index 17e15df100..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/import_from_xml.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/stop.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/stop.png deleted file mode 100644 index fa53723b0a..0000000000 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerObjectsPlugin/images/stop.png and /dev/null differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPcodeStepperPlugin/DebuggerPcodeStepperPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPcodeStepperPlugin/DebuggerPcodeStepperPlugin.html index d4c0aae718..90ce2ced2a 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPcodeStepperPlugin/DebuggerPcodeStepperPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPcodeStepperPlugin/DebuggerPcodeStepperPlugin.html @@ -13,23 +13,19 @@

      Debugger: P-code Stepper

      - - - - - - -
      +
      + +
      -

      P-code is the "microcode" of Ghidra's processor specifications, compiled from its Sleigh - specification. Originally designed to facilitate static analysis, it is easily applied to - emulation as well. Stepping each p-code operation is an effective means of debugging the - Sleigh. The plugin provides two panes: 1) The p-code listing, and 2) Temporary ("Unique") - variables. The listing works similarly to the dynamic listing. It displays each p-code - operation, highlighting the current "counter", which is the next operation to be executed. - There is also a cursor, allowing selection of an operation. The variables view operates - similarly to the registers view, displaying the current value of each unique variable.

      +

      P-code is the "microcode" or "intermediate representation" of Ghidra's processor models, + compiled from their Sleigh specifications. Originally designed to facilitate static analysis, + it is easily applied to emulation as well. Stepping each p-code operation is an effective means + of debugging the Sleigh. The plugin provides two panes: 1) The p-code listing, and 2) Unique or + temporary variables. The listing works similarly to the dynamic listing. It displays each + p-code operation, highlighting the current "counter", which is the next operation to be + executed. There is also a cursor, allowing selection of an operation. The variables view + operates similarly to the registers view, displaying the current value of each unique + variable.

      P-code stepping is built into the emulation framework, and so the other UI elements (listing, registers, etc.) will display machine state from emulated p-code operations, i.e., @@ -62,12 +58,14 @@ interact with the target, stepping at the p-code level implies you are no longer "at the present."

      -

      Emulate Trace p-code Backward

      +

      Emulate + Trace p-code Backward

      This action is available when the current coordinates have some positive number of p-code ticks. It steps the trace backward to the previous p-code tick.

      -

      Emulate Trace p-code Forward

      +

      Emulate + Trace p-code Forward

      This action is available when a thread is selected. It steps the current thread forward to the next p-code tick, using emulation. Note that emulation does not affect the target. diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPcodeStepperPlugin/images/DebuggerPcodeStepperPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPcodeStepperPlugin/images/DebuggerPcodeStepperPlugin.png index 8ea113b519..5251ac5d51 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPcodeStepperPlugin/images/DebuggerPcodeStepperPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPcodeStepperPlugin/images/DebuggerPcodeStepperPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPlatformPlugin/DebuggerPlatformPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPlatformPlugin/DebuggerPlatformPlugin.html index c6bcf7432c..5c0d7bec5b 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPlatformPlugin/DebuggerPlatformPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPlatformPlugin/DebuggerPlatformPlugin.html @@ -14,56 +14,57 @@

      Debugger: Platform Selection

      The Debugger allows the user to work with multiple platforms, i.e., architectures, - compilers, etc., within the context of a single debug target. This plugin allows the user to - switch among platforms and/or introduce new platforms via overrides.

      + compilers, etc., within the context of a single debug target. This plugin facilitates switching + among platforms and introducing new platforms.

      -

      Note we are in a transitional period between two trace database conventions. This plugin is - a necessary component when working with the new convention. In the legacy convention, the - system must ascertain the target's language and compiler at the time it begins recording. If it - fails or makes an incorrect decision, the UI remains mostly empty, or worse, the system - interrogates and instructs the target using the wrong architecture. This mode still works in - most circumstances and is the default and recommended convention. Additional platforms can - still be introduced, but there is perhaps little use for doing so. One case might be to, e.g., - disassemble JVM bytecodes when debugging a Java process at the native level.

      +

      Note we are currently supporting two trace database conventions. In the first, the system + ascertains the target's platform and maps it to a Ghidra language and compiler spec at the time + the trace is created. These are called the base language and base compiler spec. + Together, they comprise the trace's host platform. This is used by "Recorder-mode" + traces and most "TraceRmi-mode" traces.

      -

      In the new convention, the system always records the target, using the "DATA" language, - i.e., no language. The object tree is recorded, and objects with memory are assigned overlay - spaces where their contents are recorded. The only way to disassemble instructions is to add a - guest platform. This plugin will do that automatically, in more or less the same fashion as the - language and compiler are ascertained in legacy mode. If this fails, the recording still - proceeds, and most of the UI is still useful. The user can add (perhaps by trial and error) the - correct platform later. In the meantime, memory, registers, threads, etc., are all still - displayed.

      +

      However, there are some cases where it is impractical to know the platform before creating + the trace, e.g., when setting up "raw" connections. For these cases we have a second + convention: The system creates a trace with the host platform + DATA:BE:64:default:pointer64, for example. Thus, disassembly requires the system + (or user) to ascertain the platform at a later time. This can then be mapped into the existing + trace as a guest platform. Either convention permits guest platforms, but they are a + necessary aspect of the second. If the system has failed to ascertain the platform, the user + may attempt to do so by adding override platforms in trial-and-error fashion. + Furthermore, even if the system has succeeded, there may be cause to try disassembly in + alternative languages, e.g., Java bytecode when debugging its x86 JVM at the native level.

      Actions

      -

      This plugin adds actions into the Debugger menu under "Choose Platform."

      +

      This plugin adds actions under the Debugger → Choose Platform menu.

      -

      Choose Platform

      +

      Host/base

      -

      This action adds or changes to a specific platform in the current trace. One of these - actions is presented for each recommended or previously chosen platform, if any. The - recommendations are given by an opinion service, so new options may be added by extension - modules. It is possible there are no recommendations for the current trace. The current - platform is designated by a check mark or other selection indicator.

      +

      This action corresponds to the current trace's host platform. Technically, this is just one + platform option among possible recommendations, but it is always among them. If the host + language is DATA:..., then this platform will not support disassembly. A guest platform + is necessary.

      + +

      [Platform Name]

      + +

      This action is replicated for each recommended platform and for each platform already + present in the trace. The recommendations are given by an opinion service, so new options may + be added by Ghidra extension modules. It is possible there are no recommendations for the + current trace. The current platform is indicated by a check mark.

      More...

      This action is enabled whenever there is a current trace. It presents a dialog with the recommended platforms for the trace.

      - - - - - - -
      +
      + +
      -

      The "Show Only Recommended Offers" check can be disabled to display override offers as well. +

      The "Show Only Recommended Offers" check can be disabled to display override + platforms as well. Every language-compiler-spec pair is offered as an override platform. Selecting an offer and confirming the dialog will add or change to the selected platform in the - trace. Furthermore, the choice will be added to the "Choose Platform" menu until the trace is - closed.

      + trace. Furthermore, the choice will be added to the Choose Platform menu for the current + trace.

      diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPlatformPlugin/images/DebuggerSelectPlatformOfferDialog.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPlatformPlugin/images/DebuggerSelectPlatformOfferDialog.png index 48d0fd9b3e..d70ac8ec0d 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPlatformPlugin/images/DebuggerSelectPlatformOfferDialog.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerPlatformPlugin/images/DebuggerSelectPlatformOfferDialog.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/DebuggerRegionsPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/DebuggerRegionsPlugin.html index baa08878b7..96c714cf38 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/DebuggerRegionsPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/DebuggerRegionsPlugin.html @@ -13,21 +13,16 @@

      Debugger: Memory Regions

      - - - - - - -
      +
      + +
      -

      Regions refer to ranges of allocated or reserved memory reported by the target. The precise - meaning of these regions may vary depending on the nature of the target. For user-mode - applications, this is generally pages of memory allocated for image sections, the stack, the - heap, etc. The regions manager allows the user to rename pages and modify the recorded - permissions. Note that such modifications do not affect the target; but only the - recording.

      +

      Regions refer to ranges of allocated or reserved memory reported by the target, i.e., the + target's memory map. The precise meaning of these regions may vary depending on the nature of + the target. For user-mode applications, this is generally pages of memory allocated for image + sections, the stack, the heap, etc. The regions manager allows the user to rename pages and + modify the recorded permissions. Note that such modifications do not affect the + target; but only the recorded trace.

      Table Columns

      @@ -36,8 +31,6 @@
      • Name - the name given to the region by the target. This field is user modifiable.
      • -
      • Lifespan - the creation and destruction time of the region.
      • -
      • Start - the minimum address of the region. Double-clicking this field navigates to the address.
      • @@ -46,14 +39,17 @@
      • Length - the length of the region in bytes.
      • -
      • Read,Write,Execute,Volatile - various flags of the region. These flags only affect local +
      • Read, Write, Execute - various flags of the region. These flags only affect Ghidra's analysis. Toggling these do not affect the target.
      • + +
      • Key, Path - descriptions the region object in the target's model. These are hidden by + default. See the Model + window.

      Actions

      -

      Other than modifications enabled by the table, the Regions window provides the following - actions:

      +

      The Regions window provides the following actions:

      Map Regions

      @@ -68,14 +64,9 @@ include the module's file name, otherwise the matcher has no means to identify a corresponding program.

      - - - - - - -
      +
      + +

      Map Regions to Current Program

      @@ -91,12 +82,13 @@ It behaves like Map Regions, except that it will propose the selected region be mapped to the block containing the cursor in the static listing.

      -

      Select Addresses

      +

      Select + Addresses

      This action is available when at least one region is selected. It selects all addresses in the dynamic listing contained by the selected regions.

      -

      Select Rows

      +

      Select Rows

      This action is available when the dynamic listing's cursor is at a valid location. It selects the region containing that cursor. If the dynamic listing has a selection, it selects @@ -105,7 +97,7 @@

      Add Region

      This action is available when a trace is active. It adds a new region to the memory map. It - should only be used for emulation or to correct or diagnose trace recording issues.

      + should only be used for emulation or to correct a recorded trace.

      Delete Regions

      @@ -116,10 +108,10 @@

      Force Full View

      This action is available when a trace is active. It forces all physical address spaces into - the view. Ordinarily, only those addresses contained in a region at the active snap are - presented in the listing and memory windows. When this toggle is on, regions are ignored. - Instead, all physical addresses are presented. (Here "physical" includes all memory spaces - except OTHER.) This toggle applies only to the current trace for the duration it - is open.

      + the view. By default, only those addresses in the memory map — as recorded in the trace + at the current snapshot — are displayed in the listing and memory windows. When this + toggle is on, regions are ignored. Instead, all physical addresses are displayed. ("Physical" + includes all Sleigh memory spaces except OTHER.) This toggle applies only to the + current trace.

      diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionMapProposalDialog.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionMapProposalDialog.png index 286db9888b..461971367e 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionMapProposalDialog.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionMapProposalDialog.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionsPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionsPlugin.png index 83858b4464..d9261e7e80 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionsPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegionsPlugin/images/DebuggerRegionsPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html index e7fb0b76b9..15d43f3830 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html @@ -13,14 +13,9 @@

      Debugger: Registers

      - - - - - - -
      +
      + +

      Registers refer to the target processor's register banks. In multi-threaded environments, it is assumed that each thread has its own register context. The register window presents a subset @@ -30,15 +25,15 @@

      The register window uses colors to hint about the state of registers and their values. By default, changed registers are displayed in red, and stale registers are displayed in dark - grey. A "stale" register is one whose current value is not known. The value displayed is the - last recorded value or the default value 0. Simply, a "changed" register is one whose value has - just changed. For example, if a register is modified as result of stepping, then that register - is changed. However, given the possibility of rewinding, changing thread focus, etc., "changed" - is actually subtly more flexible. The registers window remembers the user's last coordinates - (time, thread, frame, etc.) as well as the current coordinates. So, "changed" more precisely - refers to a register whose value differs between those two coordinates. This permits the user - to switch focus between different coordinates and quickly identify what is different, so long - as those coordinates pertain to the same processor language.

      + grey. A stale register is one whose current value is not known. The value displayed is + the last recorded value or the default value 0. A changed register is one whose value + has just changed. For example, if a register is modified as result of stepping, then that + register is changed. However, given the possibility of rewinding, changing thread focus, etc., + "changed" is actually subtly more flexible. The registers window remembers the user's last + coordinates (time, thread, frame, etc.) as well as the current coordinates. So, "changed" more + precisely refers to a register whose value differs between those two coordinates. This permits + the user to switch focus between different coordinates and quickly identify what is different, + so long as those coordinates pertain to the same processor language.

      Table Columns

      @@ -48,24 +43,24 @@
      • Favorite - a toggle to mark the register as a favorite. By default this includes the program counter and stack pointer. Favorites are sorted to the top, by default. The list of - favorite registers is memorized per compiler specification.
      • + favorite registers is memorized per platform.
      • Number - the index of the register in Ghidra's language model. By default, this is the second sort column.
      • Name - the name of the register in Ghidra's language model.
      • -
      • Value - the value of the register as recorded in the trace. When the value refers to a - valid memory offset, right-clicking the row allows the user to navigate to that offset in a +
      • Value - the value of the register recorded in the trace. When the value refers to a valid + memory offset, right-clicking the row allows the user to navigate to that offset in a selected memory space. This field is user modifiable when the Enable Edits toggle is on, and the register is modifiable. Edits may be directed toward a live target, the trace, or the emulator. Values changed by the last event are displayed in red.
      • Type - the type of the register as marked up in the trace. There is generally no default - here. Either the user or some automation, e.g., analysis, may set this value. Changes to this - field do not affect the target. The selected type is saved to the trace "from this - time on."
      • + here. Either the user or some automation may set the type. Changes to this field do + not affect the target. The selected type is saved to the trace for the current and + future snapshots.
      • Representation - the value of the register as interpreted by its data type. If the value is an address, double-clicking this field will navigate to it. This field is user modifiable @@ -77,44 +72,38 @@

        The register window provides the following actions:

        Select Registers

        + "icon.debugger.select.registers"> Select Registers

        This displays a dialog for selecting which registers to display in the table.

        - - - - - - -
        +
        + +
        -

        The dialog provides more information about each register, potentially displays a larger set - of registers, and permits the precise selection of registers to include in the window. This - varies from using the table filter in that the register window will not query the target for a - register unless it is selected. Note that deselecting a register does not prohibit other - components from reading that register. For example, the program counter and stack pointer are - read by the recorder whether or not they're displayed in the table. The actions allow for the - addition and subtraction of selections from the register set. Most columns are self-explanatory - or duplicate the same column in the main window. The "Known" column indicates whether Ghidra - was able to find the same register on the target. Unknown registers are never populated by the - recorder, but they can still be populated by the user. Modifying the values of unknown - registers cannot affect the target. Register sets are memorized per compiler specification.

        +

        The dialog provides more information about each register, displays a potentially larger set + of registers, and permits the selection of registers to include in the window. This is a more + persistent and more precise means of removing registers from the window, compared with + filtering. Note that deselecting a register does not necessarily prevent that register from + being read. Nor does it prohibit other components from reading that register. For example, the + program counter and stack pointer are recorded by the target whether or not they're displayed + in the table. The actions allow for the addition and subtraction of selections from the + register set. Most columns are self-explanatory or duplicate the same column in the main + window. The Known column indicates whether Ghidra was able to find the same register on the + target. Modifying the values of unknown registers cannot affect the target. Selected registers + are memorized per platform.

        Register Type Settings

        This action is available on the context menu when there is a single register selected with a data type assigned. It permits the adjustment of that data type's settings, e.g., to display - decimal vs hexadecimal. The settings are saved to the data unit for the register.

        + decimal vs hexadecimal. The settings are saved to the trace's data unit for the register.

        -

        Enable Edits

        +

        Enable Edits

        This toggle is a write protector for machine state. To modify register values, this toggle must be enabled. Edits are directed according the to Control and Machine State - Plugin. Note: Only the raw "Value" column can be edited directly. The "Repr" column - cannot be edited, yet.

        + Plugin.

        Clone Window

        diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/images/DebuggerAvailableRegistersDialog.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/images/DebuggerAvailableRegistersDialog.png index 05f7946a50..89aa682bd6 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/images/DebuggerAvailableRegistersDialog.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/images/DebuggerAvailableRegistersDialog.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/images/DebuggerRegistersPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/images/DebuggerRegistersPlugin.png index 519a66d12c..a9ada72fbc 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/images/DebuggerRegistersPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerRegistersPlugin/images/DebuggerRegistersPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/DebuggerStackPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/DebuggerStackPlugin.html index d942ad3192..44137018e4 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/DebuggerStackPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/DebuggerStackPlugin.html @@ -13,27 +13,22 @@

        Debugger: Stack

        - - - - - - -
        +
        + +

        The stack window displays the current trace's execution stack, as unwound and reported by the target. Not all debuggers will unwind the stack, in which case, this window displays only the innermost frame. When emulation is used to generate the current machine state, only a single synthetic frame is shown. See the Unwind Stack action for an - alternative mechanism that unwinds using Ghidra's program databases and works with emulation. + alternative mechanism that unwinds using Ghidra's program databases and works during emulation. Level 0 always refers to the innermost frame, and each incremental level refers to the next caller in the chain — most of the time. The current frame comprises one element of the - tool's current "coordinates." Double-clicking a frame changes those coordinates, potentially - causing other windows to display different information. Namely, the Registers window will - show registers for the current frame, assuming they can be retrieved. The Listings may also - navigate to the current frame's program counter.

        + tool's current coordinates. Double-clicking a frame activates new + coordinates, potentially causing other windows to display different information. Namely, the Registers window + will show registers for the current frame, assuming they can be retrieved. The Listings may + also navigate to the current frame's program counter.

        Table Columns

        @@ -43,12 +38,12 @@
      • Level - the level of the frame, counting 0-up starting at the innermost frame.
      • PC - the address of the instruction to execute next, or upon return of the callee for - non-0 frames. Different platforms may have different subtleties in how they report PC.
      • + non-0 frames. Different debuggers may have different subtleties in how they report PC. -
      • Function - the name of the containing function, if Ghidra has the corresponding module - image imported and analyzed.
      • +
      • Function - the name of the function containing the PC, if Ghidra has the corresponding + module image imported, analyzed, and mapped.
      • -
      • Comment - a user-modifiable comment.
      • +
      • Module - the name of the module containing the PC.

      Action

      @@ -57,27 +52,22 @@

      Unwind Stack (U)

      -

      This action is in the main menu: Debugger → Analysis → Unwind - from frame 0. It attempts to unwind the current thread's stack segment, creating frame - data units in the listing. It starts by reading the program counter and stack pointer from the - innermost frame of the current thread. It then maps the program counter to the program database - and analyzes the function containing it. If successful, it can determine the frame's base - address and locate variables, saved registers, and the return address. Knowing the return - address and frame depth, it can derive the program counter and stack pointer of the next frame - and unwind it in the same manner. This proceeds until analysis fails or the stack segment is - exhausted. For best results, ensure you have imported and opened the Ghidra program database - for every module, or at least the subset you expect to see in your stack. To view the results, - navigate to or follow the stack pointer in a Dynamic Listing. The Stack window does - not display Ghidra's unwinding results.

      +

      This action is in the main menu: Debugger → Analysis → Unwind from frame 0. + It attempts to unwind the current thread's stack segment, creating frame data units in the + listing. It starts by reading the program counter and stack pointer from the innermost frame of + the current thread. It then maps the program counter to the program database and analyzes the + function containing it. If successful, it can determine the frame's base address then locate + variables, saved registers, and the return address. Knowing the return address and frame depth, + it can derive the program counter and stack pointer of the next frame and unwind it in the same + manner. This proceeds until analysis fails or the stack segment is exhausted. For best results, + ensure you have imported and opened the Ghidra program database for every module, or at least + the subset you expect to see in your stack. To view the results, navigate to or follow the + stack pointer in a Dynamic Listing. The Stack window does not display Ghidra's + unwinding results.

      - - - - - - -
      +
      + +

      Each call record generates a structure data unit derived from the function's frame. The exact contents of the structure depend on the current program counter within that function. diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/images/DebuggerStackPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/images/DebuggerStackPlugin.png index dd6f64ba9f..b9f506af45 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/images/DebuggerStackPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/images/DebuggerStackPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/images/DebuggerStackUnwindInListing.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/images/DebuggerStackUnwindInListing.png index 35b4e8f7e0..936314180e 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/images/DebuggerStackUnwindInListing.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStackPlugin/images/DebuggerStackUnwindInListing.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStaticMappingPlugin/DebuggerStaticMappingPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStaticMappingPlugin/DebuggerStaticMappingPlugin.html index e5da1b8ae4..5a9eb1c9f2 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStaticMappingPlugin/DebuggerStaticMappingPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStaticMappingPlugin/DebuggerStaticMappingPlugin.html @@ -13,25 +13,20 @@

      Debugger: Static Mappings

      - - - - - - -
      +
      + +

      A static mapping refers to a range of addresses in the dynamic listing and its corresponding - range in the static listing. These mappings provide a flexible means of mapping imported - images, i.e., Ghidra Program Databases, into a trace. Typically, this table is populated by - automation, e.g., the Auto-Map action, or - by manual user actions, e.g., the Auto-Map + action. Common mapping schemes are available in user actions, e.g., Map Modules. This under-the-hood static mapping window displays the mappings table, allowing users or - developers to diagnose image mapping issues and manually add mappings, regardless of reported - modules and/or sections. For most users, there is no reason to access this window.

      + developers to diagnose image mapping issues and manually specify mappings, regardless of + reported modules, sections, regions, etc. For most users, there is no reason to access this + window.

      Table Columns

      @@ -40,29 +35,30 @@
      • Dynamic Address - the minimum address in the dynamic address range.
      • -
      • Static Program - the Ghidra URL of the imported static image.
      • +
      • Static Program - the Ghidra URL of the program database, i.e., the imported static + image.
      • Static Address - the minimum address in the static address range.
      • -
      • Length - the number of bytes in each address range.
      • +
      • Length - the number of bytes in the mapping.
      • Shift - the offset from static address to dynamic address.
      • -
      • Lifespan - the span of time for which this mapping is applicable.
      • +
      • Lifespan - the span of snapshots for which this mapping is applicable.

      Actions

      -

      This window provides actions for finding, adding, and removing mappings. Note that entries - cannot be modified.

      +

      This window provides actions for finding, adding, and removing mappings. NOTE: To + "modify" an entry, delete and re-add it.

      -

      Select Rows

      +

      Select Rows

      This action is available when the active listing's (dynamic or static) cursor is at a valid location. It selects the mapping containing that cursor. If the active listing has a selection, it selects all mappings intersecting that selection.

      -

      Add Mapping

      +

      Add Mapping

      This action is always available. It presents a dialog to manually add a mapping. When one primary listing (dynamic or static) has a selection, and the other's cursor is at a valid @@ -70,7 +66,7 @@ cursor as the corresponding minimum address. The default lifespan is "from now on out", i.e., the current snap to infinity.

      -

      Remove Mapping

      +

      Remove Mapping

      This action is available when at least one mapping is selected. It removes those mappings.

      diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStaticMappingPlugin/images/DebuggerStaticMappingPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStaticMappingPlugin/images/DebuggerStaticMappingPlugin.png index 009bab8923..a55a6d3cbc 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStaticMappingPlugin/images/DebuggerStaticMappingPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerStaticMappingPlugin/images/DebuggerStaticMappingPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTargetsPlugin/DebuggerTargetsPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTargetsPlugin/DebuggerTargetsPlugin.html index 4dc01a1fd1..e65a8525f6 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTargetsPlugin/DebuggerTargetsPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTargetsPlugin/DebuggerTargetsPlugin.html @@ -13,14 +13,12 @@

      Debugger: Targets

      - - - - - - -
      +
      + +
      + +

      This window only supports the older "Recorder-based" + targets. For newer "TraceRmi-based" targets, see the Connection Manager window.

      The targets window manages connections to live debuggers. In most cases, each item is a GADP/TCP connection to a local "agent" process which manages a native debugger, communicating @@ -33,17 +31,13 @@

      This window provides the following actions for managing connections.

      -

      Connect

      +

      Connect

      Prompts the user to select a connector and configure its parameters.

      - - - - - - -
      +
      + +

      The top drop-down displays a list of pluggable connectors. A description and the options for the currently-selected connector are displayed below. Some will start a new session, while @@ -52,7 +46,7 @@ Each connector should provide help in the form of tool tips, accessed by hovering over an option's name. Clicking "Connect" will start the connector and dismiss the dialog.

      -

      Disconnect

      +

      Disconnect

      This action is available when a connection is selected. It closes the connection. Note, depending on the robustness of the connector's termination logic, this may not clean up all diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerThreadsPlugin/DebuggerThreadsPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerThreadsPlugin/DebuggerThreadsPlugin.html index db958bcab6..b723e96551 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerThreadsPlugin/DebuggerThreadsPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerThreadsPlugin/DebuggerThreadsPlugin.html @@ -5,98 +5,73 @@ - Debugger: Threads and Traces + Debugger: Threads -

      Debugger: Threads and Traces

      +

      Debugger: Threads

      - - - - - - -
      +
      + +

      In general, a thread refers to a unit of concurrent execution within a target. Typically, each thread carries its own execution context, so this window provides a means of navigating - those contexts. Furthermore, this window provides a means of navigating and managing open - traces, much like the static listing provides a means of navigating open programs. The window - also plots a timeline showing thread lifespans, and displays a caret which can be used to - navigate the current point in time. This window, the Stack window, and the Stack window, the Model window, and the Dynamic Listing window provide a complete trace navigation system.

      -

      Trace Tabs

      +

      Table Columns

      -

      The trace tab bar is displayed when at least one trace is open. It displays the name of each - open trace in a button, where the "current" or "focused" trace is selected. Clicking a tab will - select its trace and focus the tool onto it. A trace associated with a live target has a red - "recording" icon at its left. If that icon is not present, or has disappeared, the trace is - dead or terminated. A "dead" trace can still be manipulated and marked up, but it will not - record any new target information.

      +
        +
      • Name - the name or summary of the thread given by the debugger. If a name is not given, + this is just an index or unique id assigned to the thread. This field can be modified, but it + has no effect on the target.
      • -

        Close Trace / All / Other / Dead - Traces

        +
      • PC - the program counter of the thread. This is typically the address of the next + instruction it will execute. If the debugger records frames, this is the PC of the innermost + frame.
      • -

        In most cases, a trace is ephemeral, but occasionally, interesting behavior is observed that - is difficult to store as static mark-up. When traces are no longer needed, they can be closed - by right-clicking a tab and selecting one of the actions. See Trace - Management for details of each action.

        +
      • Function - the name of the function containing the PC, if Ghidra has the corresponding + module image imported, analyzed, and mapped.
      • + +
      • Module - the name of the module containing the PC. This column is hidden by default.
      • + +
      • SP - the stack pointer for the thread. If the debugger records per-frame registers, this + is the SP from the innermost frame. This column is hidden by default.
      • + +
      • State - the thread's current state. Depending on what is reported by the debugger, this + should be either RUNNING, STOPPED, or TERMINATED. It might also be ALIVE, if the debugger + cannot determine whether or not it is running; or UNKNOWN, if the debugger has lost + track.
      • + +
      • Plot - a graphical representation of the thread's lifespan. Threads which are alive will + appear to extend to the end of time. Unlike other column headers, clicking and dragging in + this one may navigate trace snapshots. To rearrange this column, hold SHIFT while + dragging.
      • + +
      • Comment - a user-modifiable comment about the thread. This column is hidden by + default.
      • + +
      • Path - the path of the thread object in the target's model. This is hidden by default. + See the Model + window.
      • +

      Navigating Threads

      -

      Double-clicking a thread in the table will navigate to (or "activate" or "focus") that - thread. Windows which are sensitive to the current thread will update. Notably, the Double-clicking a thread in the table will activate that thread, i.e., it becomes + the current thread throughout the Debugger UI, usually including the debugger's command-line + interface. Notably, the Registers window will display the activated thread's register values. Listing windows with configured location tracking will re-compute that location with the thread's context and - navigate to it. The thread timeline plots all recorded threads. Threads which are alive will - appear to extend "to the end of time." The threads table displays more detailed information in - the following columns:

      - -
        -
      • Name - the name of the thread given by the debugger. Often, this is just an index or - unique id assigned to the thread. This field can be modified, but it has no effect on the - target.
      • - -
      • Created - the snapshot when this thread was first observed. If the thread's creation was - observed, then it is its creation time.
      • - -
      • Destroyed - if destroyed, the snapshot when this thread was last observed. If the - thread's destruction was observed, then it is its destruction time.
      • - -
      • State - the thread's current state. For a dead trace, this is either ALIVE or TERMINATED, - and depends solely on whether or not a destruction time was recorded. For a live trace, this - may also take RUNNING, STOPPED, or UNKNOWN, depending on what is reported by the debugger. - The state always reflects the present, or latest known, state.
      • - -
      • Comment - a user-modifiable comment about the thread.
      • - -
      • Plot - a graphical representation of the thread's lifespan. Unlike other column headers, - clicking and dragging in this one will navigate trace snapshots. To rearrange this column, - hold SHIFT while dragging.
      • -
      - -

      Actions

      - -

      Synchronize Trace and Target Activation

      - -

      This toggle is always available and is enabled by default. While enabled, any changes in - navigation coordinates are translated, to the extent possible, and sent to the connected - debugger. This may, for example, issue thread and/or frame commands - to GDB so that commands typed into its CLI will refer to the same thread and frame as is active - in Ghidra. Conversely, any target events which indicate a change in activation are translated, - to the extent possible, into navigation coordinates and activated in Ghidra. For example, if - the user issues a frame command to the CLI of a GDB connection, then Ghidra will - navigate to that same frame.

      + navigate to it.

      diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerThreadsPlugin/images/DebuggerThreadsPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerThreadsPlugin/images/DebuggerThreadsPlugin.png index bbe20025d4..65b3572ee6 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerThreadsPlugin/images/DebuggerThreadsPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerThreadsPlugin/images/DebuggerThreadsPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html index 5bec7ed16e..0f74f6c0bc 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTimePlugin/DebuggerTimePlugin.html @@ -13,22 +13,19 @@

      Debugger: Time

      - - - - - - -
      +
      + +

      This window displays all recorded snapshots in the current trace. Typically, there is one snapshot per event recorded. Other windows often display the times of various events or use - time ranges to describe lifespans of various records. Those times refer to the "snap," which is - a 0-up counter of snapshot records. Thus, a snapshot is a collection of observations of a - target's state, usually while suspended, along with any mark up. Double-clicking a snapshot - navigates to the selected point in time. Note that navigating to the past may change your Control mode.

      + time ranges to describe lifespans of various objects. Those times refer to the snap, + which is a 0-up counter of snapshot records. Thus, a snapshot is a collection of observations + of a target's state, usually while suspended, along with any mark up. Double-clicking a + snapshot activates the selected point in time, i.e., the entire Debugger UI will + navigate to the selected snapshot. NOTE: Navigating through time is not permitted while + in Control Target mode.

      Table Columns

      @@ -45,11 +42,9 @@ creation, this should probably be the spawned thread, not the parent.
    • Schedule - if applicable, a source snap and the stepping schedule which produces this - snapshot. This always applies to "scratch" snapshots produced by emulation, but may also - apply if the stepping schedule between recorded events is somehow known. Typically, it is - just the number of steps of the source snapshot's event thread; however, the notation does - allow other threads to be stepped, too. See the Go To Time - action.
    • + snapshot. This always applies to scratch snapshots produced by emulation, but may + (rarely) apply to recorded events if the stepping schedule between them is somehow known. See + the Go To Time action for a description of the notation.
    • Description - a user-modifiable description of the snapshot or event. This defaults to the debugger's description of the event.
    • @@ -66,43 +61,43 @@

      Go To Time

      -

      This action is available when a trace is active. It prompts for a Time Schedule - expression. This is the same form as the expression in the sub-title of the This action is available when a trace is active. It prompts for a time schedule. + This is the same form as the notation in the sub-title of the Threads window. In many cases, it is simply the snapshot number, e.g., 3, which will go to the snapshot - with key 3. It may optionally include an emulation schedule, for example, 3:10 + with key 3. It may optionally include an emulation schedule. For example, 3:10 will use snapshot 3 for an emulator's initial state and step 10 machine instructions on snapshot 3's event thread. If the snapshot does not give an event thread, then the thread must be specified in the expression, e.g., 3:t1-10. That expression will start at snapshot 3, get the thread with key 1, and step it 10 machine instructions. The stepping commands can be repeated any number of times, separated by semicolons, to step threads in a - specified sequence, e.g., 3:t1-10;t2-5 will do the same as before, then get thread - 2 and step it 5 times.

      + specified sequence. For example, 3:t1-10;t2-5 will do the same as before, then get + thread 2 and step it 5 times.

      -

      The emulator's state can also be modified by the schedule. Instead of specifying a number of - steps, write a Sleigh statement, e.g., 3:t1-{r0=0x1234};10. This will start - at snapshot 3, patch thread 1's r0 to 0x1234, then step 10 instructions. Like stepping - commands, the thread may be omitted for Sleigh commands. Each command without a thread - specified implicitly uses the one from the previous command, or in the case of the first - command, the event thread. Only one Sleigh statement is permitted per command.

      +

      The emulator's state can also be patched by the schedule. Instead of specifying the number + of steps, write a Sleigh statement, e.g., 3:t1-{r0=0x1234};10. This will + start at snapshot 3, patch thread 1's r0 to 0x1234, then step 10 instructions. As for steps, + the thread key may be omitted for Sleigh commands. Each command without a thread specified + implicitly uses the one from the previous command, or in the case of the first command, the + event thread. Only one Sleigh statement is permitted per command.

      A second command sequence may be appended, following a dot, to command the emulator at the level of p-code operations as well. This is particularly useful when debugging a processor - specification. See also the P-code Stepper window. For example, 3:2.10 will start at snapshot 3 and step the event thread 2 machine instructions then 10 p-code operations. The same thread-by-thread sequencing and state - patching commands are allowed in the p-code command sequence. The entire instruction - sequence precedes the entire p-code sequence, i.e., only a single dot is allowed. Once the - expression enters p-code mode, it cannot re-enter instruction mode.

      + patching commands are allowed in the p-code command sequence. NOTE: the entire + instruction sequence precedes the entire p-code sequence, i.e., only a single dot is allowed. + Once the schedule enters p-code mode, it cannot re-enter instruction mode.

      Hide Scratch

      This toggle action is always available in the drop-down actions of the Time window. It is enabled by default. The emulation service, which enables trace extrapolation and interpolation, - writes emulated state into the trace's "scratch space," which comprises all negative snaps. - When this toggle is enabled, those snapshots are hidden. They can be displayed by disabling - this toggle. Note that navigating into scratch space may cause temporary undefined behavior in - some windows, and may prevent interaction with the target.

      + writes emulated state into the trace's scratch space, which comprises all negative + snaps. When this toggle is enabled, those snapshots are hidden. They can be displayed by + disabling this toggle. Note that navigating into scratch space may cause temporary undefined + behavior in some windows, and may prevent interaction with the target.

      diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTimePlugin/images/DebuggerTimePlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTimePlugin/images/DebuggerTimePlugin.png index 608e160bd4..059587abe8 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTimePlugin/images/DebuggerTimePlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTimePlugin/images/DebuggerTimePlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceManagerServicePlugin/DebuggerTraceManagerServicePlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceManagerServicePlugin/DebuggerTraceManagerServicePlugin.html index 8d82b70eca..a8afd58c51 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceManagerServicePlugin/DebuggerTraceManagerServicePlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceManagerServicePlugin/DebuggerTraceManagerServicePlugin.html @@ -14,10 +14,10 @@

      Debugger: Trace Management

      This service plugin manages the collection of open traces, and it is controlled primarily - via the Threads - window. It maintains a list of open traces, the active trace coordinates (trace, time, thread, - frame), and permits saving, opening, and closing traces. To some extent, it also tracks which - traces are being actively recorded.

      + via the Listing + window's tab panel. It maintains a list of open traces, the active trace coordinates (trace, + time, object), and permits saving, opening, and closing traces. To some extent, it also tracks + which traces have live targets.

      Actions

      @@ -26,7 +26,7 @@

      Open Trace

      This action is always available. It prompts for a trace in the current project and opens - that trace in the tool.

      + that trace in the Debugger tool.

      Save Trace

      @@ -37,26 +37,22 @@

      Close Trace

      This action is available whenever at least one trace is open and active. It closes the - current trace. WARNING: If the trace has not been saved, it will be - lost, even when Save by Default is active.

      + current trace.

      Close All Traces

      This action is available whenever at least one trace is open. It closes all traces in this - tool. WARNING: Any trace that has not been saved will be lost, even - when Save by Default is active.

      + tool.

      Close Other Traces

      This action is available whenever there is an open trace other than the active one. It - closes all traces in this tool, except the active trace. WARNING: Any - closed trace that has not been saved will be lost, even when Save by Default is active.

      + closes all traces in this tool, except the active trace.

      Close Dead Traces

      This action is available whenever at least one trace is open. It closes all dead traces in - this tool. WARNING: Any closed trace that has not been saved will be - lost, even when Save by Default is active.

      + this tool.

      Save by Default

      diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/DebuggerTraceViewDiffPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/DebuggerTraceViewDiffPlugin.html index 9d144e8a98..b5f08c468d 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/DebuggerTraceViewDiffPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/DebuggerTraceViewDiffPlugin.html @@ -13,27 +13,21 @@

      Debugger: Comparing Times

      - - - - - - -
      +
      + +

      A common strategy in dynamic analysis is to compare machine - state between two points in time. To this end, to support comparison of bytes in memory, the - "trace diff" plugin extends the Dynamic Listing to provide - side-by-side comparison of two different points in time. When active, listings for both points - in time are displayed and the byte value differences between them are highlighted. NOTE: - This does not compare annotations. It only compares raw byte values. Additionally, all stale - values are ignored, i.e., to show as a difference, the memory must be observed at both - points in time, and the values must differ.

      + side-by-side comparison of bytes between points in time. When active, listings for both times + are displayed, and the byte value differences between them are highlighted. NOTE: This + does not compare annotations. It only compares raw byte values. Additionally, all stale values + are ignored, i.e., to show as a difference, the memory must be observed at both points + in time, and the values must differ.

      NOTE: This plugin only facilitates the comparison of memory displayed in listings. To - compare registers or SLEIGH expressions, use the respective windows: Registers and Watches. By navigating back and forth between two points in time, using the This action is available whenever a trace is active in the main listing. It prompts for an alternative point in time:

      - - - - - - -
      +
      + +

      The snapshot table is exactly the same as that in the Time Window. In most cases, simply @@ -68,11 +57,11 @@ snapshots thus identifies changes over time; however, there is no guarantee that the desired variable was ever observed. Assuming the general vicinity of the variable is known, e.g., "somewhere in the .data section," the Read Selected - Memory action can ensure its value is recorded. Of course, it can also read "all memory," - but that operation and the follow-on comparison could take time. In general, the procedure to - locate a variable is to capture a baseline, execute the target until the variable has changed, - capture again, then compare:

      + "help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html#read_memory">Read Memory + action can ensure its value is recorded. Of course, it can also read "all memory," but that + operation and the follow-on comparison could take time. In general, the procedure to locate a + variable is to capture a baseline, execute the target until the variable has changed, capture + again, then compare:

      1. Execute the target up to a baseline, and take note of the variable's value, as displayed @@ -88,8 +77,8 @@ selection.
      2. Use the Read Selected - Memory action to ensure the variable's value is stored in the trace.
      3. + "help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html#read_memory">Read Memory + action to ensure the variable's value is stored in the trace.
      4. Allow the target to execute until the variable has changed. Ideally, execute as little as necessary, so that few or no other variables change.
      5. @@ -134,7 +123,7 @@

        Alternatively, if the number of steps to reach the end of the block is already known, just use the emulation expression in the Compare action's dialog. NOTE: When used this way, the baseline snapshot will be in the left pane, and the emulated snapshot in the right, - which is opposite the result from the steps above.

        + which is opposite the result from the previous procedure.

        In either case, this will highlight any memory that was modified by the emulated code. Of course, this could also be accomplished by setting a second breakpoint and allowing the target diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/images/DebuggerTimeSelectionDialog.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/images/DebuggerTimeSelectionDialog.png index 5beb6d5f02..5f20a57ece 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/images/DebuggerTimeSelectionDialog.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/images/DebuggerTimeSelectionDialog.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/images/DebuggerTraceViewDiffPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/images/DebuggerTraceViewDiffPlugin.png index 274676cf17..a8839668b2 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/images/DebuggerTraceViewDiffPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerTraceViewDiffPlugin/images/DebuggerTraceViewDiffPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html index 7f9ba9d295..b5906deb9d 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html @@ -13,14 +13,9 @@

        Debugger: Watches

        - - - - - - -
        +
        + +

        Watches refer to expressions which are evaluated each pause in order to monitor the value of variables in the target machine state. The watch variables are expressed in Sleigh and @@ -32,15 +27,15 @@

        The watch window uses colors to hint about changes in and freshness of displayed values. By default, changed values are displayed in red, and stale values are displayed in dark grey. A - "stale" value is one which depends on any register or memory whose contents are not known. The - value displayed is that computed from the last recorded contents, defaulting to 0 when never - recorded. Simply, a "changed" watch is one whose value has just changed. For example, if a - value changes as result of stepping, then that watch is changed. However, given the possibility - of rewinding, changing thread focus, etc., "changed" is actually subtly more flexible. The - watch remembers the evaluation from the user's last coordinates (time, thread, frame, etc.) as - well as the current coordinates. So, "changed" more precisely refers to a watch whose value - differs between those two coordinates. This permits the user to switch focus between different - coordinates and quickly identify what is different.

        + stale value is one which depends on any register or memory whose contents are not + known. The value displayed is that computed from the last recorded contents, defaulting to 0 + when never recorded. A changed watch is one whose value has just changed. For example, + if a value changes as result of stepping, then that watch is changed. However, given the + possibility of rewinding, changing thread focus, etc., "changed" is actually subtly more + flexible. The watch remembers the evaluation from the user's last coordinates (time, thread, + frame, etc.) as well as the current coordinates. So, "changed" more precisely refers to a watch + whose value differs between those two coordinates. This permits the user to switch focus + between different coordinates and quickly identify what is different.

        Examples

        @@ -95,8 +90,8 @@ rendered in red.
      6. Type - the user-modifiable type of the watch. Note the type is not marked up in the - trace. Clicking the Apply Data Type action will apply it to the current trace, if - possible.
      7. + trace. Clicking the Apply Data Type action will apply it to + the current trace, if possible.
      8. Representation - the value of the watch as interpreted by the selected data type. If the value is an address, i.e., Type is a pointer, then double-clicking this cell will navigate @@ -172,7 +167,6 @@

        This toggle is a write protector for machine state. To modify a watch's value, this toggle must be enabled. Edits are directed according the to Control and Machine State - Plugin. Note: Only the raw "Value" column can be edited directly. The "Repr" column - cannot be edited, yet.

        + Plugin.

        diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/images/DebuggerWatchesPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/images/DebuggerWatchesPlugin.png index 84da6b1669..85692bc897 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/images/DebuggerWatchesPlugin.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/images/DebuggerWatchesPlugin.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/VariableValueHoverPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/VariableValueHoverPlugin.html index 209827270d..ed860b0076 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/VariableValueHoverPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/VariableValueHoverPlugin.html @@ -27,7 +27,7 @@ functions to follow certain conventions. Thus, it's very easy to break and may frequently be incorrect. For hovers that include a Frame row, the displayed value depends on an accurately unwound stack. Take the value with a grain of salt, especially if the hover also - includes a Warnings: row. To diagnose the unwound stack, use the Warnings row. To diagnose the unwound stack, use the Unwind Stack action.

        @@ -72,18 +72,11 @@

        Examples

        - - - - - +
        + -
        - - - -
        A register operand in the Dynamic Listing
        +

        A register operand in the Dynamic Listing

        +

        When hovering over operands in the Dynamic Listing, that operand is most likely a register. The register's value is displayed without regard to the stack frame. It will always use the @@ -94,18 +87,11 @@ window, and so the service cannot interpret the value except as an integer. Register values are never displayed as raw byte arrays.

        - - - - - +
        + -
        - - - -
        A stack variable in the Static Listing
        +

        A stack variable in the Static Listing

        +

        When hovering over operands in the Static Listing, the service will gather context about the operand and find a frame for the relevant function. It will take the first appropriate frame it @@ -120,18 +106,11 @@ computes the integer value 1. It also interprets the value using the assigned data type, giving 1h.

        - - - - - +
        + -
        - - - -
        A stack variable in the Decompiler
        +

        A stack variable in the Decompiler

        +

        When hovering over variables in the Decompiler, the service behaves similarly to how it does for operands in the Static Listing. It locates the appropriate frame and attempts to derive the diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginBrowser.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginBrowser.png index 5c7ee4de7c..1417259723 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginBrowser.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginBrowser.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginDecompiler.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginDecompiler.png index 0a44d28236..3c9b27a452 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginDecompiler.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginDecompiler.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginListing.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginListing.png index ca5c1339d4..bc49f33838 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginListing.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/VariableValueHoverPlugin/images/VariableValueHoverPluginListing.png differ diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java index 2bf97cffae..301aabf1f9 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java @@ -119,7 +119,7 @@ public interface DebuggerResources { Icon ICON_STACK = new GIcon("icon.debugger.provider.stack"); Icon ICON_BREAKPOINTS = new GIcon("icon.debugger.provider.breakpoints"); Icon ICON_MODULES = new GIcon("icon.debugger.provider.modules"); - Icon ICON_MAPPINGS = ICON_PROGRAM; // TODO: A better icon + Icon ICON_MAPPINGS = new GIcon("icon.debugger.provider.mappings"); // TODO: A better icon Icon ICON_PCODE = new GIcon("icon.debugger.provider.pcode"); // TODO Icon ICON_REGIONS = new GIcon("icon.debugger.provider.regions"); Icon ICON_TIME = new GIcon("icon.debugger.provider.time"); @@ -132,7 +132,7 @@ public interface DebuggerResources { Icon ICON_DELETE = new GIcon("icon.debugger.delete"); Icon ICON_CLEAR = new GIcon("icon.debugger.clear"); Icon ICON_REFRESH = new GIcon("icon.debugger.refresh"); - Icon ICON_FILTER = new GIcon("icon.debugger.filter"); // Eww. + Icon ICON_FILTER = new GIcon("icon.debugger.filter"); Icon ICON_SELECT_ROWS = new GIcon("icon.debugger.select.rows"); Icon ICON_AUTOREAD = new GIcon("icon.debugger.autoread"); @@ -149,6 +149,8 @@ public interface DebuggerResources { Icon ICON_MAP_MODULES = new GIcon("icon.debugger.map.modules"); Icon ICON_MAP_SECTIONS = new GIcon("icon.debugger.map.sections"); // TODO Icon ICON_MAP_REGIONS = new GIcon("icon.debugger.map.regions"); // TODO + Icon ICON_MAP_AUTO = new GIcon("icon.debugger.map.auto"); + Icon ICON_MAP_MANUALLY = new GIcon("icon.debugger.map.manual"); Icon ICON_BLOCK = new GIcon("icon.debugger.block"); // TODO // TODO: Draw an icon Icon ICON_SELECT_ADDRESSES = new GIcon("icon.debugger.select.addresses"); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java index 4fb7b6559b..1b06c8aa2d 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java @@ -155,34 +155,36 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter protected enum BreakpointLocationTableColumns implements EnumeratedTableColumn { - STATE("State", State.class, BreakpointLocationRow::getState, BreakpointLocationRow::setState, true), - NAME("Name", String.class, BreakpointLocationRow::getName, BreakpointLocationRow::setName, true), - ADDRESS("Address", Address.class, BreakpointLocationRow::getAddress, true), - TRACE("Trace", String.class, BreakpointLocationRow::getTraceName, true), - THREADS("Threads", String.class, BreakpointLocationRow::getThreads, true), - COMMENT("Comment", String.class, BreakpointLocationRow::getComment, BreakpointLocationRow::setComment, true), - SLEIGH("Sleigh", Boolean.class, BreakpointLocationRow::hasSleigh, true); + STATE("State", State.class, BreakpointLocationRow::getState, BreakpointLocationRow::setState, true, true), + NAME("Name", String.class, BreakpointLocationRow::getName, BreakpointLocationRow::setName, true, true), + ADDRESS("Address", Address.class, BreakpointLocationRow::getAddress, true, true), + TRACE("Trace", String.class, BreakpointLocationRow::getTraceName, true, true), + THREADS("Threads", String.class, BreakpointLocationRow::getThreads, true, false), + COMMENT("Comment", String.class, BreakpointLocationRow::getComment, BreakpointLocationRow::setComment, true, true), + SLEIGH("Sleigh", Boolean.class, BreakpointLocationRow::hasSleigh, true, true); private final String header; private final Function getter; private final BiConsumer setter; private final boolean sortable; + private final boolean visible; private final Class cls; BreakpointLocationTableColumns(String header, Class cls, - Function getter, boolean sortable) { - this(header, cls, getter, null, sortable); + Function getter, boolean sortable, boolean visible) { + this(header, cls, getter, null, sortable, visible); } @SuppressWarnings("unchecked") BreakpointLocationTableColumns(String header, Class cls, Function getter, - BiConsumer setter, boolean sortable) { + BiConsumer setter, boolean sortable, boolean visible) { this.header = header; this.cls = cls; this.getter = getter; this.setter = (BiConsumer) setter; this.sortable = sortable; + this.visible = visible; } @Override @@ -210,6 +212,11 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter return sortable; } + @Override + public boolean isVisible() { + return visible; + } + @Override public void setValueOf(BreakpointLocationRow row, Object value) { setter.accept(row, value); @@ -1076,8 +1083,8 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter locsCol.setPreferredWidth(20); TableColumn bptSleighCol = bptColModel.getColumn(LogicalBreakpointTableColumns.SLEIGH.ordinal()); - bptSleighCol.setMaxWidth(24); - bptSleighCol.setMinWidth(24); + bptSleighCol.setMaxWidth(30); + bptSleighCol.setMinWidth(30); GTableColumnModel locColModel = (GTableColumnModel) locationTable.getColumnModel(); TableColumn locEnCol = @@ -1098,8 +1105,8 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter locColModel.getColumn(BreakpointLocationTableColumns.THREADS.ordinal()); TableColumn locSleighCol = locColModel.getColumn(BreakpointLocationTableColumns.SLEIGH.ordinal()); - locSleighCol.setMaxWidth(24); - locSleighCol.setMinWidth(24); + locSleighCol.setMaxWidth(30); + locSleighCol.setMinWidth(30); locColModel.setVisible(locThreadsCol, false); locColModel.setVisible(locSleighCol, false); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/ModelQuery.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/ModelQuery.java index b765338952..1dfc017764 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/ModelQuery.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/ModelQuery.java @@ -145,9 +145,13 @@ public class ModelQuery { public Stream computeAttributes(Trace trace) { TargetObjectSchema schema = computeSingleSchema(trace); return schema.getAttributeSchemas() - .values() + .entrySet() .stream() - .filter(as -> !"".equals(as.getName())); + .filter(ent -> { + String attrName = ent.getValue().getName(); + return !"".equals(attrName) && ent.getKey().equals(attrName); + }) + .map(e -> e.getValue()); } protected static boolean includes(Lifespan span, PathPattern pattern, TraceObjectValue value) { @@ -221,6 +225,8 @@ public class ModelQuery { /** * Determine whether the query results could depend on the given value * + * @param span the lifespan of interest, e.g., the span being displayed + * @param value the value that has changed * @return true if the query results depend on the given value */ public boolean involves(Lifespan span, TraceObjectValue value) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/AbstractTraceValueObjectAddressColumn.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/AbstractTraceValueObjectAddressColumn.java index 2c85a422fc..15da27966c 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/AbstractTraceValueObjectAddressColumn.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/AbstractTraceValueObjectAddressColumn.java @@ -42,6 +42,11 @@ public abstract class AbstractTraceValueObjectAddressColumn } return fromRange(range); } + + @Override + public boolean isModified() { + return row.isAttributeModified(attributeName); + } }; } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/AbstractTraceValueObjectLengthColumn.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/AbstractTraceValueObjectLengthColumn.java index 3eff5c6a01..29f3520e85 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/AbstractTraceValueObjectLengthColumn.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/AbstractTraceValueObjectLengthColumn.java @@ -58,6 +58,11 @@ public abstract class AbstractTraceValueObjectLengthColumn : ("0x" + Long.toUnsignedString(value, 16)); } + + @Override + public boolean isModified() { + return row.isAttributeModified(attributeName); + } }; } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/TraceValueObjectPropertyColumn.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/TraceValueObjectPropertyColumn.java index c84d1d8feb..d600138fe3 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/TraceValueObjectPropertyColumn.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/columns/TraceValueObjectPropertyColumn.java @@ -82,7 +82,6 @@ public abstract class TraceValueObjectPropertyColumn public class BooleanPropertyRenderer extends PropertyRenderer { protected GCheckBox cb; { - setLayout(new BorderLayout()); cb = new GCheckBox(); cb.setHorizontalAlignment(CENTER); cb.setOpaque(false); @@ -103,14 +102,14 @@ public abstract class TraceValueObjectPropertyColumn else { cb.setVisible(false); } + setVisible(true); + invalidate(); return this; } @Override public void validate() { - synchronized (getTreeLock()) { - validateTree(); - } + cb.setBounds(0, 0, getWidth(), getHeight()); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java index 0405009168..6a65bdea8b 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java @@ -106,7 +106,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter { interface MapManuallyAction { String NAME = DebuggerResources.NAME_MAP_MANUALLY; String DESCRIPTION = DebuggerResources.DESCRIPTION_MAP_MANUALLY; - Icon ICON = DebuggerResources.ICON_MAPPINGS; + Icon ICON = DebuggerResources.ICON_MAP_MANUALLY; String GROUP = DebuggerResources.GROUP_MAPPING; String HELP_ANCHOR = "map_manually"; @@ -196,7 +196,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter { interface AutoMapAction { String NAME = "Auto-Map Target Memory"; - Icon ICON = DebuggerResources.ICON_CONFIG; + Icon ICON = DebuggerResources.ICON_MAP_AUTO; String DESCRIPTION = "Automatically map dynamic memory to static counterparts"; String GROUP = DebuggerResources.GROUP_MAPPING; String HELP_ANCHOR = "auto_map"; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPanel.java index 24dd31290b..e5458adb28 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPanel.java @@ -16,16 +16,15 @@ package ghidra.app.plugin.core.debug.gui.stack; import java.util.List; +import java.util.Objects; import javax.swing.JTable; import javax.swing.event.ListSelectionListener; -import docking.widgets.table.AbstractDynamicTableColumn; import docking.widgets.table.TableColumnDescriptor; import ghidra.app.plugin.core.debug.gui.model.*; -import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow; -import ghidra.app.plugin.core.debug.gui.model.columns.TraceValueKeyColumn; -import ghidra.app.plugin.core.debug.gui.model.columns.TraceValueObjectAttributeColumn; +import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.*; +import ghidra.app.plugin.core.debug.gui.model.columns.*; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils; import ghidra.app.services.DebuggerTraceManagerService; import ghidra.dbg.target.TargetStack; @@ -55,7 +54,7 @@ public class DebuggerStackPanel extends AbstractObjectsTableBasedPanel { + static Address computeProgramCounter(ValueRow row, long snap) { + if (!(row.getValue().getValue() instanceof TraceObject object)) { + return null; + } + TraceObjectValue attrPc = object.getAttribute(snap, TargetStackFrame.PC_ATTRIBUTE_NAME); + if (attrPc == null || !(attrPc.getValue() instanceof Address pc)) { + return null; + } + return pc; + } + + private Function computeFunction(ValueRow row, long snap, ServiceProvider serviceProvider) { + Address pc = computeProgramCounter(row, snap); + if (pc == null) { + return null; + } + return DebuggerStaticMappingUtils.getFunction(pc, provider.current, serviceProvider); + } + + private class FrameFunctionColumn extends TraceValueObjectPropertyColumn { + public FrameFunctionColumn() { + super(Function.class); + } + + @Override + public ValueProperty getProperty(ValueRow row) { + throw new AssertionError(); // overrode caller to this + } + + @Override + public ValueProperty getValue(ValueRow row, Settings settings, Trace data, + ServiceProvider serviceProvider) throws IllegalArgumentException { + return new ValueDerivedProperty<>(row, Function.class) { + @Override + public Function getValue() { + return computeFunction(row, row.currentSnap(), serviceProvider); + } + + @Override + public boolean isModified() { + return !Objects.equals(computeFunction(row, row.currentSnap(), serviceProvider), + computeFunction(row, row.previousSnap(), serviceProvider)); + } + }; + } @Override public String getColumnName() { return "Function"; } - - @Override - public Function getValue(ValueRow rowObject, Settings settings, Trace data, - ServiceProvider serviceProvider) throws IllegalArgumentException { - TraceObjectValue value = - rowObject.getAttributeEntry(TargetStackFrame.PC_ATTRIBUTE_NAME); - if (value == null) { - return null; - } - return DebuggerStaticMappingUtils.getFunction(value.castValue(), provider.current, - serviceProvider); - } } - private class FrameModuleColumn extends AbstractDynamicTableColumn { + private String computeModuleName(ValueRow row, long snap) { + Address pc = computeProgramCounter(row, snap); + if (pc == null) { + return null; + } + return DebuggerStaticMappingUtils.getModuleName(pc, provider.current); + } + + private class FrameModuleColumn extends TraceValueObjectPropertyColumn { + public FrameModuleColumn() { + super(String.class); + } + + @Override + public ValueProperty getProperty(ValueRow row) { + return new ValueDerivedProperty<>(row, String.class) { + @Override + public String getValue() { + return computeModuleName(row, row.currentSnap()); + } + + @Override + public boolean isModified() { + return !Objects.equals(computeModuleName(row, row.currentSnap()), + computeModuleName(row, row.previousSnap())); + } + }; + } + @Override public String getColumnName() { return "Module"; } - - @Override - public String getValue(ValueRow rowObject, Settings settings, Trace data, - ServiceProvider serviceProvider) throws IllegalArgumentException { - TraceObjectValue value = - rowObject.getAttributeEntry(TargetStackFrame.PC_ATTRIBUTE_NAME); - if (value == null) { - return null; - } - return DebuggerStaticMappingUtils.getModuleName(value.castValue(), provider.current); - } } private class StackTableModel extends ObjectTableModel { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPanel.java index 8b55953bda..55ca501f66 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPanel.java @@ -16,10 +16,10 @@ package ghidra.app.plugin.core.debug.gui.thread; import java.util.List; +import java.util.Objects; import javax.swing.event.ListSelectionEvent; -import docking.widgets.table.AbstractDynamicTableColumn; import docking.widgets.table.RangeCursorTableHeaderRenderer.SeekListener; import docking.widgets.table.TableColumnDescriptor; import docking.widgets.table.threaded.ThreadedTableModelListener; @@ -70,20 +70,31 @@ public class DebuggerThreadsPanel extends AbstractObjectsTableBasedPanel { public ThreadPcColumn() { super(Address.class); @@ -92,13 +103,19 @@ public class DebuggerThreadsPanel extends AbstractObjectsTableBasedPanel getProperty(ValueRow row) { TraceObject obj = row.getValue().getChild(); - DebuggerCoordinates coords = coordsForObject(obj); + DebuggerCoordinates diffCoords = diffCoordsForObject(obj); return new ValueAddressProperty(row) { @Override public Address getValue() { return computeProgramCounter(coords); } + + @Override + public boolean isModified() { + return !Objects.equals(computeProgramCounter(coords), + computeProgramCounter(diffCoords)); + } }; } @@ -108,43 +125,91 @@ public class DebuggerThreadsPanel extends AbstractObjectsTableBasedPanel { + private Function computeFunction(DebuggerCoordinates coords, ServiceProvider serviceProvider) { + Address pc = computeProgramCounter(coords); + if (pc == null) { + return null; + } + return DebuggerStaticMappingUtils.getFunction(pc, coords, serviceProvider); + } + + private class ThreadFunctionColumn extends TraceValueObjectPropertyColumn { + public ThreadFunctionColumn() { + super(Function.class); + } + + @Override + public ValueProperty getProperty(ValueRow row) { + throw new AssertionError(); // overrode caller to this + } + + @Override + public ValueProperty getValue(ValueRow row, Settings settings, Trace data, + ServiceProvider serviceProvider) { + TraceObject obj = row.getValue().getChild(); + DebuggerCoordinates coords = coordsForObject(obj); + DebuggerCoordinates diffCoords = diffCoordsForObject(obj); + return new ValueDerivedProperty<>(row, Function.class) { + @Override + public Function getValue() { + return computeFunction(coords, serviceProvider); + } + + @Override + public boolean isModified() { + return !Objects.equals(computeFunction(coords, serviceProvider), + computeFunction(diffCoords, serviceProvider)); + } + }; + } + @Override public String getColumnName() { return "Function"; } - - @Override - public Function getValue(ValueRow rowObject, Settings settings, Trace data, - ServiceProvider serviceProvider) throws IllegalArgumentException { - TraceObject obj = rowObject.getValue().getChild(); - DebuggerCoordinates coords = coordsForObject(obj); - Address pc = computeProgramCounter(coords); - if (pc == null) { - return null; - } - return DebuggerStaticMappingUtils.getFunction(pc, coords, serviceProvider); - } } - private class ThreadModuleColumn extends AbstractDynamicTableColumn { + private String computeModuleName(DebuggerCoordinates coords) { + Address pc = computeProgramCounter(coords); + if (pc == null) { + return null; + } + return DebuggerStaticMappingUtils.getModuleName(pc, coords); + } + + private class ThreadModuleColumn extends TraceValueObjectPropertyColumn { + public ThreadModuleColumn() { + super(String.class); + } + + @Override + public ValueProperty getProperty(ValueRow row) { + TraceObject obj = row.getValue().getChild(); + DebuggerCoordinates coords = coordsForObject(obj); + DebuggerCoordinates diffCoords = diffCoordsForObject(obj); + return new ValueDerivedProperty<>(row, String.class) { + @Override + public String getValue() { + return computeModuleName(coords); + } + + @Override + public boolean isModified() { + return !Objects.equals(computeModuleName(coords), + computeModuleName(diffCoords)); + } + }; + } + @Override public String getColumnName() { return "Module"; } + } - @Override - public String getValue(ValueRow rowObject, Settings settings, Trace data, - ServiceProvider serviceProvider) throws IllegalArgumentException { - TraceObject obj = rowObject.getValue().getChild(); - DebuggerCoordinates coords = coordsForObject(obj); - Address pc = computeProgramCounter(coords); - if (pc == null) { - return null; - } - return DebuggerStaticMappingUtils.getModuleName(pc, coords); - } + private Address computeStackPointer(DebuggerCoordinates coords) { + return SPLocationTrackingSpec.INSTANCE.computeTraceAddress(provider.getTool(), + coords); } private class ThreadSpColumn extends TraceValueObjectPropertyColumn

        { @@ -156,11 +221,17 @@ public class DebuggerThreadsPanel extends AbstractObjectsTableBasedPanel getProperty(ValueRow row) { TraceObject obj = row.getValue().getChild(); DebuggerCoordinates coords = coordsForObject(obj); + DebuggerCoordinates diffCoords = diffCoordsForObject(obj); return new ValueAddressProperty(row) { @Override public Address getValue() { - return SPLocationTrackingSpec.INSTANCE.computeTraceAddress(provider.getTool(), - coords); + return computeStackPointer(coords); + } + + @Override + public boolean isModified() { + return !Objects.equals(computeStackPointer(coords), + computeStackPointer(diffCoords)); } }; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java index 15b8b6b64d..95ea326f73 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java @@ -851,14 +851,15 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin info.forgetMismappedBreakpoints(c.r, additionalTraces, additionalPrograms); } } - for (Trace t : additionalTraces) { - InfoPerTrace info = traceInfos.get(t); + // Load program breakpoints first, lest syncing with traces write garbage to program + for (Program p : additionalPrograms) { + InfoPerProgram info = programInfos.get(p); if (info != null) { info.reloadBreakpoints(c); } } - for (Program p : additionalPrograms) { - InfoPerProgram info = programInfos.get(p); + for (Trace t : additionalTraces) { + InfoPerTrace info = traceInfos.get(t); if (info != null) { info.reloadBreakpoints(c); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java index eccf3528ba..808c307444 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java @@ -92,6 +92,14 @@ public class ProgramEmulationUtils { + + + + + + + @@ -99,6 +107,7 @@ public class ProgramEmulationUtils { + diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java index 73894b0232..bdb9200fb5 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java @@ -23,7 +23,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import ghidra.app.plugin.core.debug.service.modules.ProgramModuleIndexer.IndexEntry; -import ghidra.app.services.*; import ghidra.dbg.util.PathUtils; import ghidra.debug.api.modules.*; import ghidra.framework.model.DomainFile; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingUtils.java index 849dcad950..395e2df02d 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingUtils.java @@ -315,12 +315,8 @@ public enum DebuggerStaticMappingUtils { if (mappingService == null) { return null; } - TraceThread curThread = coordinates.getThread(); - if (curThread == null) { - return null; - } - TraceLocation dloc = new DefaultTraceLocation(curThread.getTrace(), - curThread, Lifespan.at(coordinates.getSnap()), pc); + TraceLocation dloc = new DefaultTraceLocation(coordinates.getTrace(), + null, Lifespan.at(coordinates.getSnap()), pc); ProgramLocation sloc = mappingService.getOpenMappedLocation(dloc); if (sloc == null) { return null; diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/console/DebuggerConsolePluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/console/DebuggerConsolePluginScreenShots.java index d37d28a6e2..115db113ca 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/console/DebuggerConsolePluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/console/DebuggerConsolePluginScreenShots.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.debug.gui.console; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import org.junit.*; import org.junit.rules.TestName; @@ -25,6 +25,8 @@ import docking.DefaultActionContext; import docking.action.builder.ActionBuilder; import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest; import ghidra.app.plugin.core.debug.gui.DebuggerResources; +import ghidra.app.plugin.core.debug.service.progress.ProgressServicePlugin; +import ghidra.debug.api.progress.CloseableTaskMonitor; import ghidra.util.Msg; import help.screenshot.GhidraScreenShotGenerator; @@ -35,6 +37,7 @@ public class DebuggerConsolePluginScreenShots extends GhidraScreenShotGenerator DebuggerConsolePlugin consolePlugin; DebuggerConsoleProvider consoleProvider; + ProgressServicePlugin progressService; @Rule public TestName name = new TestName(); @@ -43,36 +46,44 @@ public class DebuggerConsolePluginScreenShots extends GhidraScreenShotGenerator public void setUpMine() throws Throwable { consolePlugin = addPlugin(tool, DebuggerConsolePlugin.class); consoleProvider = waitForComponentProvider(DebuggerConsoleProvider.class); + progressService = addPlugin(tool, ProgressServicePlugin.class); consolePlugin.addResolutionAction(new ActionBuilder("Import", name.getMethodName()) - .toolBarIcon(DebuggerResources.ICON_IMPORT) - .popupMenuIcon(DebuggerResources.ICON_IMPORT) - .popupMenuPath("Map") - .description("Import") - .withContext(ScreenShotActionContext.class) - .onAction(ctx -> Msg.info(this, "Import clicked")) - .build()); + .toolBarIcon(DebuggerResources.ICON_IMPORT) + .popupMenuIcon(DebuggerResources.ICON_IMPORT) + .popupMenuPath("Map") + .description("Import") + .withContext(ScreenShotActionContext.class) + .onAction(ctx -> Msg.info(this, "Import clicked")) + .build()); consolePlugin.addResolutionAction(new ActionBuilder("Map", name.getMethodName()) - .toolBarIcon(DebuggerResources.ICON_MODULES) - .popupMenuIcon(DebuggerResources.ICON_MODULES) - .popupMenuPath("Map") - .description("Map") - .withContext(ScreenShotActionContext.class) - .onAction(ctx -> Msg.info(this, "Map clicked")) - .build()); + .toolBarIcon(DebuggerResources.ICON_MODULES) + .popupMenuIcon(DebuggerResources.ICON_MODULES) + .popupMenuPath("Map") + .description("Map") + .withContext(ScreenShotActionContext.class) + .onAction(ctx -> Msg.info(this, "Map clicked")) + .build()); } @Test public void testCaptureDebuggerConsolePlugin() throws Throwable { - Msg.warn(this, "This is a warning message"); - Msg.error(this, "This is an error message"); + consolePlugin.log(DebuggerResources.ICON_LOG_WARN, "This is a warning message"); + consolePlugin.log(DebuggerResources.ICON_LOG_ERROR, "This is an error message", + new AssertionError()); consolePlugin.log(DebuggerResources.ICON_DEBUGGER, "You can take action to resolve this message", new ScreenShotActionContext()); - AbstractGhidraHeadedDebuggerTest - .waitForPass(() -> assertEquals(3, consolePlugin.getRowCount(ActionContext.class))); + try (CloseableTaskMonitor monitor = progressService.publishTask()) { + monitor.initialize(10, "Busy...."); + monitor.setProgress(6); - captureIsolatedProvider(consoleProvider, 600, 300); + AbstractGhidraHeadedDebuggerTest + .waitForPass( + () -> assertEquals(4, consolePlugin.getRowCount(ActionContext.class))); + + captureIsolatedProvider(consoleProvider, 600, 300); + } } } diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java index 0a45bc9487..1dbd7e4283 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java @@ -20,18 +20,17 @@ import java.util.Set; import org.junit.*; import db.Transaction; -import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest.TestDebuggerTargetTraceMapper; import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin; import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingProvider; -import ghidra.app.plugin.core.debug.service.model.DebuggerModelServicePlugin; +import ghidra.app.plugin.core.debug.service.control.MockTarget; +import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; +import ghidra.app.plugin.core.debug.service.target.DebuggerTargetServicePlugin; import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin; import ghidra.app.services.*; -import ghidra.dbg.model.TestDebuggerModelBuilder; -import ghidra.debug.api.action.ActionSource; -import ghidra.debug.api.model.TraceRecorder; import ghidra.framework.model.DomainFolder; +import ghidra.program.database.ProgramBuilder; import ghidra.program.model.address.AddressSpace; import ghidra.program.model.mem.Memory; import ghidra.program.util.ProgramLocation; @@ -50,31 +49,26 @@ public class DebuggerCopyActionsPluginScreenShots extends GhidraScreenShotGenera ProgramManager programManager; DebuggerTraceManagerService traceManager; - DebuggerModelService modelService; + DebuggerTargetService targetService; DebuggerStaticMappingServicePlugin mappingService; DebuggerListingPlugin listingPlugin; DebuggerListingProvider listingProvider; DebuggerCopyActionsPlugin copyPlugin; - TestDebuggerModelBuilder mb; ToyDBTraceBuilder tb; @Before public void setUpMine() throws Throwable { programManager = addPlugin(tool, ProgramManagerPlugin.class); traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class); - modelService = addPlugin(tool, DebuggerModelServicePlugin.class); + targetService = addPlugin(tool, DebuggerTargetServicePlugin.class); mappingService = addPlugin(tool, DebuggerStaticMappingServicePlugin.class); listingPlugin = addPlugin(tool, DebuggerListingPlugin.class); copyPlugin = addPlugin(tool, DebuggerCopyActionsPlugin.class); listingProvider = waitForComponentProvider(DebuggerListingProvider.class); - mb = new TestDebuggerModelBuilder(); - mb.createTestModel(); - mb.createTestProcessesAndThreads(); - TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, - new TestDebuggerTargetTraceMapper(mb.testProcess1), ActionSource.AUTOMATIC); - tb = new ToyDBTraceBuilder(recorder.getTrace()); + tb = new ToyDBTraceBuilder("echo", ProgramBuilder._TOY64_BE); + targetService.publishTarget(new MockTarget(tb.trace)); } @After @@ -90,23 +84,25 @@ public class DebuggerCopyActionsPluginScreenShots extends GhidraScreenShotGenera public void testCaptureDebuggerCopyIntoProgramDialog() throws Throwable { long snap; try (Transaction tx = tb.startTransaction()) { + tb.trace.getObjectManager().createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA); + snap = tb.trace.getTimeManager().createSnapshot("First").getKey(); DBTraceMemoryManager mem = tb.trace.getMemoryManager(); - mem.createRegion(".text", snap, tb.range(0x55550000, 0x5555ffff), + mem.createRegion("Memory[.text]", snap, tb.range(0x55550000, 0x5555ffff), Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE)); - mem.createRegion(".data", snap, tb.range(0x55560000, 0x5556ffff), + mem.createRegion("Memory[.data]", snap, tb.range(0x55560000, 0x5556ffff), Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.WRITE)); - mem.createRegion("[stack]", snap, tb.range(0x00100000, 0x001fffff), + mem.createRegion("Memory[stack]", snap, tb.range(0x00100000, 0x001fffff), Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.WRITE)); DBTraceModuleManager mods = tb.trace.getModuleManager(); - TraceModule modEcho = mods.addLoadedModule("Modules[/bin/echo]", "/bin/echo", tb.range(0x55550000, 0x5556ffff), snap); modEcho.addSection("Modules[/bin/echo].Sections[.text]", ".text", tb.range(0x55550000, 0x5555ffff)); modEcho.addSection("Modules[/bin/echo].Sections[.data]", ".data", tb.range(0x55560000, 0x5556ffff)); + } program = createDefaultProgram("echo", "Toy:BE:64:default", this); @@ -122,7 +118,8 @@ public class DebuggerCopyActionsPluginScreenShots extends GhidraScreenShotGenera } DomainFolder root = tool.getProject().getProjectData().getRootFolder(); - root.createFile(tb.trace.getName(), tb.trace, TaskMonitor.DUMMY); + DomainFolder traces = root.createFolder("New Traces"); + traces.createFile(tb.trace.getName(), tb.trace, TaskMonitor.DUMMY); root.createFile(program.getName(), program, TaskMonitor.DUMMY); try (Transaction tx = tb.startTransaction()) { @@ -136,6 +133,7 @@ public class DebuggerCopyActionsPluginScreenShots extends GhidraScreenShotGenera traceManager.openTrace(tb.trace); traceManager.activateTrace(tb.trace); + waitForTasks(); programManager.openProgram(program); diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/diff/DebuggerTraceViewDiffPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/diff/DebuggerTraceViewDiffPluginScreenShots.java index 24b66904bf..7c82c632f2 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/diff/DebuggerTraceViewDiffPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/diff/DebuggerTraceViewDiffPluginScreenShots.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.debug.gui.diff; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -29,6 +29,7 @@ import ghidra.app.plugin.core.debug.gui.time.DebuggerTimeSelectionDialog; import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; import ghidra.app.services.DebuggerTraceManagerService; import ghidra.async.AsyncTestUtils; +import ghidra.framework.model.DomainFolder; import ghidra.test.ToyProgramBuilder; import ghidra.trace.database.ToyDBTraceBuilder; import ghidra.trace.database.memory.DBTraceMemoryManager; @@ -37,6 +38,7 @@ import ghidra.trace.model.memory.TraceMemoryFlag; import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.time.schedule.TraceSchedule; import ghidra.util.Swing; +import ghidra.util.task.TaskMonitor; import help.screenshot.GhidraScreenShotGenerator; public class DebuggerTraceViewDiffPluginScreenShots extends GhidraScreenShotGenerator @@ -92,13 +94,16 @@ public class DebuggerTraceViewDiffPluginScreenShots extends GhidraScreenShotGene mm.putBytes(snap2, tb.addr(0x00600000), buf); } + DomainFolder root = tool.getProject().getProjectData().getRootFolder(); + root.createFile("tictactoe", tb.trace, TaskMonitor.DUMMY); + traceManager.openTrace(tb.trace); traceManager.activateTrace(tb.trace); traceManager.activateSnap(snap1); waitForSwing(); waitOn(diffPlugin.startComparison(TraceSchedule.snap(snap2))); - assertTrue(diffPlugin.gotoNextDiff()); + assertTrue(runSwing(() -> diffPlugin.gotoNextDiff())); captureIsolatedProvider(DebuggerListingProvider.class, 900, 600); } diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingPluginScreenShots.java index 841be8a71c..1617348166 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingPluginScreenShots.java @@ -25,6 +25,7 @@ import ghidra.app.plugin.assembler.Assemblers; import ghidra.app.plugin.core.debug.gui.action.DebuggerGoToDialog; import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; import ghidra.app.services.DebuggerTraceManagerService; +import ghidra.framework.model.DomainFolder; import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.symbol.SourceType; import ghidra.test.ToyProgramBuilder; @@ -34,6 +35,7 @@ import ghidra.trace.model.memory.TraceMemoryFlag; import ghidra.trace.model.memory.TraceMemorySpace; import ghidra.trace.model.symbol.*; import ghidra.trace.model.thread.TraceThread; +import ghidra.util.task.TaskMonitor; import help.screenshot.GhidraScreenShotGenerator; public class DebuggerListingPluginScreenShots extends GhidraScreenShotGenerator { @@ -115,6 +117,9 @@ public class DebuggerListingPluginScreenShots extends GhidraScreenShotGenerator childLabel.getAddress().getOffsetAsBigInteger())); } + DomainFolder root = tool.getProject().getProjectData().getRootFolder(); + root.createFile("echo", tb.trace, TaskMonitor.DUMMY); + traceManager.openTrace(tb.trace); traceManager.activateTrace(tb.trace); diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPluginScreenShots.java index c3e919a59b..3b0ea37a70 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPluginScreenShots.java @@ -24,6 +24,9 @@ import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerService import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin; import ghidra.app.services.DebuggerTraceManagerService; import ghidra.app.services.ProgramManager; +import ghidra.dbg.target.schema.SchemaContext; +import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName; +import ghidra.dbg.target.schema.XmlSchemaContext; import ghidra.framework.model.DomainFolder; import ghidra.program.database.ProgramBuilder; import ghidra.program.model.address.Address; @@ -74,21 +77,23 @@ public class DebuggerRegionsPluginScreenShots extends GhidraScreenShotGenerator } private void populateTrace() throws Exception { + SchemaContext ctx = XmlSchemaContext.deserialize(DebuggerRegionsProviderTest.CTX_XML); try (Transaction tx = tb.startTransaction()) { + tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session"))); long snap = tb.trace.getTimeManager().createSnapshot("First").getKey(); DBTraceMemoryManager mm = tb.trace.getMemoryManager(); - mm.addRegion("/bin/bash (400000:40ffff)", Lifespan.nowOn(snap), + mm.addRegion("Memory[/bin/bash (400000:40ffff)]", Lifespan.nowOn(snap), tb.range(0x00400000, 0x0040ffff), Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE)); - mm.addRegion("/bin/bash (600000:60ffff)", Lifespan.nowOn(snap), + mm.addRegion("Memory[/bin/bash (600000:60ffff)]", Lifespan.nowOn(snap), tb.range(0x00600000, 0x0060ffff), Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.WRITE)); - mm.addRegion("/lib/libc (7fac0000:7facffff)", Lifespan.nowOn(snap), + mm.addRegion("Memory[/lib/libc (7fac0000:7facffff)]", Lifespan.nowOn(snap), tb.range(0x7fac0000, 0x7facffff), Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE)); - mm.addRegion("/lib/libc (7fcc0000:7fccffff)", Lifespan.nowOn(snap), + mm.addRegion("Memory[/lib/libc (7fcc0000:7fccffff)]", Lifespan.nowOn(snap), tb.range(0x7fcc0000, 0x7fccffff), Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.WRITE)); } @@ -146,10 +151,12 @@ public class DebuggerRegionsPluginScreenShots extends GhidraScreenShotGenerator @Test public void testCaptureDebuggerRegionMapProposalDialog() throws Throwable { populateTraceAndPrograms(); + waitForTasks(); - regionsProvider - .setSelectedRegions(Set.copyOf(tb.trace.getMemoryManager().getAllRegions())); - performAction(regionsProvider.actionMapRegions, false); + runSwing(() -> regionsProvider + .setSelectedRegions(Set.copyOf(tb.trace.getMemoryManager().getAllRegions()))); + + performAction(regionsProvider.actionMapRegions, regionsProvider, false); captureDialog(DebuggerRegionMapProposalDialog.class); } diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelPluginScreenShots.java new file mode 100644 index 0000000000..cc2895f014 --- /dev/null +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelPluginScreenShots.java @@ -0,0 +1,209 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.debug.gui.model; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.jdom.JDOMException; +import org.junit.Test; + +import db.Transaction; +import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest; +import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow; +import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; +import ghidra.dbg.target.TargetEventScope; +import ghidra.dbg.target.schema.SchemaContext; +import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName; +import ghidra.dbg.target.schema.XmlSchemaContext; +import ghidra.program.database.ProgramBuilder; +import ghidra.trace.database.ToyDBTraceBuilder; +import ghidra.trace.database.target.DBTraceObjectManager; +import ghidra.trace.database.target.DBTraceObjectValue; +import ghidra.trace.model.Lifespan; +import ghidra.trace.model.target.TraceObject; +import ghidra.trace.model.target.TraceObject.ConflictResolution; +import help.screenshot.GhidraScreenShotGenerator; + +public class DebuggerModelPluginScreenShots extends GhidraScreenShotGenerator { + public static final String CTX_XML = """ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """; + public static final SchemaContext CTX; + + static { + try { + CTX = XmlSchemaContext.deserialize(CTX_XML); + } + catch (JDOMException e) { + throw new AssertionError(e); + } + } + + private DebuggerTraceManagerServicePlugin traceManager; + private DebuggerModelPlugin modelPlugin; + + record ObjHelp(TraceObject obj, Lifespan span, ConflictResolution resolution) + implements AutoCloseable { + @Override + public void close() { + } + + void value(String key, Object value) { + obj.setValue(span, key, value); + } + + ObjHelp child(String key) { + TraceObject child = + obj.getTrace().getObjectManager().createObject(obj.getCanonicalPath().extend(key)); + child.insert(span, resolution); + return new ObjHelp(child, span, resolution); + } + } + + @Test + public void testCaptureDebuggerModelPlugin() throws Throwable { + traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class); + modelPlugin = addPlugin(tool, DebuggerModelPlugin.class); + + DebuggerModelProvider provider = waitForComponentProvider(DebuggerModelProvider.class); + + var l = new Object() { + TraceObject thread; + TraceObject stack; + TraceObject frame; + TraceObject regs; + }; + try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("bash", ProgramBuilder._TOY64_BE); + Transaction tx = tb.startTransaction();) { + DBTraceObjectManager om = tb.trace.getObjectManager(); + + DBTraceObjectValue rootVal = + om.createRootObject(CTX.getSchema(new SchemaName("Session"))); + + try (ObjHelp root = + new ObjHelp(rootVal.getChild(), Lifespan.nowOn(0), ConflictResolution.DENY)) { + root.child("Available"); + try (ObjHelp processes = root.child("Processes")) { + try (ObjHelp proc = processes.child("[0]")) { + try (ObjHelp threads = proc.child("Threads")) { + try (ObjHelp thread = threads.child("[0]")) { + l.thread = thread.obj; + try (ObjHelp stack = thread.child("Stack")) { + l.stack = stack.obj; + try (ObjHelp frame = stack.child("[0]")) { + l.frame = frame.obj; + frame.value("PC", tb.addr(0x00401234)); + l.regs = frame.child("Registers").obj; + } + try (ObjHelp frame = stack.child("[1]")) { + frame.value("PC", tb.addr(0x00404321)); + } + } + } + } + proc.child("Breakpoints"); + proc.child("Memory"); + proc.child("Modules"); + } + } + root.value(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, l.thread); + } + + traceManager.openTrace(tb.trace); + traceManager.activateObject(l.frame); + waitForTasks(); + + provider.setTreeSelection(l.regs.getCanonicalPath()); + waitForTasks(); + provider.setTreeSelection(l.stack.getCanonicalPath()); + waitForTasks(); + + List frameRows = AbstractGhidraHeadedDebuggerTest.waitForPass(() -> { + assertEquals(2, provider.elementsTablePanel.getAllItems().size()); + return provider.elementsTablePanel.getAllItems(); + }); + + ValueRow frame0Row = frameRows.stream() + .filter(r -> r.getValue().getValue() == l.frame) + .findAny() + .orElseThrow(); + provider.elementsTablePanel.setSelectedItem(frame0Row); + waitForTasks(); + } + + captureIsolatedProvider(DebuggerModelProvider.class, 900, 900); + } +} diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java index da6993b934..ee11ce117e 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java @@ -20,6 +20,7 @@ import java.util.Set; import org.junit.*; import db.Transaction; +import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils; import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin; import ghidra.app.services.DebuggerTraceManagerService; @@ -70,18 +71,25 @@ public class DebuggerModulesPluginScreenShots extends GhidraScreenShotGenerator @Test public void testCaptureDebuggerModulesPlugin() throws Throwable { try (Transaction tx = tb.startTransaction()) { + tb.trace.getObjectManager().createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA); + long snap = tb.trace.getTimeManager().createSnapshot("First").getKey(); TraceModule bin = tb.trace.getModuleManager() - .addLoadedModule("/bin/bash", "/bin/bash", + .addLoadedModule("Modules[/bin/bash]", "/bin/bash", tb.range(0x00400000, 0x0060ffff), snap); - bin.addSection("bash[.text]", ".text", tb.range(0x00400000, 0x0040ffff)); - bin.addSection("bash[.data]", ".data", tb.range(0x00600000, 0x0060ffff)); + bin.addSection("Modules[/bin/bash].Sections[.text]", ".text", + tb.range(0x00400000, 0x0040ffff)); + bin.addSection("Modules[/bin/bash].Sections[.data]", ".data", + tb.range(0x00600000, 0x0060ffff)); + TraceModule lib = tb.trace.getModuleManager() - .addLoadedModule("/lib/libc.so.6", "/lib/libc.so.6", + .addLoadedModule("Modules[/lib/libc.so.6]", "/lib/libc.so.6", tb.range(0x7fac0000, 0x7faeffff), snap); - lib.addSection("libc[.text]", ".text", tb.range(0x7fac0000, 0x7facffff)); - lib.addSection("libc[.data]", ".data", tb.range(0x7fae0000, 0x7faeffff)); + lib.addSection("Modules[/lib/libc.so.6].Sections[.text]", ".text", + tb.range(0x7fac0000, 0x7facffff)); + lib.addSection("Modules[/lib/libc.so.6].Sections[.data]", ".data", + tb.range(0x7fae0000, 0x7faeffff)); traceManager.openTrace(tb.trace); traceManager.activateTrace(tb.trace); @@ -97,18 +105,25 @@ public class DebuggerModulesPluginScreenShots extends GhidraScreenShotGenerator private void populateTraceAndPrograms() throws Exception { DomainFolder root = tool.getProject().getProjectData().getRootFolder(); try (Transaction tx = tb.startTransaction()) { + tb.trace.getObjectManager().createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA); long snap = tb.trace.getTimeManager().createSnapshot("First").getKey(); TraceModule bin = tb.trace.getModuleManager() - .addLoadedModule("/bin/bash", "/bin/bash", + .addLoadedModule("Modules[/bin/bash]", "/bin/bash", tb.range(0x00400000, 0x0060ffff), snap); - bin.addSection("bash[.text]", ".text", tb.range(0x00400000, 0x0040ffff)); - bin.addSection("bash[.data]", ".data", tb.range(0x00600000, 0x0060ffff)); + bin.addSection("Modules[/bin/bash].Sections[.text]", ".text", + tb.range(0x00400000, 0x0040ffff)); + bin.addSection("Modules[/bin/bash].Sections[.data]", ".data", + tb.range(0x00600000, 0x0060ffff)); + TraceModule lib = tb.trace.getModuleManager() - .addLoadedModule("/lib/libc.so.6", "/lib/libc.so.6", + .addLoadedModule("Modules[/lib/libc.so.6]", "/lib/libc.so.6", tb.range(0x7fac0000, 0x7faeffff), snap); - lib.addSection("libc[.text]", ".text", tb.range(0x7fac0000, 0x7facffff)); - lib.addSection("libc[.data]", ".data", tb.range(0x7fae0000, 0x7faeffff)); + lib.addSection("Modules[/lib/libc.so.6].Sections[.text]", ".text", + tb.range(0x7fac0000, 0x7facffff)); + lib.addSection("Modules[/lib/libc.so.6].Sections[.data]", ".data", + tb.range(0x7fae0000, 0x7faeffff)); + } progBash = createDefaultProgram("bash", ProgramBuilder._X64, this); @@ -148,6 +163,7 @@ public class DebuggerModulesPluginScreenShots extends GhidraScreenShotGenerator @Test public void testCaptureDebuggerModuleMapProposalDialog() throws Throwable { populateTraceAndPrograms(); + waitForTasks(); modulesProvider.setSelectedModules(Set.copyOf(tb.trace.getModuleManager().getAllModules())); performAction(modulesProvider.actionMapModules, false); @@ -158,6 +174,7 @@ public class DebuggerModulesPluginScreenShots extends GhidraScreenShotGenerator @Test public void testCaptureDebuggerSectionMapProposalDialog() throws Throwable { populateTraceAndPrograms(); + waitForTasks(); modulesProvider .setSelectedSections(Set.copyOf(tb.trace.getModuleManager().getAllSections())); diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java index 5a26f90a69..169be425b5 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java @@ -16,10 +16,12 @@ package ghidra.app.plugin.core.debug.gui.modules; import java.util.*; +import java.util.concurrent.TimeUnit; import org.junit.*; import db.Transaction; +import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin; @@ -79,21 +81,27 @@ public class DebuggerStaticMappingPluginScreenShots extends GhidraScreenShotGene public void testCaptureDebuggerStaticMappingPlugin() throws Throwable { DomainFolder root = tool.getProject().getProjectData().getRootFolder(); try (Transaction tx = tb.startTransaction()) { + tb.trace.getObjectManager().createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA); long snap = tb.trace.getTimeManager().createSnapshot("First").getKey(); TraceModule bin = tb.trace.getModuleManager() - .addLoadedModule("/bin/bash", "/bin/bash", + .addLoadedModule("Modules[/bin/echo]", "/bin/echo", tb.range(0x00400000, 0x0060ffff), snap); - bin.addSection("bash[.text]", ".text", tb.range(0x00400000, 0x0040ffff)); - bin.addSection("bash[.data]", ".data", tb.range(0x00600000, 0x0060ffff)); + bin.addSection("Modules[/bin/echo].Sections[.text]", ".text", + tb.range(0x00400000, 0x0040ffff)); + bin.addSection("Modules[/bin/echo].Sections[.data]", ".data", + tb.range(0x00600000, 0x0060ffff)); + TraceModule lib = tb.trace.getModuleManager() - .addLoadedModule("/lib/libc.so.6", "/lib/libc.so.6", + .addLoadedModule("Modules[/lib/libc.so.6]", "/lib/libc.so.6", tb.range(0x7fac0000, 0x7faeffff), snap); - lib.addSection("libc[.text]", ".text", tb.range(0x7fac0000, 0x7facffff)); - lib.addSection("libc[.data]", ".data", tb.range(0x7fae0000, 0x7faeffff)); + lib.addSection("Modules[/lib/libc.so.6].Sections[.text]", ".text", + tb.range(0x7fac0000, 0x7facffff)); + lib.addSection("Modules[/lib/libc.so.6].Sections[.data]", ".data", + tb.range(0x7fae0000, 0x7faeffff)); } - progEcho = createDefaultProgram("bash", ProgramBuilder._X64, this); + progEcho = createDefaultProgram("echo", ProgramBuilder._X64, this); progLibC = createDefaultProgram("libc.so.6", ProgramBuilder._X64, this); try (Transaction tx = progEcho.openTransaction("Add memory")) { @@ -133,6 +141,8 @@ public class DebuggerStaticMappingPluginScreenShots extends GhidraScreenShotGene Collection entries = MapProposal.flatten(proposal.values()); mappingService.addModuleMappings(entries, TaskMonitor.DUMMY, false); } + mappingService.changesSettled().get(1, TimeUnit.SECONDS); + waitForTasks(); captureIsolatedProvider(DebuggerStaticMappingProvider.class, 700, 400); } diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/pcode/DebuggerPcodeStepperPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/pcode/DebuggerPcodeStepperPluginScreenShots.java index 90cabff25d..f732fa1dc2 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/pcode/DebuggerPcodeStepperPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/pcode/DebuggerPcodeStepperPluginScreenShots.java @@ -20,6 +20,7 @@ import org.junit.*; import db.Transaction; import ghidra.app.plugin.assembler.Assembler; import ghidra.app.plugin.assembler.Assemblers; +import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils; import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; import ghidra.app.services.DebuggerTraceManagerService; import ghidra.pcode.exec.PcodeExecutor; @@ -28,7 +29,7 @@ import ghidra.test.ToyProgramBuilder; import ghidra.trace.database.ToyDBTraceBuilder; import ghidra.trace.model.Lifespan; import ghidra.trace.model.memory.TraceMemoryFlag; -import ghidra.trace.model.thread.TraceThread; +import ghidra.trace.model.thread.TraceObjectThread; import ghidra.trace.model.time.schedule.TraceSchedule; import help.screenshot.GhidraScreenShotGenerator; @@ -57,14 +58,17 @@ public class DebuggerPcodeStepperPluginScreenShots extends GhidraScreenShotGener @Test public void testCaptureDebuggerPcodeStepperPlugin() throws Throwable { try (Transaction tx = tb.startTransaction()) { + tb.trace.getObjectManager().createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA); long snap0 = tb.trace.getTimeManager().createSnapshot("First").getKey(); tb.trace.getMemoryManager() - .addRegion("[echo:.text]", Lifespan.nowOn(snap0), + .addRegion("Memory[echo:.text]", Lifespan.nowOn(snap0), tb.range(0x00400000, 0x0040ffff), TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE); - TraceThread thread = tb.getOrAddThread("[1]", snap0); + TraceObjectThread thread = (TraceObjectThread) tb.getOrAddThread("Threads[1]", snap0); + tb.trace.getObjectManager() + .createObject(thread.getObject().getCanonicalPath().key("Registers")); PcodeExecutor exe = TraceSleighUtils.buildByteExecutor(tb.trace, snap0, thread, 0); @@ -78,7 +82,7 @@ public class DebuggerPcodeStepperPluginScreenShots extends GhidraScreenShotGener traceManager.openTrace(tb.trace); traceManager.activateThread(thread); - traceManager.activateTime(TraceSchedule.parse("0:.t0-7")); + traceManager.activateTime(TraceSchedule.snap(0).steppedPcodeForward(thread, 7)); waitForSwing(); runSwing(() -> pcodeProvider.mainPanel.setDividerLocation(360)); diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java index 8c5e7ee812..9b23e4370e 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java @@ -40,6 +40,9 @@ import ghidra.app.services.*; import ghidra.app.services.DebuggerControlService.StateEditor; import ghidra.app.services.DebuggerEmulationService.EmulationResult; import ghidra.async.AsyncTestUtils; +import ghidra.dbg.target.schema.SchemaContext; +import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName; +import ghidra.dbg.target.schema.XmlSchemaContext; import ghidra.debug.api.control.ControlMode; import ghidra.debug.api.tracemgr.DebuggerCoordinates; import ghidra.framework.model.DomainFolder; @@ -53,9 +56,11 @@ import ghidra.program.model.lang.*; import ghidra.program.model.listing.*; import ghidra.program.model.listing.Function.FunctionUpdateType; import ghidra.program.model.symbol.SourceType; +import ghidra.program.util.GhidraProgramUtilities; import ghidra.program.util.ProgramLocation; import ghidra.test.ToyProgramBuilder; import ghidra.trace.database.ToyDBTraceBuilder; +import ghidra.trace.database.target.DBTraceObjectManager; import ghidra.trace.model.DefaultTraceLocation; import ghidra.trace.model.Lifespan; import ghidra.trace.model.breakpoint.TraceBreakpointKind; @@ -127,11 +132,17 @@ public class DebuggerStackPluginScreenShots extends GhidraScreenShotGenerator fMan.createFunction("FUN_00404300", addr(0x00404300), set(program, 0x00404300, 0x00404400), SourceType.USER_DEFINED); } + + SchemaContext ctx = XmlSchemaContext.deserialize(DebuggerStackProviderTest.CTX_XML); + long snap; TraceThread thread; try (Transaction tx = tb.startTransaction()) { + DBTraceObjectManager om = tb.trace.getObjectManager(); + om.createRootObject(ctx.getSchema(new SchemaName("Session"))); snap = tb.trace.getTimeManager().createSnapshot("First").getKey(); - thread = tb.getOrAddThread("[1]", snap); + + thread = tb.getOrAddThread("Processes[1].Threads[1]", snap); TraceStack stack = tb.trace.getStackManager().getStack(thread, snap, true); stack.setDepth(3, true); @@ -154,6 +165,8 @@ public class DebuggerStackPluginScreenShots extends GhidraScreenShotGenerator programManager.openProgram(program); traceManager.openTrace(tb.trace); traceManager.activateThread(thread); + traceManager.activateFrame(0); + waitForTasks(); captureIsolatedProvider(DebuggerStackProvider.class, 600, 300); } @@ -285,12 +298,16 @@ public class DebuggerStackPluginScreenShots extends GhidraScreenShotGenerator Function function = createFibonacciProgramX86_32(); Address entry = function.getEntryPoint(); + GhidraProgramUtilities.markProgramNotToAskToAnalyze(program); programManager.openProgram(program); tb.close(); tb = new ToyDBTraceBuilder( ProgramEmulationUtils.launchEmulationTrace(program, entry, this)); tb.trace.release(this); + DomainFolder root = tool.getProject().getProjectData().getRootFolder(); + root.createFile("Emulate fibonacci", tb.trace, TaskMonitor.DUMMY); + TraceThread thread = Unique.assertOne(tb.trace.getThreadManager().getAllThreads()); traceManager.openTrace(tb.trace); traceManager.activateThread(thread); diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/vars/VariableValueHoverPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/vars/VariableValueHoverPluginScreenShots.java index 7abeb3a9d5..0db2ced92a 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/vars/VariableValueHoverPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/vars/VariableValueHoverPluginScreenShots.java @@ -74,6 +74,7 @@ import ghidra.util.InvalidNameException; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.task.ConsoleTaskMonitor; +import ghidra.util.task.TaskMonitor; import help.screenshot.GhidraScreenShotGenerator; public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerator @@ -96,8 +97,8 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat protected void intoProject(DomainObject obj) { waitForDomainObject(obj); DomainFolder rootFolder = tool.getProject() - .getProjectData() - .getRootFolder(); + .getProjectData() + .getRootFolder(); waitForCondition(() -> { try { rootFolder.createFile(obj.getName(), obj, monitor); @@ -142,7 +143,7 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat try (Transaction tx = program.openTransaction("Assemble")) { Address entry = addr(program, 0x00400000); program.getMemory() - .createInitializedBlock(".text", entry, 0x1000, (byte) 0, monitor, false); + .createInitializedBlock(".text", entry, 0x1000, (byte) 0, monitor, false); Assembler asm = Assemblers.getAssembler(program.getLanguage(), StackUnwinderTest.NO_16BIT_CALLS); AssemblyBuffer buf = new AssemblyBuffer(asm, entry); @@ -194,9 +195,9 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat dis.disassemble(entry, null); Function function = program.getFunctionManager() - .createFunction("fib", entry, - new AddressSet(entry, entry.add(bytes.length - 1)), - SourceType.USER_DEFINED); + .createFunction("fib", entry, + new AddressSet(entry, entry.add(bytes.length - 1)), + SourceType.USER_DEFINED); function.updateFunction("__cdecl", new ReturnParameterImpl(UnsignedIntegerDataType.dataType, program), @@ -240,6 +241,8 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat tb = new ToyDBTraceBuilder( ProgramEmulationUtils.launchEmulationTrace(program, entry, this)); tb.trace.release(this); + DomainFolder root = tool.getProject().getProjectData().getRootFolder(); + root.createFile("Emulate fibonacci", tb.trace, TaskMonitor.DUMMY); TraceThread thread = Unique.assertOne(tb.trace.getThreadManager().getAllThreads()); traceManager.openTrace(tb.trace); traceManager.activateThread(thread); @@ -272,9 +275,9 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat try (Transaction tx = tb.startTransaction()) { tb.trace.getBreakpointManager() - .addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr, - Set.of(), - Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack"); + .addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr, + Set.of(), + Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack"); } EmulationResult result = emuService.run(atSetup.getPlatform(), atSetup.getTime(), monitor, diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java index e725338c8e..5140c883a4 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java @@ -15,98 +15,195 @@ */ package ghidra.app.plugin.core.debug.gui.thread; -import org.junit.Before; -import org.junit.Test; +import java.math.BigInteger; +import java.util.concurrent.TimeUnit; + +import org.junit.*; import db.Transaction; -import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest; -import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest.TestDebuggerTargetTraceMapper; -import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceProxyPlugin; +import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils; +import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; -import ghidra.app.services.*; -import ghidra.dbg.model.*; -import ghidra.debug.api.action.ActionSource; -import ghidra.debug.api.model.TraceRecorder; -import ghidra.trace.model.Trace; +import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin; +import ghidra.app.services.DebuggerTraceManagerService; +import ghidra.app.services.ProgramManager; +import ghidra.framework.model.DomainFolder; +import ghidra.program.database.ProgramBuilder; +import ghidra.program.model.address.*; +import ghidra.program.model.lang.Register; +import ghidra.program.model.lang.RegisterValue; +import ghidra.program.model.listing.Program; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.util.ProgramLocation; +import ghidra.test.ToyProgramBuilder; +import ghidra.trace.database.ToyDBTraceBuilder; +import ghidra.trace.database.memory.DBTraceMemorySpace; +import ghidra.trace.database.target.DBTraceObjectManager; +import ghidra.trace.database.thread.DBTraceThreadManager; +import ghidra.trace.database.time.DBTraceTimeManager; +import ghidra.trace.model.DefaultTraceLocation; +import ghidra.trace.model.Lifespan; +import ghidra.trace.model.target.TraceObject.ConflictResolution; +import ghidra.trace.model.target.TraceObjectKeyPath; +import ghidra.trace.model.thread.TraceObjectThread; import ghidra.trace.model.thread.TraceThread; +import ghidra.util.task.TaskMonitor; import help.screenshot.GhidraScreenShotGenerator; public class DebuggerThreadsPluginScreenShots extends GhidraScreenShotGenerator { - // NOTE: Using model builder to capture "recording" icon in tabs - TestDebuggerModelBuilder mb = new TestDebuggerModelBuilder(); - DebuggerModelServiceProxyPlugin modelService; + ProgramManager programManager; + DebuggerStaticMappingServicePlugin mappingService; DebuggerTraceManagerService traceManager; DebuggerThreadsPlugin threadsPlugin; + ToyDBTraceBuilder tb; + Program progBash; @Before public void setUpMine() throws Throwable { - modelService = addPlugin(tool, DebuggerModelServiceProxyPlugin.class); + programManager = addPlugin(tool, ProgramManagerPlugin.class); + mappingService = addPlugin(tool, DebuggerStaticMappingServicePlugin.class); traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class); threadsPlugin = addPlugin(tool, DebuggerThreadsPlugin.class); + + tb = new ToyDBTraceBuilder("echo", ToyProgramBuilder._X64); + } + + @After + public void tearDownMine() { + tb.close(); + + if (progBash != null) { + progBash.release(this); + } + } + + private static Address addr(Program program, long offset) { + return program.getAddressFactory().getDefaultAddressSpace().getAddress(offset); + } + + private static AddressRange rng(Program program, long min, long max) { + return new AddressRangeImpl(addr(program, min), addr(program, max)); + } + + private static AddressSetView set(AddressRange... ranges) { + AddressSet set = new AddressSet(); + for (AddressRange r : ranges) { + set.add(r); + } + return set; } protected boolean nullOrDead(TraceThread thread) { return thread == null || !thread.isAlive(); } - @Test - public void testCaptureDebuggerThreadsPlugin() throws Throwable { - mb.createTestModel(); - TestTargetProcess process = mb.testModel.addProcess(1234); + private void populateTrace() throws Exception { + try (Transaction tx = tb.startTransaction()) { + DBTraceObjectManager om = tb.trace.getObjectManager(); + om.createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA); - TraceRecorder recorder = modelService.recordTarget(process, - new TestDebuggerTargetTraceMapper(process), ActionSource.AUTOMATIC); - Trace trace = recorder.getTrace(); + DBTraceTimeManager sm = tb.trace.getTimeManager(); + sm.createSnapshot("First").getKey(); + sm.getSnapshot(13, true); - TestTargetThread mainThread = process.addThread(1); - waitForValue(() -> recorder.getTraceThread(mainThread)); - recorder.forceSnapshot(); - TestTargetThread serverThread = process.addThread(2); - waitForValue(() -> recorder.getTraceThread(serverThread)); - recorder.forceSnapshot(); - recorder.forceSnapshot(); - TestTargetThread handler1Thread = process.addThread(3); - waitForValue(() -> recorder.getTraceThread(handler1Thread)); - recorder.forceSnapshot(); - recorder.forceSnapshot(); - TestTargetThread handler2Thread = process.addThread(4); - waitForValue(() -> recorder.getTraceThread(handler2Thread)); - AbstractGhidraHeadedDebuggerTest.waitForDomainObject(trace); + DBTraceThreadManager tm = tb.trace.getThreadManager(); + TraceObjectThread t1 = + (TraceObjectThread) tm.addThread("Threads[1]", "main", Lifespan.nowOn(0)); + TraceObjectThread t2 = + (TraceObjectThread) tm.addThread("Threads[2]", "server", Lifespan.nowOn(2)); + TraceObjectThread t3 = + (TraceObjectThread) tm.addThread("Threads[3]", "handler 1", Lifespan.span(5, 10)); + TraceObjectThread t4 = + (TraceObjectThread) tm.addThread("Threads[4]", "handler 2", Lifespan.span(8, 13)); - try (Transaction tx = trace.openTransaction("Comments")) { - recorder.getTraceThread(mainThread).setComment("GUI main loop"); - recorder.getTraceThread(serverThread).setComment("Server"); - recorder.getTraceThread(handler1Thread).setComment("Handler 1"); - recorder.getTraceThread(handler2Thread).setComment("Handler 2"); + t1.getObject().setValue(Lifespan.nowOn(0), "_state", "STOPPED"); + t2.getObject().setValue(Lifespan.nowOn(0), "_state", "STOPPED"); + t3.getObject().setValue(Lifespan.nowOn(0), "_state", "TERMINATED"); + t4.getObject().setValue(Lifespan.nowOn(0), "_state", "TERMINATED"); + + om.createObject(TraceObjectKeyPath.parse("Threads[1].Registers")) + .insert(Lifespan.nowOn(0), ConflictResolution.DENY); + om.createObject(TraceObjectKeyPath.parse("Threads[2].Registers")) + .insert(Lifespan.nowOn(2), ConflictResolution.DENY); + om.createObject(TraceObjectKeyPath.parse("Threads[3].Registers")) + .insert(Lifespan.nowOn(5), ConflictResolution.DENY); + om.createObject(TraceObjectKeyPath.parse("Threads[4].Registers")) + .insert(Lifespan.nowOn(10), ConflictResolution.DENY); + // insert calls will extend thread life :/ + t3.getObject().getCanonicalParent(13).setMaxSnap(10); + t4.getObject().getCanonicalParent(13).setMaxSnap(13); + + Register pc = tb.host.getLanguage().getProgramCounter(); + Register sp = tb.host.getCompilerSpec().getStackPointer(); + + DBTraceMemorySpace r1 = tb.trace.getMemoryManager().getMemoryRegisterSpace(t1, true); + r1.setValue(13, new RegisterValue(pc, BigInteger.valueOf(0x00400123))); + r1.setValue(13, new RegisterValue(sp, BigInteger.valueOf(0x0001ff08))); + + DBTraceMemorySpace r2 = tb.trace.getMemoryManager().getMemoryRegisterSpace(t2, true); + r2.setValue(12, new RegisterValue(pc, BigInteger.valueOf(0x004063d9))); + r2.setValue(12, new RegisterValue(sp, BigInteger.valueOf(0x0002fe68))); + + DBTraceMemorySpace r3 = tb.trace.getMemoryManager().getMemoryRegisterSpace(t3, true); + r3.setValue(12, new RegisterValue(pc, BigInteger.valueOf(0x004066ee))); + r3.setValue(12, new RegisterValue(sp, BigInteger.valueOf(0x0003ff10))); + + DBTraceMemorySpace r4 = tb.trace.getMemoryManager().getMemoryRegisterSpace(t4, true); + r4.setValue(12, new RegisterValue(pc, BigInteger.valueOf(0x004066ee))); + r4.setValue(12, new RegisterValue(sp, BigInteger.valueOf(0x0004ff10))); + } + } + + private void populateTraceAndPrograms() throws Exception { + DomainFolder root = tool.getProject().getProjectData().getRootFolder(); + + populateTrace(); + + progBash = createDefaultProgram("bash", ProgramBuilder._X64, this); + + try (Transaction tx = progBash.openTransaction("Add memory")) { + progBash.setImageBase(addr(progBash, 0x00400000), true); + progBash.getMemory() + .createInitializedBlock(".text", addr(progBash, 0x00400000), 0x10000, (byte) 0, + TaskMonitor.DUMMY, false); + progBash.getMemory() + .createInitializedBlock(".data", addr(progBash, 0x00600000), 0x10000, (byte) 0, + TaskMonitor.DUMMY, false); + + progBash.getFunctionManager() + .createFunction("main", addr(progBash, 0x00400000), + set(rng(progBash, 0x00400000, 0x00400fff)), SourceType.ANALYSIS); + progBash.getFunctionManager() + .createFunction("service_loop", addr(progBash, 0x00406000), + set(rng(progBash, 0x00406000, 0x004063ff)), SourceType.ANALYSIS); + progBash.getFunctionManager() + .createFunction("parse_req", addr(progBash, 0x00406600), + set(rng(progBash, 0x00406600, 0x004066ff)), SourceType.ANALYSIS); } - recorder.forceSnapshot(); - process.removeThreads(handler1Thread); - waitFor(() -> nullOrDead(recorder.getTraceThread(handler1Thread))); - recorder.forceSnapshot(); - recorder.forceSnapshot(); - recorder.forceSnapshot(); - process.removeThreads(handler2Thread); - waitFor(() -> nullOrDead(recorder.getTraceThread(handler2Thread))); - long lastSnap = recorder.forceSnapshot().getKey(); + root.createFile("trace", tb.trace, TaskMonitor.DUMMY); + root.createFile("bash", progBash, TaskMonitor.DUMMY); - traceManager.openTrace(trace); - traceManager.activateThread(recorder.getTraceThread(serverThread)); - traceManager.activateSnap(lastSnap); + traceManager.openTrace(tb.trace); + traceManager.activateTrace(tb.trace); - TestTargetProcess dummy1 = mb.testModel.addProcess(4321); - TestTargetProcess dummy2 = mb.testModel.addProcess(5432); - TraceRecorder recDummy1 = modelService.recordTarget(dummy1, - new TestDebuggerTargetTraceMapper(dummy1), ActionSource.AUTOMATIC); - TraceRecorder recDummy2 = modelService.recordTarget(dummy2, - new TestDebuggerTargetTraceMapper(dummy2), ActionSource.AUTOMATIC); + programManager.openProgram(progBash); + waitForTasks(); - traceManager.setAutoCloseOnTerminate(false); + mappingService.addMapping( + new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0), tb.addr(0x00400000)), + new ProgramLocation(progBash, addr(progBash, 0x00400000)), 0x10000, true); + mappingService.changesSettled().get(1, TimeUnit.SECONDS); + } - traceManager.openTrace(recDummy1.getTrace()); - traceManager.openTrace(recDummy2.getTrace()); - recDummy1.stopRecording(); + @Test + public void testCaptureDebuggerThreadsPlugin() throws Throwable { + populateTraceAndPrograms(); + traceManager.activateSnap(12); + waitForTasks(); + traceManager.activateSnap(13); + waitForTasks(); captureIsolatedProvider(DebuggerThreadsProvider.class, 900, 300); } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java index 1733745649..62e175dca0 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java @@ -57,6 +57,25 @@ import ghidra.util.table.GhidraTable; @Category(NightlyCategory.class) public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerTest { + public static final String CTX_XML = """ + + + + + + + + + + + + """; DebuggerRegionsProvider provider; @@ -82,25 +101,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerTes } public void activateObjectsMode() throws Exception { - ctx = XmlSchemaContext.deserialize(""" - - - - - - - - - - - - """); + ctx = XmlSchemaContext.deserialize(CTX_XML); try (Transaction tx = tb.startTransaction()) { tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session"))); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProviderTest.java index 800fed28a8..5aa4cbb81b 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProviderTest.java @@ -61,6 +61,56 @@ import ghidra.util.task.TaskMonitor; * don't know if it's really valuable. In fact, in might obscure the fact that the stack is absent. */ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerTest { + public static final String CTX_XML = """ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """; + protected DebuggerStackPlugin stackPlugin; protected DebuggerStackProvider stackProvider; protected DebuggerStaticMappingService mappingService; @@ -111,54 +161,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerTest public void activateObjectsMode() throws Exception { // NOTE the use of index='1' allowing object-based managers to ID unique path - ctx = XmlSchemaContext.deserialize(""" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - """); + ctx = XmlSchemaContext.deserialize(CTX_XML); try (Transaction tx = tb.startTransaction()) { tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session"))); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsProviderTest.java index 5b4651a083..9cc9120ae0 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsProviderTest.java @@ -49,6 +49,28 @@ import ghidra.util.table.GhidraTable; @Category(NightlyCategory.class) public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerTest { + // NOTE the use of index='1' allowing object-based managers to ID unique path + public static final String CTX_XML = """ + + + + + + + + + + + + + + + + + + """; DebuggerThreadsProvider provider; @@ -69,28 +91,7 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerTes } public void activateObjectsMode() throws Exception { - // NOTE the use of index='1' allowing object-based managers to ID unique path - ctx = XmlSchemaContext.deserialize(""" - - - - - - - - - - - - - - - - - - """); + ctx = XmlSchemaContext.deserialize(CTX_XML); try (Transaction tx = tb.startTransaction()) { tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session"))); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/control/MockTarget.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/control/MockTarget.java index 40fe1bcdf7..b86ea8390c 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/control/MockTarget.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/control/MockTarget.java @@ -38,7 +38,7 @@ import ghidra.trace.model.thread.TraceThread; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -class MockTarget implements Target { +public class MockTarget implements Target { private final Trace trace; private long snap = 0; @@ -226,7 +226,7 @@ class MockTarget implements Target { @Override public boolean isBreakpointValid(TraceBreakpoint breakpoint) { - return false; + return true; } @Override diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/XmlSchemaContext.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/XmlSchemaContext.java index c0d4f0109a..c7484bdba7 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/XmlSchemaContext.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/XmlSchemaContext.java @@ -212,10 +212,10 @@ public class XmlSchemaContext extends DefaultSchemaContext { } builder.setCanonicalContainer(parseBoolean(schemaElem, ATTR_CANONICAL)); - builder.setElementResyncMode( - ResyncMode.valueOf(requireAttributeValue(schemaElem, ATTR_ELEMENT_RESYNC))); - builder.setAttributeResyncMode( - ResyncMode.valueOf(requireAttributeValue(schemaElem, ATTR_ATTRIBUTE_RESYNC))); + builder.setElementResyncMode(ResyncMode.valueOf( + schemaElem.getAttributeValue(ATTR_ELEMENT_RESYNC, ResyncMode.NEVER.name()))); + builder.setAttributeResyncMode(ResyncMode.valueOf( + schemaElem.getAttributeValue(ATTR_ATTRIBUTE_RESYNC, ResyncMode.NEVER.name()))); for (Element elemElem : XmlUtilities.getChildren(schemaElem, ELEM_ELEMENT)) { SchemaName schema = name(requireAttributeValue(elemElem, ATTR_SCHEMA)); diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/util/ShellUtils.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/util/ShellUtils.java index 5164c557d8..60731e9359 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/util/ShellUtils.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/util/ShellUtils.java @@ -15,6 +15,7 @@ */ package ghidra.dbg.util; +import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; @@ -109,6 +110,19 @@ public class ShellUtils { return argsList; } + public static String removePath(String exec) { + return Paths.get(exec).getFileName().toString(); + } + + public static List removePath(List args) { + if (args.isEmpty()) { + return List.of(); + } + List copy = new ArrayList<>(args); + copy.set(0, removePath(args.get(0))); + return List.copyOf(copy); + } + public static String generateLine(List args) { if (args.isEmpty()) { return ""; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/pcode/exec/trace/data/AbstractPcodeTraceDataAccess.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/pcode/exec/trace/data/AbstractPcodeTraceDataAccess.java index afdaa69f00..0bf9ec3fed 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/pcode/exec/trace/data/AbstractPcodeTraceDataAccess.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/pcode/exec/trace/data/AbstractPcodeTraceDataAccess.java @@ -186,7 +186,7 @@ public abstract class AbstractPcodeTraceDataAccess implements InternalPcodeTrace TraceMemoryOperations ops = getMemoryOps(true); if (ops == null) { throw new AssertionError("Cannot get memory operations for writing. " + - "This usually indicates a schema issue."); + "This usually indicates a schema issue or a missing object."); } return ops.putBytes(snap, toOverlay(hostStart), buf); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java index 814e874383..43a65dadb7 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java @@ -297,18 +297,13 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra } protected static String keyForFlag(TraceMemoryFlag flag) { - switch (flag) { - case READ: - return TargetMemoryRegion.READABLE_ATTRIBUTE_NAME; - case WRITE: - return TargetMemoryRegion.WRITABLE_ATTRIBUTE_NAME; - case EXECUTE: - return TargetMemoryRegion.EXECUTABLE_ATTRIBUTE_NAME; - case VOLATILE: - return KEY_VOLATILE; - default: - throw new AssertionError(); - } + return switch (flag) { + case READ -> TargetMemoryRegion.READABLE_ATTRIBUTE_NAME; + case WRITE -> TargetMemoryRegion.WRITABLE_ATTRIBUTE_NAME; + case EXECUTE -> TargetMemoryRegion.EXECUTABLE_ATTRIBUTE_NAME; + case VOLATILE -> KEY_VOLATILE; + default -> throw new AssertionError(); + }; } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObjectManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObjectManager.java index 608b3620fa..0485bf7f8f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObjectManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObjectManager.java @@ -119,7 +119,9 @@ public class DBTraceObjectManager implements TraceObjectManager, DBTraceManager @DBAnnotatedColumn(SCHEMA_COLUMN_NAME) static DBObjectColumn SCHEMA_COLUMN; - @DBAnnotatedField(column = CONTEXT_COLUMN_NAME, codec = DBTraceObjectSchemaDBFieldCodec.class) + @DBAnnotatedField( + column = CONTEXT_COLUMN_NAME, + codec = DBTraceObjectSchemaDBFieldCodec.class) private SchemaContext context; @DBAnnotatedField(column = SCHEMA_COLUMN_NAME) private String schemaName; @@ -807,7 +809,7 @@ public class DBTraceObjectManager implements TraceObjectManager, DBTraceManager try (LockHold hold = trace.lockWrite()) { checkDuplicateThread(path, lifespan); TraceObjectThread thread = doAddWithInterface(path, TraceObjectThread.class); - thread.setName(lifespan, display); + thread.setName(lifespan.withMax(Lifespan.DOMAIN.lmax()), display); thread.getObject().insert(lifespan, ConflictResolution.DENY); return thread; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/terminal/TerminalPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/terminal/TerminalPlugin.java index 34fe44f1e9..8f57d2056e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/terminal/TerminalPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/terminal/TerminalPlugin.java @@ -65,10 +65,10 @@ public class TerminalPlugin extends Plugin implements TerminalService { } } - public TerminalProvider createProvider(Charset charset, VtOutput outputCb) { + public TerminalProvider createProvider(Plugin helpPlugin, Charset charset, VtOutput outputCb) { return Swing.runNow(() -> { cleanTerminated(); - TerminalProvider provider = new TerminalProvider(this, charset); + TerminalProvider provider = new TerminalProvider(this, charset, helpPlugin); provider.setOutputCallback(outputCb); provider.addToTool(); provider.setVisible(true); @@ -80,14 +80,20 @@ public class TerminalPlugin extends Plugin implements TerminalService { } @Override - public Terminal createNullTerminal(Charset charset, VtOutput outputCb) { - return new DefaultTerminal(createProvider(charset, outputCb)); + public Terminal createNullTerminal(Plugin helpPlugin, Charset charset, VtOutput outputCb) { + return new DefaultTerminal(createProvider(helpPlugin, charset, outputCb)); } @Override - public Terminal createWithStreams(Charset charset, InputStream in, OutputStream out) { + public Terminal createNullTerminal(Charset charset, VtOutput outputCb) { + return createNullTerminal(this, charset, outputCb); + } + + @Override + public Terminal createWithStreams(Plugin helpPlugin, Charset charset, InputStream in, + OutputStream out) { WritableByteChannel channel = Channels.newChannel(out); - return new ThreadedTerminal(createProvider(charset, buf -> { + return new ThreadedTerminal(createProvider(helpPlugin, charset, buf -> { while (buf.hasRemaining()) { try { //ThreadedTerminal.printBuffer(">> ", buf); @@ -100,6 +106,11 @@ public class TerminalPlugin extends Plugin implements TerminalService { }), in); } + @Override + public Terminal createWithStreams(Charset charset, InputStream in, OutputStream out) { + return createWithStreams(this, charset, in, out); + } + @Override public void serviceAdded(Class interfaceClass, Object service) { if (interfaceClass == ClipboardService.class) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/terminal/TerminalProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/terminal/TerminalProvider.java index 25f7fa0d04..1b4d067c8d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/terminal/TerminalProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/terminal/TerminalProvider.java @@ -40,6 +40,8 @@ import ghidra.app.plugin.core.terminal.TerminalPanel.FindOptions; import ghidra.app.plugin.core.terminal.vt.VtOutput; import ghidra.app.services.ClipboardService; import ghidra.framework.plugintool.ComponentProviderAdapter; +import ghidra.framework.plugintool.Plugin; +import ghidra.util.HelpLocation; import ghidra.util.Swing; /** @@ -153,6 +155,7 @@ public class TerminalProvider extends ComponentProviderAdapter { } protected final TerminalPlugin plugin; + protected final Plugin helpPlugin; protected final TerminalPanel panel; protected final FindDialog findDialog = new FindDialog(); @@ -164,9 +167,10 @@ public class TerminalProvider extends ComponentProviderAdapter { private boolean terminated = false; - public TerminalProvider(TerminalPlugin plugin, Charset charset) { + public TerminalProvider(TerminalPlugin plugin, Charset charset, Plugin helpPlugin) { super(plugin.getTool(), "Terminal", plugin.getName()); this.plugin = plugin; + this.helpPlugin = helpPlugin; this.panel = new TerminalPanel(charset, this); this.panel.addTerminalListener(new TerminalListener() { @Override @@ -177,6 +181,7 @@ public class TerminalProvider extends ComponentProviderAdapter { createActions(); setWindowMenuGroup("Terminals"); setDefaultWindowPosition(WindowPosition.BOTTOM); + setHelpLocation(new HelpLocation(helpPlugin.getName(), "plugin")); // Avoid change in dimension when "terminated" border is applied panel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); @@ -225,6 +230,7 @@ public class TerminalProvider extends ComponentProviderAdapter { .menuGroup("Find") .keyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)) + .helpLocation(new HelpLocation(helpPlugin.getName(), "find")) .onAction(this::activatedFind) .buildAndInstallLocal(this); actionFindNext = new ActionBuilder("Find Next", plugin.getName()) @@ -232,6 +238,7 @@ public class TerminalProvider extends ComponentProviderAdapter { .menuGroup("Find") .keyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)) + .helpLocation(new HelpLocation(helpPlugin.getName(), "find_next")) .enabledWhen(this::isEnabledFindStep) .onAction(this::activatedFindNext) .buildAndInstallLocal(this); @@ -240,6 +247,7 @@ public class TerminalProvider extends ComponentProviderAdapter { .menuGroup("Find") .keyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)) + .helpLocation(new HelpLocation(helpPlugin.getName(), "find_previous")) .enabledWhen(this::isEnabledFindStep) .onAction(this::activatedFindPrevious) .buildAndInstallLocal(this); @@ -392,6 +400,7 @@ public class TerminalProvider extends ComponentProviderAdapter { .menuIcon(new GIcon("icon.plugin.terminal.terminate")) .menuPath("Terminate") .menuGroup("Terminate") + .helpLocation(new HelpLocation(helpPlugin.getName(), "terminate")) .enabledWhen(ctx -> true) .onAction(ctx -> action.run()) .buildAndInstallLocal(this); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/services/TerminalService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/services/TerminalService.java index d0573fc3ef..278ea507c6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/services/TerminalService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/services/TerminalService.java @@ -21,6 +21,7 @@ import java.nio.charset.Charset; import ghidra.app.plugin.core.terminal.TerminalPlugin; import ghidra.app.plugin.core.terminal.vt.VtOutput; +import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.ServiceInfo; /** @@ -95,10 +96,20 @@ public interface TerminalService { * To display application output, use {@link Terminal#injectDisplayOutput(java.nio.ByteBuffer)}. * Application input is delivered to the given terminal output callback. If the application is * connected via streams, esp., those from a pty, consider using - * {@link #createWithStreams(Charset, InputStream, OutputStream)}, instead. + * {@link #createWithStreams(Plugin, Charset, InputStream, OutputStream)}, instead. * + * @param helpPlugin the invoking plugin, which ought to provide a help topic for this terminal. * @param charset the character set for the terminal. See note in - * {@link #createWithStreams(Charset, InputStream, OutputStream)}. + * {@link #createWithStreams(Plugin, Charset, InputStream, OutputStream)}. + * @param outputCb callback for output from the terminal, i.e., the application's input. + * @return the terminal + */ + Terminal createNullTerminal(Plugin helpPlugin, Charset charset, VtOutput outputCb); + + /** + * @see #createNullTerminal(Plugin, Charset, VtOutput) + * @param charset the character set for the terminal. See note in + * {@link #createWithStreams(Plugin, Charset, InputStream, OutputStream)}. * @param outputCb callback for output from the terminal, i.e., the application's input. * @return the terminal */ @@ -107,6 +118,20 @@ public interface TerminalService { /** * Create a terminal connected to the application (or pty session) via the given streams. * + * @param helpPlugin the invoking plugin, which ought to provide a help topic for this terminal. + * @param charset the character set for the terminal. NOTE: Only US-ASCII and UTF-8 have + * been tested. So long as the bytes 0x00-0x7f map one-to-one with characters with + * the same code point, it'll probably work. Charsets that require more than one byte + * to decode those characters will almost certainly break things. + * @param in the application's output, i.e., input for the terminal to display. + * @param out the application's input, i.e., output from the terminal's keyboard and mouse. + * @return the terminal + */ + Terminal createWithStreams(Plugin helpPlugin, Charset charset, InputStream in, + OutputStream out); + + /** + * @see #createWithStreams(Plugin, Charset, InputStream, OutputStream) * @param charset the character set for the terminal. NOTE: Only US-ASCII and UTF-8 have * been tested. So long as the bytes 0x00-0x7f map one-to-one with characters with * the same code point, it'll probably work. Charsets that require more than one byte diff --git a/Ghidra/Framework/Help/src/main/java/help/validator/HTMLFileParser.java b/Ghidra/Framework/Help/src/main/java/help/validator/HTMLFileParser.java index 17392440c3..d356a0fb7a 100644 --- a/Ghidra/Framework/Help/src/main/java/help/validator/HTMLFileParser.java +++ b/Ghidra/Framework/Help/src/main/java/help/validator/HTMLFileParser.java @@ -38,7 +38,14 @@ public class HTMLFileParser { String text; while ((text = rdr.readLine()) != null) { Line line = new Line(file, text, rdr.getLineNumber()); - processLine(line, rdr, file, tagProcessor); + try { + processLine(line, rdr, file, tagProcessor); + } + catch (Exception e) { + String message = + "Error parsing HTML at %s:%s.".formatted(file, rdr.getLineNumber()); + throw new IOException(message, e); + } } tagProcessor.endOfFile(); } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java b/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java index 0468022155..c8eb6be044 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java @@ -15,37 +15,43 @@ */ package ghidra.app.plugin.core.debug.gui.breakpoint; -import static ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest.*; -import static org.junit.Assert.*; +import static ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest.waitForPass; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import java.util.List; import java.util.Set; import org.junit.*; import db.Transaction; import generic.Unique; -import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest.TestDebuggerTargetTraceMapper; import ghidra.app.plugin.core.debug.service.breakpoint.DebuggerLogicalBreakpointServicePlugin; -import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceProxyPlugin; +import ghidra.app.plugin.core.debug.service.control.MockTarget; +import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils; +import ghidra.app.plugin.core.debug.service.target.DebuggerTargetServicePlugin; import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin; import ghidra.app.services.*; -import ghidra.dbg.model.TestDebuggerModelBuilder; import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind; import ghidra.dbg.target.TargetBreakpointSpecContainer; import ghidra.dbg.target.TargetTogglable; import ghidra.dbg.testutil.DebuggerModelTestUtils; -import ghidra.debug.api.action.ActionSource; import ghidra.debug.api.breakpoint.LogicalBreakpoint; -import ghidra.debug.api.model.TraceRecorder; +import ghidra.framework.model.DomainFolder; +import ghidra.program.database.ProgramBuilder; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; import ghidra.program.util.ProgramLocation; import ghidra.test.ToyProgramBuilder; +import ghidra.trace.database.ToyDBTraceBuilder; +import ghidra.trace.database.breakpoint.DBTraceBreakpointManager; import ghidra.trace.model.*; import ghidra.trace.model.breakpoint.TraceBreakpoint; +import ghidra.trace.model.breakpoint.TraceBreakpointKind; +import ghidra.trace.model.target.TraceObjectKeyPath; import ghidra.util.Msg; import ghidra.util.task.TaskMonitor; import help.screenshot.GhidraScreenShotGenerator; @@ -53,8 +59,7 @@ import help.screenshot.GhidraScreenShotGenerator; public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenerator implements DebuggerModelTestUtils { - TestDebuggerModelBuilder mb = new TestDebuggerModelBuilder(); - DebuggerModelServiceProxyPlugin modelService; + DebuggerTargetService targetService; DebuggerStaticMappingService mappingService; DebuggerLogicalBreakpointService breakpointService; DebuggerTraceManagerService traceManager; @@ -73,7 +78,7 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera @Before public void setUpMine() throws Exception { breakpointService = addPlugin(tool, DebuggerLogicalBreakpointServicePlugin.class); - modelService = addPlugin(tool, DebuggerModelServiceProxyPlugin.class); + targetService = addPlugin(tool, DebuggerTargetServicePlugin.class); mappingService = addPlugin(tool, DebuggerStaticMappingServicePlugin.class); traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class); programManager = addPlugin(tool, ProgramManagerPlugin.class); @@ -110,80 +115,85 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera DebuggerBreakpointsProvider provider = waitForComponentProvider(DebuggerBreakpointsProvider.class); - mb.createTestModel(); - modelService.addModel(mb.testModel); - mb.createTestProcessesAndThreads(); + try ( + ToyDBTraceBuilder tb1 = + new ToyDBTraceBuilder("echo.1", ProgramBuilder._TOY64_BE); + ToyDBTraceBuilder tb2 = + new ToyDBTraceBuilder("echo.2", ProgramBuilder._TOY64_BE);) { - TraceRecorder recorder1 = modelService.recordTarget(mb.testProcess1, - new TestDebuggerTargetTraceMapper(mb.testProcess1), ActionSource.AUTOMATIC); - TraceRecorder recorder3 = modelService.recordTarget(mb.testProcess3, - new TestDebuggerTargetTraceMapper(mb.testProcess3), ActionSource.AUTOMATIC); - Trace trace1 = recorder1.getTrace(); - Trace trace3 = recorder3.getTrace(); + targetService.publishTarget(new MockTarget(tb1.trace)); + targetService.publishTarget(new MockTarget(tb2.trace)); + DomainFolder root = tool.getProject().getProjectData().getRootFolder(); + root.createFile("echo.1", tb1.trace, TaskMonitor.DUMMY); + root.createFile("echo.2", tb2.trace, TaskMonitor.DUMMY); - programManager.openProgram(program); - traceManager.openTrace(trace1); - traceManager.openTrace(trace3); + try (Transaction tx = tb1.startTransaction()) { + DebuggerStaticMappingUtils.addMapping( + new DefaultTraceLocation(tb1.trace, null, Lifespan.nowOn(0), + addr(tb1.trace, 0x00400000)), + new ProgramLocation(program, addr(program, 0x00400000)), 0x00210000, false); + } + try (Transaction tx = tb2.startTransaction()) { + DebuggerStaticMappingUtils.addMapping( + new DefaultTraceLocation(tb2.trace, null, Lifespan.nowOn(0), + addr(tb2.trace, 0x7fac0000)), + new ProgramLocation(program, addr(program, 0x00400000)), 0x00010000, false); + } + waitForSwing(); - mb.testProcess1.addRegion("echo:.text", mb.rng(0x00400000, 0x00400fff), "rx"); - mb.testProcess1.addRegion("echo:.data", mb.rng(0x00600000, 0x00600fff), "rw"); - mb.testProcess3.addRegion("echo:.text", mb.rng(0x7fac0000, 0x7fac0fff), "rx"); + try (Transaction tx = program.openTransaction("Add breakpoint")) { + program.getBookmarkManager() + .setBookmark(addr(program, 0x00401234), + LogicalBreakpoint.ENABLED_BOOKMARK_TYPE, + "SW_EXECUTE;1", "before connect"); + program.getBookmarkManager() + .setBookmark(addr(program, 0x00604321), + LogicalBreakpoint.ENABLED_BOOKMARK_TYPE, + "WRITE;4", "write version"); + } - try (Transaction tx = trace1.openTransaction("Add mapping")) { - DebuggerStaticMappingUtils.addMapping( - new DefaultTraceLocation(trace1, null, Lifespan.nowOn(0), addr(trace1, 0x00400000)), - new ProgramLocation(program, addr(program, 0x00400000)), 0x00210000, false); + try (Transaction tx = tb1.startTransaction()) { + tb1.trace.getObjectManager() + .createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA); + long snap = tb1.trace.getTimeManager().createSnapshot("First").getKey(); + + DBTraceBreakpointManager bm = tb1.trace.getBreakpointManager(); + bm.placeBreakpoint("Breakpoints[1]", snap, tb1.addr(0x00401234), List.of(), + Set.of(TraceBreakpointKind.SW_EXECUTE), true, "ram:00401234"); + bm.placeBreakpoint("Breakpoints[2]", snap, tb1.range(0x00604321, 0x00604324), + List.of(), + Set.of(TraceBreakpointKind.WRITE), true, "ram:00604321"); + } + + try (Transaction tx = tb2.startTransaction()) { + tb2.trace.getObjectManager() + .createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA); + long snap = tb2.trace.getTimeManager().createSnapshot("First").getKey(); + + DBTraceBreakpointManager bm = tb2.trace.getBreakpointManager(); + bm.placeBreakpoint("Breakpoints[1]", snap, tb2.addr(0x7fac1234), List.of(), + Set.of(TraceBreakpointKind.SW_EXECUTE), false, "ram:7fac1234"); + } + + programManager.openProgram(program); + traceManager.openTrace(tb1.trace); + traceManager.openTrace(tb2.trace); + + waitForPass(() -> { + Set allBreakpoints = breakpointService.getAllBreakpoints(); + assertEquals(2, allBreakpoints.size()); + }); + /** + * TODO: Might be necessary to debounce and wait for service callbacks to settle. + * Sometimes, there are 3 for just a moment, and then additional callbacks mess things + * up. + */ + waitForPass(() -> { + assertEquals(2, provider.breakpointTable.getRowCount()); + assertEquals(3, provider.locationTable.getRowCount()); + }); + + captureIsolatedProvider(provider, 600, 600); } - try (Transaction tx = trace3.openTransaction("Add mapping")) { - DebuggerStaticMappingUtils.addMapping( - new DefaultTraceLocation(trace3, null, Lifespan.nowOn(0), addr(trace3, 0x7fac0000)), - new ProgramLocation(program, addr(program, 0x00400000)), 0x00010000, false); - } - waitForSwing(); - - try (Transaction tx = program.openTransaction("Add breakpoint")) { - program.getBookmarkManager() - .setBookmark(addr(program, 0x00401234), LogicalBreakpoint.ENABLED_BOOKMARK_TYPE, - "SW_EXECUTE;1", "before connect"); - program.getBookmarkManager() - .setBookmark(addr(program, 0x00604321), LogicalBreakpoint.ENABLED_BOOKMARK_TYPE, - "WRITE;4", "write version"); - } - - TargetBreakpointSpecContainer bc1 = - waitFor(() -> Unique.assertAtMostOne(recorder1.collectBreakpointContainers(null)), - "No container"); - waitOn(bc1.placeBreakpoint(mb.addr(0x00401234), Set.of(TargetBreakpointKind.SW_EXECUTE))); - waitOn(bc1.placeBreakpoint(mb.rng(0x00604321, 0x00604324), - Set.of(TargetBreakpointKind.WRITE))); - TargetBreakpointSpecContainer bc3 = - waitFor(() -> Unique.assertAtMostOne(recorder3.collectBreakpointContainers(null)), - "No container"); - waitOn(bc3.placeBreakpoint(mb.addr(0x7fac1234), Set.of(TargetBreakpointKind.SW_EXECUTE))); - TargetTogglable bp3 = (TargetTogglable) waitForValue( - () -> Unique.assertAtMostOne(bc3.getCachedElements().values())); - waitOn(bp3.disable()); - - TraceBreakpoint bpt = waitForValue(() -> Unique.assertAtMostOne( - trace3.getBreakpointManager() - .getBreakpointsAt(recorder3.getSnap(), addr(trace3, 0x7fac1234)))); - - waitForPass(() -> { - Set allBreakpoints = breakpointService.getAllBreakpoints(); - assertEquals(2, allBreakpoints.size()); - }); - waitForPass(() -> { - assertFalse(bpt.isEnabled(0)); - }); - /** - * TODO: Might be necessary to debounce and wait for service callbacks to settle. Sometimes, - * there are 3 for just a moment, and then additional callbacks mess things up. - */ - waitForPass(() -> { - assertEquals(2, provider.breakpointTable.getRowCount()); - assertEquals(3, provider.locationTable.getRowCount()); - }); - - captureIsolatedProvider(provider, 600, 600); } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/TraceRmiLauncherServicePluginScreenShots.java b/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/TraceRmiLauncherServicePluginScreenShots.java new file mode 100644 index 0000000000..845ba3ea7c --- /dev/null +++ b/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/TraceRmiLauncherServicePluginScreenShots.java @@ -0,0 +1,69 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.debug.gui.tracermi.launcher; + +import java.util.Map; + +import org.junit.Test; + +import ghidra.app.plugin.core.debug.gui.objects.components.DebuggerMethodInvocationDialog; +import ghidra.app.plugin.core.terminal.TerminalProvider; +import ghidra.debug.api.tracermi.TraceRmiLaunchOffer; +import ghidra.test.ToyProgramBuilder; +import help.screenshot.GhidraScreenShotGenerator; + +public class TraceRmiLauncherServicePluginScreenShots extends GhidraScreenShotGenerator { + TraceRmiLauncherServicePlugin servicePlugin; + + protected void captureLauncherByTitle(String title, Map args) throws Throwable { + servicePlugin = addPlugin(tool, TraceRmiLauncherServicePlugin.class); + + ToyProgramBuilder pb = new ToyProgramBuilder("demo", false); + + TraceRmiLaunchOffer offer = servicePlugin.getOffers(pb.getProgram()) + .stream() + .filter(o -> title.equals(o.getTitle())) + .findAny() + .orElseThrow(); + + AbstractTraceRmiLaunchOffer aoff = (AbstractTraceRmiLaunchOffer) offer; + aoff.saveLauncherArgs(args, aoff.getParameters()); + + runSwingLater(() -> servicePlugin.configureAndLaunch(offer)); + + captureDialog(DebuggerMethodInvocationDialog.class); + } + + @Test + public void testCaptureGdbLauncher() throws Throwable { + captureLauncherByTitle("gdb", Map.of("arg:1", "/home/user/demo")); + } + + @Test + public void testCaptureGdbTerminal() throws Throwable { + servicePlugin = addPlugin(tool, TraceRmiLauncherServicePlugin.class); + + TraceRmiLaunchOffer offer = servicePlugin.getOffers(null) + .stream() + .filter(o -> "raw gdb".equals(o.getTitle())) + .findAny() + .orElseThrow(); + + servicePlugin.relaunch(offer); + + captureIsolatedProvider(TerminalProvider.class, 600, 600); + } +}