GP-571: dbgeng schema implementation

This commit is contained in:
d-millar 2021-01-07 19:16:39 +00:00 committed by Dan
parent eb66a90f6c
commit c81a17405d
49 changed files with 397 additions and 80 deletions

View File

@ -26,8 +26,14 @@ import agent.dbgeng.manager.breakpoint.DbgBreakpointType;
import ghidra.async.AsyncFence;
import ghidra.dbg.target.TargetBreakpointContainer;
import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind;
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)
public interface DbgModelTargetBreakpointContainer extends DbgModelTargetObject,
TargetBreakpointContainer<DbgModelTargetBreakpointContainer>, DbgEventsListenerAdapter {

View File

@ -15,7 +15,6 @@
*/
package agent.dbgeng.model.iface2;
public interface DbgModelTargetDebugContainer extends
DbgModelTargetObject {
public interface DbgModelTargetDebugContainer extends DbgModelTargetObject {
}

View File

@ -15,7 +15,6 @@
*/
package agent.dbgeng.model.iface2;
public interface DbgModelTargetModuleSectionContainer
extends DbgModelTargetObject {
public interface DbgModelTargetModuleSectionContainer extends DbgModelTargetObject {
}

View File

@ -16,6 +16,7 @@
package agent.dbgeng.model.impl;
import ghidra.dbg.target.TargetAggregate;
import ghidra.dbg.target.schema.TargetObjectSchema;
public class DbgModelDefaultTargetModelRoot extends DbgModelTargetObjectImpl
implements TargetAggregate {
@ -23,4 +24,10 @@ public class DbgModelDefaultTargetModelRoot extends DbgModelTargetObjectImpl
public DbgModelDefaultTargetModelRoot(DbgModelImpl model, String typeHint) {
super(model, null, null, typeHint);
}
public DbgModelDefaultTargetModelRoot(DbgModelImpl model, String typeHint,
TargetObjectSchema schema) {
super(model, null, null, typeHint, schema);
}
}

View File

@ -26,6 +26,8 @@ import agent.dbgeng.model.AbstractDbgModel;
import agent.dbgeng.model.iface2.DbgModelTargetSession;
import agent.dbgeng.model.iface2.DbgModelTargetSessionContainer;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.AnnotatedSchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.program.model.address.*;
public class DbgModelImpl extends AbstractDbgModel {
@ -33,6 +35,10 @@ public class DbgModelImpl extends AbstractDbgModel {
// The model must convert to and from Ghidra's address space names
protected static final String SPACE_NAME = "ram";
protected static final AnnotatedSchemaContext SCHEMA_CTX = new AnnotatedSchemaContext();
protected static final TargetObjectSchema ROOT_SCHEMA =
SCHEMA_CTX.getSchemaForClass(DbgModelTargetRootImpl.class);
// Don't make this static, so each model has a unique "GDB" space
protected final AddressSpace space =
new GenericAddressSpace(SPACE_NAME, 64, AddressSpace.TYPE_RAM, 0);
@ -47,7 +53,8 @@ public class DbgModelImpl extends AbstractDbgModel {
public DbgModelImpl() {
this.dbg = DbgManager.newInstance();
this.root = new DbgModelTargetRootImpl(this);
//System.out.println(XmlSchemaContext.serialize(SCHEMA_CTX));
this.root = new DbgModelTargetRootImpl(this, ROOT_SCHEMA);
this.completedRoot = CompletableFuture.completedFuture(root);
DbgSessionImpl s = new DbgSessionImpl((DbgManagerImpl) dbg, new DebugSessionId(0));
s.add();

View File

@ -24,8 +24,14 @@ import org.apache.commons.lang3.tuple.Pair;
import agent.dbgeng.model.iface2.*;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.*;
import ghidra.util.datastruct.WeakValueHashMap;
@TargetObjectSchemaInfo(name = "AvailableContainer", elements = { //
@TargetElementType(type = DbgModelTargetAvailableImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetAvailableContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetAvailableContainer {

View File

@ -20,8 +20,14 @@ import java.util.Map;
import agent.dbgeng.model.iface2.DbgModelTargetAvailable;
import agent.dbgeng.model.iface2.DbgModelTargetAvailableContainer;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
@TargetObjectSchemaInfo(name = "Available", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetAvailableImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetAvailable {
@ -44,7 +50,7 @@ public class DbgModelTargetAvailableImpl extends DbgModelTargetObjectImpl
this.pid = pid;
this.changeAttributes(List.of(), List.of(), Map.of(//
PID_ATTRIBUTE_NAME, pid, //
PID_ATTRIBUTE_NAME, (long) pid, //
DISPLAY_ATTRIBUTE_NAME, keyAttachable(pid) + " : " + name.trim(),
UPDATE_MODE_ATTRIBUTE_NAME, TargetUpdateMode.FIXED //
), "Initialized");
@ -61,6 +67,7 @@ public class DbgModelTargetAvailableImpl extends DbgModelTargetObjectImpl
), "Initialized");
}
@TargetAttributeType(name = PID_ATTRIBUTE_NAME, hidden = true)
@Override
public long getPid() {
return pid;

View File

@ -26,8 +26,14 @@ import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.model.iface2.*;
import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.*;
import ghidra.util.datastruct.WeakValueHashMap;
@TargetObjectSchemaInfo(name = "BreakpointContainer", elements = { //
@TargetElementType(type = DbgModelTargetBreakpointSpecImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetBreakpointContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetBreakpointContainer {

View File

@ -22,9 +22,14 @@ import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo;
import agent.dbgeng.model.iface2.DbgModelTargetBreakpointContainer;
import agent.dbgeng.model.iface2.DbgModelTargetBreakpointSpec;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.TargetAttributeType;
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
import ghidra.dbg.util.PathUtils;
import ghidra.util.datastruct.ListenerSet;
@TargetObjectSchemaInfo(name = "BreakpointSpec", attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetBreakpointSpecImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetBreakpointSpec {

View File

@ -20,7 +20,16 @@ import java.util.Map;
import agent.dbgeng.model.iface2.DbgModelTargetConnector;
import agent.dbgeng.model.iface2.DbgModelTargetRoot;
import ghidra.dbg.target.schema.TargetAttributeType;
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
@TargetObjectSchemaInfo(name = "ConnectorContainer", attributes = { //
@TargetAttributeType(name = "Launch process", type = DbgModelTargetProcessLaunchConnectorImpl.class, required = true, fixed = true), //
@TargetAttributeType(name = "Attach to process", type = DbgModelTargetProcessAttachConnectorImpl.class, required = true, fixed = true), //
@TargetAttributeType(name = "Load trace/dump", type = DbgModelTargetTraceOrDumpConnectorImpl.class, required = true, fixed = true), //
@TargetAttributeType(name = "Attach to kernel", type = DbgModelTargetKernelConnectorImpl.class, required = true, fixed = true), //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetConnectorContainerImpl extends DbgModelTargetObjectImpl {
protected final DbgModelTargetRoot root;

View File

@ -20,7 +20,13 @@ import java.util.Map;
import agent.dbgeng.model.iface2.DbgModelTargetDebugContainer;
import agent.dbgeng.model.iface2.DbgModelTargetProcess;
import ghidra.dbg.target.schema.TargetAttributeType;
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
@TargetObjectSchemaInfo(name = "DebugContainer", attributes = { //
@TargetAttributeType(name = "Breakpoints", type = DbgModelTargetBreakpointContainerImpl.class, required = true, fixed = true), //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetDebugContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetDebugContainer {

View File

@ -26,7 +26,13 @@ import ghidra.dbg.error.DebuggerUserException;
import ghidra.dbg.target.TargetMethod;
import ghidra.dbg.target.TargetMethod.ParameterDescription;
import ghidra.dbg.target.TargetMethod.TargetParameterMap;
import ghidra.dbg.target.schema.*;
@TargetObjectSchemaInfo(name = "KernelConnector", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetKernelConnectorImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetConnector {

View File

@ -31,9 +31,15 @@ import ghidra.dbg.error.DebuggerMemoryAccessException;
import ghidra.dbg.error.DebuggerModelAccessException;
import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibility;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.*;
import ghidra.program.model.address.Address;
import ghidra.util.datastruct.WeakValueHashMap;
@TargetObjectSchemaInfo(name = "Memory", elements = { //
@TargetElementType(type = DbgModelTargetMemoryRegionImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetMemoryContainer {

View File

@ -21,9 +21,23 @@ import java.util.Map;
import agent.dbgeng.manager.DbgModuleMemory;
import agent.dbgeng.model.iface2.DbgModelTargetMemoryContainer;
import agent.dbgeng.model.iface2.DbgModelTargetMemoryRegion;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
import ghidra.program.model.address.*;
@TargetObjectSchemaInfo(name = "MemoryRegion", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(name = "BaseAddress", type = Address.class), //
@TargetAttributeType(name = "EndAddress", type = Address.class), //
@TargetAttributeType(name = "RegionSize", type = String.class), //
@TargetAttributeType(name = "AllocationBase", type = Address.class), //
@TargetAttributeType(name = "AllocationProtect", type = String.class), //
@TargetAttributeType(name = "Protect", type = String.class), //
@TargetAttributeType(name = "State", type = String.class), //
@TargetAttributeType(name = "Type", type = String.class), //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetMemoryRegionImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetMemoryRegion {

View File

@ -26,9 +26,15 @@ import ghidra.async.AsyncFence;
import ghidra.async.AsyncLazyMap;
import ghidra.dbg.target.TargetModule;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.*;
import ghidra.lifecycle.Internal;
import ghidra.util.Msg;
@TargetObjectSchemaInfo(name = "ModuleContainer", elements = { //
@TargetElementType(type = DbgModelTargetModuleImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetModuleContainer {
// NOTE: -file-list-shared-libraries omits the main module and system-supplied DSO.

View File

@ -20,9 +20,20 @@ import java.util.Map;
import agent.dbgeng.manager.*;
import agent.dbgeng.model.iface2.DbgModelTargetModule;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
import ghidra.program.model.address.*;
@TargetObjectSchemaInfo(name = "Module", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(name = "Symbols", type = DbgModelTargetSymbolContainerImpl.class, required = true, fixed = true), //
@TargetAttributeType(name = "BaseAddress", type = Address.class), //
@TargetAttributeType(name = "ImageName", type = String.class), //
@TargetAttributeType(name = "TimeStamp", type = Integer.class), //
@TargetAttributeType(name = "Len", type = String.class), //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetModuleImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetModule {
protected static String indexModule(DbgModule module) {

View File

@ -21,8 +21,14 @@ import java.util.concurrent.CompletableFuture;
import agent.dbgeng.manager.DbgModule;
import agent.dbgeng.manager.DbgModuleSection;
import agent.dbgeng.model.iface2.*;
import ghidra.dbg.target.schema.*;
import ghidra.util.datastruct.WeakValueHashMap;
@TargetObjectSchemaInfo(name = "SectionContainer", elements = { //
@TargetElementType(type = DbgModelTargetModuleSectionImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetModuleSectionContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetModuleSectionContainer {

View File

@ -20,8 +20,14 @@ import java.util.Map;
import agent.dbgeng.manager.DbgModuleSection;
import agent.dbgeng.model.iface2.DbgModelTargetModuleSection;
import ghidra.dbg.target.schema.*;
import ghidra.program.model.address.*;
@TargetObjectSchemaInfo(name = "Section", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetModuleSectionImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetModuleSection {
protected static final String OBJFILE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "objfile";
@ -46,6 +52,7 @@ public class DbgModelTargetModuleSectionImpl extends DbgModelTargetObjectImpl
), "Initialized");
}
@TargetAttributeType(name = RANGE_ATTRIBUTE_NAME)
@Override
public AddressRange getRange() {
return range;

View File

@ -29,6 +29,7 @@ import ghidra.dbg.target.*;
import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibility;
import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibilityListener;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.schema.TargetObjectSchema;
public class DbgModelTargetObjectImpl extends DefaultTargetObject<TargetObject, TargetObject>
implements DbgModelTargetObject {
@ -43,6 +44,12 @@ public class DbgModelTargetObjectImpl extends DefaultTargetObject<TargetObject,
getManager().addStateListener(accessListener);
}
public DbgModelTargetObjectImpl(AbstractDbgModel impl, TargetObject parent, String name,
String typeHint, TargetObjectSchema schema) {
super(impl, parent, name, typeHint, schema);
getManager().addStateListener(accessListener);
}
public void setAttribute(String key, String value) {
changeAttributes(List.of(), List.of(), Map.of( //
key, value), "Initialized");

View File

@ -27,7 +27,13 @@ import ghidra.dbg.error.DebuggerUserException;
import ghidra.dbg.target.TargetMethod;
import ghidra.dbg.target.TargetMethod.ParameterDescription;
import ghidra.dbg.target.TargetMethod.TargetParameterMap;
import ghidra.dbg.target.schema.*;
@TargetObjectSchemaInfo(name = "ProcessAttachConnector", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetProcessAttachConnectorImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetConnector {

View File

@ -25,9 +25,15 @@ import agent.dbgeng.dbgeng.DebugThreadId;
import agent.dbgeng.manager.*;
import agent.dbgeng.model.iface2.*;
import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibility;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.TargetObject;
import ghidra.util.datastruct.WeakValueHashMap;
@TargetObjectSchemaInfo(name = "ProcessContainer", elements = { //
@TargetElementType(type = DbgModelTargetProcessImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetProcessContainer {

View File

@ -33,14 +33,27 @@ import ghidra.dbg.DebuggerObjectModel;
import ghidra.dbg.attributes.TargetObjectRef;
import ghidra.dbg.attributes.TypedTargetObjectRef;
import ghidra.dbg.target.*;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
@TargetObjectSchemaInfo(name = "Process", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(name = "Debug", type = DbgModelTargetDebugContainerImpl.class, required = true, fixed = true), //
@TargetAttributeType(name = "Memory", type = DbgModelTargetMemoryContainerImpl.class, required = true, fixed = true), //
@TargetAttributeType(name = "Modules", type = DbgModelTargetModuleContainerImpl.class, required = true, fixed = true), //
@TargetAttributeType(name = "Threads", type = DbgModelTargetThreadContainerImpl.class, required = true, fixed = true), //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetProcess {
public static final String PID_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "pid";
public static final String EXIT_CODE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "exit_code";
protected static final TargetAttachKindSet SUPPORTED_KINDS = TargetAttachKindSet.of( //
TargetAttachKind.BY_OBJECT_REF, TargetAttachKind.BY_ID);
protected static String indexProcess(DebugProcessId debugProcessId) {
return PathUtils.makeIndex(debugProcessId.id);
}
@ -79,8 +92,11 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
//sections, //
threads //
), Map.of( //
ACCESSIBLE_ATTRIBUTE_NAME, false, //
DISPLAY_ATTRIBUTE_NAME, getDisplay(), //
TargetMethod.PARAMETERS_ATTRIBUTE_NAME, PARAMETERS //
TargetMethod.PARAMETERS_ATTRIBUTE_NAME, PARAMETERS, //
SUPPORTED_ATTACH_KINDS_ATTRIBUTE_NAME, SUPPORTED_KINDS, //
SUPPORTED_STEP_KINDS_ATTRIBUTE_NAME, DbgModelTargetThreadImpl.SUPPORTED_KINDS //
), "Initialized");
setExecutionState(TargetExecutionState.ALIVE, "Initialized");

View File

@ -25,7 +25,13 @@ import ghidra.dbg.error.DebuggerUserException;
import ghidra.dbg.target.TargetMethod;
import ghidra.dbg.target.TargetMethod.ParameterDescription;
import ghidra.dbg.target.TargetMethod.TargetParameterMap;
import ghidra.dbg.target.schema.*;
@TargetObjectSchemaInfo(name = "ProcessLaunchConnector", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetProcessLaunchConnectorImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetConnector {

View File

@ -31,8 +31,14 @@ import ghidra.dbg.error.DebuggerRegisterAccessException;
import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibility;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.TargetRegisterBank;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.ConversionUtils;
@TargetObjectSchemaInfo(name = "RegisterContainer", elements = { //
@TargetElementType(type = DbgModelTargetRegisterImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetRegisterContainerAndBank {

View File

@ -21,8 +21,14 @@ import java.util.Map;
import agent.dbgeng.manager.impl.DbgRegister;
import agent.dbgeng.model.iface2.DbgModelTargetRegister;
import agent.dbgeng.model.iface2.DbgModelTargetRegisterContainerAndBank;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
@TargetObjectSchemaInfo(name = "RegisterDescriptor", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetRegisterImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetRegister {

View File

@ -27,7 +27,16 @@ import ghidra.async.AsyncUtils;
import ghidra.async.TypeSpec;
import ghidra.dbg.error.DebuggerUserException;
import ghidra.dbg.target.*;
import ghidra.dbg.target.schema.*;
@TargetObjectSchemaInfo(name = "Debugger", elements = { //
@TargetElementType(type = Void.class) //
}, 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) //
})
public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot
implements DbgModelTargetRoot {
@ -39,8 +48,8 @@ public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot
protected DbgModelSelectableObject focus;
public DbgModelTargetRootImpl(DbgModelImpl impl) {
super(impl, "Debugger");
public DbgModelTargetRootImpl(DbgModelImpl impl, TargetObjectSchema schema) {
super(impl, "Debugger", schema);
this.available = new DbgModelTargetAvailableContainerImpl(this);
this.connectors = new DbgModelTargetConnectorContainerImpl(this);

View File

@ -21,7 +21,14 @@ import java.util.concurrent.CompletableFuture;
import agent.dbgeng.model.iface2.DbgModelTargetSession;
import agent.dbgeng.model.iface2.DbgModelTargetSessionAttributes;
import ghidra.dbg.target.schema.*;
@TargetObjectSchemaInfo(name = "SessionAttributes", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(name = "Machine", type = DbgModelTargetSessionAttributesMachineImpl.class, fixed = true), //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetSessionAttributesImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetSessionAttributes {

View File

@ -28,13 +28,23 @@ import agent.dbgeng.model.iface2.DbgModelTargetSessionAttributes;
import agent.dbgeng.model.iface2.DbgModelTargetSessionAttributesMachine;
import ghidra.async.AsyncUtils;
import ghidra.async.TypeSpec;
import ghidra.dbg.target.schema.*;
@TargetObjectSchemaInfo(name = "SessionAttributesMachine", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(name = "Arch", type = String.class), //
@TargetAttributeType(name = "Debugger", type = String.class), //
@TargetAttributeType(name = "OS", type = String.class), //
@TargetAttributeType(name = "Mode", type = String.class), //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetSessionAttributesMachineImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetSessionAttributesMachine {
String ARCH_ATTRIBUTE_NAME = "Arch";
String DEBUGGER_ATTRIBUTE_NAME = "Debugger";
String OS_ATTRIBUTE_NAME = "OS";
static String ARCH_ATTRIBUTE_NAME = "Arch";
static String DEBUGGER_ATTRIBUTE_NAME = "Debugger";
static String OS_ATTRIBUTE_NAME = "OS";
public DbgModelTargetSessionAttributesMachineImpl(DbgModelTargetSessionAttributes attributes) {
super(attributes.getModel(), attributes, "Machine", "SessionMachineAttributes");

View File

@ -23,8 +23,14 @@ import agent.dbgeng.dbgeng.DebugSessionId;
import agent.dbgeng.manager.DbgCause;
import agent.dbgeng.manager.DbgSession;
import agent.dbgeng.model.iface2.*;
import ghidra.dbg.target.schema.*;
import ghidra.util.datastruct.WeakValueHashMap;
@TargetObjectSchemaInfo(name = "SessionContainer", elements = { //
@TargetElementType(type = DbgModelTargetSessionImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetSessionContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetSessionContainer {

View File

@ -24,8 +24,16 @@ import agent.dbgeng.manager.*;
import agent.dbgeng.model.iface1.DbgModelSelectableObject;
import agent.dbgeng.model.iface2.DbgModelTargetProcessContainer;
import agent.dbgeng.model.iface2.DbgModelTargetSession;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
@TargetObjectSchemaInfo(name = "Session", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(name = "Attributes", type = DbgModelTargetSessionAttributesImpl.class, fixed = true), //
@TargetAttributeType(name = "Processes", type = DbgModelTargetProcessContainerImpl.class, required = true, fixed = true), //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetSessionImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetSession {
@ -61,8 +69,9 @@ public class DbgModelTargetSessionImpl extends DbgModelTargetObjectImpl
attributes, //
processes //
), Map.of( //
ACCESSIBLE_ATTRIBUTE_NAME, true, //
PROMPT_ATTRIBUTE_NAME, DBG_PROMPT, //
//STATE_ATTRIBUTE_NAME, TargetExecutionState.RUNNING, //
STATE_ATTRIBUTE_NAME, TargetExecutionState.ALIVE, //
UPDATE_MODE_ATTRIBUTE_NAME, TargetUpdateMode.FIXED //
), "Initialized");

View File

@ -30,9 +30,26 @@ import ghidra.async.AsyncUtils;
import ghidra.async.TypeSpec;
import ghidra.dbg.DebugModelConventions;
import ghidra.dbg.attributes.TargetObjectRef;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
import ghidra.program.model.address.Address;
@TargetObjectSchemaInfo(name = "StackFrame", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(name = DbgModelTargetStackFrame.FUNC_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(name = DbgModelTargetStackFrame.FUNC_TABLE_ENTRY_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(name = DbgModelTargetStackFrame.INST_OFFSET_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(name = DbgModelTargetStackFrame.FRAME_OFFSET_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(name = DbgModelTargetStackFrame.RETURN_OFFSET_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(name = DbgModelTargetStackFrame.STACK_OFFSET_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(name = DbgModelTargetStackFrame.VIRTUAL_ATTRIBUTE_NAME, type = Boolean.class), //
@TargetAttributeType(name = DbgModelTargetStackFrame.PARAM0_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(name = DbgModelTargetStackFrame.PARAM1_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(name = DbgModelTargetStackFrame.PARAM2_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(name = DbgModelTargetStackFrame.PARAM3_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetStackFrameImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetStackFrame {

View File

@ -24,19 +24,27 @@ import agent.dbgeng.manager.DbgStackFrame;
import agent.dbgeng.model.iface2.*;
import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibility;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.*;
import ghidra.util.Msg;
import ghidra.util.datastruct.WeakValueHashMap;
@TargetObjectSchemaInfo(name = "Stack", elements = { //
@TargetElementType(type = DbgModelTargetStackFrameImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetStackImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetStack {
protected final DbgModelTargetThread thread;
public static final String NAME = "Stack";
protected final Map<Integer, DbgModelTargetStackFrameImpl> framesByLevel =
new WeakValueHashMap<>();
public DbgModelTargetStackImpl(DbgModelTargetThread thread, DbgModelTargetProcess process) {
super(thread.getModel(), thread, "Stack", "Stack");
super(thread.getModel(), thread, NAME, "Stack");
this.thread = thread;
}

View File

@ -23,8 +23,14 @@ import java.util.stream.Collectors;
import agent.dbgeng.manager.impl.DbgMinimalSymbol;
import agent.dbgeng.model.iface2.DbgModelTargetSymbolContainer;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.*;
import ghidra.util.datastruct.WeakValueHashMap;
@TargetObjectSchemaInfo(name = "SymbolContainer", elements = { //
@TargetElementType(type = DbgModelTargetSymbolImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetSymbolContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetSymbolContainer {

View File

@ -20,9 +20,15 @@ import java.util.Map;
import agent.dbgeng.manager.impl.DbgMinimalSymbol;
import agent.dbgeng.model.iface2.DbgModelTargetSymbol;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
import ghidra.program.model.address.Address;
@TargetObjectSchemaInfo(name = "Symbol", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetSymbolImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetSymbol {
protected static String indexSymbol(DbgMinimalSymbol symbol) {

View File

@ -25,9 +25,14 @@ import agent.dbgeng.manager.*;
import agent.dbgeng.manager.reason.*;
import agent.dbgeng.model.iface2.*;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.*;
import ghidra.util.datastruct.WeakValueHashMap;
// TODO: Should TargetThreadContainer be a thing?
@TargetObjectSchemaInfo(name = "ThreadContainer", elements = { //
@TargetElementType(type = DbgModelTargetThreadImpl.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
}, canonicalContainer = true)
public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetThreadContainer {

View File

@ -31,8 +31,17 @@ import ghidra.async.AsyncUtils;
import ghidra.async.TypeSpec;
import ghidra.dbg.DebugModelConventions;
import ghidra.dbg.target.TargetEnvironment;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
@TargetObjectSchemaInfo(name = "Thread", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(name = "Registers", type = DbgModelTargetRegisterContainerImpl.class, required = true, fixed = true), //
@TargetAttributeType(name = "Stack", type = DbgModelTargetStackImpl.class, required = true, fixed = true), //
@TargetAttributeType(name = TargetEnvironment.ARCH_ATTRIBUTE_NAME, type = String.class), //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetThread {
@ -72,6 +81,7 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
registers, //
stack //
), Map.of( //
ACCESSIBLE_ATTRIBUTE_NAME, false, //
DISPLAY_ATTRIBUTE_NAME, getDisplay(), //
SUPPORTED_STEP_KINDS_ATTRIBUTE_NAME, SUPPORTED_KINDS //
), "Initialized");

View File

@ -25,7 +25,13 @@ import ghidra.dbg.error.DebuggerUserException;
import ghidra.dbg.target.TargetMethod;
import ghidra.dbg.target.TargetMethod.ParameterDescription;
import ghidra.dbg.target.TargetMethod.TargetParameterMap;
import ghidra.dbg.target.schema.*;
@TargetObjectSchemaInfo(name = "TraceOrDumpConnector", elements = { //
@TargetElementType(type = Void.class) //
}, attributes = { //
@TargetAttributeType(type = Void.class) //
})
public class DbgModelTargetTraceOrDumpConnectorImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetConnector {

View File

@ -45,6 +45,8 @@ import ghidra.dbg.target.TargetConsole.Channel;
import ghidra.dbg.target.TargetFocusScope.TargetFocusScopeListener;
import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher;
import ghidra.dbg.target.TargetObject.TargetObjectListener;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.dbg.util.AllTargetObjectListenerAdapter;
import ghidra.dbg.util.PathUtils;
import ghidra.program.model.address.Address;
@ -1067,4 +1069,22 @@ public abstract class AbstractModelForDbgTest
}).finish());
}
}
protected void init(ModelHost m) throws Throwable {
waitOn(m.init());
}
@Test
public void testSerializeSchema() throws Throwable {
try (ModelHost m = modelHost()) {
DebuggerObjectModel model = m.getModel();
init(m);
TargetObjectSchema rootSchema = model.getRootSchema();
String serialized = XmlSchemaContext.serialize(rootSchema.getContext());
System.out.println(serialized);
assertEquals("Debugger", rootSchema.getName().toString());
}
}
}

View File

@ -24,7 +24,6 @@ import ghidra.dbg.agent.DefaultTargetObject;
import ghidra.dbg.target.TargetEnvironment;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.*;
import ghidra.util.Msg;
@TargetObjectSchemaInfo(name = "Environment", elements = {
@TargetElementType(type = Void.class)
@ -36,6 +35,10 @@ public class GdbModelTargetEnvironment
implements TargetEnvironment<GdbModelTargetEnvironment> {
public static final String NAME = "Environment";
public static final String VISIBLE_ARCH_ATTRIBUTE_NAME = "arch";
public static final String VISIBLE_OS_ATTRIBUTE_NAME = "os";
public static final String VISIBLE_ENDIAN_ATTRIBUTE_NAME = "endian";
protected final GdbModelImpl impl;
protected String arch = "(unknown)";
@ -96,7 +99,7 @@ public class GdbModelTargetEnvironment
// But, that may also be (perhaps more) version dependent
this.arch = arch;
}).exceptionally(e -> {
Msg.error(this, "Could not get target architecture", e);
model.reportError(this, "Could not get target architecture", e);
return null;
});
}
@ -130,7 +133,7 @@ public class GdbModelTargetEnvironment
// Would need to ignore "auto", "default", and "none"?
this.os = os;
}).exceptionally(e -> {
Msg.error(this, "Could not get target os", e);
model.reportError(this, "Could not get target os", e);
return null;
});
}
@ -148,7 +151,7 @@ public class GdbModelTargetEnvironment
endian = "(unknown)";
}
}).exceptionally(e -> {
Msg.error(this, "Could not get target endian", e);
model.reportError(this, "Could not get target endian", e);
return null;
});
}
@ -170,21 +173,18 @@ public class GdbModelTargetEnvironment
});
}
@TargetAttributeType(name = ARCH_ATTRIBUTE_NAME, hidden = true)
@Deprecated(forRemoval = true)
public String getInvisibleArch() {
@TargetAttributeType(name = VISIBLE_ARCH_ATTRIBUTE_NAME)
public String getVisibleArch() {
return arch;
}
@TargetAttributeType(name = OS_ATTRIBUTE_NAME, hidden = true)
@Deprecated(forRemoval = true)
public String getInvisibleOs() {
@TargetAttributeType(name = VISIBLE_OS_ATTRIBUTE_NAME)
public String getVisibleOs() {
return os;
}
@TargetAttributeType(name = ENDIAN_ATTRIBUTE_NAME, hidden = true)
@Deprecated(forRemoval = true)
public String getInvisibleEndian() {
@TargetAttributeType(name = VISIBLE_ENDIAN_ATTRIBUTE_NAME)
public String getVisibleEndian() {
return endian;
}

View File

@ -37,6 +37,9 @@ import ghidra.util.Msg;
public class GdbModelTargetModule
extends DefaultTargetObject<TargetObject, GdbModelTargetModuleContainer>
implements TargetModule<GdbModelTargetModule> {
public static final String VISIBLE_RANGE_ATTRIBUTE_NAME = "range";
protected static String indexModule(GdbModule module) {
return module.getName();
}
@ -124,9 +127,10 @@ public class GdbModelTargetModule
return range;
}
@Deprecated(forRemoval = true)
@TargetAttributeType(name = RANGE_ATTRIBUTE_NAME)
public AddressRange getInvisibleRange() {
// TODO: Consider a way to override the "hidden" field of an attribute
// Otherwise, this information is duplicated in memory and on the wire
@TargetAttributeType(name = VISIBLE_RANGE_ATTRIBUTE_NAME)
public AddressRange getVisibleRange() {
return range;
}
}

View File

@ -34,6 +34,9 @@ import ghidra.program.model.address.*;
public class GdbModelTargetSection
extends DefaultTargetObject<TargetObject, GdbModelTargetSectionContainer>
implements TargetSection<GdbModelTargetSection> {
public static final String VISIBLE_RANGE_ATTRIBUTE_NAME = "range";
protected static String indexSection(GdbModuleSection section) {
return section.getName();
}
@ -85,9 +88,8 @@ public class GdbModelTargetSection
return range;
}
@Deprecated(forRemoval = true)
@TargetAttributeType(name = RANGE_ATTRIBUTE_NAME)
public AddressRange getInvisibleRange() {
@TargetAttributeType(name = VISIBLE_RANGE_ATTRIBUTE_NAME)
public AddressRange getVisibleRange() {
return range;
}

View File

@ -230,7 +230,7 @@ public class GdbModelTargetThread
protected CompletableFuture<?> updateStack() {
Msg.debug(this, "Updating stack for " + this);
return stack.update().thenCompose(__ -> updateInfo()).exceptionally(ex -> {
Msg.error(this, "Could not update stack for thread " + this, ex);
model.reportError(this, "Could not update stack for thread " + this, ex);
return null;
});
}

View File

@ -1993,6 +1993,7 @@ public class DefaultTraceRecorder implements TraceRecorder {
protected synchronized void removeProcessModule(TargetModule<?> module) {
String path = PathUtils.toString(module.getPath());
long snap = snapshot.getKey();
TraceThread eventThread = snapshot.getEventThread();
TraceModule traceModule = moduleManager.getLoadedModuleByPath(snap, path);
if (traceModule == null) {
Msg.warn(this, "unloaded " + path + " is not in the trace");
@ -2000,6 +2001,11 @@ public class DefaultTraceRecorder implements TraceRecorder {
}
try (PermanentTransaction tid =
PermanentTransaction.start(trace, "Module " + path + " unloaded")) {
if (traceModule.getLoadedSnap() == snap) {
Msg.warn(this, "Observed module unload in the same snap as its load");
createSnapshot("WARN: Module removed", eventThread, tid);
snap = snapshot.getKey();
}
traceModule.setUnloadedSnap(snap - 1);
}
catch (DuplicateNameException e) {

View File

@ -22,14 +22,14 @@ import java.util.concurrent.CompletableFuture;
import ghidra.async.AsyncUtils;
import ghidra.async.TypeSpec;
import ghidra.dbg.attributes.TargetObjectRef;
import ghidra.dbg.error.DebuggerModelNoSuchPathException;
import ghidra.dbg.error.DebuggerModelTypeException;
import ghidra.dbg.error.*;
import ghidra.dbg.target.TargetMemory;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.EnumerableTargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.util.PathUtils;
import ghidra.program.model.address.*;
import ghidra.util.Msg;
/**
* A debugger model, often a connection to an external debugger
@ -220,6 +220,7 @@ public interface DebuggerObjectModel {
/**
* Create a reference to the given path in this model
*
* <p>
* Note that the path is not checked until the object is fetched. Thus, it is possible for a
* reference to refer to a non-existent object.
*
@ -238,6 +239,7 @@ public interface DebuggerObjectModel {
/**
* Fetch the attributes of a given model path
*
* <p>
* Giving an empty path will retrieve the attributes of the root object. If the path does not
* exist, the future completes with {@code null}.
*
@ -269,6 +271,7 @@ public interface DebuggerObjectModel {
/**
* Fetch the elements of a given model path
*
* <p>
* Giving an empty path will retrieve all the top-level objects, i.e., elements of the root. If
* the path does not exist, the future completes with {@code null}.
*
@ -300,6 +303,7 @@ public interface DebuggerObjectModel {
/**
* Fetch the root object of the model
*
* <p>
* The root is a virtual object to contain all the top-level objects of the model tree. This
* object represents the debugger itself.
*
@ -310,7 +314,6 @@ public interface DebuggerObjectModel {
/**
* Fetch the value at the given path
*
*
* @param path the path of the value
* @return a future completing with the value or with {@code null} if the path does not exist
*/
@ -462,6 +465,7 @@ public interface DebuggerObjectModel {
/**
* Invalidate the caches for every object known locally.
*
* <p>
* Unlike, {@link TargetObject#invalidateCaches()}, this does not push the request to a remote
* object. If the objects are proxies, just the proxies' caches are cleared. Again, this does
* not apply to caches for the objects' children.
@ -471,10 +475,30 @@ public interface DebuggerObjectModel {
/**
* Close the session and dispose the model
*
* <p>
* For local sessions, terminate the debugger. For client sessions, disconnect.
*
* @return a future which completes when the session is closed
*/
public CompletableFuture<Void> close();
/**
* A convenience for reporting errors conditionally
*
* <p>
* If the message is ignorable, e.g., a {@link DebuggerModelTerminatingException}, then the
* report will be reduced to a stack-free warning.
*
* @param origin the object producing the error
* @param message the error message
* @param ex the exception
*/
default void reportError(Object origin, String message, Throwable ex) {
if (ex == null || DebuggerModelTerminatingException.isIgnorable(ex)) {
Msg.warn(origin, message + ": " + ex);
}
else {
Msg.error(origin, message, ex);
}
}
}

View File

@ -50,9 +50,6 @@ public interface TargetEnvironment<T extends TargetEnvironment<T>> extends Typed
String DEBUGGER_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "debugger";
String OS_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "os";
String ENDIAN_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "endian";
String VISIBLE_ARCH_ATTRIBUTE_NAME = "arch";
String VISIBLE_OS_ATTRIBUTE_NAME = "os";
String VISIBLE_ENDIAN_ATTRIBUTE_NAME = "endian";
/**
* Get a description of the target architecture
@ -66,9 +63,9 @@ public interface TargetEnvironment<T extends TargetEnvironment<T>> extends Typed
*
* @return the target architecture
*/
@TargetAttributeType(name = VISIBLE_ARCH_ATTRIBUTE_NAME)
@TargetAttributeType(name = ARCH_ATTRIBUTE_NAME, hidden = true)
default String getArchitecture() {
return getTypedAttributeNowByName(VISIBLE_ARCH_ATTRIBUTE_NAME, String.class, "");
return getTypedAttributeNowByName(ARCH_ATTRIBUTE_NAME, String.class, "");
}
/**
@ -101,9 +98,9 @@ public interface TargetEnvironment<T extends TargetEnvironment<T>> extends Typed
*
* @return the target operating system
*/
@TargetAttributeType(name = VISIBLE_OS_ATTRIBUTE_NAME)
@TargetAttributeType(name = OS_ATTRIBUTE_NAME, hidden = true)
default String getOperatingSystem() {
return getTypedAttributeNowByName(VISIBLE_OS_ATTRIBUTE_NAME, String.class, "");
return getTypedAttributeNowByName(OS_ATTRIBUTE_NAME, String.class, "");
}
/**
@ -116,9 +113,9 @@ public interface TargetEnvironment<T extends TargetEnvironment<T>> extends Typed
*
* @return the target endianness
*/
@TargetAttributeType(name = VISIBLE_ENDIAN_ATTRIBUTE_NAME)
@TargetAttributeType(name = ENDIAN_ATTRIBUTE_NAME, hidden = true)
default String getEndian() {
return getTypedAttributeNowByName(VISIBLE_ENDIAN_ATTRIBUTE_NAME, String.class, "");
return getTypedAttributeNowByName(ENDIAN_ATTRIBUTE_NAME, String.class, "");
}
// TODO: Devices? File System?

View File

@ -39,7 +39,6 @@ public interface TargetModule<T extends TargetModule<T>> extends TypedTargetObje
Class<Private.Cls> tclass = (Class) TargetModule.class;
TypeSpec<TargetModule<?>> TYPE = TypeSpec.auto();
String VISIBLE_RANGE_ATTRIBUTE_NAME = "range";
String RANGE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "range";
String MODULE_NAME_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "module_name";
@ -54,9 +53,9 @@ public interface TargetModule<T extends TargetModule<T>> extends TypedTargetObje
*
* @return the base address, or {@code null}
*/
@TargetAttributeType(name = VISIBLE_RANGE_ATTRIBUTE_NAME, required = true)
@TargetAttributeType(name = RANGE_ATTRIBUTE_NAME, required = true, hidden = true)
public default AddressRange getRange() {
return getTypedAttributeNowByName(VISIBLE_RANGE_ATTRIBUTE_NAME, AddressRange.class, null);
return getTypedAttributeNowByName(RANGE_ATTRIBUTE_NAME, AddressRange.class, null);
}
/**

View File

@ -221,7 +221,12 @@ public interface TargetObject extends TargetObjectRef {
.collect(Collectors.toList());
}
@Deprecated
/**
* A conventional prefix of hidden attributes defined by the {@code TargetObject} interfaces
*
* <p>
* When the "hidden" field of attributes can be overridden, this prefix should be removed
*/
String PREFIX_INVISIBLE = "_";
String DISPLAY_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "display";

View File

@ -45,7 +45,6 @@ public interface TargetSection<T extends TargetSection<T>> extends TypedTargetOb
String MODULE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "module";
String RANGE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "range";
String VISIBLE_RANGE_ATTRIBUTE_NAME = "range";
/**
* Get the module to which this section belongs
@ -66,9 +65,9 @@ public interface TargetSection<T extends TargetSection<T>> extends TypedTargetOb
*
* @return the range
*/
@TargetAttributeType(name = VISIBLE_RANGE_ATTRIBUTE_NAME, required = true, fixed = true)
@TargetAttributeType(name = RANGE_ATTRIBUTE_NAME, required = true, fixed = true)
public default AddressRange getRange() {
return getTypedAttributeNowByName(VISIBLE_RANGE_ATTRIBUTE_NAME, AddressRange.class, null);
return getTypedAttributeNowByName(RANGE_ATTRIBUTE_NAME, AddressRange.class, null);
}
/**

View File

@ -31,6 +31,7 @@ import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.DefaultTargetObjectSchema.DefaultAttributeSchema;
import ghidra.dbg.target.schema.TargetObjectSchema.AttributeSchema;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.util.Msg;
import utilities.util.reflection.ReflectionUtilities;
public class AnnotatedSchemaContext extends DefaultSchemaContext {
@ -115,8 +116,7 @@ public class AnnotatedSchemaContext extends DefaultSchemaContext {
return Set.of(TargetObject.class);
}
throw new IllegalArgumentException("Getter " + getter +
" for attribute must return primitive or subclass of " +
TargetObjectRef.class);
" for attribute must return primitive or subclass of " + TargetObjectRef.class);
}
protected final Map<Class<? extends TargetObject>, SchemaName> namesByClass =
@ -126,13 +126,14 @@ public class AnnotatedSchemaContext extends DefaultSchemaContext {
protected SchemaName nameFromAnnotatedClass(Class<? extends TargetObject> cls) {
synchronized (namesByClass) {
TargetObjectSchemaInfo info = cls.getAnnotation(TargetObjectSchemaInfo.class);
if (info == null) {
// TODO: Compile-time validation?
Msg.warn(this, "Class " + cls + " is not annotated with @" +
TargetObjectSchemaInfo.class.getSimpleName());
return EnumerableTargetObjectSchema.OBJECT.getName();
}
return namesByClass.computeIfAbsent(cls, c -> {
TargetObjectSchemaInfo info = cls.getAnnotation(TargetObjectSchemaInfo.class);
if (info == null) {
// TODO: Compile-time validation?
throw new IllegalArgumentException("Class " + cls + " is not annotated with @" +
TargetObjectSchemaInfo.class.getSimpleName());
}
String name = info.name();
if (name.equals("")) {
return new SchemaName(cls.getSimpleName());
@ -166,8 +167,7 @@ public class AnnotatedSchemaContext extends DefaultSchemaContext {
AttributeSchema attrSchema;
try {
attrSchema =
attributeSchemaFromAnnotatedMethod(declCls, method, at);
attrSchema = attributeSchemaFromAnnotatedMethod(declCls, method, at);
}
catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
@ -209,7 +209,7 @@ public class AnnotatedSchemaContext extends DefaultSchemaContext {
if (bounds.size() != 1) {
// TODO: Compile-time validation?
throw new IllegalArgumentException(
"Could not identify unique element class: " + bounds);
"Could not identify unique element class (" + bounds + ") for " + cls);
}
else {
Class<? extends TargetObject> bound = bounds.iterator().next();
@ -219,8 +219,8 @@ public class AnnotatedSchemaContext extends DefaultSchemaContext {
}
catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
"Could not get schema name from bound " + bound + " of " +
cls + ".fetchElements()",
"Could not get schema name from bound " + bound + " of " + cls +
".fetchElements()",
e);
}
builder.setDefaultElementSchema(schemaName);
@ -245,30 +245,27 @@ public class AnnotatedSchemaContext extends DefaultSchemaContext {
}
protected String attributeNameFromBean(String beanName, boolean isBool) {
beanName = isBool
? StringUtils.removeStartIgnoreCase(beanName, "is")
beanName = isBool ? StringUtils.removeStartIgnoreCase(beanName, "is")
: StringUtils.removeStartIgnoreCase(beanName, "get");
if (beanName.equals("")) {
throw new IllegalArgumentException("Attribute getter must have a name");
}
return beanName
.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2")
return beanName.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2")
.replaceAll("([a-z])([A-Z])", "$1_$2")
.toLowerCase();
}
protected AttributeSchema attributeSchemaFromAnnotation(TargetAttributeType at) {
return new DefaultAttributeSchema(at.name(), nameFromClass(at.type()),
at.required(), at.fixed(), at.hidden());
return new DefaultAttributeSchema(at.name(), nameFromClass(at.type()), at.required(),
at.fixed(), at.hidden());
}
protected AttributeSchema attributeSchemaFromAnnotatedMethod(Class<? extends TargetObject> cls,
Method method, TargetAttributeType at) {
if (method.getParameterCount() != 0) {
// TODO: Compile-time validation?
throw new IllegalArgumentException(
"Non-getter method " + method + " is annotated with @" +
TargetAttributeType.class.getSimpleName());
throw new IllegalArgumentException("Non-getter method " + method +
" is annotated with @" + TargetAttributeType.class.getSimpleName());
}
String name = at.name();
Class<?> ret = method.getReturnType();
@ -276,11 +273,10 @@ public class AnnotatedSchemaContext extends DefaultSchemaContext {
name = attributeNameFromBean(method.getName(),
EnumerableTargetObjectSchema.BOOL.getTypes().contains(ret));
}
SchemaName primitiveName =
EnumerableTargetObjectSchema.nameForPrimitive(ret);
SchemaName primitiveName = EnumerableTargetObjectSchema.nameForPrimitive(ret);
if (primitiveName != null) {
return new DefaultAttributeSchema(name, primitiveName,
at.required(), at.fixed(), at.hidden());
return new DefaultAttributeSchema(name, primitiveName, at.required(), at.fixed(),
at.hidden());
}
Set<Class<? extends TargetObject>> bounds = getBoundsOfObjectAttributeGetter(cls, method);
if (bounds.size() != 1) {