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()); + } + } + +}