diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/methods.py b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/methods.py
index 6d97489a6e..e3eab8cc75 100644
--- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/methods.py
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/methods.py
@@ -26,7 +26,7 @@ from ghidratrace.client import (MethodRegistry, ParamDesc, Address,
from pybag import pydbg # type: ignore
from pybag.dbgeng import core as DbgEng, exception # type: ignore
-from . import util, commands
+from . import arch, util, commands
REGISTRY = MethodRegistry(ThreadPoolExecutor(
@@ -846,8 +846,11 @@ def write_reg(frame: StackFrame, name: str, value: bytes) -> None:
"""Write a register."""
f = find_frame_by_obj(frame)
util.select_frame(f.FrameNumber)
- nproc = pydbg.selected_process()
- dbg().reg._set_register(name, value)
+ nproc = util.selected_process()
+ trace: Trace[commands.Extra] = frame.trace
+ rv = trace.extra.require_rm().map_value_back(nproc, name, value)
+ rval = int.from_bytes(rv.value, signed=False)
+ dbg().reg._set_register(name, rval)
@REGISTRY.method(display='Refresh Events (custom)', condition=util.dbg.IS_TRACE)
diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/schema.xml b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/schema.xml
index 72d8b60425..e56d789961 100644
--- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/schema.xml
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/schema.xml
@@ -309,6 +309,9 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/schema_exdi.xml b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/schema_exdi.xml
index 9dcbb43239..ba44582d57 100644
--- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/schema_exdi.xml
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/schema_exdi.xml
@@ -270,7 +270,10 @@
-
+
+
+
+
diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/schema.xml b/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/schema.xml
index b87c0546c7..d1cf8f11b0 100644
--- a/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/schema.xml
+++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/schema.xml
@@ -225,6 +225,9 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/arch.py b/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/arch.py
index 73eaafe1d9..d82e6cb596 100644
--- a/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/arch.py
+++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/arch.py
@@ -308,6 +308,8 @@ class DefaultRegisterMapper(object):
def map_value_back(self, proc: lldb.SBProcess, name: str,
value: bytes) -> RegVal:
+ if self.byte_order == 'little':
+ value = bytes(reversed(value))
return RegVal(self.map_name_back(proc, name), value)
diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py b/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py
index baffe62583..158b91449f 100644
--- a/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py
+++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py
@@ -106,6 +106,10 @@ def find_proc_by_modules_obj(object: TraceObject) -> lldb.SBProcess:
return find_proc_by_pattern(object, MODULES_PATTERN, "a ModuleContainer")
+def find_proc_by_frame(object: TraceObject) -> lldb.SBProcess:
+ return find_proc_by_pattern(object, FRAME_PATTERN, "a StaclFrame")
+
+
def find_thread_by_num(proc: lldb.SBThread, tnum: int) -> lldb.SBThread:
for t in proc.threads:
if t.GetThreadID() == tnum:
@@ -731,11 +735,22 @@ def write_mem(process: Process, address: Address, data: bytes) -> None:
@REGISTRY.method()
def write_reg(frame: StackFrame, name: str, value: bytes) -> None:
"""Write a register."""
+ proc = find_proc_by_frame(frame)
+ util.get_debugger().SetSelectedTarget(proc.target)
f = find_frame_by_obj(frame)
- f.select()
- proc = lldb.selected_process()
- mname, mval = frame.trace.extra.require_rm().map_value_back(proc, name, value)
- size = int(lldb.parse_and_eval(f'sizeof(${mname})'))
- arr = '{' + ','.join(str(b) for b in mval) + '}'
- exec_convert_errors(
- f'expr ((unsigned char[{size}])${mname}) = {arr};')
+ exec_convert_errors(f'frame select {f.idx}')
+ rv = frame.trace.extra.require_rm().map_value_back(proc, name, value)
+ reg = f.registers[0].GetChildMemberWithName(name)
+ error = lldb.SBError()
+ data = lldb.SBData()
+ tgt = util.get_target()
+ for b in rv.value:
+ bv = tgt.EvaluateExpression(f"(char){b}")
+ if bv.error.fail:
+ raise Exception(bv.error.description)
+ if not data.Append(bv.GetData()):
+ raise Exception(f"Could not build data for register value {rv.value}")
+ if not reg.SetData(data, error):
+ raise Exception(error.description)
+ with commands.open_tracked_tx(f'Write Register {name}'):
+ exec_convert_errors('ghidra trace putreg')
diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/schema.xml b/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/schema.xml
index 1c37118bf7..e45d091fce 100644
--- a/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/schema.xml
+++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/schema.xml
@@ -260,6 +260,9 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTargetTest.java b/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTargetTest.java
new file mode 100644
index 0000000000..67ae4e6ad9
--- /dev/null
+++ b/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTargetTest.java
@@ -0,0 +1,103 @@
+/* ###
+ * 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.service.tracermi;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import db.Transaction;
+import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
+import ghidra.app.plugin.core.debug.service.tracermi.TraceRmiTarget.FoundRegister;
+import ghidra.app.services.DebuggerControlService;
+import ghidra.app.services.DebuggerTraceManagerService;
+import ghidra.debug.api.tracermi.TraceRmiConnection;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.lang.Register;
+import ghidra.trace.model.Lifespan;
+import ghidra.trace.model.target.TraceObject;
+import ghidra.trace.model.target.TraceObject.ConflictResolution;
+import ghidra.trace.model.target.path.KeyPath;
+import ghidra.trace.model.target.schema.SchemaContext;
+import ghidra.trace.model.target.schema.XmlSchemaContext;
+import ghidra.trace.model.thread.TraceThread;
+
+public class TraceRmiTargetTest extends AbstractGhidraHeadedDebuggerTest {
+
+ class MyTraceRmiConnection extends TestTraceRmiConnection {
+
+ @Override
+ protected DebuggerTraceManagerService getTraceManager() {
+ return null;
+ }
+
+ @Override
+ protected DebuggerControlService getControlService() {
+ return null;
+ }
+ }
+
+ @Test
+ public void testSearchForRegistersInGroups() throws Exception {
+ SchemaContext ctx = XmlSchemaContext.deserialize("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """);
+
+ PluginTool tool = env.getTool();
+ createTrace("x86:LE:64:default");
+ Register regRax = tb.reg("RAX");
+ try (Transaction tx = tb.startTransaction()) {
+ tb.createRootObject(ctx, "root");
+ TraceObject objRax = tb.trace.getObjectManager()
+ .createObject(KeyPath.parse("Threads[1].Registers.General Purpose.RAX"));
+ objRax.insert(Lifespan.ALL, ConflictResolution.DENY);
+ }
+
+ try (TraceRmiConnection cx = new MyTraceRmiConnection()) {
+ TraceRmiTarget target = new TraceRmiTarget(tool, cx, tb.trace);
+
+ TraceThread thread = tb.obj("Threads[1]").queryInterface(TraceThread.class);
+ FoundRegister found = target.findRegister(thread, 0, regRax);
+ assertEquals("Threads[1].Registers.General Purpose.RAX",
+ found.value().getCanonicalPath().toString());
+ }
+ }
+
+}