GP-930: Various improvements and fixes for Windows debugging

This commit is contained in:
d-millar 2021-05-06 22:02:33 +00:00 committed by Dan
parent a1cfeebcc9
commit 10674175bb
39 changed files with 438 additions and 246 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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
*

View file

@ -21,6 +21,8 @@ public interface DbgModuleMemory {
String getName();
Long getId();
long getVmaStart();
long getVmaEnd();

View file

@ -85,6 +85,10 @@ public class DbgBreakpointInfo {
offset, expression);
}
public int getId() {
return bpt.getId();
}
@Override
public String toString() {
return Integer.toHexString(bpt.getId());

View file

@ -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);
}
}

View file

@ -55,7 +55,7 @@ public class DbgReadRegistersCommand extends AbstractDbgCommand<Map<DbgRegister,
}
}
}
//so.setCurrentThreadId(previous);
so.setCurrentThreadId(previous);
return result;
}

View file

@ -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);
}
}
}
}

View file

@ -63,6 +63,6 @@ public class DbgStackListFramesCommand extends AbstractDbgCommand<List<DbgStackF
tf.Params[3].longValue());
result.add(frame);
}
//so.setCurrentThreadId(previous);
so.setCurrentThreadId(previous);
}
}

View file

@ -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);
}
}
}

View file

@ -66,6 +66,6 @@ public class DbgWriteRegistersCommand extends AbstractDbgCommand<Void> {
}
}
registers.setValues(DebugRegisterSource.DEBUG_REGSRC_DEBUGGEE, values);
//so.setCurrentThreadId(previous);
so.setCurrentThreadId(previous);
}
}

View file

@ -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;
}

View file

@ -55,6 +55,11 @@ public class DbgModuleMemoryImpl implements DbgModuleMemory {
return index;
}
@Override
public Long getId() {
return vmaStart;
}
@Override
public long getVmaStart() {
return vmaStart;

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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() {

View file

@ -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) {

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 {

View file

@ -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)

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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

View file

@ -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;

View file

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

View file

@ -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;
});
}
}

View file

@ -123,6 +123,7 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
), reason.desc());
//setExecutionState(targetState, reason.desc());
registers.threadStateChangedSpecific(state, reason);
stack.threadStateChangedSpecific(state, reason);
}
@Override