mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-930: Various improvements and fixes for Windows debugging
This commit is contained in:
parent
a1cfeebcc9
commit
10674175bb
39 changed files with 438 additions and 246 deletions
|
@ -103,8 +103,8 @@ public class WrapCallbackIDebugEventCallbacks implements CallbackIDebugEventCall
|
|||
try {
|
||||
DebugBreakpoint bpt = DebugBreakpointInternal
|
||||
.tryPreferredInterfaces(client.getControlInternal(), Bp::QueryInterface);
|
||||
cb.breakpoint(bpt);
|
||||
return WinError.S_OK;
|
||||
DebugStatus status = cb.breakpoint(bpt);
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
|
@ -125,8 +125,8 @@ public class WrapCallbackIDebugEventCallbacks implements CallbackIDebugEventCall
|
|||
Exception.ExceptionFlags.intValue(), Exception.ExceptionRecord.longValue(),
|
||||
Exception.ExceptionAddress.longValue(), information);
|
||||
boolean firstChance = FirstChance.intValue() != 0;
|
||||
cb.exception(exc, firstChance);
|
||||
return WinError.S_OK;
|
||||
DebugStatus status = cb.exception(exc, firstChance);
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
|
|
|
@ -105,8 +105,8 @@ public class WrapCallbackIDebugEventCallbacksWide implements CallbackIDebugEvent
|
|||
try {
|
||||
DebugBreakpoint bpt = DebugBreakpointInternal
|
||||
.tryPreferredInterfaces(client.getControlInternal(), Bp::QueryInterface);
|
||||
cb.breakpoint(bpt);
|
||||
return WinError.S_OK;
|
||||
DebugStatus status = cb.breakpoint(bpt);
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
|
@ -127,8 +127,8 @@ public class WrapCallbackIDebugEventCallbacksWide implements CallbackIDebugEvent
|
|||
Exception.ExceptionFlags.intValue(), Exception.ExceptionRecord.longValue(),
|
||||
Exception.ExceptionAddress.longValue(), information);
|
||||
boolean firstChance = FirstChance.intValue() != 0;
|
||||
cb.exception(exc, firstChance);
|
||||
return WinError.S_OK;
|
||||
DebugStatus status = cb.exception(exc, firstChance);
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
|
|
|
@ -192,6 +192,16 @@ public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions {
|
|||
*/
|
||||
Map<Long, DbgBreakpointInfo> getKnownBreakpoints();
|
||||
|
||||
/**
|
||||
* Get all memory regions known to the manager
|
||||
*
|
||||
* This does not ask dbgeng to list its regions. Rather it returns a read-only view of the
|
||||
* manager's understanding of the current ememory based on its tracking of dbgeng events.
|
||||
*
|
||||
* @return a map of dbgeng-assigned breakpoint IDs to corresponding breakpoint information
|
||||
*/
|
||||
Map<Long, DbgModuleMemory> getKnownMemoryRegions();
|
||||
|
||||
/**
|
||||
* Send an interrupt to dbgeng regardless of other queued commands
|
||||
*
|
||||
|
@ -242,6 +252,21 @@ public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions {
|
|||
*/
|
||||
CompletableFuture<Void> removeSession(DbgSession session);
|
||||
|
||||
/**
|
||||
* Add a memory region
|
||||
*
|
||||
* @return a future which completes with the handle to the new process
|
||||
*/
|
||||
CompletableFuture<Void> addMemory(DbgModuleMemory region);
|
||||
|
||||
/**
|
||||
* Remove a memory region
|
||||
*
|
||||
* @param regionId the region to remove
|
||||
* @return a future which completes then dbgeng has executed the command
|
||||
*/
|
||||
CompletableFuture<Void> removeMemory(Long regionId);
|
||||
|
||||
/**
|
||||
* Execute an arbitrary CLI command, printing output to the CLI console
|
||||
*
|
||||
|
|
|
@ -21,6 +21,8 @@ public interface DbgModuleMemory {
|
|||
|
||||
String getName();
|
||||
|
||||
Long getId();
|
||||
|
||||
long getVmaStart();
|
||||
|
||||
long getVmaEnd();
|
||||
|
|
|
@ -85,6 +85,10 @@ public class DbgBreakpointInfo {
|
|||
offset, expression);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return bpt.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Integer.toHexString(bpt.getId());
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
*/
|
||||
package agent.dbgeng.manager.cmd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.sun.jna.platform.win32.COM.COMException;
|
||||
|
||||
|
@ -27,6 +27,7 @@ import agent.dbgeng.dbgeng.DebugModule.DebugModuleName;
|
|||
import agent.dbgeng.manager.DbgModuleMemory;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.manager.impl.DbgModuleMemoryImpl;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class DbgListMemoryRegionsCommand extends AbstractDbgCommand<List<DbgModuleMemory>> {
|
||||
|
||||
|
@ -38,6 +39,23 @@ public class DbgListMemoryRegionsCommand extends AbstractDbgCommand<List<DbgModu
|
|||
|
||||
@Override
|
||||
public List<DbgModuleMemory> complete(DbgPendingCommand<?> pending) {
|
||||
Map<Long, DbgModuleMemory> memory = manager.getKnownMemoryRegions();
|
||||
for (DbgModuleMemory region : memoryRegions) {
|
||||
if (memory.containsValue(region)) {
|
||||
continue; // Do nothing, we're in sync
|
||||
}
|
||||
// Need to create the thread as if we receive =thread-created
|
||||
if (!memory.isEmpty()) {
|
||||
Msg.warn(this, "Resync: Was missing memory: " + region.getId());
|
||||
}
|
||||
manager.addMemory(region);
|
||||
}
|
||||
for (Entry<Long, DbgModuleMemory> entry : memory.entrySet()) {
|
||||
if (memoryRegions.contains(entry.getValue())) {
|
||||
continue; // Do nothing, we're in sync
|
||||
}
|
||||
manager.removeMemory(entry.getKey());
|
||||
}
|
||||
return memoryRegions;
|
||||
}
|
||||
|
||||
|
@ -83,10 +101,10 @@ public class DbgListMemoryRegionsCommand extends AbstractDbgCommand<List<DbgModu
|
|||
isWrite |= protect.isWrite();
|
||||
isExec |= protect.isExecute();
|
||||
}
|
||||
DbgModuleMemoryImpl section =
|
||||
DbgModuleMemoryImpl region =
|
||||
new DbgModuleMemoryImpl(Long.toHexString(vmaStart), vmaStart, vmaEnd,
|
||||
info.allocationBase, ap, ip, info.state, type, isRead, isWrite, isExec);
|
||||
memoryRegions.add(section);
|
||||
memoryRegions.add(region);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ public class DbgReadRegistersCommand extends AbstractDbgCommand<Map<DbgRegister,
|
|||
}
|
||||
}
|
||||
}
|
||||
//so.setCurrentThreadId(previous);
|
||||
so.setCurrentThreadId(previous);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package agent.dbgeng.manager.cmd;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugSystemObjects;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
|
||||
|
@ -39,7 +40,11 @@ public class DbgSetActiveProcessCommand extends AbstractDbgCommand<Void> {
|
|||
if (process != null) {
|
||||
DebugProcessId id = process.getId();
|
||||
if (id != null) {
|
||||
manager.getSystemObjects().setCurrentProcessId(id);
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
DebugProcessId currentProcessId = so.getCurrentProcessId();
|
||||
if (id.id != currentProcessId.id) {
|
||||
so.setCurrentProcessId(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,6 @@ public class DbgStackListFramesCommand extends AbstractDbgCommand<List<DbgStackF
|
|||
tf.Params[3].longValue());
|
||||
result.add(frame);
|
||||
}
|
||||
//so.setCurrentThreadId(previous);
|
||||
so.setCurrentThreadId(previous);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package agent.dbgeng.manager.cmd;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugControl;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
|
||||
|
@ -56,7 +55,9 @@ public class DbgThreadHoldCommand extends AbstractDbgCommand<Void> {
|
|||
public void invoke() {
|
||||
DebugThreadId id = thread.getId();
|
||||
if (id != null) {
|
||||
manager.getSystemObjects().setCurrentThreadId(id);
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
DebugThreadId previous = so.getCurrentThreadId();
|
||||
so.setCurrentThreadId(id);
|
||||
if (!manager.isKernelMode()) {
|
||||
DebugControl control = manager.getControl();
|
||||
if (preferFreeze) {
|
||||
|
@ -68,6 +69,7 @@ public class DbgThreadHoldCommand extends AbstractDbgCommand<Void> {
|
|||
set ? SUSPEND_CURRENT_THREAD_COMMAND : RESUME_CURRENT_THREAD_COMMAND);
|
||||
}
|
||||
}
|
||||
so.setCurrentThreadId(previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,6 @@ public class DbgWriteRegistersCommand extends AbstractDbgCommand<Void> {
|
|||
}
|
||||
}
|
||||
registers.setValues(DebugRegisterSource.DEBUG_REGSRC_DEBUGGEE, values);
|
||||
//so.setCurrentThreadId(previous);
|
||||
so.setCurrentThreadId(previous);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ import agent.dbgeng.manager.breakpoint.DbgBreakpointType;
|
|||
import agent.dbgeng.manager.cmd.*;
|
||||
import agent.dbgeng.manager.evt.*;
|
||||
import agent.dbgeng.model.iface1.*;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetObject;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetThread;
|
||||
import ghidra.async.*;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
|
@ -92,6 +94,10 @@ public class DbgManagerImpl implements DbgManager {
|
|||
private final Map<Long, DbgBreakpointInfo> unmodifiableBreakpoints =
|
||||
Collections.unmodifiableMap(breakpoints);
|
||||
|
||||
private final NavigableMap<Long, DbgModuleMemory> memory = new TreeMap<>();
|
||||
private final NavigableMap<Long, DbgModuleMemory> unmodifiableMemory =
|
||||
Collections.unmodifiableNavigableMap(memory);
|
||||
|
||||
protected final AsyncReference<DbgState, DbgCause> state =
|
||||
new AsyncReference<>(DbgState.NOT_STARTED);
|
||||
private final HandlerMap<DbgEvent<?>, Void, DebugStatus> handlerMap = new HandlerMap<>();
|
||||
|
@ -109,6 +115,7 @@ public class DbgManagerImpl implements DbgManager {
|
|||
private DbgThread eventThread;
|
||||
private volatile boolean waiting = false;
|
||||
private boolean kernelMode = false;
|
||||
private boolean ignoreEventThread = false;
|
||||
private CompletableFuture<String> continuation;
|
||||
private long processCount = 0;
|
||||
|
||||
|
@ -267,6 +274,11 @@ public class DbgManagerImpl implements DbgManager {
|
|||
return unmodifiableBreakpoints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, DbgModuleMemory> getKnownMemoryRegions() {
|
||||
return unmodifiableMemory;
|
||||
}
|
||||
|
||||
private DbgBreakpointInfo addKnownBreakpoint(DbgBreakpointInfo bkpt, boolean expectExisting) {
|
||||
DbgBreakpointInfo old = breakpoints.put(bkpt.getNumber(), bkpt);
|
||||
if (expectExisting && old == null) {
|
||||
|
@ -606,8 +618,8 @@ public class DbgManagerImpl implements DbgManager {
|
|||
DebugControl control = dbgeng.getControl();
|
||||
int execType = WinNTExtra.Machine.IMAGE_FILE_MACHINE_AMD64.val;
|
||||
try {
|
||||
so.setCurrentProcessId(epid);
|
||||
so.setCurrentThreadId(etid);
|
||||
//so.setCurrentProcessId(epid);
|
||||
//so.setCurrentThreadId(etid);
|
||||
execType = control.getExecutingProcessorType();
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
@ -652,6 +664,7 @@ public class DbgManagerImpl implements DbgManager {
|
|||
|
||||
DebugBreakpoint bp = evt.getInfo();
|
||||
DbgBreakpointInfo info = new DbgBreakpointInfo(bp, getEventProcess(), getEventThread());
|
||||
getEventListeners().fire.threadSelected(eventThread, null, evt.getCause());
|
||||
getEventListeners().fire.breakpointHit(info, evt.getCause());
|
||||
|
||||
String key = Integer.toHexString(bp.getId());
|
||||
|
@ -670,6 +683,7 @@ public class DbgManagerImpl implements DbgManager {
|
|||
*/
|
||||
protected DebugStatus processException(DbgExceptionEvent evt, Void v) {
|
||||
DebugThreadId eventId = updateState();
|
||||
getEventListeners().fire.threadSelected(eventThread, null, evt.getCause());
|
||||
|
||||
DebugExceptionRecord64 info = evt.getInfo();
|
||||
String key = Integer.toHexString(info.code);
|
||||
|
@ -764,16 +778,17 @@ public class DbgManagerImpl implements DbgManager {
|
|||
DebugProcessInfo info = evt.getInfo();
|
||||
long handle = info.handle;
|
||||
DebugProcessId id = so.getProcessIdByHandle(handle);
|
||||
so.setCurrentProcessId(id);
|
||||
//so.setCurrentProcessId(id);
|
||||
int pid = so.getCurrentProcessSystemId();
|
||||
DbgProcessImpl proc = getProcessComputeIfAbsent(id, pid);
|
||||
getEventListeners().fire.processAdded(proc, DbgCause.Causes.UNCLAIMED);
|
||||
getEventListeners().fire.processAdded(proc, evt.getCause());
|
||||
getEventListeners().fire.processSelected(proc, evt.getCause());
|
||||
|
||||
handle = info.initialThreadInfo.handle;
|
||||
DebugThreadId idt = so.getThreadIdByHandle(handle);
|
||||
int tid = so.getCurrentThreadSystemId();
|
||||
DbgThreadImpl thread = getThreadComputeIfAbsent(idt, proc, tid);
|
||||
getEventListeners().fire.threadCreated(thread, evt.getCause());
|
||||
getEventListeners().fire.threadSelected(thread, null, evt.getCause());
|
||||
|
||||
//proc.moduleLoaded(info.moduleInfo);
|
||||
|
@ -1041,24 +1056,25 @@ public class DbgManagerImpl implements DbgManager {
|
|||
if (bptId == DbgEngUtil.DEBUG_ANY_ID.longValue()) {
|
||||
changeBreakpoints();
|
||||
}
|
||||
DebugBreakpoint bpt = getControl().getBreakpointById((int) bptId);
|
||||
if (bpt == null) {
|
||||
doBreakpointDeleted(bptId, evt.getCause());
|
||||
return;
|
||||
}
|
||||
DbgBreakpointInfo knownBreakpoint = getKnownBreakpoint(bptId);
|
||||
if (knownBreakpoint == null) {
|
||||
breakpointInfo = new DbgBreakpointInfo(bpt, getCurrentProcess());
|
||||
if (breakpointInfo.getOffset() != null) {
|
||||
doBreakpointCreated(breakpointInfo, evt.getCause());
|
||||
else {
|
||||
DebugBreakpoint bpt = getControl().getBreakpointById((int) bptId);
|
||||
if (bpt == null && bptId != DbgEngUtil.DEBUG_ANY_ID.longValue()) {
|
||||
doBreakpointDeleted(bptId, evt.getCause());
|
||||
return;
|
||||
}
|
||||
return;
|
||||
DbgBreakpointInfo knownBreakpoint = getKnownBreakpoint(bptId);
|
||||
if (knownBreakpoint == null) {
|
||||
breakpointInfo = new DbgBreakpointInfo(bpt, getCurrentProcess());
|
||||
if (breakpointInfo.getOffset() != null) {
|
||||
doBreakpointCreated(breakpointInfo, evt.getCause());
|
||||
}
|
||||
return;
|
||||
}
|
||||
breakpointInfo = knownBreakpoint;
|
||||
breakpointInfo.setBreakpoint(bpt);
|
||||
doBreakpointModified(breakpointInfo, evt.getCause());
|
||||
}
|
||||
breakpointInfo = knownBreakpoint;
|
||||
breakpointInfo.setBreakpoint(bpt);
|
||||
|
||||
}
|
||||
doBreakpointModified(breakpointInfo, evt.getCause());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1274,6 +1290,18 @@ public class DbgManagerImpl implements DbgManager {
|
|||
return execute(new DbgRemoveSessionCommand(this, session.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> addMemory(DbgModuleMemory region) {
|
||||
memory.put(region.getId(), region);
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> removeMemory(Long id) {
|
||||
memory.remove(id);
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<?> launch(List<String> args) {
|
||||
return execute(new DbgLaunchProcessCommand(this, args));
|
||||
|
@ -1492,6 +1520,7 @@ public class DbgManagerImpl implements DbgManager {
|
|||
//System.err.println("EXIT");
|
||||
waiting = false;
|
||||
updateState();
|
||||
getEventListeners().fire.threadSelected(eventThread, null, Causes.UNCLAIMED);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
|
@ -1511,6 +1540,18 @@ public class DbgManagerImpl implements DbgManager {
|
|||
return lastEventInformation;
|
||||
}
|
||||
|
||||
public boolean shouldUpdate(TargetObject object) {
|
||||
if (ignoreEventThread || !(object instanceof DbgModelTargetObject)) {
|
||||
return true;
|
||||
}
|
||||
DbgModelTargetObject modelObject = (DbgModelTargetObject) object;
|
||||
DbgModelTargetThread parentThread = modelObject.getParentThread();
|
||||
if (parentThread == null) {
|
||||
return true;
|
||||
}
|
||||
return parentThread.getThread().equals(eventThread);
|
||||
}
|
||||
|
||||
public CompletableFuture<? extends Map<String, ?>> getRegisterMap(List<String> path) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,11 @@ public class DbgModuleMemoryImpl implements DbgModuleMemory {
|
|||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return vmaStart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getVmaStart() {
|
||||
return vmaStart;
|
||||
|
|
|
@ -43,9 +43,11 @@ public interface DbgModelTargetExecutionStateful
|
|||
}
|
||||
|
||||
public default void setExecutionState(TargetExecutionState state, String reason) {
|
||||
changeAttributes(List.of(), Map.of( //
|
||||
STATE_ATTRIBUTE_NAME, state //
|
||||
), reason);
|
||||
if (isValid()) {
|
||||
changeAttributes(List.of(), Map.of( //
|
||||
STATE_ATTRIBUTE_NAME, state //
|
||||
), reason);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -67,21 +67,11 @@ public interface DbgModelTargetBreakpointSpec extends //
|
|||
|
||||
@Override
|
||||
public default TargetBreakpointKindSet getKinds() {
|
||||
switch (getBreakpointInfo().getType()) {
|
||||
case BREAKPOINT:
|
||||
return TargetBreakpointKindSet.of(TargetBreakpointKind.SW_EXECUTE);
|
||||
case HW_BREAKPOINT:
|
||||
return TargetBreakpointKindSet.of(TargetBreakpointKind.HW_EXECUTE);
|
||||
case HW_WATCHPOINT:
|
||||
return TargetBreakpointKindSet.of(TargetBreakpointKind.WRITE);
|
||||
case READ_WATCHPOINT:
|
||||
return TargetBreakpointKindSet.of(TargetBreakpointKind.READ);
|
||||
case ACCESS_WATCHPOINT:
|
||||
return TargetBreakpointKindSet.of(TargetBreakpointKind.READ,
|
||||
TargetBreakpointKind.WRITE);
|
||||
default:
|
||||
return TargetBreakpointKindSet.of();
|
||||
}
|
||||
return TargetBreakpointKindSet.of(
|
||||
TargetBreakpointKind.SW_EXECUTE,
|
||||
TargetBreakpointKind.HW_EXECUTE,
|
||||
TargetBreakpointKind.READ,
|
||||
TargetBreakpointKind.WRITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,4 +31,6 @@ public interface DbgModelTargetMemoryContainer extends DbgModelTargetObject, Tar
|
|||
@Override
|
||||
public CompletableFuture<Void> writeMemory(Address address, byte[] data);
|
||||
|
||||
public CompletableFuture<Void> requestElements(boolean refresh);
|
||||
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ public interface DbgModelTargetProcess extends //
|
|||
|
||||
public DbgModelTargetModuleContainer getModules();
|
||||
|
||||
public DbgModelTargetMemoryContainer getMemory();
|
||||
|
||||
public void threadStateChangedSpecific(DbgThread thread, DbgState state);
|
||||
|
||||
public default DbgProcess getProcess() {
|
||||
|
|
|
@ -21,7 +21,7 @@ import java.util.Map.Entry;
|
|||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.impl.*;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.async.TypeSpec;
|
||||
|
@ -36,10 +36,6 @@ public interface DbgModelTargetRegisterBank extends DbgModelTargetObject, Target
|
|||
|
||||
public DbgModelTargetRegister getTargetRegister(DbgRegister register);
|
||||
|
||||
public default void threadStateChangedSpecific(DbgState state, DbgReason reason) {
|
||||
readRegistersNamed(getCachedElements().keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public default CompletableFuture<? extends Map<String, byte[]>> readRegistersNamed(
|
||||
Collection<String> names) {
|
||||
|
|
|
@ -59,6 +59,9 @@ public interface DbgModelTargetSession extends //
|
|||
@Override
|
||||
public default void consoleOutput(String output, int mask) {
|
||||
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
Channel chan = TargetConsole.Channel.STDOUT;
|
||||
if (((mask & DebugOutputFlags.DEBUG_OUTPUT_ERROR.getValue()) //
|
||||
== DebugOutputFlags.DEBUG_OUTPUT_ERROR.getValue()) || //
|
||||
|
@ -69,6 +72,9 @@ public interface DbgModelTargetSession extends //
|
|||
if (output.contains("loaded *kernel* extension dll for usermode")) {
|
||||
return;
|
||||
}
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
getListeners().fire.consoleOutput(getProxy(), chan, output);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import agent.dbgeng.manager.cmd.DbgSetActiveThreadCommand;
|
|||
import agent.dbgeng.manager.impl.*;
|
||||
import agent.dbgeng.model.iface1.*;
|
||||
import agent.dbgeng.model.impl.DbgModelTargetStackImpl;
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.dbg.target.TargetThread;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
|
||||
public interface DbgModelTargetThread extends //
|
||||
|
@ -55,15 +55,6 @@ public interface DbgModelTargetThread extends //
|
|||
}
|
||||
}
|
||||
|
||||
public default void threadStateChangedSpecific(DbgState state, DbgReason reason) {
|
||||
TargetRegisterContainer container =
|
||||
(TargetRegisterContainer) getCachedAttribute("Registers");
|
||||
TargetRegisterBank bank = (TargetRegisterBank) container.getCachedAttribute("User");
|
||||
if (state.equals(DbgState.STOPPED)) {
|
||||
bank.readRegistersNamed(getCachedElements().keySet());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public default CompletableFuture<Void> setActive() {
|
||||
DbgManagerImpl manager = getManager();
|
||||
|
@ -75,4 +66,6 @@ public interface DbgModelTargetThread extends //
|
|||
|
||||
public String getExecutingProcessorType();
|
||||
|
||||
public void threadStateChangedSpecific(DbgState state, DbgReason reason);
|
||||
|
||||
}
|
||||
|
|
|
@ -28,11 +28,15 @@ import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind;
|
|||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.*;
|
||||
|
||||
@TargetObjectSchemaInfo(name = "BreakpointContainer", elements = { //
|
||||
@TargetElementType(type = DbgModelTargetBreakpointSpecImpl.class) //
|
||||
}, attributes = { //
|
||||
@TargetAttributeType(type = Void.class) //
|
||||
}, canonicalContainer = true)
|
||||
@TargetObjectSchemaInfo(
|
||||
name = "BreakpointContainer",
|
||||
elements = { //
|
||||
@TargetElementType(type = DbgModelTargetBreakpointSpecImpl.class) //
|
||||
},
|
||||
attributes = { //
|
||||
@TargetAttributeType(type = Void.class) //
|
||||
},
|
||||
canonicalContainer = true)
|
||||
public class DbgModelTargetBreakpointContainerImpl extends DbgModelTargetObjectImpl
|
||||
implements DbgModelTargetBreakpointContainer {
|
||||
|
||||
|
|
|
@ -28,19 +28,30 @@ import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
|
|||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.util.datastruct.ListenerSet;
|
||||
|
||||
@TargetObjectSchemaInfo(name = "BreakpointSpec", attributes = { //
|
||||
@TargetAttributeType( //
|
||||
@TargetObjectSchemaInfo(
|
||||
name = "BreakpointSpec",
|
||||
attributes = { //
|
||||
@TargetAttributeType( //
|
||||
name = TargetBreakpointSpec.CONTAINER_ATTRIBUTE_NAME, //
|
||||
type = DbgModelTargetBreakpointContainerImpl.class), //
|
||||
@TargetAttributeType( //
|
||||
@TargetAttributeType( //
|
||||
name = TargetBreakpointLocation.SPEC_ATTRIBUTE_NAME, //
|
||||
type = DbgModelTargetBreakpointSpecImpl.class), //
|
||||
@TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_TYPE_ATTRIBUTE_NAME, type = String.class), //
|
||||
@TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_DISP_ATTRIBUTE_NAME, type = String.class), //
|
||||
@TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_PENDING_ATTRIBUTE_NAME, type = String.class), //
|
||||
@TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_TIMES_ATTRIBUTE_NAME, type = Integer.class), //
|
||||
@TargetAttributeType(type = Void.class) //
|
||||
}, canonicalContainer = true)
|
||||
@TargetAttributeType(
|
||||
name = DbgModelTargetBreakpointSpecImpl.BPT_TYPE_ATTRIBUTE_NAME,
|
||||
type = String.class), //
|
||||
@TargetAttributeType(
|
||||
name = DbgModelTargetBreakpointSpecImpl.BPT_DISP_ATTRIBUTE_NAME,
|
||||
type = String.class), //
|
||||
@TargetAttributeType(
|
||||
name = DbgModelTargetBreakpointSpecImpl.BPT_PENDING_ATTRIBUTE_NAME,
|
||||
type = String.class), //
|
||||
@TargetAttributeType(
|
||||
name = DbgModelTargetBreakpointSpecImpl.BPT_TIMES_ATTRIBUTE_NAME,
|
||||
type = Integer.class), //
|
||||
@TargetAttributeType(type = Void.class) //
|
||||
},
|
||||
canonicalContainer = true)
|
||||
public class DbgModelTargetBreakpointSpecImpl extends DbgModelTargetObjectImpl
|
||||
implements DbgModelTargetBreakpointSpec {
|
||||
|
||||
|
@ -117,10 +128,9 @@ public class DbgModelTargetBreakpointSpecImpl extends DbgModelTargetObjectImpl
|
|||
/**
|
||||
* Update the enabled field
|
||||
*
|
||||
* This does not actually toggle the breakpoint. It just updates the field
|
||||
* and calls the proper listeners. To actually toggle the breakpoint, use
|
||||
* {@link #toggle(boolean)} instead, which if effective, should eventually
|
||||
* cause this method to be called.
|
||||
* This does not actually toggle the breakpoint. It just updates the field and calls the proper
|
||||
* listeners. To actually toggle the breakpoint, use {@link #toggle(boolean)} instead, which if
|
||||
* effective, should eventually cause this method to be called.
|
||||
*
|
||||
* @param enabled true if enabled, false if disabled
|
||||
* @param reason a description of the cause (not really used, yet)
|
||||
|
|
|
@ -35,9 +35,13 @@ import ghidra.dbg.target.schema.*;
|
|||
import ghidra.program.model.address.Address;
|
||||
import ghidra.util.datastruct.WeakValueHashMap;
|
||||
|
||||
@TargetObjectSchemaInfo(name = "Memory", elements = {
|
||||
@TargetElementType(type = DbgModelTargetMemoryRegionImpl.class) }, attributes = {
|
||||
@TargetAttributeType(type = Void.class) }, canonicalContainer = true)
|
||||
@TargetObjectSchemaInfo(
|
||||
name = "Memory",
|
||||
elements = {
|
||||
@TargetElementType(type = DbgModelTargetMemoryRegionImpl.class) },
|
||||
attributes = {
|
||||
@TargetAttributeType(type = Void.class) },
|
||||
canonicalContainer = true)
|
||||
public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
|
||||
implements DbgModelTargetMemoryContainer {
|
||||
|
||||
|
@ -49,12 +53,13 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
|
|||
public DbgModelTargetMemoryContainerImpl(DbgModelTargetProcess process) {
|
||||
super(process.getModel(), process, "Memory", "MemoryContainer");
|
||||
this.process = process;
|
||||
requestElements(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> requestElements(boolean refresh) {
|
||||
DbgModelTargetProcess targetProcess = getParentProcess();
|
||||
if (!targetProcess.getProcess().equals(getManager().getCurrentProcess())) {
|
||||
if (!refresh || !targetProcess.getProcess().equals(getManager().getCurrentProcess())) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
return listMemory().thenAccept(byName -> {
|
||||
|
@ -258,8 +263,4 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
|
|||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void update() {
|
||||
requestElements(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,22 +84,12 @@ public class DbgModelTargetObjectImpl extends DefaultTargetObject<TargetObject,
|
|||
|
||||
public void onStopped() {
|
||||
setAccessible(true);
|
||||
update();
|
||||
}
|
||||
|
||||
public void onExit() {
|
||||
setAccessible(true);
|
||||
}
|
||||
|
||||
protected void update() {
|
||||
Map<String, ?> existingAttributes = getCachedAttributes();
|
||||
Boolean autoupdate = (Boolean) existingAttributes.get("autoupdate");
|
||||
if (autoupdate != null && autoupdate) {
|
||||
requestAttributes(true);
|
||||
requestElements(true);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkExited(DbgState state, DbgCause cause) {
|
||||
TargetExecutionState exec = TargetExecutionState.INACTIVE;
|
||||
switch (state) {
|
||||
|
|
|
@ -30,12 +30,16 @@ import ghidra.dbg.target.TargetConfigurable;
|
|||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.*;
|
||||
|
||||
@TargetObjectSchemaInfo(name = "ProcessContainer", elements = { //
|
||||
@TargetElementType(type = DbgModelTargetProcessImpl.class) //
|
||||
}, attributes = { //
|
||||
@TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class), //
|
||||
@TargetAttributeType(type = Void.class) //
|
||||
}, canonicalContainer = true)
|
||||
@TargetObjectSchemaInfo(
|
||||
name = "ProcessContainer",
|
||||
elements = { //
|
||||
@TargetElementType(type = DbgModelTargetProcessImpl.class) //
|
||||
},
|
||||
attributes = { //
|
||||
@TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class), //
|
||||
@TargetAttributeType(type = Void.class) //
|
||||
},
|
||||
canonicalContainer = true)
|
||||
public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl
|
||||
implements DbgModelTargetProcessContainer, DbgModelTargetConfigurable {
|
||||
|
||||
|
@ -99,12 +103,20 @@ public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl
|
|||
if (modules != null) {
|
||||
modules.libraryLoaded(info.toString());
|
||||
}
|
||||
DbgModelTargetMemoryContainer memory = process.getMemory();
|
||||
if (memory != null) {
|
||||
memory.requestElements(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moduleUnloaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) {
|
||||
DbgModelTargetProcess process = getTargetProcess(proc);
|
||||
process.getModules().libraryUnloaded(info.toString());
|
||||
DbgModelTargetMemoryContainer memory = process.getMemory();
|
||||
if (memory != null) {
|
||||
memory.requestElements(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,13 +29,34 @@ import ghidra.dbg.target.TargetEventScope.TargetEventType;
|
|||
import ghidra.dbg.target.schema.*;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
|
||||
@TargetObjectSchemaInfo(name = "Process", elements = {
|
||||
@TargetElementType(type = Void.class) }, attributes = {
|
||||
@TargetAttributeType(name = "Debug", type = DbgModelTargetDebugContainerImpl.class, required = true, fixed = true),
|
||||
@TargetAttributeType(name = "Memory", type = DbgModelTargetMemoryContainerImpl.class, required = true, fixed = true),
|
||||
@TargetAttributeType(name = "Modules", type = DbgModelTargetModuleContainerImpl.class, required = true, fixed = true),
|
||||
@TargetAttributeType(name = "Threads", type = DbgModelTargetThreadContainerImpl.class, required = true, fixed = true),
|
||||
@TargetAttributeType(name = DbgModelTargetProcessImpl.EXIT_CODE_ATTRIBUTE_NAME, type = Long.class),
|
||||
@TargetObjectSchemaInfo(
|
||||
name = "Process",
|
||||
elements = {
|
||||
@TargetElementType(type = Void.class) },
|
||||
attributes = {
|
||||
@TargetAttributeType(
|
||||
name = "Debug",
|
||||
type = DbgModelTargetDebugContainerImpl.class,
|
||||
required = true,
|
||||
fixed = true),
|
||||
@TargetAttributeType(
|
||||
name = "Memory",
|
||||
type = DbgModelTargetMemoryContainerImpl.class,
|
||||
required = true,
|
||||
fixed = true),
|
||||
@TargetAttributeType(
|
||||
name = "Modules",
|
||||
type = DbgModelTargetModuleContainerImpl.class,
|
||||
required = true,
|
||||
fixed = true),
|
||||
@TargetAttributeType(
|
||||
name = "Threads",
|
||||
type = DbgModelTargetThreadContainerImpl.class,
|
||||
required = true,
|
||||
fixed = true),
|
||||
@TargetAttributeType(
|
||||
name = DbgModelTargetProcessImpl.EXIT_CODE_ATTRIBUTE_NAME,
|
||||
type = Long.class),
|
||||
@TargetAttributeType(type = Void.class) })
|
||||
public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
|
||||
implements DbgModelTargetProcess {
|
||||
|
@ -219,6 +240,11 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
|
|||
return modules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbgModelTargetMemoryContainer getMemory() {
|
||||
return memory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbgProcess getProcess() {
|
||||
return process;
|
||||
|
|
|
@ -31,11 +31,17 @@ import ghidra.dbg.target.schema.*;
|
|||
import ghidra.dbg.target.schema.TargetObjectSchema.ResyncMode;
|
||||
import ghidra.dbg.util.ConversionUtils;
|
||||
|
||||
@TargetObjectSchemaInfo(name = "RegisterContainer", elements = {
|
||||
@TargetElementType(type = DbgModelTargetRegisterImpl.class) }, elementResync = ResyncMode.ONCE, //
|
||||
attributes = {
|
||||
@TargetAttributeType(name = TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME, type = DbgModelTargetRegisterContainerImpl.class),
|
||||
@TargetAttributeType(type = Void.class) }, canonicalContainer = true)
|
||||
@TargetObjectSchemaInfo(
|
||||
name = "RegisterContainer",
|
||||
elements = {
|
||||
@TargetElementType(type = DbgModelTargetRegisterImpl.class) },
|
||||
elementResync = ResyncMode.ONCE, //
|
||||
attributes = {
|
||||
@TargetAttributeType(
|
||||
name = TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME,
|
||||
type = DbgModelTargetRegisterContainerImpl.class),
|
||||
@TargetAttributeType(type = Void.class) },
|
||||
canonicalContainer = true)
|
||||
public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImpl
|
||||
implements DbgModelTargetRegisterContainerAndBank {
|
||||
|
||||
|
@ -78,7 +84,7 @@ public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImp
|
|||
}
|
||||
|
||||
public void threadStateChangedSpecific(DbgState state, DbgReason reason) {
|
||||
if (state.equals(DbgState.STOPPED)) {
|
||||
if (!state.equals(DbgState.RUNNING)) {
|
||||
readRegistersNamed(getCachedElements().keySet());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Map;
|
|||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import agent.dbgeng.manager.DbgStackFrame;
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.model.iface2.*;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.*;
|
||||
|
@ -83,32 +83,12 @@ public class DbgModelTargetStackImpl extends DbgModelTargetObjectImpl
|
|||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onRunning() {
|
||||
// NB: We don't want to do this apparently
|
||||
//invalidateRegisterCaches();
|
||||
setAccessible(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopped() {
|
||||
setAccessible(true);
|
||||
if (thread.getThread().getId().equals(getManager().getEventThread().getId())) {
|
||||
update();
|
||||
public void threadStateChangedSpecific(DbgState state, DbgReason reason) {
|
||||
if (!state.equals(DbgState.RUNNING)) {
|
||||
requestElements(true).exceptionally(e -> {
|
||||
Msg.error(this, "Could not update stack " + this + " on STOPPED");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-fetch the stack frames, generating events for updates
|
||||
*
|
||||
* GDB doesn't produce stack change events, but they should only ever happen by running a
|
||||
* target. Thus, every time we're STOPPED, this method should be called.
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
requestElements(true).exceptionally(e -> {
|
||||
Msg.error(this, "Could not update stack " + this + " on STOPPED");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
|
|||
), reason.desc());
|
||||
//setExecutionState(targetState, reason.desc());
|
||||
registers.threadStateChangedSpecific(state, reason);
|
||||
stack.threadStateChangedSpecific(state, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue