mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-2023 This is a combination of 15 commits.
GP-2023: fix for endless region iterator GP-2023: fix for large-value register display in Objects GP-2023: script for !address GP-2023: de facto event for new process GP-2023: alt command for memory GP-2023: cosmetic stuff GP-2023: fix for NPE GP-2023: added a few methods (unnecessarily, but...), fixes to !address processing, and the bits of code being introduced in GP-2011 GP-2023: adding a parameter for QV vs !address GP-2023: fix for duplicate process creation triggered by getProcess() and/or getSession() GP-2023: fixes for null program, _state, and (possibly) invalidMemory exception GP-2023: better fix for re-entrant process/session creation GP-2023: Adding maintenance method to suppress auto-descent into containers GP-2023: missed a piece re firing add events GP-2023: fix for switching between non-program & program
This commit is contained in:
parent
672c1f11e2
commit
050391a391
40 changed files with 578 additions and 77 deletions
|
@ -224,6 +224,8 @@ public interface DebugDataSpaces {
|
||||||
|
|
||||||
DebugMemoryBasicInformation queryVirtual(long offset);
|
DebugMemoryBasicInformation queryVirtual(long offset);
|
||||||
|
|
||||||
|
long virtualToPhysical(long offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A shortcut for iterating over virtual memory regions.
|
* A shortcut for iterating over virtual memory regions.
|
||||||
*
|
*
|
||||||
|
@ -276,6 +278,9 @@ public interface DebugDataSpaces {
|
||||||
public DebugMemoryBasicInformation next() {
|
public DebugMemoryBasicInformation next() {
|
||||||
DebugMemoryBasicInformation ret = next;
|
DebugMemoryBasicInformation ret = next;
|
||||||
next = getNext();
|
next = getNext();
|
||||||
|
if (ret.equals(next)) {
|
||||||
|
next = null;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -268,4 +268,9 @@ public class DebugDataSpacesImpl1 implements DebugDataSpacesInternal {
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long virtualToPhysical(long offset) {
|
||||||
|
throw new UnsupportedOperationException("Not implemented in this interface");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package agent.dbgeng.impl.dbgeng.dataspaces;
|
package agent.dbgeng.impl.dbgeng.dataspaces;
|
||||||
|
|
||||||
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
||||||
|
import com.sun.jna.platform.win32.WinDef.ULONGLONGByReference;
|
||||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||||
|
|
||||||
|
@ -40,6 +41,9 @@ public class DebugDataSpacesImpl2 extends DebugDataSpacesImpl1 {
|
||||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
COMUtils.checkRC(hr);
|
COMUtils.checkRC(hr);
|
||||||
|
|
||||||
return new DebugMemoryBasicInformation(pInfo.BaseAddress.longValue(),
|
return new DebugMemoryBasicInformation(pInfo.BaseAddress.longValue(),
|
||||||
|
@ -49,4 +53,14 @@ public class DebugDataSpacesImpl2 extends DebugDataSpacesImpl1 {
|
||||||
new BitmaskSet<>(PageProtection.class, pInfo.Protect.intValue()),
|
new BitmaskSet<>(PageProtection.class, pInfo.Protect.intValue()),
|
||||||
PageType.byValue(pInfo.Type.intValue()));
|
PageType.byValue(pInfo.Type.intValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long virtualToPhysical(long offsetV) {
|
||||||
|
ULONGLONG ullOffset = new ULONGLONG(offsetV);
|
||||||
|
ULONGLONGByReference pulOffset = new ULONGLONGByReference();
|
||||||
|
HRESULT hr = jnaData.VirtualToPhysical(ullOffset, pulOffset);
|
||||||
|
COMUtils.checkRC(hr);
|
||||||
|
|
||||||
|
return pulOffset.getValue().longValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ package agent.dbgeng.jna.dbgeng.dataspaces;
|
||||||
|
|
||||||
import com.sun.jna.platform.win32.Guid.IID;
|
import com.sun.jna.platform.win32.Guid.IID;
|
||||||
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
||||||
|
import com.sun.jna.platform.win32.WinDef.ULONGLONGByReference;
|
||||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||||
|
|
||||||
import agent.dbgeng.jna.dbgeng.UnknownWithUtils.VTableIndex;
|
import agent.dbgeng.jna.dbgeng.UnknownWithUtils.VTableIndex;
|
||||||
|
@ -43,4 +44,6 @@ public interface IDebugDataSpaces2 extends IDebugDataSpaces {
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT QueryVirtual(ULONGLONG Offset, MEMORY_BASIC_INFORMATION64.ByReference Info);
|
HRESULT QueryVirtual(ULONGLONG Offset, MEMORY_BASIC_INFORMATION64.ByReference Info);
|
||||||
|
|
||||||
|
HRESULT VirtualToPhysical(ULONGLONG OffsetVirtual, ULONGLONGByReference OffsetPhysical);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package agent.dbgeng.jna.dbgeng.dataspaces;
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
import com.sun.jna.Structure;
|
import com.sun.jna.Structure;
|
||||||
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
||||||
|
import com.sun.jna.platform.win32.WinDef.ULONGLONGByReference;
|
||||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||||
|
|
||||||
import agent.dbgeng.jna.dbgeng.WinNTExtra.MEMORY_BASIC_INFORMATION64;
|
import agent.dbgeng.jna.dbgeng.WinNTExtra.MEMORY_BASIC_INFORMATION64;
|
||||||
|
@ -39,4 +40,11 @@ public class WrapIDebugDataSpaces2 extends WrapIDebugDataSpaces implements IDebu
|
||||||
public HRESULT QueryVirtual(ULONGLONG Offset, MEMORY_BASIC_INFORMATION64.ByReference Info) {
|
public HRESULT QueryVirtual(ULONGLONG Offset, MEMORY_BASIC_INFORMATION64.ByReference Info) {
|
||||||
return _invokeHR(VTIndices2.QUERY_VIRTUAL, getPointer(), Offset, Info);
|
return _invokeHR(VTIndices2.QUERY_VIRTUAL, getPointer(), Offset, Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HRESULT VirtualToPhysical(ULONGLONG OffsetVirtual, ULONGLONGByReference OffsetPhysical) {
|
||||||
|
return _invokeHR(VTIndices2.VIRTUAL_TO_PHYSICAL, getPointer(), OffsetVirtual,
|
||||||
|
OffsetPhysical);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class DbgListMappingsCommand extends AbstractDbgCommand<Map<Long, DbgSect
|
||||||
Msg.warn(this, "Resync: Was missing thread: " + id);
|
Msg.warn(this, "Resync: Was missing thread: " + id);
|
||||||
so.setCurrentThreadId(id);
|
so.setCurrentThreadId(id);
|
||||||
int tid = so.getCurrentThreadSystemId();
|
int tid = so.getCurrentThreadSystemId();
|
||||||
manager.getThreadComputeIfAbsent(id, process, tid);
|
manager.getThreadComputeIfAbsent(id, process, tid, false);
|
||||||
}
|
}
|
||||||
for (DebugThreadId id : new ArrayList<>(cur)) {
|
for (DebugThreadId id : new ArrayList<>(cur)) {
|
||||||
if (updatedThreadIds.contains(id)) {
|
if (updatedThreadIds.contains(id)) {
|
||||||
|
|
|
@ -40,12 +40,16 @@ public class DbgListMemoryRegionsCommand extends AbstractDbgCommand<List<DbgModu
|
||||||
@Override
|
@Override
|
||||||
public List<DbgModuleMemory> complete(DbgPendingCommand<?> pending) {
|
public List<DbgModuleMemory> complete(DbgPendingCommand<?> pending) {
|
||||||
Map<Long, DbgModuleMemory> memory = manager.getKnownMemoryRegions();
|
Map<Long, DbgModuleMemory> memory = manager.getKnownMemoryRegions();
|
||||||
|
if (memoryRegions.isEmpty()) {
|
||||||
|
Msg.error(this, "Switching to !address for memory");
|
||||||
|
manager.setAltMemoryQuery(true);
|
||||||
|
}
|
||||||
for (DbgModuleMemory region : memoryRegions) {
|
for (DbgModuleMemory region : memoryRegions) {
|
||||||
if (memory.containsValue(region)) {
|
if (memory.containsValue(region)) {
|
||||||
continue; // Do nothing, we're in sync
|
continue; // Do nothing, we're in sync
|
||||||
}
|
}
|
||||||
if (!memory.isEmpty()) {
|
if (!memory.isEmpty()) {
|
||||||
Msg.warn(this, "Resync: Was missing memory: " + region.getId());
|
Msg.warn(this, "Resync: Was missing memory: " + Long.toHexString(region.getId()));
|
||||||
}
|
}
|
||||||
manager.addMemory(region);
|
manager.addMemory(region);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
/* ###
|
||||||
|
* 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 agent.dbgeng.manager.cmd;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import agent.dbgeng.dbgeng.DebugControl;
|
||||||
|
import agent.dbgeng.dbgeng.DebugDataSpaces.PageState;
|
||||||
|
import agent.dbgeng.manager.DbgEvent;
|
||||||
|
import agent.dbgeng.manager.DbgModuleMemory;
|
||||||
|
import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent;
|
||||||
|
import agent.dbgeng.manager.evt.DbgConsoleOutputEvent;
|
||||||
|
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||||
|
import agent.dbgeng.manager.impl.DbgModuleMemoryImpl;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
|
public class DbgListMemoryRegionsCommandAlt extends AbstractDbgCommand<List<DbgModuleMemory>> {
|
||||||
|
|
||||||
|
private List<DbgModuleMemory> memoryRegions = new ArrayList<>();
|
||||||
|
|
||||||
|
public DbgListMemoryRegionsCommandAlt(DbgManagerImpl manager) {
|
||||||
|
super(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(DbgEvent<?> evt, DbgPendingCommand<?> pending) {
|
||||||
|
if (evt instanceof AbstractDbgCompletedCommandEvent && pending.getCommand().equals(this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (evt instanceof DbgConsoleOutputEvent) {
|
||||||
|
pending.steal(evt);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DbgModuleMemory> complete(DbgPendingCommand<?> pending) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (DbgConsoleOutputEvent out : pending.findAllOf(DbgConsoleOutputEvent.class)) {
|
||||||
|
builder.append(out.getOutput());
|
||||||
|
}
|
||||||
|
parse(builder.toString());
|
||||||
|
|
||||||
|
Map<Long, DbgModuleMemory> memory = manager.getKnownMemoryRegions();
|
||||||
|
for (DbgModuleMemory region : memoryRegions) {
|
||||||
|
if (memory.containsValue(region)) {
|
||||||
|
continue; // Do nothing, we're in sync
|
||||||
|
}
|
||||||
|
if (!memory.isEmpty()) {
|
||||||
|
Msg.warn(this, "Resync: Was missing memory: " + Long.toHexString(region.getId()));
|
||||||
|
}
|
||||||
|
manager.addMemory(region);
|
||||||
|
}
|
||||||
|
List<Long> toRemove = new ArrayList<>();
|
||||||
|
for (Entry<Long, DbgModuleMemory> entry : memory.entrySet()) {
|
||||||
|
if (memoryRegions.contains(entry.getValue())) {
|
||||||
|
continue; // Do nothing, we're in sync
|
||||||
|
}
|
||||||
|
toRemove.add(entry.getKey());
|
||||||
|
}
|
||||||
|
for (Long key : toRemove) {
|
||||||
|
manager.removeMemory(key);
|
||||||
|
}
|
||||||
|
return memoryRegions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parse(String result) {
|
||||||
|
String[] lines = result.split("\n");
|
||||||
|
for (String line : lines) {
|
||||||
|
if (line.startsWith("Mapping")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String[] fields = line.trim().split("\\s+");
|
||||||
|
if (fields.length < 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String start = fields[0].replaceAll("`", "");
|
||||||
|
String end = fields[1].replaceAll("`", "");
|
||||||
|
long startVal, endVal;
|
||||||
|
try {
|
||||||
|
startVal = Long.parseUnsignedLong(start, 16);
|
||||||
|
endVal = Long.parseUnsignedLong(end, 16);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = fields[3];
|
||||||
|
ArrayList<String> protect = new ArrayList<String>();
|
||||||
|
DbgModuleMemoryImpl region = new DbgModuleMemoryImpl(start, startVal, endVal, startVal,
|
||||||
|
protect, protect, PageState.COMMIT, name, true, true, true);
|
||||||
|
memoryRegions.add(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke() {
|
||||||
|
DebugControl control = manager.getControl();
|
||||||
|
control.execute("!address");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ public class DbgListProcessesCommand extends AbstractDbgCommand<Map<DebugProcess
|
||||||
DebugSystemObjects so = manager.getSystemObjects();
|
DebugSystemObjects so = manager.getSystemObjects();
|
||||||
so.setCurrentProcessId(id);
|
so.setCurrentProcessId(id);
|
||||||
int pid = so.getCurrentProcessSystemId();
|
int pid = so.getCurrentProcessSystemId();
|
||||||
manager.getProcessComputeIfAbsent(id, pid);
|
manager.getProcessComputeIfAbsent(id, pid, true);
|
||||||
}
|
}
|
||||||
for (DebugProcessId id : new ArrayList<>(cur)) {
|
for (DebugProcessId id : new ArrayList<>(cur)) {
|
||||||
if (updatedProcessIds.contains(id)) {
|
if (updatedProcessIds.contains(id)) {
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class DbgListSessionsCommand extends AbstractDbgCommand<Map<DebugSessionI
|
||||||
}
|
}
|
||||||
// Need to create the inferior as if we received =thread-group-created
|
// Need to create the inferior as if we received =thread-group-created
|
||||||
Msg.warn(this, "Resync: Was missing group: i" + id);
|
Msg.warn(this, "Resync: Was missing group: i" + id);
|
||||||
manager.getSessionComputeIfAbsent(id);
|
manager.getSessionComputeIfAbsent(id, true);
|
||||||
}
|
}
|
||||||
for (DebugSessionId id : new ArrayList<>(cur)) {
|
for (DebugSessionId id : new ArrayList<>(cur)) {
|
||||||
if (updatedSessionIds.contains(id)) {
|
if (updatedSessionIds.contains(id)) {
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class DbgListThreadsCommand extends AbstractDbgCommand<Map<DebugThreadId,
|
||||||
DebugSystemObjects so = manager.getSystemObjects();
|
DebugSystemObjects so = manager.getSystemObjects();
|
||||||
so.setCurrentThreadId(id);
|
so.setCurrentThreadId(id);
|
||||||
int tid = so.getCurrentThreadSystemId();
|
int tid = so.getCurrentThreadSystemId();
|
||||||
manager.getThreadComputeIfAbsent(id, process, tid);
|
manager.getThreadComputeIfAbsent(id, process, tid, false);
|
||||||
}
|
}
|
||||||
for (DebugThreadId id : new ArrayList<>(cur)) {
|
for (DebugThreadId id : new ArrayList<>(cur)) {
|
||||||
if (updatedThreadIds.contains(id)) {
|
if (updatedThreadIds.contains(id)) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
|
|
||||||
|
import agent.dbgeng.dbgeng.DebugDataSpaces;
|
||||||
import agent.dbgeng.manager.DbgThread;
|
import agent.dbgeng.manager.DbgThread;
|
||||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@ public class DbgReadMemoryCommand extends AbstractDbgCommand<RangeSet<Long>> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke() {
|
public void invoke() {
|
||||||
readLen = manager.getDataSpaces().readVirtual(addr, buf, len);
|
DebugDataSpaces dataSpaces = manager.getDataSpaces();
|
||||||
|
readLen = dataSpaces.readVirtual(addr, buf, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||||
private DbgThread eventThread;
|
private DbgThread eventThread;
|
||||||
private volatile boolean waiting = false;
|
private volatile boolean waiting = false;
|
||||||
private boolean kernelMode = false;
|
private boolean kernelMode = false;
|
||||||
|
private boolean altMemoryQuery = false;
|
||||||
private boolean ignoreEventThread = false;
|
private boolean ignoreEventThread = false;
|
||||||
private CompletableFuture<String> continuation;
|
private CompletableFuture<String> continuation;
|
||||||
private long processCount = 0;
|
private long processCount = 0;
|
||||||
|
@ -139,11 +140,16 @@ public class DbgManagerImpl implements DbgManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbgThreadImpl getThreadComputeIfAbsent(DebugThreadId id, DbgProcessImpl process,
|
public DbgThreadImpl getThreadComputeIfAbsent(DebugThreadId id, DbgProcessImpl process,
|
||||||
int tid) {
|
int tid, boolean fire) {
|
||||||
synchronized (threads) {
|
synchronized (threads) {
|
||||||
if (!threads.containsKey(id)) {
|
if (!threads.containsKey(id)) {
|
||||||
DbgThreadImpl thread = new DbgThreadImpl(this, process, id, tid);
|
DbgThreadImpl thread = new DbgThreadImpl(this, process, id, tid);
|
||||||
thread.add();
|
thread.add();
|
||||||
|
if (fire) {
|
||||||
|
Causes cause = DbgCause.Causes.UNCLAIMED;
|
||||||
|
getEventListeners().fire.threadCreated(thread, cause);
|
||||||
|
getEventListeners().fire.threadSelected(thread, null, cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return threads.get(id);
|
return threads.get(id);
|
||||||
}
|
}
|
||||||
|
@ -208,11 +214,14 @@ public class DbgManagerImpl implements DbgManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbgProcessImpl getProcessComputeIfAbsent(DebugProcessId id, int pid) {
|
public DbgProcessImpl getProcessComputeIfAbsent(DebugProcessId id, int pid, boolean fire) {
|
||||||
synchronized (processes) {
|
synchronized (processes) {
|
||||||
if (!processes.containsKey(id)) {
|
if (!processes.containsKey(id)) {
|
||||||
DbgProcessImpl process = new DbgProcessImpl(this, id, pid);
|
DbgProcessImpl process = new DbgProcessImpl(this, id, pid);
|
||||||
process.add();
|
process.add();
|
||||||
|
if (fire) {
|
||||||
|
getEventListeners().fire.processAdded(process, DbgCause.Causes.UNCLAIMED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return processes.get(id);
|
return processes.get(id);
|
||||||
}
|
}
|
||||||
|
@ -245,11 +254,14 @@ public class DbgManagerImpl implements DbgManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbgSessionImpl getSessionComputeIfAbsent(DebugSessionId id) {
|
public DbgSessionImpl getSessionComputeIfAbsent(DebugSessionId id, boolean fire) {
|
||||||
synchronized (sessions) {
|
synchronized (sessions) {
|
||||||
if (!sessions.containsKey(id) && id.id >= 0) {
|
if (!sessions.containsKey(id) && id.id >= 0) {
|
||||||
DbgSessionImpl session = new DbgSessionImpl(this, id);
|
DbgSessionImpl session = new DbgSessionImpl(this, id);
|
||||||
session.add();
|
session.add();
|
||||||
|
if (fire) {
|
||||||
|
getEventListeners().fire.sessionAdded(session, DbgCause.Causes.UNCLAIMED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sessions.get(id);
|
return sessions.get(id);
|
||||||
}
|
}
|
||||||
|
@ -635,11 +647,11 @@ public class DbgManagerImpl implements DbgManager {
|
||||||
lastEventInformation = control.getLastEventInformation();
|
lastEventInformation = control.getLastEventInformation();
|
||||||
lastEventInformation.setSession(esid);
|
lastEventInformation.setSession(esid);
|
||||||
lastEventInformation.setExecutingProcessorType(execType);
|
lastEventInformation.setExecutingProcessorType(execType);
|
||||||
currentSession = eventSession = getSessionComputeIfAbsent(esid);
|
currentSession = eventSession = getSessionComputeIfAbsent(esid, true);
|
||||||
currentProcess =
|
currentProcess =
|
||||||
eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId());
|
eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId(), true);
|
||||||
currentThread = eventThread = getThreadComputeIfAbsent(etid, (DbgProcessImpl) eventProcess,
|
currentThread = eventThread = getThreadComputeIfAbsent(etid, (DbgProcessImpl) eventProcess,
|
||||||
so.getCurrentThreadSystemId());
|
so.getCurrentThreadSystemId(), false);
|
||||||
if (eventThread != null) {
|
if (eventThread != null) {
|
||||||
((DbgThreadImpl) eventThread).setInfo(lastEventInformation);
|
((DbgThreadImpl) eventThread).setInfo(lastEventInformation);
|
||||||
}
|
}
|
||||||
|
@ -714,9 +726,9 @@ public class DbgManagerImpl implements DbgManager {
|
||||||
DebugThreadId eventId = updateState();
|
DebugThreadId eventId = updateState();
|
||||||
DbgProcessImpl process = getCurrentProcess();
|
DbgProcessImpl process = getCurrentProcess();
|
||||||
int tid = so.getCurrentThreadSystemId();
|
int tid = so.getCurrentThreadSystemId();
|
||||||
DbgThreadImpl thread = getThreadComputeIfAbsent(eventId, process, tid);
|
DbgThreadImpl thread = getThreadComputeIfAbsent(eventId, process, tid, true);
|
||||||
getEventListeners().fire.eventSelected(evt, evt.getCause());
|
getEventListeners().fire.eventSelected(evt, evt.getCause());
|
||||||
getEventListeners().fire.threadCreated(thread, DbgCause.Causes.UNCLAIMED);
|
//getEventListeners().fire.threadCreated(thread, DbgCause.Causes.UNCLAIMED);
|
||||||
getEventListeners().fire.threadSelected(thread, null, evt.getCause());
|
getEventListeners().fire.threadSelected(thread, null, evt.getCause());
|
||||||
|
|
||||||
String key = Integer.toHexString(eventId.id);
|
String key = Integer.toHexString(eventId.id);
|
||||||
|
@ -789,7 +801,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||||
DebugProcessId id = so.getProcessIdByHandle(handle);
|
DebugProcessId id = so.getProcessIdByHandle(handle);
|
||||||
//so.setCurrentProcessId(id);
|
//so.setCurrentProcessId(id);
|
||||||
int pid = so.getCurrentProcessSystemId();
|
int pid = so.getCurrentProcessSystemId();
|
||||||
DbgProcessImpl proc = getProcessComputeIfAbsent(id, pid);
|
DbgProcessImpl proc = getProcessComputeIfAbsent(id, pid, true);
|
||||||
getEventListeners().fire.eventSelected(evt, evt.getCause());
|
getEventListeners().fire.eventSelected(evt, evt.getCause());
|
||||||
getEventListeners().fire.processAdded(proc, evt.getCause());
|
getEventListeners().fire.processAdded(proc, evt.getCause());
|
||||||
getEventListeners().fire.processSelected(proc, evt.getCause());
|
getEventListeners().fire.processSelected(proc, evt.getCause());
|
||||||
|
@ -797,9 +809,9 @@ public class DbgManagerImpl implements DbgManager {
|
||||||
handle = info.initialThreadInfo.handle;
|
handle = info.initialThreadInfo.handle;
|
||||||
DebugThreadId idt = so.getThreadIdByHandle(handle);
|
DebugThreadId idt = so.getThreadIdByHandle(handle);
|
||||||
int tid = so.getCurrentThreadSystemId();
|
int tid = so.getCurrentThreadSystemId();
|
||||||
DbgThreadImpl thread = getThreadComputeIfAbsent(idt, proc, tid);
|
getThreadComputeIfAbsent(idt, proc, tid, true);
|
||||||
getEventListeners().fire.threadCreated(thread, evt.getCause());
|
//getEventListeners().fire.threadCreated(thread, evt.getCause());
|
||||||
getEventListeners().fire.threadSelected(thread, null, evt.getCause());
|
//getEventListeners().fire.threadSelected(thread, null, evt.getCause());
|
||||||
|
|
||||||
//proc.moduleLoaded(info.moduleInfo);
|
//proc.moduleLoaded(info.moduleInfo);
|
||||||
//getEventListeners().fire.moduleLoaded(proc, info.moduleInfo, evt.getCause());
|
//getEventListeners().fire.moduleLoaded(proc, info.moduleInfo, evt.getCause());
|
||||||
|
@ -1606,6 +1618,14 @@ public class DbgManagerImpl implements DbgManager {
|
||||||
this.kernelMode = kernelMode;
|
this.kernelMode = kernelMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean useAltMemoryQuery() {
|
||||||
|
return altMemoryQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAltMemoryQuery(boolean altMemoryQuery) {
|
||||||
|
this.altMemoryQuery = altMemoryQuery;
|
||||||
|
}
|
||||||
|
|
||||||
public void setContinuation(CompletableFuture<String> continuation) {
|
public void setContinuation(CompletableFuture<String> continuation) {
|
||||||
this.continuation = continuation;
|
this.continuation = continuation;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class DbgSessionImpl implements DbgSession {
|
||||||
*/
|
*/
|
||||||
public void add() {
|
public void add() {
|
||||||
manager.sessions.put(id, this);
|
manager.sessions.put(id, this);
|
||||||
manager.getEventListeners().fire.sessionAdded(this, DbgCause.Causes.UNCLAIMED);
|
//manager.getEventListeners().fire.sessionAdded(this, DbgCause.Causes.UNCLAIMED);
|
||||||
//manager.addSession(this, cause);
|
//manager.addSession(this, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,4 +44,6 @@ public abstract class AbstractDbgModel extends AbstractDebuggerObjectModel {
|
||||||
|
|
||||||
public abstract void deleteModelObject(Object object);
|
public abstract void deleteModelObject(Object object);
|
||||||
|
|
||||||
|
public abstract boolean isSuppressDescent();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,10 @@ public interface DbgModelTargetProcess extends //
|
||||||
public void threadStateChangedSpecific(DbgThread thread, DbgState state);
|
public void threadStateChangedSpecific(DbgThread thread, DbgState state);
|
||||||
|
|
||||||
public default DbgProcess getProcess() {
|
public default DbgProcess getProcess() {
|
||||||
|
return getProcess(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public default DbgProcess getProcess(boolean fire) {
|
||||||
DbgManagerImpl manager = getManager();
|
DbgManagerImpl manager = getManager();
|
||||||
DebugSystemObjects so = manager.getSystemObjects();
|
DebugSystemObjects so = manager.getSystemObjects();
|
||||||
try {
|
try {
|
||||||
|
@ -62,7 +66,7 @@ public interface DbgModelTargetProcess extends //
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
id = so.getCurrentProcessId();
|
id = so.getCurrentProcessId();
|
||||||
}
|
}
|
||||||
return manager.getProcessComputeIfAbsent(id, pid);
|
return manager.getProcessComputeIfAbsent(id, pid, fire);
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
return manager.getCurrentProcess();
|
return manager.getCurrentProcess();
|
||||||
|
|
|
@ -44,12 +44,16 @@ public interface DbgModelTargetSession extends //
|
||||||
DbgModelTargetProcessContainer getProcesses();
|
DbgModelTargetProcessContainer getProcesses();
|
||||||
|
|
||||||
public default DbgSession getSession() {
|
public default DbgSession getSession() {
|
||||||
|
return getSession(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public default DbgSession getSession(boolean fire) {
|
||||||
DbgManagerImpl manager = getManager();
|
DbgManagerImpl manager = getManager();
|
||||||
try {
|
try {
|
||||||
String index = PathUtils.parseIndex(getName());
|
String index = PathUtils.parseIndex(getName());
|
||||||
Integer sid = Integer.decode(index);
|
Integer sid = Integer.decode(index);
|
||||||
DebugSessionId id = new DebugSessionId(sid);
|
DebugSessionId id = new DebugSessionId(sid);
|
||||||
return manager.getSessionComputeIfAbsent(id);
|
return manager.getSessionComputeIfAbsent(id, fire);
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
return manager.getCurrentSession();
|
return manager.getCurrentSession();
|
||||||
|
|
|
@ -35,6 +35,10 @@ public interface DbgModelTargetThread extends //
|
||||||
DbgModelSelectableObject {
|
DbgModelSelectableObject {
|
||||||
|
|
||||||
public default DbgThread getThread() {
|
public default DbgThread getThread() {
|
||||||
|
return getThread(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public default DbgThread getThread(boolean fire) {
|
||||||
DbgManagerImpl manager = getManager();
|
DbgManagerImpl manager = getManager();
|
||||||
DebugSystemObjects so = manager.getSystemObjects();
|
DebugSystemObjects so = manager.getSystemObjects();
|
||||||
try {
|
try {
|
||||||
|
@ -46,7 +50,7 @@ public interface DbgModelTargetThread extends //
|
||||||
}
|
}
|
||||||
DbgModelTargetProcess parentProcess = getParentProcess();
|
DbgModelTargetProcess parentProcess = getParentProcess();
|
||||||
DbgProcessImpl process = (DbgProcessImpl) parentProcess.getProcess();
|
DbgProcessImpl process = (DbgProcessImpl) parentProcess.getProcess();
|
||||||
DbgThreadImpl thread = manager.getThreadComputeIfAbsent(id, process, tid);
|
DbgThreadImpl thread = manager.getThreadComputeIfAbsent(id, process, tid, fire);
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
|
|
|
@ -54,21 +54,21 @@ public class DbgModelImpl extends AbstractDbgModel implements DebuggerObjectMode
|
||||||
protected final AddressFactory addressFactory =
|
protected final AddressFactory addressFactory =
|
||||||
new DefaultAddressFactory(new AddressSpace[] { space });
|
new DefaultAddressFactory(new AddressSpace[] { space });
|
||||||
|
|
||||||
protected final DbgManager dbg;
|
protected final DbgManagerImpl dbg;
|
||||||
protected final DbgModelTargetRootImpl root;
|
protected final DbgModelTargetRootImpl root;
|
||||||
protected final DbgModelTargetSessionImpl session;
|
protected final DbgModelTargetSessionImpl session;
|
||||||
|
|
||||||
protected final CompletableFuture<DbgModelTargetRootImpl> completedRoot;
|
protected final CompletableFuture<DbgModelTargetRootImpl> completedRoot;
|
||||||
|
|
||||||
protected Map<Object, TargetObject> objectMap = new HashMap<>();
|
protected Map<Object, TargetObject> objectMap = new HashMap<>();
|
||||||
|
private boolean suppressDescent = false;
|
||||||
|
|
||||||
public DbgModelImpl() {
|
public DbgModelImpl() {
|
||||||
this.dbg = DbgManager.newInstance();
|
this.dbg = (DbgManagerImpl) DbgManager.newInstance();
|
||||||
//System.out.println(XmlSchemaContext.serialize(SCHEMA_CTX));
|
//System.out.println(XmlSchemaContext.serialize(SCHEMA_CTX));
|
||||||
this.root = new DbgModelTargetRootImpl(this, ROOT_SCHEMA);
|
this.root = new DbgModelTargetRootImpl(this, ROOT_SCHEMA);
|
||||||
this.completedRoot = CompletableFuture.completedFuture(root);
|
this.completedRoot = CompletableFuture.completedFuture(root);
|
||||||
DbgSessionImpl s = new DbgSessionImpl((DbgManagerImpl) dbg, new DebugSessionId(0));
|
DbgSessionImpl s = dbg.getSessionComputeIfAbsent(new DebugSessionId(0), true);
|
||||||
s.add();
|
|
||||||
DbgModelTargetSessionContainer sessions = root.sessions;
|
DbgModelTargetSessionContainer sessions = root.sessions;
|
||||||
this.session = (DbgModelTargetSessionImpl) sessions.getTargetSession(s);
|
this.session = (DbgModelTargetSessionImpl) sessions.getTargetSession(s);
|
||||||
addModelRoot(root);
|
addModelRoot(root);
|
||||||
|
@ -180,4 +180,12 @@ public class DbgModelImpl extends AbstractDbgModel implements DebuggerObjectMode
|
||||||
return ExceptionUtils.rethrow(ex);
|
return ExceptionUtils.rethrow(ex);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSuppressDescent() {
|
||||||
|
return suppressDescent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuppressDescent(boolean suppressDescent) {
|
||||||
|
this.suppressDescent = suppressDescent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.stream.Collectors;
|
||||||
import agent.dbgeng.manager.DbgEventFilter;
|
import agent.dbgeng.manager.DbgEventFilter;
|
||||||
import agent.dbgeng.manager.cmd.DbgListEventFiltersCommand;
|
import agent.dbgeng.manager.cmd.DbgListEventFiltersCommand;
|
||||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||||
|
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||||
import agent.dbgeng.model.iface2.*;
|
import agent.dbgeng.model.iface2.*;
|
||||||
import ghidra.async.AsyncUtils;
|
import ghidra.async.AsyncUtils;
|
||||||
import ghidra.dbg.target.TargetObject;
|
import ghidra.dbg.target.TargetObject;
|
||||||
|
@ -53,7 +54,9 @@ public class DbgModelTargetEventContainerImpl extends DbgModelTargetObjectImpl
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> requestElements(boolean refresh) {
|
public CompletableFuture<Void> requestElements(boolean refresh) {
|
||||||
DbgModelTargetProcess targetProcess = getParentProcess();
|
DbgModelTargetProcess targetProcess = getParentProcess();
|
||||||
if (!refresh || !targetProcess.getProcess().equals(getManager().getCurrentProcess())) {
|
DbgProcessImpl currentProcess = getManager().getCurrentProcess();
|
||||||
|
if (!refresh ||
|
||||||
|
(currentProcess != null && !currentProcess.equals(targetProcess.getProcess()))) {
|
||||||
return AsyncUtils.NIL;
|
return AsyncUtils.NIL;
|
||||||
}
|
}
|
||||||
return listEventFilters().thenAccept(byName -> {
|
return listEventFilters().thenAccept(byName -> {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.stream.Collectors;
|
||||||
import agent.dbgeng.manager.DbgExceptionFilter;
|
import agent.dbgeng.manager.DbgExceptionFilter;
|
||||||
import agent.dbgeng.manager.cmd.DbgListExceptionFiltersCommand;
|
import agent.dbgeng.manager.cmd.DbgListExceptionFiltersCommand;
|
||||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||||
|
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||||
import agent.dbgeng.model.iface2.*;
|
import agent.dbgeng.model.iface2.*;
|
||||||
import ghidra.async.AsyncUtils;
|
import ghidra.async.AsyncUtils;
|
||||||
import ghidra.dbg.target.TargetObject;
|
import ghidra.dbg.target.TargetObject;
|
||||||
|
@ -53,7 +54,9 @@ public class DbgModelTargetExceptionContainerImpl extends DbgModelTargetObjectIm
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> requestElements(boolean refresh) {
|
public CompletableFuture<Void> requestElements(boolean refresh) {
|
||||||
DbgModelTargetProcess targetProcess = getParentProcess();
|
DbgModelTargetProcess targetProcess = getParentProcess();
|
||||||
if (!refresh || !targetProcess.getProcess().equals(getManager().getCurrentProcess())) {
|
DbgProcessImpl currentProcess = getManager().getCurrentProcess();
|
||||||
|
if (!refresh ||
|
||||||
|
(currentProcess != null && !currentProcess.equals(targetProcess.getProcess()))) {
|
||||||
return AsyncUtils.NIL;
|
return AsyncUtils.NIL;
|
||||||
}
|
}
|
||||||
return listExceptionFilters().thenAccept(byName -> {
|
return listExceptionFilters().thenAccept(byName -> {
|
||||||
|
|
|
@ -26,6 +26,7 @@ import com.google.common.collect.RangeSet;
|
||||||
import agent.dbgeng.manager.DbgModuleMemory;
|
import agent.dbgeng.manager.DbgModuleMemory;
|
||||||
import agent.dbgeng.manager.cmd.*;
|
import agent.dbgeng.manager.cmd.*;
|
||||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||||
|
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||||
import agent.dbgeng.model.iface2.*;
|
import agent.dbgeng.model.iface2.*;
|
||||||
import ghidra.async.AsyncUtils;
|
import ghidra.async.AsyncUtils;
|
||||||
import ghidra.dbg.error.DebuggerMemoryAccessException;
|
import ghidra.dbg.error.DebuggerMemoryAccessException;
|
||||||
|
@ -53,13 +54,17 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
|
||||||
public DbgModelTargetMemoryContainerImpl(DbgModelTargetProcess process) {
|
public DbgModelTargetMemoryContainerImpl(DbgModelTargetProcess process) {
|
||||||
super(process.getModel(), process, "Memory", "MemoryContainer");
|
super(process.getModel(), process, "Memory", "MemoryContainer");
|
||||||
this.process = process;
|
this.process = process;
|
||||||
requestElements(true);
|
if (!getModel().isSuppressDescent()) {
|
||||||
|
requestElements(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> requestElements(boolean refresh) {
|
public CompletableFuture<Void> requestElements(boolean refresh) {
|
||||||
DbgModelTargetProcess targetProcess = getParentProcess();
|
DbgModelTargetProcess targetProcess = getParentProcess();
|
||||||
if (!refresh || !targetProcess.getProcess().equals(getManager().getCurrentProcess())) {
|
DbgProcessImpl currentProcess = getManager().getCurrentProcess();
|
||||||
|
if (!refresh ||
|
||||||
|
(currentProcess != null && !currentProcess.equals(targetProcess.getProcess()))) {
|
||||||
return AsyncUtils.NIL;
|
return AsyncUtils.NIL;
|
||||||
}
|
}
|
||||||
return listMemory().thenAccept(byName -> {
|
return listMemory().thenAccept(byName -> {
|
||||||
|
@ -90,6 +95,9 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
|
||||||
if (manager.isKernelMode()) {
|
if (manager.isKernelMode()) {
|
||||||
return manager.execute(new DbgListKernelMemoryRegionsCommand(manager));
|
return manager.execute(new DbgListKernelMemoryRegionsCommand(manager));
|
||||||
}
|
}
|
||||||
|
if (manager.useAltMemoryQuery()) {
|
||||||
|
return manager.execute(new DbgListMemoryRegionsCommandAlt(manager));
|
||||||
|
}
|
||||||
return manager.execute(new DbgListMemoryRegionsCommand(manager));
|
return manager.execute(new DbgListMemoryRegionsCommand(manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,9 @@ public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl
|
||||||
super(process.getModel(), process, "Modules", "ModuleContainer");
|
super(process.getModel(), process, "Modules", "ModuleContainer");
|
||||||
this.targetProcess = process;
|
this.targetProcess = process;
|
||||||
this.process = process.process;
|
this.process = process.process;
|
||||||
requestElements(false);
|
if (!getModel().isSuppressDescent()) {
|
||||||
|
requestElements(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -121,7 +121,11 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
|
||||||
return "[kernel]";
|
return "[kernel]";
|
||||||
}
|
}
|
||||||
|
|
||||||
String pidstr = Long.toString(process.getPid(), base);
|
Long pid = process.getPid();
|
||||||
|
if (pid < 0) {
|
||||||
|
return "[" + process.getId().id + "]";
|
||||||
|
}
|
||||||
|
String pidstr = Long.toString(pid, base);
|
||||||
if (base == 16) {
|
if (base == 16) {
|
||||||
pidstr = "0x" + pidstr;
|
pidstr = "0x" + pidstr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,10 +55,12 @@ public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImp
|
||||||
super(thread.getModel(), thread, "Registers", "RegisterContainer");
|
super(thread.getModel(), thread, "Registers", "RegisterContainer");
|
||||||
this.thread = thread.getThread();
|
this.thread = thread.getThread();
|
||||||
|
|
||||||
requestElements(false);
|
if (!getModel().isSuppressDescent()) {
|
||||||
changeAttributes(List.of(), List.of(), Map.of( //
|
requestElements(false);
|
||||||
TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME, this //
|
changeAttributes(List.of(), List.of(), Map.of( //
|
||||||
), "Initialized");
|
TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME, this //
|
||||||
|
), "Initialized");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -129,7 +131,20 @@ public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImp
|
||||||
BigInteger value = vals.get(dbgReg);
|
BigInteger value = vals.get(dbgReg);
|
||||||
byte[] bytes = ConversionUtils.bigIntegerToBytes(dbgReg.getSize(), value);
|
byte[] bytes = ConversionUtils.bigIntegerToBytes(dbgReg.getSize(), value);
|
||||||
result.put(dbgReg.getName(), bytes);
|
result.put(dbgReg.getName(), bytes);
|
||||||
|
<<<<<<< Upstream, based on origin/master
|
||||||
changeAttrs(reg, value);
|
changeAttrs(reg, value);
|
||||||
|
=======
|
||||||
|
reg.changeAttributes(List.of(), Map.of( //
|
||||||
|
VALUE_ATTRIBUTE_NAME, value.toString(16) //
|
||||||
|
), "Refreshed");
|
||||||
|
if (value.longValue() != 0) {
|
||||||
|
String newval = reg.getName() + " : " + Long.toHexString(value.longValue());
|
||||||
|
reg.changeAttributes(List.of(), Map.of( //
|
||||||
|
DISPLAY_ATTRIBUTE_NAME, newval //
|
||||||
|
), "Refreshed");
|
||||||
|
reg.setModified(!value.toString(16).equals(oldval));
|
||||||
|
}
|
||||||
|
>>>>>>> 3de71f3 GP-2023 This is a combination of 15 commits. GP-2023: fix for endless region iterator
|
||||||
}
|
}
|
||||||
this.values = result;
|
this.values = result;
|
||||||
listeners.fire.registersUpdated(getProxy(), result);
|
listeners.fire.registersUpdated(getProxy(), result);
|
||||||
|
|
|
@ -48,7 +48,9 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl
|
||||||
this.changeAttributes(List.of(), Map.of(BASE_ATTRIBUTE_NAME, 16), "Initialized");
|
this.changeAttributes(List.of(), Map.of(BASE_ATTRIBUTE_NAME, 16), "Initialized");
|
||||||
|
|
||||||
getManager().addEventsListener(this);
|
getManager().addEventsListener(this);
|
||||||
requestElements(false);
|
if (!getModel().isSuppressDescent()) {
|
||||||
|
requestElements(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -109,7 +109,11 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
|
||||||
if (getManager().isKernelMode()) {
|
if (getManager().isKernelMode()) {
|
||||||
return "[PR" + thread.getId().id + "]";
|
return "[PR" + thread.getId().id + "]";
|
||||||
}
|
}
|
||||||
String tidstr = Long.toString(thread.getTid(), base);
|
Long tid = thread.getTid();
|
||||||
|
if (tid < 0) {
|
||||||
|
return "[" + thread.getId().id + "]";
|
||||||
|
}
|
||||||
|
String tidstr = Long.toString(tid, base);
|
||||||
if (base == 16) {
|
if (base == 16) {
|
||||||
tidstr = "0x" + tidstr;
|
tidstr = "0x" + tidstr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package agent.dbgeng.model.impl;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||||
import agent.dbgeng.model.iface2.DbgModelTargetConnector;
|
import agent.dbgeng.model.iface2.DbgModelTargetConnector;
|
||||||
import ghidra.async.AsyncUtils;
|
import ghidra.async.AsyncUtils;
|
||||||
import ghidra.async.TypeSpec;
|
import ghidra.async.TypeSpec;
|
||||||
|
@ -66,8 +67,12 @@ public class DbgModelTargetTraceOrDumpConnectorImpl extends DbgModelTargetObject
|
||||||
true, ".opendump", "Cmd", "native loader command");
|
true, ".opendump", "Cmd", "native loader command");
|
||||||
ParameterDescription<String> p2 = ParameterDescription.create(String.class, "TraceOrDump",
|
ParameterDescription<String> p2 = ParameterDescription.create(String.class, "TraceOrDump",
|
||||||
true, "", "File", "trace or dump to be loaded");
|
true, "", "File", "trace or dump to be loaded");
|
||||||
|
ParameterDescription<Boolean> p3 = ParameterDescription.create(Boolean.class,
|
||||||
|
"UseQueryVirtual", false, true, "QueryVirtual", "use QueryVirtual (vs. !address)");
|
||||||
map.put("CommandLine", p1);
|
map.put("CommandLine", p1);
|
||||||
map.put("TraceOrDump", p2);
|
map.put("TraceOrDump", p2);
|
||||||
|
// For the moment, we'll leave this out (deadlocks the GUI)
|
||||||
|
//map.put("UseQueryVirtual", p3);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +84,12 @@ public class DbgModelTargetTraceOrDumpConnectorImpl extends DbgModelTargetObject
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> launch(Map<String, ?> args) {
|
public CompletableFuture<Void> launch(Map<String, ?> args) {
|
||||||
return AsyncUtils.sequence(TypeSpec.VOID).then(seq -> {
|
return AsyncUtils.sequence(TypeSpec.VOID).then(seq -> {
|
||||||
getManager().openFile(args).handle(seq::nextIgnore);
|
DbgManagerImpl manager = getManager();
|
||||||
|
Boolean qv = (Boolean) args.get("UseQueryVirtual");
|
||||||
|
if (qv != null) {
|
||||||
|
manager.setAltMemoryQuery(!qv);
|
||||||
|
}
|
||||||
|
manager.openFile(args).handle(seq::nextIgnore);
|
||||||
}).finish().exceptionally((exc) -> {
|
}).finish().exceptionally((exc) -> {
|
||||||
throw new DebuggerUserException("Launch failed for " + args);
|
throw new DebuggerUserException("Launch failed for " + args);
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
/* ###
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
import com.google.common.collect.Range;
|
||||||
|
|
||||||
|
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||||
|
import agent.dbgeng.model.AbstractDbgModel;
|
||||||
|
import ghidra.app.script.GhidraScript;
|
||||||
|
import ghidra.app.services.DebuggerModelService;
|
||||||
|
import ghidra.app.services.DebuggerTraceManagerService;
|
||||||
|
import ghidra.dbg.DebuggerObjectModel;
|
||||||
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.lang.Language;
|
||||||
|
import ghidra.trace.model.Trace;
|
||||||
|
import ghidra.trace.model.memory.*;
|
||||||
|
import ghidra.util.LockHold;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.database.UndoableTransaction;
|
||||||
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This script populates a trace database with memory derived from "!address". This is particularly
|
||||||
|
* useful for dump files and other cases where QueryVirtual fails.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Your current tool had better be the "TraceBrowser"! The demonstration serves two purposes. 1) It
|
||||||
|
* puts interesting data into the TraceBrowser and leaves some annotations as an exercise. 2) It
|
||||||
|
* demonstrates how a decent portion the Trace API works.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* A Trace is basically a collection of observations of memory and registers over the lifetime of an
|
||||||
|
* application or computer system. In Ghidra, the Trace object also supports many of the same
|
||||||
|
* annotations as does Program. In the same way that Program brings knowledge markup to an image of
|
||||||
|
* bytes, Trace brings knowledge markup to bytes observed over time.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BangAddressToMemory extends GhidraScript {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Memory APIs all use Java NIO ByteBuffer. While it has it can sometimes be annoying, it
|
||||||
|
* provides most of the conveniences you'd need for packing arbitrary data into a memory buffer.
|
||||||
|
* I'll allocate one here large enough to write a couple values at a time.
|
||||||
|
*/
|
||||||
|
private ByteBuffer buf = ByteBuffer.allocate(16).order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
private Language lang;
|
||||||
|
private Trace trace;
|
||||||
|
private TraceMemoryManager memory;
|
||||||
|
|
||||||
|
private AddressSpace defaultSpace;
|
||||||
|
|
||||||
|
|
||||||
|
private DebuggerModelService modelService;
|
||||||
|
private DebuggerTraceManagerService managerService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an address in the processor's (x86_64) default space.
|
||||||
|
*
|
||||||
|
* @param offset the byte offset
|
||||||
|
* @return the address
|
||||||
|
*/
|
||||||
|
protected Address addr(long offset) {
|
||||||
|
return defaultSpace.getAddress(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an address range in the processor's default space.
|
||||||
|
*
|
||||||
|
* @param min the minimum byte offset
|
||||||
|
* @param max the maximum (inclusive) byte offset
|
||||||
|
* @return the range
|
||||||
|
*/
|
||||||
|
protected AddressRange rng(long min, long max) {
|
||||||
|
return new AddressRangeImpl(addr(min), addr(max));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void run() throws Exception {
|
||||||
|
|
||||||
|
modelService = state.getTool().getService(DebuggerModelService.class);
|
||||||
|
if (modelService == null) {
|
||||||
|
throw new RuntimeException("Unable to find DebuggerMemviewPlugin");
|
||||||
|
}
|
||||||
|
|
||||||
|
DebuggerObjectModel model = modelService.getCurrentModel();
|
||||||
|
if (!(model instanceof AbstractDbgModel)) {
|
||||||
|
throw new RuntimeException("Current model must be an AbstractDbgModel");
|
||||||
|
}
|
||||||
|
AbstractDbgModel dbgmodel = (AbstractDbgModel) model;
|
||||||
|
DbgManagerImpl manager = (DbgManagerImpl) dbgmodel.getManager();
|
||||||
|
//client = manager.getClient();
|
||||||
|
|
||||||
|
managerService = state.getTool().getService(DebuggerTraceManagerService.class);
|
||||||
|
trace = managerService.getCurrentTrace();
|
||||||
|
if (trace == null) {
|
||||||
|
throw new RuntimeException("Script requires an active trace");
|
||||||
|
}
|
||||||
|
memory = trace.getMemoryManager();
|
||||||
|
|
||||||
|
lang = currentProgram.getLanguage();
|
||||||
|
defaultSpace = lang.getAddressFactory().getDefaultAddressSpace();
|
||||||
|
|
||||||
|
manager.consoleCapture("!address").thenAccept(result -> {
|
||||||
|
parse(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parse(String result) {
|
||||||
|
try (UndoableTransaction tid = UndoableTransaction.start(trace, "Populate memory", true);
|
||||||
|
LockHold hold = trace.lockWrite();) {
|
||||||
|
//Pattern pattern = Pattern.compile("\\s+(*)\\s+(*)\\s+");
|
||||||
|
//Matcher matcher = pattern.matcher(fullclassname);
|
||||||
|
String[] lines = result.split("\n");
|
||||||
|
for (String line : lines) {
|
||||||
|
if (line.startsWith("Mapping")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String[] fields = line.trim().split("\\s+");
|
||||||
|
if (fields.length < 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String startStr = fields[0].replaceAll("`", "");
|
||||||
|
String endStr = fields[1].replaceAll("`", "");
|
||||||
|
long start, end;
|
||||||
|
try {
|
||||||
|
start = Long.parseUnsignedLong(startStr, 16);
|
||||||
|
end = Long.parseUnsignedLong(endStr, 16);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = fields[3];
|
||||||
|
AddressRange rng = rng(start, end - 1);
|
||||||
|
try {
|
||||||
|
TraceMemoryRegion region =
|
||||||
|
memory.addRegion(startStr, Range.atLeast(0L), rng, TraceMemoryFlag.READ,
|
||||||
|
TraceMemoryFlag.WRITE, TraceMemoryFlag.EXECUTE);
|
||||||
|
region.setName(name);
|
||||||
|
}
|
||||||
|
catch (TraceOverlappedRegionException | DuplicateNameException e) {
|
||||||
|
Msg.info(this, "Duplicate range at " + start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -338,6 +338,11 @@ public class WrappedDbgModel
|
||||||
return client.getDataSpaces().queryVirtual(offset);
|
return client.getDataSpaces().queryVirtual(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long virtualToPhysical(long offset) {
|
||||||
|
return client.getDataSpaces().virtualToPhysical(offset);
|
||||||
|
}
|
||||||
|
|
||||||
// REGISTERS INTERFACE
|
// REGISTERS INTERFACE
|
||||||
|
|
||||||
public DebugRegisterDescription getRegisterDescription(int i) {
|
public DebugRegisterDescription getRegisterDescription(int i) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import agent.dbgmodel.dbgmodel.DbgModel;
|
||||||
import agent.dbgmodel.dbgmodel.DbgModel.OpaqueCleanable;
|
import agent.dbgmodel.dbgmodel.DbgModel.OpaqueCleanable;
|
||||||
import agent.dbgmodel.dbgmodel.main.ModelObject;
|
import agent.dbgmodel.dbgmodel.main.ModelObject;
|
||||||
import agent.dbgmodel.jna.dbgmodel.main.IKeyEnumerator;
|
import agent.dbgmodel.jna.dbgmodel.main.IKeyEnumerator;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
public class KeyEnumeratorImpl implements KeyEnumeratorInternal {
|
public class KeyEnumeratorImpl implements KeyEnumeratorInternal {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -56,12 +57,17 @@ public class KeyEnumeratorImpl implements KeyEnumeratorInternal {
|
||||||
BSTRByReference bref = new BSTRByReference();
|
BSTRByReference bref = new BSTRByReference();
|
||||||
PointerByReference ppValue = new PointerByReference();
|
PointerByReference ppValue = new PointerByReference();
|
||||||
PointerByReference ppMetaData = new PointerByReference();
|
PointerByReference ppMetaData = new PointerByReference();
|
||||||
HRESULT hr = jnaData.GetNext(bref, ppValue, ppMetaData);
|
try {
|
||||||
if (hr.equals(COMUtilsExtra.E_BOUNDS) || hr.equals(COMUtilsExtra.E_FAIL)) {
|
HRESULT hr = jnaData.GetNext(bref, ppValue, ppMetaData);
|
||||||
//System.err.println("ret null");
|
if (hr.equals(COMUtilsExtra.E_BOUNDS) || hr.equals(COMUtilsExtra.E_FAIL)) {
|
||||||
return null;
|
//System.err.println("ret null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
COMUtils.checkRC(hr);
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
Msg.error(this, e.getMessage());
|
||||||
}
|
}
|
||||||
COMUtils.checkRC(hr);
|
|
||||||
|
|
||||||
Pointer val = ppValue.getValue();
|
Pointer val = ppValue.getValue();
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
|
|
|
@ -152,6 +152,10 @@ public class ModelObjectImpl implements ModelObjectInternal {
|
||||||
Msg.debug(this, searchKey + " scope not found");
|
Msg.debug(this, searchKey + " scope not found");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (hr.equals(COMUtilsExtra.E_CANNOT_READ)) {
|
||||||
|
Msg.debug(this, searchKey + " cannot be read");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
COMUtils.checkRC(hr);
|
COMUtils.checkRC(hr);
|
||||||
|
|
||||||
ModelObject retval = getObjectWithMetadata(ppObject, ppMetadata);
|
ModelObject retval = getObjectWithMetadata(ppObject, ppMetadata);
|
||||||
|
|
|
@ -72,6 +72,7 @@ public class DbgModel2Impl extends AbstractDbgModel
|
||||||
protected DbgModelTargetSession session;
|
protected DbgModelTargetSession session;
|
||||||
|
|
||||||
protected Map<Object, TargetObject> objectMap = new HashMap<>();
|
protected Map<Object, TargetObject> objectMap = new HashMap<>();
|
||||||
|
private boolean suppressDescent = false;
|
||||||
|
|
||||||
public DbgModel2Impl() {
|
public DbgModel2Impl() {
|
||||||
this.dbg = new DbgManager2Impl();
|
this.dbg = new DbgManager2Impl();
|
||||||
|
@ -198,4 +199,12 @@ public class DbgModel2Impl extends AbstractDbgModel
|
||||||
return ExceptionUtils.rethrow(ex);
|
return ExceptionUtils.rethrow(ex);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSuppressDescent() {
|
||||||
|
return suppressDescent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuppressDescent(boolean suppressDescent) {
|
||||||
|
this.suppressDescent = suppressDescent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,9 +250,14 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
|
||||||
}
|
}
|
||||||
if (proxy instanceof TargetExecutionStateful) {
|
if (proxy instanceof TargetExecutionStateful) {
|
||||||
if (isValid()) {
|
if (isValid()) {
|
||||||
TargetExecutionStateful stateful = (TargetExecutionStateful) proxy;
|
if (attributes.containsKey(TargetExecutionStateful.STATE_ATTRIBUTE_NAME)) {
|
||||||
TargetExecutionState state = stateful.getExecutionState();
|
TargetExecutionStateful stateful = (TargetExecutionStateful) proxy;
|
||||||
attrs.put(TargetExecutionStateful.STATE_ATTRIBUTE_NAME, state);
|
TargetExecutionState state = stateful.getExecutionState();
|
||||||
|
attrs.put(TargetExecutionStateful.STATE_ATTRIBUTE_NAME, state);
|
||||||
|
} else {
|
||||||
|
attrs.put(TargetExecutionStateful.STATE_ATTRIBUTE_NAME,
|
||||||
|
TargetExecutionState.INACTIVE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (proxy instanceof TargetAttacher) {
|
if (proxy instanceof TargetAttacher) {
|
||||||
|
|
|
@ -284,6 +284,21 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
|
||||||
if (PathUtils.isLink(parent.getPath(), proxy.getName(), proxy.getPath())) {
|
if (PathUtils.isLink(parent.getPath(), proxy.getName(), proxy.getPath())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (proxy instanceof DbgModelTargetSession) {
|
||||||
|
DbgModelTargetSession targetSession = (DbgModelTargetSession) proxy;
|
||||||
|
targetSession.getSession(false);
|
||||||
|
}
|
||||||
|
if (proxy instanceof DbgModelTargetProcess) {
|
||||||
|
DbgModelTargetProcess targetProcess = (DbgModelTargetProcess) proxy;
|
||||||
|
targetProcess.getProcess(false);
|
||||||
|
}
|
||||||
|
if (proxy instanceof DbgModelTargetThread) {
|
||||||
|
DbgModelTargetThread targetThread = (DbgModelTargetThread) proxy;
|
||||||
|
targetThread.getThread(false);
|
||||||
|
}
|
||||||
|
if (getModel().isSuppressDescent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (proxy instanceof DbgModelTargetSession || //
|
if (proxy instanceof DbgModelTargetSession || //
|
||||||
proxy instanceof DbgModelTargetProcess || //
|
proxy instanceof DbgModelTargetProcess || //
|
||||||
proxy instanceof DbgModelTargetThread) {
|
proxy instanceof DbgModelTargetThread) {
|
||||||
|
@ -402,7 +417,9 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (proxy instanceof TargetRegisterContainer) {
|
if (proxy instanceof TargetRegisterContainer) {
|
||||||
requestElements(false);
|
if (!getModel().isSuppressDescent()) {
|
||||||
|
requestElements(false);
|
||||||
|
}
|
||||||
requestAttributes(false);
|
requestAttributes(false);
|
||||||
}
|
}
|
||||||
if (proxy instanceof TargetRegisterBank) {
|
if (proxy instanceof TargetRegisterBank) {
|
||||||
|
|
|
@ -222,7 +222,7 @@
|
||||||
<interface name="Access" />
|
<interface name="Access" />
|
||||||
<interface name="Attacher" />
|
<interface name="Attacher" />
|
||||||
<interface name="Attachable" />
|
<interface name="Attachable" />
|
||||||
<interface name="Launcher" />
|
<!-- interface name="Launcher" / -->
|
||||||
<interface name="Deletable" />
|
<interface name="Deletable" />
|
||||||
<interface name="Detachable" />
|
<interface name="Detachable" />
|
||||||
<interface name="Killable" />
|
<interface name="Killable" />
|
||||||
|
|
|
@ -248,6 +248,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
|
||||||
private ToggleDockingAction actionToggleSelectionOnly;
|
private ToggleDockingAction actionToggleSelectionOnly;
|
||||||
private ToggleDockingAction actionToggleIgnoreState;
|
private ToggleDockingAction actionToggleIgnoreState;
|
||||||
private ToggleDockingAction actionToggleUpdateWhileRunning;
|
private ToggleDockingAction actionToggleUpdateWhileRunning;
|
||||||
|
private ToggleDockingAction actionSuppressDescent;
|
||||||
|
|
||||||
@AutoConfigStateField
|
@AutoConfigStateField
|
||||||
private boolean autoRecord = true;
|
private boolean autoRecord = true;
|
||||||
|
@ -259,6 +260,8 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
|
||||||
private boolean ignoreState = false;
|
private boolean ignoreState = false;
|
||||||
@AutoConfigStateField
|
@AutoConfigStateField
|
||||||
private boolean updateWhileRunning = true;
|
private boolean updateWhileRunning = true;
|
||||||
|
@AutoConfigStateField
|
||||||
|
private boolean suppressDescent = false;
|
||||||
|
|
||||||
Set<TargetConfigurable> configurables = new HashSet<>();
|
Set<TargetConfigurable> configurables = new HashSet<>();
|
||||||
private String lastMethod = "";
|
private String lastMethod = "";
|
||||||
|
@ -1002,6 +1005,17 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
|
||||||
.enabled(true)
|
.enabled(true)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstallLocal(this);
|
||||||
|
|
||||||
|
groupTargetIndex++;
|
||||||
|
|
||||||
|
actionSuppressDescent = new ToggleActionBuilder("Automatically populate containers", plugin.getName())
|
||||||
|
.menuPath("Maintenance","&Auto-populate")
|
||||||
|
.menuGroup(DebuggerResources.GROUP_TARGET, "M" + groupTargetIndex)
|
||||||
|
.helpLocation(new HelpLocation(plugin.getName(), "auto-populate containers"))
|
||||||
|
.onAction(ctx -> performToggleAutoPopulateContainers(ctx))
|
||||||
|
.selected(isUpdateWhileRunning())
|
||||||
|
.enabled(true)
|
||||||
|
.buildAndInstallLocal(this);
|
||||||
|
|
||||||
groupTargetIndex = 0;
|
groupTargetIndex = 0;
|
||||||
|
|
||||||
new ActionBuilder("Quick Launch", plugin.getName())
|
new ActionBuilder("Quick Launch", plugin.getName())
|
||||||
|
@ -1434,6 +1448,14 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
|
||||||
refresh("");
|
refresh("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void performToggleAutoPopulateContainers(ActionContext context) {
|
||||||
|
suppressDescent = !actionSuppressDescent.isSelected();
|
||||||
|
if (currentModel != null) {
|
||||||
|
currentModel.setSuppressDescent(suppressDescent);
|
||||||
|
}
|
||||||
|
refresh("");
|
||||||
|
}
|
||||||
|
|
||||||
protected <T extends TargetObject> void performAction(ActionContext context,
|
protected <T extends TargetObject> void performAction(ActionContext context,
|
||||||
boolean fallbackRoot, Class<T> cls,
|
boolean fallbackRoot, Class<T> cls,
|
||||||
Function<T, CompletableFuture<Void>> func, String errorMsg) {
|
Function<T, CompletableFuture<Void>> func, String errorMsg) {
|
||||||
|
|
|
@ -228,11 +228,13 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
|
||||||
val);
|
val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ProgramUserData userData = program.getProgramUserData();
|
if (program != null) {
|
||||||
try (UndoableTransaction tid = UndoableTransaction.start(userData)) {
|
ProgramUserData userData = program.getProgramUserData();
|
||||||
Element element = state.saveToXml();
|
try (UndoableTransaction tid = UndoableTransaction.start(userData)) {
|
||||||
userData.setStringProperty(TargetCmdLineLauncher.CMDLINE_ARGS_NAME,
|
Element element = state.saveToXml();
|
||||||
XmlUtilities.toString(element));
|
userData.setStringProperty(TargetCmdLineLauncher.CMDLINE_ARGS_NAME,
|
||||||
|
XmlUtilities.toString(element));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +255,9 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
|
||||||
*/
|
*/
|
||||||
protected Map<String, ?> generateDefaultLauncherArgs(
|
protected Map<String, ?> generateDefaultLauncherArgs(
|
||||||
Map<String, ParameterDescription<?>> params) {
|
Map<String, ParameterDescription<?>> params) {
|
||||||
|
if (program == null) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
return Map.of(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, program.getExecutablePath());
|
return Map.of(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, program.getExecutablePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,34 +308,44 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
|
||||||
* TODO: Supposedly, per-program, per-user config stuff is being generalized for analyzers.
|
* TODO: Supposedly, per-program, per-user config stuff is being generalized for analyzers.
|
||||||
* Re-examine this if/when that gets merged
|
* Re-examine this if/when that gets merged
|
||||||
*/
|
*/
|
||||||
ProgramUserData userData = program.getProgramUserData();
|
if (program != null) {
|
||||||
String property = userData.getStringProperty(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, null);
|
ProgramUserData userData = program.getProgramUserData();
|
||||||
if (property != null) {
|
String property =
|
||||||
try {
|
userData.getStringProperty(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, null);
|
||||||
Element element = XmlUtilities.fromString(property);
|
if (property != null) {
|
||||||
SaveState state = new SaveState(element);
|
try {
|
||||||
Map<String, Object> args = new LinkedHashMap<>();
|
Element element = XmlUtilities.fromString(property);
|
||||||
for (ParameterDescription<?> param : params.values()) {
|
SaveState state = new SaveState(element);
|
||||||
args.put(param.name,
|
Map<String, Object> args = new LinkedHashMap<>();
|
||||||
ConfigStateField.getState(state, param.type, param.name));
|
for (ParameterDescription<?> param : params.values()) {
|
||||||
|
Object configState =
|
||||||
|
ConfigStateField.getState(state, param.type, param.name);
|
||||||
|
if (configState != null) {
|
||||||
|
args.put(param.name, configState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!args.isEmpty()) {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return args;
|
catch (JDOMException | IOException e) {
|
||||||
}
|
if (!forPrompt) {
|
||||||
catch (JDOMException | IOException e) {
|
throw new RuntimeException(
|
||||||
if (!forPrompt) {
|
"Saved launcher args are corrupt, or launcher parameters changed. Not launching.",
|
||||||
throw new RuntimeException(
|
e);
|
||||||
"Saved launcher args are corrupt, or launcher parameters changed. Not launching.",
|
}
|
||||||
|
Msg.error(this,
|
||||||
|
"Saved launcher args are corrup, or launcher parameters changed. Defaulting.",
|
||||||
e);
|
e);
|
||||||
}
|
}
|
||||||
Msg.error(this,
|
|
||||||
"Saved launcher args are corrup, or launcher parameters changed. Defaulting.",
|
|
||||||
e);
|
|
||||||
}
|
}
|
||||||
|
Map<String, ?> args = generateDefaultLauncherArgs(params);
|
||||||
|
saveLauncherArgs(args, params);
|
||||||
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, ?> args = generateDefaultLauncherArgs(params);
|
return new LinkedHashMap<>();
|
||||||
saveLauncherArgs(args, params);
|
|
||||||
return args;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -580,4 +580,12 @@ public interface DebuggerObjectModel {
|
||||||
* @return a future which completes when all queued callbacks have been invoked
|
* @return a future which completes when all queued callbacks have been invoked
|
||||||
*/
|
*/
|
||||||
CompletableFuture<Void> flushEvents();
|
CompletableFuture<Void> flushEvents();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the model permits, suppress automatic descent into containers
|
||||||
|
*/
|
||||||
|
default void setSuppressDescent(boolean suppressDescent) {
|
||||||
|
// Do nothing by default
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ import java.util.*;
|
||||||
import ghidra.framework.model.DomainObjectChangeRecord;
|
import ghidra.framework.model.DomainObjectChangeRecord;
|
||||||
|
|
||||||
public class DefaultTraceChangeType<T, U> implements TraceChangeType<T, U> {
|
public class DefaultTraceChangeType<T, U> implements TraceChangeType<T, U> {
|
||||||
private static int nextType = 0x3ACE0000; // Stay far away from manually-assigned types
|
private static int nextType = 0x100; // Stay far away from manually-assigned types
|
||||||
|
|
||||||
private static final Map<Integer, String> TYPE_NAMES = new HashMap<>();
|
private static final Map<Integer, String> TYPE_NAMES = new HashMap<>();
|
||||||
private static final Set<Field> FIELD_BACKLOG = new HashSet<>();
|
private static final Set<Field> FIELD_BACKLOG = new HashSet<>();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue