GP-878: ObjectsProvider fixes. dbgeng termination/exit fixes.

This commit is contained in:
d-millar 2021-04-22 20:12:10 +00:00 committed by Dan
parent 75f950880e
commit 93b2f5cc64
16 changed files with 211 additions and 61 deletions

View file

@ -103,7 +103,11 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
@Override @Override
public int getNumberThreads() { public int getNumberThreads() {
ULONGByReference pulNumber = new ULONGByReference(); ULONGByReference pulNumber = new ULONGByReference();
COMUtils.checkRC(jnaSysobj.GetNumberThreads(pulNumber)); HRESULT hr = jnaSysobj.GetNumberThreads(pulNumber);
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
return 0;
}
COMUtils.checkRC(hr);
return pulNumber.getValue().intValue(); return pulNumber.getValue().intValue();
} }

View file

@ -110,7 +110,8 @@ public class DbgDebugEventCallbacksAdapter extends DebugEventCallbacksAdapter {
DebugStatus status = DebugStatus.fromArgument(argument); DebugStatus status = DebugStatus.fromArgument(argument);
Msg.info(this, "***ExecutionStatus: " + status); Msg.info(this, "***ExecutionStatus: " + status);
if (status.equals(DebugStatus.NO_DEBUGGEE)) { if (status.equals(DebugStatus.NO_DEBUGGEE)) {
event.setState(DbgState.SESSION_EXIT); long processCount = manager.getProcessCount();
event.setState(processCount > 0 ? DbgState.SESSION_EXIT : DbgState.EXIT);
} }
return checkInterrupt(manager.processEvent(event)); return checkInterrupt(manager.processEvent(event));
} }
@ -131,10 +132,18 @@ public class DbgDebugEventCallbacksAdapter extends DebugEventCallbacksAdapter {
return checkInterrupt(DebugStatus.NO_CHANGE); return checkInterrupt(DebugStatus.NO_CHANGE);
} }
//@Override /*
//public DebugStatus changeDebuggeeState(BitmaskSet<ChangeDebuggeeState> flags, long argument) { @Override
// System.err.println("CHANGE_DEBUGGEE_STATE: " + flags + ":" + argument); public DebugStatus changeDebuggeeState(BitmaskSet<ChangeDebuggeeState> flags, long argument) {
// return DebugStatus.NO_CHANGE; System.err.println("CHANGE_DEBUGGEE_STATE: " + flags + ":" + argument);
//} return DebugStatus.NO_CHANGE;
}
@Override
public DebugStatus sessionStatus(SessionStatus status) {
System.err.println("SESSION_STATUS: " + status);
return DebugStatus.NO_CHANGE;
}
*/
} }

View file

@ -110,6 +110,7 @@ public class DbgManagerImpl implements DbgManager {
private volatile boolean waiting = false; private volatile boolean waiting = false;
private boolean kernelMode = false; private boolean kernelMode = false;
private CompletableFuture<String> continuation; private CompletableFuture<String> continuation;
private long processCount = 0;
/** /**
* Instantiate a new manager * Instantiate a new manager
@ -998,6 +999,12 @@ public class DbgManagerImpl implements DbgManager {
waiting = true; waiting = true;
Long info = evt.getInfo(); Long info = evt.getInfo();
if (info.intValue() >= 0) {
processCount++;
}
else {
processCount--;
}
DebugProcessId id = new DebugProcessId(info.intValue()); DebugProcessId id = new DebugProcessId(info.intValue());
String key = Integer.toHexString(id.id); String key = Integer.toHexString(id.id);
@ -1523,4 +1530,9 @@ public class DbgManagerImpl implements DbgManager {
public void setContinuation(CompletableFuture<String> continuation) { public void setContinuation(CompletableFuture<String> continuation) {
this.continuation = continuation; this.continuation = continuation;
} }
public long getProcessCount() {
return processCount;
}
} }

View file

@ -27,11 +27,26 @@ import ghidra.dbg.target.*;
import ghidra.dbg.target.schema.*; import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils; import ghidra.dbg.util.PathUtils;
@TargetObjectSchemaInfo(name = "Debugger", elements = { @TargetObjectSchemaInfo(
@TargetElementType(type = Void.class) }, attributes = { name = "Debugger",
@TargetAttributeType(name = "Available", type = DbgModelTargetAvailableContainerImpl.class, required = true, fixed = true), elements = {
@TargetAttributeType(name = "Connectors", type = DbgModelTargetConnectorContainerImpl.class, required = true, fixed = true), @TargetElementType(type = Void.class) },
@TargetAttributeType(name = "Sessions", type = DbgModelTargetSessionContainerImpl.class, required = true, fixed = true), attributes = {
@TargetAttributeType(
name = "Available",
type = DbgModelTargetAvailableContainerImpl.class,
required = true,
fixed = true),
@TargetAttributeType(
name = "Connectors",
type = DbgModelTargetConnectorContainerImpl.class,
required = true,
fixed = true),
@TargetAttributeType(
name = "Sessions",
type = DbgModelTargetSessionContainerImpl.class,
required = true,
fixed = true),
@TargetAttributeType(type = Void.class) }) @TargetAttributeType(type = Void.class) })
public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot
implements DbgModelTargetRoot { implements DbgModelTargetRoot {
@ -120,10 +135,12 @@ public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot
DbgReason reason) { DbgReason reason) {
DbgModelTargetThread targetThread = DbgModelTargetThread targetThread =
(DbgModelTargetThread) getModel().getModelObject(thread); (DbgModelTargetThread) getModel().getModelObject(thread);
if (targetThread != null) {
changeAttributes(List.of(), List.of(), Map.of( // changeAttributes(List.of(), List.of(), Map.of( //
TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread // TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread //
), reason.desc()); ), reason.desc());
} }
}
@Override @Override
public boolean isAccessible() { public boolean isAccessible() {

View file

@ -68,4 +68,14 @@ public abstract class AbstractModelForDbgengInterpreterTest
public DebuggerTestSpecimen getLaunchSpecimen() { public DebuggerTestSpecimen getLaunchSpecimen() {
return WindowsSpecimen.PRINT; return WindowsSpecimen.PRINT;
} }
/*
@Override
@Ignore
@Test(expected = DebuggerModelTerminatingException.class)
public void testExecuteQuit() throws Throwable {
// Different behavior for dbg clients vice gdb
}
*/
} }

View file

@ -19,7 +19,6 @@ import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import agent.dbgeng.model.AbstractModelForDbgengInterpreterTest; import agent.dbgeng.model.AbstractModelForDbgengInterpreterTest;
import ghidra.dbg.error.DebuggerModelTerminatingException;
public class GadpModelForDbgengInterpreterTest extends AbstractModelForDbgengInterpreterTest { public class GadpModelForDbgengInterpreterTest extends AbstractModelForDbgengInterpreterTest {
@ -37,11 +36,4 @@ public class GadpModelForDbgengInterpreterTest extends AbstractModelForDbgengInt
super.testAttachViaInterpreterShowsInProcessContainer(); super.testAttachViaInterpreterShowsInProcessContainer();
} }
@Override
@Ignore
@Test(expected = DebuggerModelTerminatingException.class)
public void testExecuteQuit() throws Throwable {
// Hangs after DebuggerModelTerminatingException
}
} }

View file

@ -19,6 +19,7 @@ import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import agent.dbgeng.model.AbstractModelForDbgengInterpreterTest; import agent.dbgeng.model.AbstractModelForDbgengInterpreterTest;
import ghidra.dbg.error.DebuggerModelTerminatingException;
public class InVmModelForDbgengInterpreterTest extends AbstractModelForDbgengInterpreterTest { public class InVmModelForDbgengInterpreterTest extends AbstractModelForDbgengInterpreterTest {
@Override @Override
@ -32,4 +33,12 @@ public class InVmModelForDbgengInterpreterTest extends AbstractModelForDbgengInt
public void testAttachViaInterpreterShowsInProcessContainer() throws Throwable { public void testAttachViaInterpreterShowsInProcessContainer() throws Throwable {
super.testAttachViaInterpreterShowsInProcessContainer(); super.testAttachViaInterpreterShowsInProcessContainer();
} }
@Override
@Ignore
@Test(expected = DebuggerModelTerminatingException.class)
public void testExecuteQuit() throws Throwable {
// Different behavior for dbg clients vice gdb
}
} }

View file

@ -16,6 +16,7 @@
package agent.dbgmodel.model.impl; package agent.dbgmodel.model.impl;
import java.util.*; import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -112,9 +113,11 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
@Override @Override
public CompletableFuture<Void> requestElements(boolean refresh) { public CompletableFuture<Void> requestElements(boolean refresh) {
List<TargetObject> nlist = new ArrayList<>(); List<TargetObject> nlist = new ArrayList<>();
List<String> rlist = new ArrayList<>();
return requestNativeElements().thenCompose(list -> { return requestNativeElements().thenCompose(list -> {
synchronized (elements) { synchronized (elements) {
for (TargetObject element : elements.values()) { for (Entry<String, TargetObject> entry : elements.entrySet()) {
TargetObject element = entry.getValue();
if (!list.contains(element)) { if (!list.contains(element)) {
if (element instanceof DbgStateListener) { if (element instanceof DbgStateListener) {
getManager().removeStateListener((DbgStateListener) element); getManager().removeStateListener((DbgStateListener) element);
@ -122,6 +125,7 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
if (element instanceof DbgEventsListener) { if (element instanceof DbgEventsListener) {
getManager().removeEventsListener((DbgEventsListener) element); getManager().removeEventsListener((DbgEventsListener) element);
} }
rlist.add(entry.getKey());
} }
} }
nlist.addAll(list); nlist.addAll(list);
@ -129,18 +133,20 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
//return processModelObjectElements(nlist); //return processModelObjectElements(nlist);
} }
}).thenAccept(__ -> { }).thenAccept(__ -> {
changeElements(List.of(), nlist, Map.of(), "Refreshed"); changeElements(rlist, nlist, Map.of(), "Refreshed");
}); });
} }
@Override @Override
public CompletableFuture<Void> requestAttributes(boolean refresh) { public CompletableFuture<Void> requestAttributes(boolean refresh) {
Map<String, Object> nmap = new HashMap<>(); Map<String, Object> nmap = new HashMap<>();
List<String> rlist = new ArrayList<>();
return requestNativeAttributes().thenCompose(map -> { return requestNativeAttributes().thenCompose(map -> {
synchronized (attributes) { synchronized (attributes) {
if (map != null) { if (map != null) {
Collection<?> values = map.values(); Collection<?> values = map.values();
for (Object attribute : attributes.values()) { for (Entry<String, Object> entry : attributes.entrySet()) {
Object attribute = entry.getValue();
if (!values.contains(attribute)) { if (!values.contains(attribute)) {
if (attribute instanceof DbgStateListener) { if (attribute instanceof DbgStateListener) {
getManager().removeStateListener((DbgStateListener) attribute); getManager().removeStateListener((DbgStateListener) attribute);
@ -148,6 +154,7 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
if (attribute instanceof DbgEventsListener) { if (attribute instanceof DbgEventsListener) {
getManager().removeEventsListener((DbgEventsListener) attribute); getManager().removeEventsListener((DbgEventsListener) attribute);
} }
rlist.add(entry.getKey());
} }
} }
nmap.putAll(map); nmap.putAll(map);

View file

@ -332,10 +332,10 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
return; return;
} }
DbgModelTargetProcess process = (DbgModelTargetProcess) object.getProxy(); DbgModelTargetProcess process = (DbgModelTargetProcess) object.getProxy();
if (!process.getExecutionState().equals(TargetExecutionState.TERMINATED)) {
process.setExecutionState(TargetExecutionState.INACTIVE, "Detached"); process.setExecutionState(TargetExecutionState.INACTIVE, "Detached");
DbgProcess proc = process.getProcess(); }
getListeners().fire.event(getProxy(), null, TargetEventType.PROCESS_EXITED, process.getParent().resync();
"Process " + proc.getId() + " exited code=" + proc.getExitCode(), List.of(process));
}); });
} }
@ -540,8 +540,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
} }
return TargetEventType.STOPPED; return TargetEventType.STOPPED;
case SESSION_EXIT: case SESSION_EXIT:
getModel().close(); return TargetEventType.PROCESS_EXITED;
break;
default: default:
break; break;
} }

View file

@ -143,6 +143,7 @@ src/main/resources/images/launch.png||GHIDRA||||END|
src/main/resources/images/modules.png||GHIDRA||||END| src/main/resources/images/modules.png||GHIDRA||||END|
src/main/resources/images/object-populated.png||GHIDRA||||END| src/main/resources/images/object-populated.png||GHIDRA||||END|
src/main/resources/images/object-running.png||GHIDRA||||END| src/main/resources/images/object-running.png||GHIDRA||||END|
src/main/resources/images/object-terminated.png||GHIDRA||||END|
src/main/resources/images/object-unpopulated.png||GHIDRA||||END| src/main/resources/images/object-unpopulated.png||GHIDRA||||END|
src/main/resources/images/process.png||GHIDRA||||END| src/main/resources/images/process.png||GHIDRA||||END|
src/main/resources/images/record.png||GHIDRA||||END| src/main/resources/images/record.png||GHIDRA||||END|
@ -182,6 +183,7 @@ src/main/svg/disconnect.svg||GHIDRA||||END|
src/main/svg/kill.svg||GHIDRA||||END| src/main/svg/kill.svg||GHIDRA||||END|
src/main/svg/launch.svg||GHIDRA||||END| src/main/svg/launch.svg||GHIDRA||||END|
src/main/svg/memory.svg||GHIDRA||||END| src/main/svg/memory.svg||GHIDRA||||END|
src/main/svg/object-terminated.svg||GHIDRA||||END|
src/main/svg/process.svg||GHIDRA||||END| src/main/svg/process.svg||GHIDRA||||END|
src/main/svg/recording.svg||GHIDRA||||END| src/main/svg/recording.svg||GHIDRA||||END|
src/main/svg/register-marker.svg||GHIDRA||||END| src/main/svg/register-marker.svg||GHIDRA||||END|

View file

@ -101,6 +101,8 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
public static final String OPTION_NAME_SUBSCRIBED_FOREGROUND_COLOR = "Object Colors.Subscribed"; public static final String OPTION_NAME_SUBSCRIBED_FOREGROUND_COLOR = "Object Colors.Subscribed";
public static final String OPTION_NAME_INVISIBLE_FOREGROUND_COLOR = public static final String OPTION_NAME_INVISIBLE_FOREGROUND_COLOR =
"Object Colors.Invisible (when toggled on)"; "Object Colors.Invisible (when toggled on)";
public static final String OPTION_NAME_INVALIDATED_FOREGROUND_COLOR =
"Object Colors.Invalidated";
public static final String OPTION_NAME_ERROR_FOREGROUND_COLOR = "Object Colors.Errors"; public static final String OPTION_NAME_ERROR_FOREGROUND_COLOR = "Object Colors.Errors";
public static final String OPTION_NAME_INTRINSIC_FOREGROUND_COLOR = "Object Colors.Intrinsics"; public static final String OPTION_NAME_INTRINSIC_FOREGROUND_COLOR = "Object Colors.Intrinsics";
public static final String OPTION_NAME_TARGET_FOREGROUND_COLOR = "Object Colors.Targets"; public static final String OPTION_NAME_TARGET_FOREGROUND_COLOR = "Object Colors.Targets";
@ -127,6 +129,12 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
help = @HelpInfo(anchor = "colors") // help = @HelpInfo(anchor = "colors") //
) )
Color invisibleForegroundColor = Color.LIGHT_GRAY; Color invisibleForegroundColor = Color.LIGHT_GRAY;
@AutoOptionDefined( //
name = OPTION_NAME_INVALIDATED_FOREGROUND_COLOR, //
description = "The foreground color for items no longer valid", //
help = @HelpInfo(anchor = "colors") //
)
Color invalidatedForegroundColor = Color.LIGHT_GRAY;
@AutoOptionDefined( // @AutoOptionDefined( //
name = OPTION_NAME_MODIFIED_FOREGROUND_COLOR, // name = OPTION_NAME_MODIFIED_FOREGROUND_COLOR, //
description = "The foreground color for modified items in the objects tree", // description = "The foreground color for modified items in the objects tree", //
@ -388,6 +396,14 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
} }
} }
@AutoOptionConsumed(name = OPTION_NAME_INVALIDATED_FOREGROUND_COLOR)
private void setInvalidatedForegroundColor(Color color) {
invalidatedForegroundColor = color;
if (pane != null) {
pane.getComponent().repaint();
}
}
@AutoOptionConsumed(name = OPTION_NAME_LINK_FOREGROUND_COLOR) @AutoOptionConsumed(name = OPTION_NAME_LINK_FOREGROUND_COLOR)
private void setLinkForegroundColor(Color color) { private void setLinkForegroundColor(Color color) {
linkForegroundColor = color; linkForegroundColor = color;
@ -734,16 +750,13 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
boolean usingAttributes) { boolean usingAttributes) {
String xkey = usingAttributes ? key : "[" + key + "]"; String xkey = usingAttributes ? key : "[" + key + "]";
if (val instanceof TargetObject) { if (val instanceof TargetObject) {
TargetObject ref = (TargetObject) val; TargetObject to = (TargetObject) val;
List<String> path = ref.getPath(); List<String> path = to.getPath();
boolean isLink = PathUtils.isLink(parent.getPath(), xkey, path); boolean isLink = PathUtils.isLink(parent.getPath(), xkey, path);
boolean isMethod = false; boolean isMethod = false;
if (ref instanceof TargetObject) {
TargetObject to = ref;
isMethod = to instanceof TargetMethod; isMethod = to instanceof TargetMethod;
}
if (!(val instanceof DummyTargetObject) && !isMethod) { if (!(val instanceof DummyTargetObject) && !isMethod) {
return new ObjectContainer(ref, isLink ? xkey : null); return new ObjectContainer(to, isLink ? xkey : null);
} }
} }
else { else {
@ -1786,6 +1799,8 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
return intrinsicForegroundColor; return intrinsicForegroundColor;
case OPTION_NAME_INVISIBLE_FOREGROUND_COLOR: case OPTION_NAME_INVISIBLE_FOREGROUND_COLOR:
return invisibleForegroundColor; return invisibleForegroundColor;
case OPTION_NAME_INVALIDATED_FOREGROUND_COLOR:
return invalidatedForegroundColor;
case OPTION_NAME_MODIFIED_FOREGROUND_COLOR: case OPTION_NAME_MODIFIED_FOREGROUND_COLOR:
return modifiedForegroundColor; return modifiedForegroundColor;
case OPTION_NAME_SUBSCRIBED_FOREGROUND_COLOR: case OPTION_NAME_SUBSCRIBED_FOREGROUND_COLOR:

View file

@ -16,6 +16,7 @@
package ghidra.app.plugin.core.debug.gui.objects; package ghidra.app.plugin.core.debug.gui.objects;
import java.util.*; import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.jdom.Element; import org.jdom.Element;
@ -64,6 +65,14 @@ public class ObjectContainer implements Comparable<ObjectContainer> {
return nc; return nc;
} }
public void updateUsing(ObjectContainer container) {
attributeMap.clear();
attributeMap.putAll(container.getAttributeMap());
elementMap.clear();
elementMap.putAll(container.getElementMap());
targetObject = container.targetObject;
}
public boolean hasElements() { public boolean hasElements() {
return !elementMap.isEmpty(); return !elementMap.isEmpty();
} }
@ -168,32 +177,40 @@ public class ObjectContainer implements Comparable<ObjectContainer> {
public void augmentElements(Collection<String> elementsRemoved, public void augmentElements(Collection<String> elementsRemoved,
Map<String, ? extends TargetObject> elementsAdded) { Map<String, ? extends TargetObject> elementsAdded) {
Set<ObjectContainer> result = new TreeSet<ObjectContainer>(); Set<ObjectContainer> result = new TreeSet<ObjectContainer>();
Map<String, Object> newAdds = new HashMap<>();
for (Entry<String, ? extends TargetObject> entry : elementsAdded.entrySet()) {
newAdds.put(entry.getKey(), entry.getValue());
}
boolean structureChanged = false; boolean structureChanged = false;
synchronized (elementMap) { synchronized (elementMap) {
for (ObjectContainer child : currentChildren) { for (ObjectContainer child : currentChildren) {
String name = child.getName(); String key = child.getName();
if (name.startsWith("[")) { if (key.startsWith("[")) {
name = name.substring(1, name.length() - 1); key = key.substring(1, key.length() - 1);
} }
if (elementsRemoved.contains(name) && !elementsAdded.containsKey(name)) { if (elementsRemoved.contains(key) && !elementsAdded.containsKey(key)) {
elementMap.remove(name); elementMap.remove(key);
structureChanged = true; structureChanged = true;
continue; continue;
} }
if (elementsAdded.containsKey(key)) {
Object val = elementsAdded.get(key);
ObjectContainer newChild =
DebuggerObjectsProvider.buildContainerFromObject(targetObject, key, val,
true);
child.updateUsing(newChild);
newAdds.remove(key);
provider.signalDataChanged(child);
}
result.add(child); result.add(child);
} }
for (String key : elementsAdded.keySet()) { for (String key : elementsAdded.keySet()) {
TargetObject val = elementsAdded.get(key); TargetObject val = elementsAdded.get(key);
ObjectContainer child = ObjectContainer child =
DebuggerObjectsProvider.buildContainerFromObject(targetObject, key, val, false); DebuggerObjectsProvider.buildContainerFromObject(targetObject, key, val, false);
if (!elementMap.containsKey(key)) {
structureChanged = true;
}
else {
provider.signalDataChanged(child);
}
elementMap.put(key, val); elementMap.put(key, val);
result.add(child); result.add(child);
structureChanged = true;
} }
} }
currentChildren = result; currentChildren = result;
@ -207,30 +224,38 @@ public class ObjectContainer implements Comparable<ObjectContainer> {
public void augmentAttributes(Collection<String> attributesRemoved, public void augmentAttributes(Collection<String> attributesRemoved,
Map<String, ?> attributesAdded) { Map<String, ?> attributesAdded) {
Set<ObjectContainer> result = new TreeSet<ObjectContainer>(); Set<ObjectContainer> result = new TreeSet<ObjectContainer>();
Map<String, Object> newAdds = new HashMap<>();
for (Entry<String, ?> entry : attributesAdded.entrySet()) {
newAdds.put(entry.getKey(), entry.getValue());
}
boolean structureChanged = false; boolean structureChanged = false;
synchronized (attributeMap) { synchronized (attributeMap) {
for (ObjectContainer child : currentChildren) { for (ObjectContainer child : currentChildren) {
String name = child.getName(); String key = child.getName();
if (attributesRemoved.contains(name) && !attributesAdded.containsKey(name)) { if (attributesRemoved.contains(key) && !attributesAdded.containsKey(key)) {
attributeMap.remove(name); attributeMap.remove(key);
structureChanged = true; structureChanged = true;
continue; continue;
} }
if (attributesAdded.containsKey(key)) {
Object val = attributesAdded.get(key);
ObjectContainer newChild =
DebuggerObjectsProvider.buildContainerFromObject(targetObject, key, val,
true);
child.updateUsing(newChild);
newAdds.remove(key);
provider.signalDataChanged(child);
}
result.add(child); result.add(child);
} }
for (String key : attributesAdded.keySet()) { for (String key : newAdds.keySet()) {
Object val = attributesAdded.get(key); Object val = newAdds.get(key);
ObjectContainer child = ObjectContainer child =
DebuggerObjectsProvider.buildContainerFromObject(targetObject, key, val, true); DebuggerObjectsProvider.buildContainerFromObject(targetObject, key, val, true);
if (child != null) { if (child != null) {
if (!attributeMap.containsKey(key)) {
structureChanged = true;
}
else {
provider.signalDataChanged(child);
}
attributeMap.put(key, val); attributeMap.put(key, val);
result.add(child); result.add(child);
structureChanged = true;
} }
} }
} }

View file

@ -37,6 +37,8 @@ public class ObjectNode extends GTreeSlowLoadingNode { //extends GTreeNode
ResourceManager.loadImage("images/object-populated.png"); ResourceManager.loadImage("images/object-populated.png");
static final ImageIcon ICON_EMPTY = ResourceManager.loadImage("images/object-unpopulated.png"); static final ImageIcon ICON_EMPTY = ResourceManager.loadImage("images/object-unpopulated.png");
static final ImageIcon ICON_RUNNING = ResourceManager.loadImage("images/object-running.png"); static final ImageIcon ICON_RUNNING = ResourceManager.loadImage("images/object-running.png");
static final ImageIcon ICON_TERMINATED =
ResourceManager.loadImage("images/object-terminated.png");
static final ImageIcon ICON_EVENT = ResourceManager.loadImage("images/register-marker.png"); static final ImageIcon ICON_EVENT = ResourceManager.loadImage("images/register-marker.png");
private ObjectContainer container; private ObjectContainer container;
@ -142,6 +144,9 @@ public class ObjectNode extends GTreeSlowLoadingNode { //extends GTreeNode
if (stateful.getExecutionState().equals(TargetExecutionState.RUNNING)) { if (stateful.getExecutionState().equals(TargetExecutionState.RUNNING)) {
return ICON_RUNNING; return ICON_RUNNING;
} }
if (stateful.getExecutionState().equals(TargetExecutionState.TERMINATED)) {
return ICON_TERMINATED;
}
} }
/* /*
Map<String, Object> attributeMap = container.getAttributeMap(); Map<String, Object> attributeMap = container.getAttributeMap();

View file

@ -24,6 +24,8 @@ import javax.swing.tree.TreePath;
import docking.widgets.tree.support.GTreeRenderer; import docking.widgets.tree.support.GTreeRenderer;
import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider;
import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer;
import ghidra.dbg.target.TargetExecutionStateful;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.TargetObject;
// TODO: In the new scheme, I'm not sure this is applicable anymore. // TODO: In the new scheme, I'm not sure this is applicable anymore.
@ -66,6 +68,14 @@ class ObjectTreeCellRenderer extends GTreeRenderer {
component.setForeground(provider component.setForeground(provider
.getColor(DebuggerObjectsProvider.OPTION_NAME_INVISIBLE_FOREGROUND_COLOR)); .getColor(DebuggerObjectsProvider.OPTION_NAME_INVISIBLE_FOREGROUND_COLOR));
} }
if (container.getTargetObject() instanceof TargetExecutionStateful) {
TargetExecutionStateful stateful = (TargetExecutionStateful) targetObject;
if (stateful.getExecutionState().equals(TargetExecutionState.TERMINATED)) {
component.setForeground(provider
.getColor(
DebuggerObjectsProvider.OPTION_NAME_INVALIDATED_FOREGROUND_COLOR));
}
}
if (container.isLink()) { if (container.isLink()) {
component.setForeground( component.setForeground(
provider.getColor(DebuggerObjectsProvider.OPTION_NAME_LINK_FOREGROUND_COLOR)); provider.getColor(DebuggerObjectsProvider.OPTION_NAME_LINK_FOREGROUND_COLOR));

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
width="16px"
height="16px"
viewBox="0 0 16 16"
version="1.1"
id="SVGRoot">
<defs
id="defs5287" />
<metadata
id="metadata5290">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1">
<path
style="opacity:1;fill:#7f7f7f;fill-opacity:1;stroke:none;stroke-width:1.14285719;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 8 4 A 4 4 0 0 0 4 8 A 4 4 0 0 0 8 12 A 4 4 0 0 0 12 8 A 4 4 0 0 0 8 4 z M 8 6 A 2 2 0 0 1 10 8 A 2 2 0 0 1 8 10 A 2 2 0 0 1 6 8 A 2 2 0 0 1 8 6 z "
id="path821" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB