From bdfeae4baf5a28e61968fd1e080b1f653cc74842 Mon Sep 17 00:00:00 2001 From: d-millar <33498836+d-millar@users.noreply.github.com> Date: Mon, 11 Jan 2021 20:47:49 +0000 Subject: [PATCH] GP-572: Schema implementation for dbgmodel. Some dbgeng fixes. --- .../DbgModelTargetBreakpointContainer.java | 16 +- .../DbgModelTargetBreakpointSpecImpl.java | 8 +- .../certification.manifest | 1 + .../dbgmodel/model/impl/DbgModel2Impl.java | 30 +- .../model/impl/DbgModel2TargetRootImpl.java | 2 +- .../impl/DelegateDbgModel2TargetObject.java | 15 +- .../dbgmodel/model/impl/dbgmodel_schema.xml | 555 ++++++++++++++++++ .../debug/gui/objects/ObjectContainer.java | 95 +++ .../dbg/target/schema/XmlSchemaContext.java | 23 +- 9 files changed, 719 insertions(+), 26 deletions(-) create mode 100644 Ghidra/Debug/Debugger-agent-dbgmodel/sxrc/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetBreakpointContainer.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetBreakpointContainer.java index 7d80dd29de..9fa88029eb 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetBreakpointContainer.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetBreakpointContainer.java @@ -19,9 +19,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.function.Function; -import agent.dbgeng.manager.DbgCause; import agent.dbgeng.manager.DbgEventsListenerAdapter; -import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo; import agent.dbgeng.manager.breakpoint.DbgBreakpointType; import ghidra.async.AsyncFence; import ghidra.dbg.target.TargetBreakpointContainer; @@ -30,25 +28,25 @@ import ghidra.dbg.target.schema.*; import ghidra.program.model.address.AddressRange; @TargetObjectSchemaInfo(name = "BreakpointContainer", elements = { - @TargetElementType(type = DbgModelTargetBreakpointSpec.class) -}, attributes = { - @TargetAttributeType(type = Void.class) -}, canonicalContainer = true) + @TargetElementType(type = DbgModelTargetBreakpointSpec.class) }, attributes = { + @TargetAttributeType(type = Void.class) }, canonicalContainer = true) public interface DbgModelTargetBreakpointContainer extends DbgModelTargetObject, TargetBreakpointContainer, DbgEventsListenerAdapter { + /* @Override public void breakpointCreated(DbgBreakpointInfo info, DbgCause cause); - + @Override public void breakpointModified(DbgBreakpointInfo newInfo, DbgBreakpointInfo oldInfo, DbgCause cause); - + @Override public void breakpointDeleted(DbgBreakpointInfo info, DbgCause cause); - + @Override public void breakpointHit(DbgBreakpointInfo info, DbgCause cause); + */ public default CompletableFuture doPlaceBreakpoint(Set kinds, Function> placer) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointSpecImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointSpecImpl.java index 018f9fd66b..939571288d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointSpecImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointSpecImpl.java @@ -32,8 +32,12 @@ import ghidra.util.datastruct.ListenerSet; name = TargetBreakpointSpec.CONTAINER_ATTRIBUTE_NAME, // type = DbgModelTargetBreakpointContainerImpl.class), // @TargetAttributeType( // - name = TargetBreakpointLocation.SPEC_ATTRIBUTE_NAME, // - type = DbgModelTargetBreakpointSpecImpl.class), // + name = TargetBreakpointLocation.SPEC_ATTRIBUTE_NAME, // + type = DbgModelTargetBreakpointSpecImpl.class), // + @TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_TYPE_ATTRIBUTE_NAME, type = String.class), // + @TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_DISP_ATTRIBUTE_NAME, type = String.class), // + @TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_PENDING_ATTRIBUTE_NAME, type = String.class), // + @TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_TIMES_ATTRIBUTE_NAME, type = Integer.class), // @TargetAttributeType(type = Void.class) // }, canonicalContainer = true) public class DbgModelTargetBreakpointSpecImpl extends DbgModelTargetObjectImpl diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/certification.manifest b/Ghidra/Debug/Debugger-agent-dbgmodel/certification.manifest index fc6bcc9c98..294a1fa195 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/certification.manifest +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/certification.manifest @@ -6,3 +6,4 @@ Module.manifest||GHIDRA||||END| build.gradle||GHIDRA||||END| src/javaprovider/def/javaprovider.def||GHIDRA||||END| src/javaprovider/rc/javaprovider.rc||GHIDRA||||END| +sxrc/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java index e24fcdacdd..2a1c0d1cac 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java @@ -18,11 +18,16 @@ package agent.dbgmodel.model.impl; import java.io.IOException; import java.util.concurrent.CompletableFuture; +import org.jdom.JDOMException; + import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.model.AbstractDbgModel; import agent.dbgeng.model.iface2.DbgModelTargetSession; import agent.dbgmodel.manager.DbgManager2Impl; import ghidra.dbg.target.TargetObject; +import ghidra.dbg.target.schema.TargetObjectSchema; +import ghidra.dbg.target.schema.XmlSchemaContext; +import ghidra.framework.Application; import ghidra.program.model.address.*; public class DbgModel2Impl extends AbstractDbgModel { @@ -30,7 +35,22 @@ public class DbgModel2Impl extends AbstractDbgModel { // The model must convert to and from Ghidra's address space names protected static final String SPACE_NAME = "ram"; - // Don't make this static, so each model has a unique "GDB" space + public static final XmlSchemaContext SCHEMA_CTX; + public static final TargetObjectSchema ROOT_SCHEMA; + static { + try { + //SCHEMA_CTX = + // XmlSchemaContext.deserialize(ResourceManager.getResourceAsStream("dbgmodel.xml")); + SCHEMA_CTX = XmlSchemaContext + .deserialize(DbgModel2Impl.class.getResourceAsStream("dbgmodel_schema.xml")); + ROOT_SCHEMA = SCHEMA_CTX.getSchema(SCHEMA_CTX.name("Debugger")); + } + catch (IOException | JDOMException e) { + throw new AssertionError(e); + } + } + + // Don't make this static, so each model has a unique "ram" space protected final AddressSpace space = new GenericAddressSpace(SPACE_NAME, 64, AddressSpace.TYPE_RAM, 0); protected final AddressFactory addressFactory = @@ -44,7 +64,8 @@ public class DbgModel2Impl extends AbstractDbgModel { public DbgModel2Impl() { this.dbg = new DbgManager2Impl(); - this.root = new DbgModel2TargetRootImpl(this, null); + //System.out.println(XmlSchemaContext.serialize(SCHEMA_CTX)); + this.root = new DbgModel2TargetRootImpl(this, ROOT_SCHEMA); this.completedRoot = CompletableFuture.completedFuture(root); } @@ -77,6 +98,11 @@ public class DbgModel2Impl extends AbstractDbgModel { dbg.terminate(); } + @Override + public TargetObjectSchema getRootSchema() { + return root.getSchema(); + } + @Override public CompletableFuture fetchModelRoot() { return completedRoot; diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java index 392379ac16..e3886196ce 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java @@ -484,7 +484,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot if (map == null) { return; } - setAttributes(List.of(), map, "Refreshed"); + changeAttributes(List.of(), map, "Refreshed"); }); } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java index 90e9a971ef..8905cf4c71 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java @@ -139,6 +139,8 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp List> mixins = new ArrayList<>(); String lkey = key; String pname = parent.getName(); + + /* if (object.getKind().equals(ModelObjectKind.OBJECT_METHOD) || lkey.contains(")")) { mixins.add(DbgModelTargetMethod.class); // NB: We're passing the parent's mixin model to the method on the assumption @@ -147,9 +149,16 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp lkey = pname; pname = ""; } - Class mixin = lookupWrapperType(lkey, pname); - if (mixin != null) { - mixins.add(mixin); + */ + + if (object.getKind().equals(ModelObjectKind.OBJECT_METHOD)) { + mixins.add(DbgModelTargetMethod.class); + } + else { + Class mixin = lookupWrapperType(lkey, pname); + if (mixin != null) { + mixins.add(mixin); + } } return new DelegateDbgModel2TargetObject(model, parent, key, object, mixins).proxy; } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/sxrc/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml b/Ghidra/Debug/Debugger-agent-dbgmodel/sxrc/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml new file mode 100644 index 0000000000..2e52b324cc --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/sxrc/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/ObjectContainer.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/ObjectContainer.java index 406a5ca403..df02f50ca2 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/ObjectContainer.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/ObjectContainer.java @@ -409,6 +409,100 @@ public class ObjectContainer implements Comparable { return result; } + /* + public void toXmlSchema(Element root) { + Element element = this.toXmlSchema(); + root.addContent(element); + + for (ObjectContainer child : getCurrentChildren()) { + String key = child.getShortName(); + if (attributeMap.containsKey(key)) { + if (!(child.targetObject instanceof DummyTargetObject)) { + child.toXmlSchema(root); + } + } + } + for (ObjectContainer child : getCurrentChildren()) { + if (elementMap.containsValue(child.targetObject)) { + child.toXmlSchema(root); + break; + } + } + } + + public Element toXmlSchema() { + String name = getPrefixedName(); + if (name == null) { + name = provider.getRoot().getName(); + } + name = sanitize(name); + Element result = new Element("schema"); + XmlUtilities.setStringAttr(result, "name", name); + for (ObjectContainer child : getCurrentChildren()) { + String key = child.getShortName(); + if (attributeMap.containsKey(key)) { + Element n = new Element("attribute"); + String typeHint = null; + if (child.targetObject != null) { + typeHint = child.targetObject.getTypeHint(); + } + XmlUtilities.setStringAttr(n, "name", key); + if (typeHint != null) { + XmlUtilities.setStringAttr(n, "schema", typeHint); + } + if (key.startsWith("_")) { + XmlUtilities.setStringAttr(n, "hidden", "yes"); + } + result.addContent(n); + } + } + if (elementMap.isEmpty()) { + Element n = new Element("element"); + XmlUtilities.setStringAttr(n, "schema", "VOID"); + result.addContent(n); + } + else { + for (ObjectContainer child : getCurrentChildren()) { + if (elementMap.containsValue(child.targetObject)) { + Element n = new Element("element"); + String typeHint = null; + if (child.targetObject != null) { + typeHint = child.targetObject.getTypeHint(); + } + XmlUtilities.setStringAttr(n, "name", child.getName()); + if (typeHint != null) { + Element ifc = new Element("interface"); + try { + XmlUtilities.setStringAttr(n, "name", sanitize(typeHint)); + } + catch (Exception e) { + //do nothing + } + result.addContent(ifc); + } + result.addContent(n); + break; + } + } + } + Element n = new Element("attribute"); + XmlUtilities.setStringAttr(n, "schema", "VOID"); + result.addContent(n); + return result; + } + + private String sanitize(String name) { + name = name.replaceAll(" ", "_"); + name = name.replaceAll("/", "_"); + if (name.contains("[")) { + name = name.replaceAll("\\[", "_"); + name = name.replaceAll("\\]", ""); + name = name.replaceAll("/", "_"); + } + return name; + } + */ + public boolean isImmutable() { return immutable; } @@ -502,4 +596,5 @@ public class ObjectContainer implements Comparable { } return this.hashCode() - that.hashCode(); } + } diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/XmlSchemaContext.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/XmlSchemaContext.java index 7192ebef91..8475d81506 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/XmlSchemaContext.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/XmlSchemaContext.java @@ -15,8 +15,7 @@ */ package ghidra.dbg.target.schema; -import java.io.ByteArrayInputStream; -import java.io.IOException; +import java.io.*; import java.util.*; import org.jdom.*; @@ -82,8 +81,7 @@ public class XmlSchemaContext extends DefaultSchemaContext { XmlUtilities.setStringAttr(result, "name", schema.getName().toString()); for (Class iface : schema.getInterfaces()) { Element ifElem = new Element("interface"); - XmlUtilities.setStringAttr(ifElem, "name", - DebuggerObjectModel.requireIfaceName(iface)); + XmlUtilities.setStringAttr(ifElem, "name", DebuggerObjectModel.requireIfaceName(iface)); result.addContent(ifElem); } @@ -98,8 +96,7 @@ public class XmlSchemaContext extends DefaultSchemaContext { result.addContent(elemElem); } Element deElem = new Element("element"); - XmlUtilities.setStringAttr(deElem, "schema", - schema.getDefaultElementSchema().toString()); + XmlUtilities.setStringAttr(deElem, "schema", schema.getDefaultElementSchema().toString()); result.addContent(deElem); for (AttributeSchema as : schema.getAttributeSchemas().values()) { @@ -119,15 +116,23 @@ public class XmlSchemaContext extends DefaultSchemaContext { public static XmlSchemaContext deserialize(byte[] xml) throws JDOMException { try { - SAXBuilder sb = XmlUtilities.createSecureSAXBuilder(false, false); - Document doc = sb.build(new ByteArrayInputStream(xml)); - return contextFromXml(doc.getRootElement()); + return deserialize(new ByteArrayInputStream(xml)); } catch (IOException e) { throw new AssertionError(e); } } + public static XmlSchemaContext deserialize(File file) throws JDOMException, IOException { + return deserialize(new FileInputStream(file)); + } + + public static XmlSchemaContext deserialize(InputStream is) throws JDOMException, IOException { + SAXBuilder sb = XmlUtilities.createSecureSAXBuilder(false, false); + Document doc = sb.build(Objects.requireNonNull(is)); + return contextFromXml(doc.getRootElement()); + } + public static XmlSchemaContext contextFromXml(Element contextElem) { XmlSchemaContext ctx = new XmlSchemaContext(); for (Element schemaElem : XmlUtilities.getChildren(contextElem, "schema")) {