GP-4390 Collapse DomainObject Undoable interfaces and refactor Command processing.

This commit is contained in:
ghidra1
2024-03-08 12:49:50 -05:00
parent 136b933af2
commit 445494ba25
214 changed files with 2862 additions and 3813 deletions
@@ -322,8 +322,7 @@ public class TraceRmiHandler implements TraceRmiConnection {
} }
} }
protected DomainFolder getOrCreateNewTracesFolder() protected DomainFolder getOrCreateNewTracesFolder() throws InvalidNameException, IOException {
throws InvalidNameException, IOException {
return getOrCreateFolder(plugin.getTool().getProject().getProjectData().getRootFolder(), return getOrCreateFolder(plugin.getTool().getProject().getProjectData().getRootFolder(),
"New Traces"); "New Traces");
} }
@@ -494,10 +493,8 @@ public class TraceRmiHandler implements TraceRmiConnection {
return rep == null ? null : rep.build(); return rep == null ? null : rep.build();
} }
catch (Throwable e) { catch (Throwable e) {
return rep return rep.setError(ReplyError.newBuilder()
.setError(ReplyError.newBuilder() .setMessage(e.getMessage() + "\n" + ExceptionUtils.getStackTrace(e)))
.setMessage(
e.getMessage() + "\n" + ExceptionUtils.getStackTrace(e)))
.build(); .build();
} }
} }
@@ -509,8 +506,8 @@ public class TraceRmiHandler implements TraceRmiConnection {
req.getRequestActivate().getOid().getId(), req.getRequestActivate().getOid().getId(),
req.getRequestActivate().getObject().getId(), req.getRequestActivate().getObject().getId(),
req.getRequestActivate().getObject().getPath().getPath()); req.getRequestActivate().getObject().getPath().getPath());
case REQUEST_END_TX -> "endTx(%d)".formatted( case REQUEST_END_TX -> "endTx(%d)"
req.getRequestEndTx().getTxid().getId()); .formatted(req.getRequestEndTx().getTxid().getId());
case REQUEST_START_TX -> "startTx(%d,%s)".formatted( case REQUEST_START_TX -> "startTx(%d,%s)".formatted(
req.getRequestStartTx().getTxid().getId(), req.getRequestStartTx().getTxid().getId(),
req.getRequestStartTx().getDescription()); req.getRequestStartTx().getDescription());
@@ -530,49 +527,40 @@ public class TraceRmiHandler implements TraceRmiConnection {
} }
final Dispatcher dispatchNegotiate = (req, rep) -> switch (req.getMsgCase()) { final Dispatcher dispatchNegotiate = (req, rep) -> switch (req.getMsgCase()) {
case REQUEST_NEGOTIATE -> rep case REQUEST_NEGOTIATE -> rep.setReplyNegotiate(handleNegotiate(req.getRequestNegotiate()));
.setReplyNegotiate(handleNegotiate(req.getRequestNegotiate()));
default -> throw new InvalidRequestError(req); default -> throw new InvalidRequestError(req);
}; };
final Dispatcher dispatchNominal = (req, rep) -> switch (req.getMsgCase()) { final Dispatcher dispatchNominal = (req, rep) -> switch (req.getMsgCase()) {
case REQUEST_ACTIVATE -> rep case REQUEST_ACTIVATE -> rep.setReplyActivate(handleActivate(req.getRequestActivate()));
.setReplyActivate(handleActivate(req.getRequestActivate()));
case REQUEST_CLOSE_TRACE -> rep case REQUEST_CLOSE_TRACE -> rep
.setReplyCloseTrace(handleCloseTrace(req.getRequestCloseTrace())); .setReplyCloseTrace(handleCloseTrace(req.getRequestCloseTrace()));
case REQUEST_CREATE_OBJECT -> rep case REQUEST_CREATE_OBJECT -> rep
.setReplyCreateObject(handleCreateObject(req.getRequestCreateObject())); .setReplyCreateObject(handleCreateObject(req.getRequestCreateObject()));
case REQUEST_CREATE_OVERLAY -> rep case REQUEST_CREATE_OVERLAY -> rep
.setReplyCreateOverlay( .setReplyCreateOverlay(handleCreateOverlay(req.getRequestCreateOverlay()));
handleCreateOverlay(req.getRequestCreateOverlay()));
case REQUEST_CREATE_ROOT_OBJECT -> rep case REQUEST_CREATE_ROOT_OBJECT -> rep
.setReplyCreateObject( .setReplyCreateObject(handleCreateRootObject(req.getRequestCreateRootObject()));
handleCreateRootObject(req.getRequestCreateRootObject()));
case REQUEST_CREATE_TRACE -> rep case REQUEST_CREATE_TRACE -> rep
.setReplyCreateTrace(handleCreateTrace(req.getRequestCreateTrace())); .setReplyCreateTrace(handleCreateTrace(req.getRequestCreateTrace()));
case REQUEST_DELETE_BYTES -> rep case REQUEST_DELETE_BYTES -> rep
.setReplyDeleteBytes(handleDeleteBytes(req.getRequestDeleteBytes())); .setReplyDeleteBytes(handleDeleteBytes(req.getRequestDeleteBytes()));
case REQUEST_DELETE_REGISTER_VALUE -> rep case REQUEST_DELETE_REGISTER_VALUE -> rep.setReplyDeleteRegisterValue(
.setReplyDeleteRegisterValue( handleDeleteRegisterValue(req.getRequestDeleteRegisterValue()));
handleDeleteRegisterValue(req.getRequestDeleteRegisterValue()));
case REQUEST_DISASSEMBLE -> rep case REQUEST_DISASSEMBLE -> rep
.setReplyDisassemble(handleDisassemble(req.getRequestDisassemble())); .setReplyDisassemble(handleDisassemble(req.getRequestDisassemble()));
case REQUEST_END_TX -> rep case REQUEST_END_TX -> rep.setReplyEndTx(handleEndTx(req.getRequestEndTx()));
.setReplyEndTx(handleEndTx(req.getRequestEndTx()));
case REQUEST_GET_OBJECT -> rep case REQUEST_GET_OBJECT -> rep
.setReplyGetObject(handleGetObject(req.getRequestGetObject())); .setReplyGetObject(handleGetObject(req.getRequestGetObject()));
case REQUEST_GET_VALUES -> rep case REQUEST_GET_VALUES -> rep
.setReplyGetValues(handleGetValues(req.getRequestGetValues())); .setReplyGetValues(handleGetValues(req.getRequestGetValues()));
case REQUEST_GET_VALUES_INTERSECTING -> rep case REQUEST_GET_VALUES_INTERSECTING -> rep.setReplyGetValues(
.setReplyGetValues( handleGetValuesIntersecting(req.getRequestGetValuesIntersecting()));
handleGetValuesIntersecting(req.getRequestGetValuesIntersecting()));
case REQUEST_INSERT_OBJECT -> rep case REQUEST_INSERT_OBJECT -> rep
.setReplyInsertObject(handleInsertObject(req.getRequestInsertObject())); .setReplyInsertObject(handleInsertObject(req.getRequestInsertObject()));
case REQUEST_PUT_BYTES -> rep case REQUEST_PUT_BYTES -> rep.setReplyPutBytes(handlePutBytes(req.getRequestPutBytes()));
.setReplyPutBytes(handlePutBytes(req.getRequestPutBytes()));
case REQUEST_PUT_REGISTER_VALUE -> rep case REQUEST_PUT_REGISTER_VALUE -> rep
.setReplyPutRegisterValue( .setReplyPutRegisterValue(handlePutRegisterValue(req.getRequestPutRegisterValue()));
handlePutRegisterValue(req.getRequestPutRegisterValue()));
case REQUEST_REMOVE_OBJECT -> rep case REQUEST_REMOVE_OBJECT -> rep
.setReplyRemoveObject(handleRemoveObject(req.getRequestRemoveObject())); .setReplyRemoveObject(handleRemoveObject(req.getRequestRemoveObject()));
case REQUEST_RETAIN_VALUES -> rep case REQUEST_RETAIN_VALUES -> rep
@@ -580,14 +568,10 @@ public class TraceRmiHandler implements TraceRmiConnection {
case REQUEST_SAVE_TRACE -> rep case REQUEST_SAVE_TRACE -> rep
.setReplySaveTrace(handleSaveTrace(req.getRequestSaveTrace())); .setReplySaveTrace(handleSaveTrace(req.getRequestSaveTrace()));
case REQUEST_SET_MEMORY_STATE -> rep case REQUEST_SET_MEMORY_STATE -> rep
.setReplySetMemoryState( .setReplySetMemoryState(handleSetMemoryState(req.getRequestSetMemoryState()));
handleSetMemoryState(req.getRequestSetMemoryState())); case REQUEST_SET_VALUE -> rep.setReplySetValue(handleSetValue(req.getRequestSetValue()));
case REQUEST_SET_VALUE -> rep case REQUEST_SNAPSHOT -> rep.setReplySnapshot(handleSnapshot(req.getRequestSnapshot()));
.setReplySetValue(handleSetValue(req.getRequestSetValue())); case REQUEST_START_TX -> rep.setReplyStartTx(handleStartTx(req.getRequestStartTx()));
case REQUEST_SNAPSHOT -> rep
.setReplySnapshot(handleSnapshot(req.getRequestSnapshot()));
case REQUEST_START_TX -> rep
.setReplyStartTx(handleStartTx(req.getRequestStartTx()));
case XREPLY_INVOKE_METHOD -> handleXInvokeMethod(req.getXreplyInvokeMethod()); case XREPLY_INVOKE_METHOD -> handleXInvokeMethod(req.getXreplyInvokeMethod());
default -> throw new InvalidRequestError(req); default -> throw new InvalidRequestError(req);
}; };
@@ -666,15 +650,11 @@ public class TraceRmiHandler implements TraceRmiConnection {
} }
protected static ObjSpec makeObjSpec(TraceObject object) { protected static ObjSpec makeObjSpec(TraceObject object) {
return ObjSpec.newBuilder() return ObjSpec.newBuilder().setId(object.getKey()).build();
.setId(object.getKey())
.build();
} }
protected static ObjPath makeObjPath(TraceObjectKeyPath path) { protected static ObjPath makeObjPath(TraceObjectKeyPath path) {
return ObjPath.newBuilder() return ObjPath.newBuilder().setPath(path.toString()).build();
.setPath(path.toString())
.build();
} }
protected static ObjDesc makeObjDesc(TraceObject object) { protected static ObjDesc makeObjDesc(TraceObject object) {
@@ -767,15 +747,13 @@ public class TraceRmiHandler implements TraceRmiConnection {
if (value instanceof int[] ia) { if (value instanceof int[] ia) {
return Value.newBuilder() return Value.newBuilder()
.setIntArrValue( .setIntArrValue(
IntArr.newBuilder() IntArr.newBuilder().addAllArr(IntStream.of(ia).mapToObj(i -> i).toList()))
.addAllArr(IntStream.of(ia).mapToObj(i -> i).toList()))
.build(); .build();
} }
if (value instanceof long[] la) { if (value instanceof long[] la) {
return Value.newBuilder() return Value.newBuilder()
.setLongArrValue( .setLongArrValue(
LongArr.newBuilder() LongArr.newBuilder().addAllArr(LongStream.of(la).mapToObj(l -> l).toList()))
.addAllArr(LongStream.of(la).mapToObj(l -> l).toList()))
.build(); .build();
} }
if (value instanceof String[] sa) { if (value instanceof String[] sa) {
@@ -847,8 +825,7 @@ public class TraceRmiHandler implements TraceRmiConnection {
protected ReplyCreateObject handleCreateObject(RequestCreateObject req) { protected ReplyCreateObject handleCreateObject(RequestCreateObject req) {
OpenTrace open = requireOpenTrace(req.getOid()); OpenTrace open = requireOpenTrace(req.getOid());
TraceObject object = TraceObject object = open.trace.getObjectManager().createObject(toKeyPath(req.getPath()));
open.trace.getObjectManager().createObject(toKeyPath(req.getPath()));
return ReplyCreateObject.newBuilder().setObject(makeObjSpec(object)).build(); return ReplyCreateObject.newBuilder().setObject(makeObjSpec(object)).build();
} }
@@ -904,8 +881,7 @@ public class TraceRmiHandler implements TraceRmiConnection {
return ReplyDeleteBytes.getDefaultInstance(); return ReplyDeleteBytes.getDefaultInstance();
} }
protected ReplyDeleteRegisterValue handleDeleteRegisterValue( protected ReplyDeleteRegisterValue handleDeleteRegisterValue(RequestDeleteRegisterValue req) {
RequestDeleteRegisterValue req) {
OpenTrace open = requireOpenTrace(req.getOid()); OpenTrace open = requireOpenTrace(req.getOid());
long snap = req.getSnap().getSnap(); long snap = req.getSnap().getSnap();
AddressSpace space = open.trace.getBaseAddressFactory().getAddressSpace(req.getSpace()); AddressSpace space = open.trace.getBaseAddressFactory().getAddressSpace(req.getSpace());
@@ -932,15 +908,13 @@ public class TraceRmiHandler implements TraceRmiConnection {
// Want addresses satisfying {@code known | (readOnly & everKnown)} // Want addresses satisfying {@code known | (readOnly & everKnown)}
TraceMemoryManager memoryManager = open.trace.getMemoryManager(); TraceMemoryManager memoryManager = open.trace.getMemoryManager();
AddressSetView readOnly = AddressSetView readOnly = memoryManager.getRegionsAddressSetWith(snap, r -> !r.isWrite());
memoryManager.getRegionsAddressSetWith(snap, r -> !r.isWrite());
AddressSetView everKnown = memoryManager.getAddressesWithState(Lifespan.since(snap), AddressSetView everKnown = memoryManager.getAddressesWithState(Lifespan.since(snap),
s -> s == TraceMemoryState.KNOWN); s -> s == TraceMemoryState.KNOWN);
AddressSetView roEverKnown = new IntersectionAddressSetView(readOnly, everKnown); AddressSetView roEverKnown = new IntersectionAddressSetView(readOnly, everKnown);
AddressSetView known = AddressSetView known =
memoryManager.getAddressesWithState(snap, s -> s == TraceMemoryState.KNOWN); memoryManager.getAddressesWithState(snap, s -> s == TraceMemoryState.KNOWN);
AddressSetView disassemblable = AddressSetView disassemblable = new AddressSet(new UnionAddressSetView(known, roEverKnown));
new AddressSet(new UnionAddressSetView(known, roEverKnown));
Address start = open.toAddress(req.getStart(), true); Address start = open.toAddress(req.getStart(), true);
TracePlatform host = open.trace.getPlatformManager().getHostPlatform(); TracePlatform host = open.trace.getPlatformManager().getHostPlatform();
@@ -950,7 +924,7 @@ public class TraceRmiHandler implements TraceRmiConnection {
host.getLanguage(), host.getLanguage().getLanguageID(), start)); host.getLanguage(), host.getLanguage().getLanguageID(), start));
try (CloseableTaskMonitor monitor = plugin.createMonitor()) { try (CloseableTaskMonitor monitor = plugin.createMonitor()) {
dis.applyToTyped(open.trace.getFixedProgramView(snap), monitor); dis.applyTo(open.trace.getFixedProgramView(snap), monitor);
} }
return ReplyDisassemble.newBuilder() return ReplyDisassemble.newBuilder()
@@ -988,21 +962,19 @@ public class TraceRmiHandler implements TraceRmiConnection {
OpenTrace open = requireOpenTrace(req.getOid()); OpenTrace open = requireOpenTrace(req.getOid());
return ReplyGetValues.newBuilder() return ReplyGetValues.newBuilder()
.addAllValues(open.trace.getObjectManager() .addAllValues(open.trace.getObjectManager()
.getValuePaths(toLifespan(req.getSpan()), .getValuePaths(toLifespan(req.getSpan()), toPathPattern(req.getPattern()))
toPathPattern(req.getPattern()))
.map(TraceRmiHandler::makeValDesc) .map(TraceRmiHandler::makeValDesc)
.sorted(Comparator.comparing(ValDesc::getKey)) .sorted(Comparator.comparing(ValDesc::getKey))
.toList()) .toList())
.build(); .build();
} }
protected ReplyGetValues handleGetValuesIntersecting( protected ReplyGetValues handleGetValuesIntersecting(RequestGetValuesIntersecting req)
RequestGetValuesIntersecting req) throws AddressOverflowException { throws AddressOverflowException {
OpenTrace open = requireOpenTrace(req.getOid()); OpenTrace open = requireOpenTrace(req.getOid());
AddressRange range = open.toRange(req.getBox().getRange(), false); AddressRange range = open.toRange(req.getBox().getRange(), false);
String key = req.getKey() == "" ? null : req.getKey(); String key = req.getKey() == "" ? null : req.getKey();
Collection<? extends TraceObjectValue> col = range == null Collection<? extends TraceObjectValue> col = range == null ? List.of()
? List.of()
: open.trace.getObjectManager() : open.trace.getObjectManager()
.getValuesIntersecting(toLifespan(req.getBox().getSpan()), range, key); .getValuesIntersecting(toLifespan(req.getBox().getSpan()), range, key);
return ReplyGetValues.newBuilder() return ReplyGetValues.newBuilder()
@@ -1018,9 +990,7 @@ public class TraceRmiHandler implements TraceRmiConnection {
.stream() .stream()
.map(TraceObjectValue::getLifespan) .map(TraceObjectValue::getLifespan)
.reduce(Lifespan.ALL, Lifespan::intersect); .reduce(Lifespan.ALL, Lifespan::intersect);
return ReplyInsertObject.newBuilder() return ReplyInsertObject.newBuilder().setSpan(makeSpan(span)).build();
.setSpan(makeSpan(span))
.build();
} }
protected ReplyNegotiate handleNegotiate(RequestNegotiate req) { protected ReplyNegotiate handleNegotiate(RequestNegotiate req) {
@@ -1031,8 +1001,8 @@ public class TraceRmiHandler implements TraceRmiConnection {
} }
for (Method m : req.getMethodsList()) { for (Method m : req.getMethodsList()) {
RemoteMethod rm = new RecordRemoteMethod(this, m.getName(), RemoteMethod rm = new RecordRemoteMethod(this, m.getName(),
ActionName.name(m.getAction()), m.getDisplay(), ActionName.name(m.getAction()), m.getDisplay(), m.getDescription(),
m.getDescription(), m.getParametersList() m.getParametersList()
.stream() .stream()
.collect(Collectors.toMap(MethodParameter::getName, this::makeParameter)), .collect(Collectors.toMap(MethodParameter::getName, this::makeParameter)),
new SchemaName(m.getReturnType().getName())); new SchemaName(m.getReturnType().getName()));
@@ -1141,8 +1111,7 @@ public class TraceRmiHandler implements TraceRmiConnection {
return ReplySetMemoryState.getDefaultInstance(); return ReplySetMemoryState.getDefaultInstance();
} }
protected ReplySetValue handleSetValue(RequestSetValue req) protected ReplySetValue handleSetValue(RequestSetValue req) throws AddressOverflowException {
throws AddressOverflowException {
ValSpec value = req.getValue(); ValSpec value = req.getValue();
OpenTrace open = requireOpenTrace(req.getOid()); OpenTrace open = requireOpenTrace(req.getOid());
Object objVal = open.toValue(value.getValue()); Object objVal = open.toValue(value.getValue());
@@ -1152,8 +1121,8 @@ public class TraceRmiHandler implements TraceRmiConnection {
return ReplySetValue.newBuilder().setSpan(makeSpan(Lifespan.EMPTY)).build(); return ReplySetValue.newBuilder().setSpan(makeSpan(Lifespan.EMPTY)).build();
} }
TraceObjectValue val = object.setValue(toLifespan(value.getSpan()), value.getKey(), TraceObjectValue val = object.setValue(toLifespan(value.getSpan()), value.getKey(), objVal,
objVal, toResolution(req.getResolution())); toResolution(req.getResolution()));
return ReplySetValue.newBuilder() return ReplySetValue.newBuilder()
.setSpan(makeSpan(val == null ? Lifespan.EMPTY : val.getLifespan())) .setSpan(makeSpan(val == null ? Lifespan.EMPTY : val.getLifespan()))
.build(); .build();
@@ -22,7 +22,7 @@ import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.debug.api.platform.DebuggerPlatformMapper; import ghidra.debug.api.platform.DebuggerPlatformMapper;
import ghidra.debug.api.platform.DisassemblyResult; import ghidra.debug.api.platform.DisassemblyResult;
import ghidra.debug.api.tracemgr.DebuggerCoordinates; import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.cmd.TypedBackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView; import ghidra.program.model.address.AddressSetView;
@@ -33,7 +33,7 @@ import ghidra.trace.model.thread.TraceThread;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public final class CurrentPlatformTraceDisassembleCommand public final class CurrentPlatformTraceDisassembleCommand
extends TypedBackgroundCommand<TraceProgramView> { extends BackgroundCommand<TraceProgramView> {
public static final String NAME = "Disassemble"; public static final String NAME = "Disassemble";
public record Reqs(DebuggerPlatformMapper mapper, TraceThread thread, TraceObject object, public record Reqs(DebuggerPlatformMapper mapper, TraceThread thread, TraceObject object,
@@ -48,8 +48,7 @@ public final class CurrentPlatformTraceDisassembleCommand
return null; return null;
} }
Trace trace = view.getTrace(); Trace trace = view.getTrace();
DebuggerCoordinates current = traceManager == null DebuggerCoordinates current = traceManager == null ? DebuggerCoordinates.NOWHERE
? DebuggerCoordinates.NOWHERE
: traceManager.getCurrentFor(trace); : traceManager.getCurrentFor(trace);
TraceThread thread = current.getThread(); TraceThread thread = current.getThread();
TraceObject object = current.getObject(); TraceObject object = current.getObject();
@@ -74,8 +73,8 @@ public final class CurrentPlatformTraceDisassembleCommand
private final Reqs reqs; private final Reqs reqs;
private final Address address; private final Address address;
public CurrentPlatformTraceDisassembleCommand(PluginTool tool, AddressSetView set, public CurrentPlatformTraceDisassembleCommand(PluginTool tool, AddressSetView set, Reqs reqs,
Reqs reqs, Address address) { Address address) {
super(NAME, true, true, false); super(NAME, true, true, false);
this.tool = tool; this.tool = tool;
this.set = set; this.set = set;
@@ -84,9 +83,9 @@ public final class CurrentPlatformTraceDisassembleCommand
} }
@Override @Override
public boolean applyToTyped(TraceProgramView view, TaskMonitor monitor) { public boolean applyTo(TraceProgramView view, TaskMonitor monitor) {
DisassemblyResult result = reqs.mapper.disassemble( DisassemblyResult result = reqs.mapper.disassemble(reqs.thread, reqs.object, address, set,
reqs.thread, reqs.object, address, set, view.getSnap(), monitor); view.getSnap(), monitor);
if (!result.isSuccess()) { if (!result.isSuccess()) {
tool.setStatusInfo(result.getErrorMessage(), true); tool.setStatusInfo(result.getErrorMessage(), true);
} }
@@ -15,7 +15,7 @@
*/ */
package ghidra.app.plugin.core.debug.disassemble; package ghidra.app.plugin.core.debug.disassemble;
import ghidra.framework.cmd.TypedBackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.program.disassemble.Disassembler; import ghidra.program.disassemble.Disassembler;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
@@ -27,7 +27,7 @@ import ghidra.trace.model.program.TraceProgramView;
import ghidra.util.MathUtilities; import ghidra.util.MathUtilities;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class TraceDisassembleCommand extends TypedBackgroundCommand<TraceProgramView> { public class TraceDisassembleCommand extends BackgroundCommand<TraceProgramView> {
protected final TracePlatform platform; protected final TracePlatform platform;
protected final Address start; protected final Address start;
@@ -76,7 +76,7 @@ public class TraceDisassembleCommand extends TypedBackgroundCommand<TraceProgram
} }
@Override @Override
public boolean applyToTyped(TraceProgramView view, TaskMonitor monitor) { public boolean applyTo(TraceProgramView view, TaskMonitor monitor) {
Disassembler disassembler = getDisassembler(view, monitor); Disassembler disassembler = getDisassembler(view, monitor);
MemBuffer buffer = getBuffer(view); MemBuffer buffer = getBuffer(view);
if (buffer == null) { if (buffer == null) {
@@ -73,8 +73,8 @@ public abstract class AbstractDebuggerPlatformMapper implements DebuggerPlatform
} }
@Override @Override
public DisassemblyResult disassemble(TraceThread thread, TraceObject object, public DisassemblyResult disassemble(TraceThread thread, TraceObject object, Address start,
Address start, AddressSetView restricted, long snap, TaskMonitor monitor) { AddressSetView restricted, long snap, TaskMonitor monitor) {
if (isCancelSilently(start, snap)) { if (isCancelSilently(start, snap)) {
return DisassemblyResult.CANCELLED; return DisassemblyResult.CANCELLED;
} }
@@ -86,7 +86,7 @@ public abstract class AbstractDebuggerPlatformMapper implements DebuggerPlatform
for (DisassemblyInject i : injects) { for (DisassemblyInject i : injects) {
i.pre(tool, dis, platform, snap, thread, startSet, restricted); i.pre(tool, dis, platform, snap, thread, startSet, restricted);
} }
boolean result = dis.applyToTyped(trace.getFixedProgramView(snap), monitor); boolean result = dis.applyTo(trace.getFixedProgramView(snap), monitor);
if (!result) { if (!result) {
return DisassemblyResult.failed(dis.getStatusMsg()); return DisassemblyResult.failed(dis.getStatusMsg());
} }
@@ -24,8 +24,8 @@ import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import ghidra.app.plugin.core.debug.utils.DefaultTransactionCoalescer; import ghidra.app.plugin.core.debug.utils.DefaultTransactionCoalescer;
import ghidra.app.plugin.core.debug.utils.TransactionCoalescer; import ghidra.app.plugin.core.debug.utils.TransactionCoalescer;
import ghidra.app.plugin.core.debug.utils.TransactionCoalescer.CoalescedTx; import ghidra.app.plugin.core.debug.utils.TransactionCoalescer.CoalescedTx;
import ghidra.framework.model.DomainObject;
import ghidra.framework.model.DomainObjectException; import ghidra.framework.model.DomainObjectException;
import ghidra.framework.model.UndoableDomainObject;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.ClosedException; import ghidra.util.exception.ClosedException;
@@ -33,17 +33,17 @@ public class PermanentTransactionExecutor {
private final TransactionCoalescer txc; private final TransactionCoalescer txc;
private final ExecutorService[] threads; private final ExecutorService[] threads;
private final UndoableDomainObject obj; private final DomainObject obj;
public PermanentTransactionExecutor(UndoableDomainObject obj, String name, int threadCount, public PermanentTransactionExecutor(DomainObject obj, String name, int threadCount,
int delayMs) { int delayMs) {
this.obj = obj; this.obj = obj;
txc = new DefaultTransactionCoalescer<>(obj, RecorderPermanentTransaction::start, delayMs); txc = new DefaultTransactionCoalescer<>(obj, RecorderPermanentTransaction::start, delayMs);
this.threads = new ExecutorService[threadCount]; this.threads = new ExecutorService[threadCount];
for (int i = 0; i < threadCount; i++) { for (int i = 0; i < threadCount; i++) {
ThreadFactory factory = new BasicThreadFactory.Builder() ThreadFactory factory =
.namingPattern(name + "thread-" + i + "-%d") new BasicThreadFactory.Builder().namingPattern(name + "thread-" + i + "-%d")
.build(); .build();
threads[i] = Executors.newSingleThreadExecutor(factory); threads[i] = Executors.newSingleThreadExecutor(factory);
} }
} }
@@ -16,19 +16,19 @@
package ghidra.app.plugin.core.debug.service.model; package ghidra.app.plugin.core.debug.service.model;
import db.Transaction; import db.Transaction;
import ghidra.framework.model.UndoableDomainObject; import ghidra.framework.model.DomainObject;
public class RecorderPermanentTransaction implements AutoCloseable { public class RecorderPermanentTransaction implements AutoCloseable {
public static RecorderPermanentTransaction start(UndoableDomainObject obj, String description) { public static RecorderPermanentTransaction start(DomainObject obj, String description) {
Transaction tx = obj.openTransaction(description); Transaction tx = obj.openTransaction(description);
return new RecorderPermanentTransaction(obj, tx); return new RecorderPermanentTransaction(obj, tx);
} }
private final UndoableDomainObject obj; private final DomainObject obj;
private final Transaction tx; private final Transaction tx;
public RecorderPermanentTransaction(UndoableDomainObject obj, Transaction tx) { public RecorderPermanentTransaction(DomainObject obj, Transaction tx) {
this.obj = obj; this.obj = obj;
this.tx = tx; this.tx = tx;
} }
@@ -20,11 +20,11 @@ import java.util.Collection;
import ghidra.app.services.DebuggerStaticMappingService; import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry; import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject; import ghidra.trace.model.Trace;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class MapModulesBackgroundCommand extends BackgroundCommand { public class MapModulesBackgroundCommand extends BackgroundCommand<Trace> {
private final DebuggerStaticMappingService service; private final DebuggerStaticMappingService service;
private final Collection<ModuleMapEntry> entries; private final Collection<ModuleMapEntry> entries;
@@ -36,7 +36,7 @@ public class MapModulesBackgroundCommand extends BackgroundCommand {
} }
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public boolean applyTo(Trace trace, TaskMonitor monitor) {
try { try {
service.addModuleMappings(entries, monitor, true); service.addModuleMappings(entries, monitor, true);
} }
@@ -20,11 +20,11 @@ import java.util.Collection;
import ghidra.app.services.DebuggerStaticMappingService; import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.debug.api.modules.RegionMapProposal.RegionMapEntry; import ghidra.debug.api.modules.RegionMapProposal.RegionMapEntry;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject; import ghidra.trace.model.Trace;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class MapRegionsBackgroundCommand extends BackgroundCommand { public class MapRegionsBackgroundCommand extends BackgroundCommand<Trace> {
private final DebuggerStaticMappingService service; private final DebuggerStaticMappingService service;
private final Collection<RegionMapEntry> entries; private final Collection<RegionMapEntry> entries;
@@ -36,7 +36,7 @@ public class MapRegionsBackgroundCommand extends BackgroundCommand {
} }
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public boolean applyTo(Trace trace, TaskMonitor monitor) {
try { try {
service.addRegionMappings(entries, monitor, true); service.addRegionMappings(entries, monitor, true);
} }
@@ -20,11 +20,11 @@ import java.util.Collection;
import ghidra.app.services.DebuggerStaticMappingService; import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.debug.api.modules.SectionMapProposal.SectionMapEntry; import ghidra.debug.api.modules.SectionMapProposal.SectionMapEntry;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject; import ghidra.trace.model.Trace;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class MapSectionsBackgroundCommand extends BackgroundCommand { public class MapSectionsBackgroundCommand extends BackgroundCommand<Trace> {
private final DebuggerStaticMappingService service; private final DebuggerStaticMappingService service;
private final Collection<SectionMapEntry> entries; private final Collection<SectionMapEntry> entries;
@@ -36,7 +36,7 @@ public class MapSectionsBackgroundCommand extends BackgroundCommand {
} }
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public boolean applyTo(Trace trace, TaskMonitor monitor) {
try { try {
service.addSectionMappings(entries, monitor, true); service.addSectionMappings(entries, monitor, true);
} }
@@ -16,7 +16,7 @@
package ghidra.app.plugin.core.debug.stack; package ghidra.app.plugin.core.debug.stack;
import ghidra.debug.api.tracemgr.DebuggerCoordinates; import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.cmd.TypedBackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.pcode.exec.DebuggerPcodeUtils.WatchValue; import ghidra.pcode.exec.DebuggerPcodeUtils.WatchValue;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
@@ -27,7 +27,7 @@ import ghidra.util.task.TaskMonitor;
* A command to unwind as much of the stack as possible and annotate the resulting frame in the * A command to unwind as much of the stack as possible and annotate the resulting frame in the
* dynamic listing * dynamic listing
*/ */
public class UnwindStackCommand extends TypedBackgroundCommand<Trace> { public class UnwindStackCommand extends BackgroundCommand<Trace> {
private final PluginTool tool; private final PluginTool tool;
private final DebuggerCoordinates where; private final DebuggerCoordinates where;
@@ -39,7 +39,7 @@ public class UnwindStackCommand extends TypedBackgroundCommand<Trace> {
} }
@Override @Override
public boolean applyToTyped(Trace obj, TaskMonitor monitor) { public boolean applyTo(Trace obj, TaskMonitor monitor) {
try { try {
StackUnwinder unwinder = new StackUnwinder(tool, where.getPlatform()); StackUnwinder unwinder = new StackUnwinder(tool, where.getPlatform());
int prevParamSize = 0; int prevParamSize = 0;
@@ -25,7 +25,6 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
import ghidra.async.AsyncUtils; import ghidra.async.AsyncUtils;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject; import ghidra.framework.model.DomainObject;
import ghidra.framework.model.UndoableDomainObject;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.Swing; import ghidra.util.Swing;
@@ -35,8 +34,8 @@ import ghidra.util.task.*;
public enum BackgroundUtils { public enum BackgroundUtils {
; ;
public static class AsyncBackgroundCommand<T extends UndoableDomainObject> public static class AsyncBackgroundCommand<T extends DomainObject>
extends BackgroundCommand { extends BackgroundCommand<T> {
private CompletableFuture<?> promise; private CompletableFuture<?> promise;
private final CancelledListener cancelledListener = this::cancelled; private final CancelledListener cancelledListener = this::cancelled;
@@ -53,9 +52,8 @@ public enum BackgroundUtils {
} }
@Override @Override
@SuppressWarnings("unchecked") public boolean applyTo(T obj, TaskMonitor monitor) {
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { promise = futureProducer.apply(obj, monitor);
promise = futureProducer.apply((T) obj, monitor);
monitor.addCancelledListener(cancelledListener); monitor.addCancelledListener(cancelledListener);
try { try {
promise.get(); promise.get();
@@ -103,8 +101,8 @@ public enum BackgroundUtils {
* @param futureProducer a function to start the task * @param futureProducer a function to start the task
* @return a future which completes when the task is finished. * @return a future which completes when the task is finished.
*/ */
public static <T extends UndoableDomainObject> AsyncBackgroundCommand<T> async(PluginTool tool, public static <T extends DomainObject> AsyncBackgroundCommand<T> async(PluginTool tool, T obj,
T obj, String name, boolean hasProgress, boolean canCancel, boolean isModal, String name, boolean hasProgress, boolean canCancel, boolean isModal,
BiFunction<T, TaskMonitor, CompletableFuture<?>> futureProducer) { BiFunction<T, TaskMonitor, CompletableFuture<?>> futureProducer) {
AsyncBackgroundCommand<T> cmd = AsyncBackgroundCommand<T> cmd =
new AsyncBackgroundCommand<>(name, hasProgress, canCancel, isModal, futureProducer); new AsyncBackgroundCommand<>(name, hasProgress, canCancel, isModal, futureProducer);
@@ -119,7 +117,7 @@ public enum BackgroundUtils {
* The returned future includes error handling, so even if the task completes in error, the * The returned future includes error handling, so even if the task completes in error, the
* returned future will just complete with null. If further error handling is required, then the * returned future will just complete with null. If further error handling is required, then the
* {@code futureProducer} should make the future available. This differs from * {@code futureProducer} should make the future available. This differs from
* {@link #async(PluginTool, UndoableDomainObject, String, boolean, boolean, boolean, BiFunction)} * {@link #async(PluginTool, DomainObject, String, boolean, boolean, boolean, BiFunction)}
* in that it doesn't use the tool's task manager, so it can run in parallel with other tasks. * in that it doesn't use the tool's task manager, so it can run in parallel with other tasks.
* There is not currently a supported method to run multiple non-modal tasks concurrently, since * There is not currently a supported method to run multiple non-modal tasks concurrently, since
* they would have to share a single task monitor component. * they would have to share a single task monitor component.
@@ -172,14 +170,14 @@ public enum BackgroundUtils {
private final PluginTool tool; private final PluginTool tool;
private final String name; private final String name;
private final UndoableDomainObject obj; private final DomainObject obj;
private final int delay; private final int delay;
private final EnumSet<TaskOpt> opts; private final EnumSet<TaskOpt> opts;
private TaskMonitor lastMonitor; private TaskMonitor lastMonitor;
public PluginToolExecutorService(PluginTool tool, String name, UndoableDomainObject obj, public PluginToolExecutorService(PluginTool tool, String name, DomainObject obj, int delay,
int delay, TaskOpt... opts) { TaskOpt... opts) {
this.tool = tool; this.tool = tool;
this.name = name; this.name = name;
this.obj = obj; this.obj = obj;
@@ -223,10 +221,8 @@ public enum BackgroundUtils {
} }
protected void executeForeground(Runnable command) { protected void executeForeground(Runnable command) {
Task task = new Task(name, Task task = new Task(name, opts.contains(TaskOpt.CAN_CANCEL),
opts.contains(TaskOpt.CAN_CANCEL), opts.contains(TaskOpt.HAS_PROGRESS), opts.contains(TaskOpt.IS_MODAL)) {
opts.contains(TaskOpt.HAS_PROGRESS),
opts.contains(TaskOpt.IS_MODAL)) {
@Override @Override
public void run(TaskMonitor monitor) throws CancelledException { public void run(TaskMonitor monitor) throws CancelledException {
lastMonitor = monitor; lastMonitor = monitor;
@@ -237,10 +233,8 @@ public enum BackgroundUtils {
} }
protected void executeBackground(Runnable command) { protected void executeBackground(Runnable command) {
BackgroundCommand cmd = new BackgroundCommand(name, BackgroundCommand cmd = new BackgroundCommand(name, opts.contains(TaskOpt.HAS_PROGRESS),
opts.contains(TaskOpt.HAS_PROGRESS), opts.contains(TaskOpt.CAN_CANCEL), opts.contains(TaskOpt.IS_MODAL)) {
opts.contains(TaskOpt.CAN_CANCEL),
opts.contains(TaskOpt.IS_MODAL)) {
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
lastMonitor = monitor; lastMonitor = monitor;
@@ -17,10 +17,10 @@ package ghidra.app.plugin.core.debug.utils;
import ghidra.async.AsyncDebouncer; import ghidra.async.AsyncDebouncer;
import ghidra.async.AsyncTimer; import ghidra.async.AsyncTimer;
import ghidra.framework.model.UndoableDomainObject; import ghidra.framework.model.DomainObject;
import ghidra.util.Msg; import ghidra.util.Msg;
public class DefaultTransactionCoalescer<T extends UndoableDomainObject, U extends AutoCloseable> public class DefaultTransactionCoalescer<T extends DomainObject, U extends AutoCloseable>
implements TransactionCoalescer { implements TransactionCoalescer {
protected class Coalescer { protected class Coalescer {
@@ -17,11 +17,10 @@ package ghidra.app.plugin.core.debug.utils;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import ghidra.framework.model.UndoableDomainObject; import ghidra.framework.model.DomainObject;
public interface TransactionCoalescer { public interface TransactionCoalescer {
public interface TxFactory<T extends UndoableDomainObject, U> public interface TxFactory<T extends DomainObject, U> extends BiFunction<T, String, U> {
extends BiFunction<T, String, U> {
} }
public interface CoalescedTx extends AutoCloseable { public interface CoalescedTx extends AutoCloseable {
@@ -197,9 +197,8 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
DBTraceMemoryManager memory = tb.trace.getMemoryManager(); DBTraceMemoryManager memory = tb.trace.getMemoryManager();
if (pcInStack) { if (pcInStack) {
DBTraceObject objFrame = DBTraceObject objFrame = objects
objects.createObject( .createObject(TraceObjectKeyPath.parse("Targets[0].Threads[0].Stack[0]"));
TraceObjectKeyPath.parse("Targets[0].Threads[0].Stack[0]"));
objFrame.insert(zeroOn, ConflictResolution.DENY); objFrame.insert(zeroOn, ConflictResolution.DENY);
TraceObjectStackFrame frame = objFrame.queryInterface(TraceObjectStackFrame.class); TraceObjectStackFrame frame = objFrame.queryInterface(TraceObjectStackFrame.class);
frame.setProgramCounter(zeroOn, tb.addr(offset)); frame.setProgramCounter(zeroOn, tb.addr(offset));
@@ -208,8 +207,8 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
objects.createObject( objects.createObject(
TraceObjectKeyPath.parse("Targets[0].Threads[0].Stack[0].Registers")) TraceObjectKeyPath.parse("Targets[0].Threads[0].Stack[0].Registers"))
.insert(zeroOn, ConflictResolution.DENY); .insert(zeroOn, ConflictResolution.DENY);
TraceObjectThread thread = objects.getObjectByCanonicalPath( TraceObjectThread thread = objects
TraceObjectKeyPath.parse("Targets[0].Threads[0]")) .getObjectByCanonicalPath(TraceObjectKeyPath.parse("Targets[0].Threads[0]"))
.queryInterface(TraceObjectThread.class); .queryInterface(TraceObjectThread.class);
traceManager.activateThread(thread); traceManager.activateThread(thread);
DBTraceMemorySpace regs = DBTraceMemorySpace regs =
@@ -248,8 +247,8 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
} }
} }
protected void createLegacyTrace(String langID, long offset, protected void createLegacyTrace(String langID, long offset, Supplier<ByteBuffer> byteSupplier)
Supplier<ByteBuffer> byteSupplier) throws Throwable { throws Throwable {
createAndOpenTrace(langID); createAndOpenTrace(langID);
try (Transaction tx = tb.startTransaction()) { try (Transaction tx = tb.startTransaction()) {
@@ -358,8 +357,8 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = program.openTransaction("Load")) { try (Transaction tx = program.openTransaction("Load")) {
start = program.getAddressFactory().getDefaultAddressSpace().getAddress(0x00400000); start = program.getAddressFactory().getDefaultAddressSpace().getAddress(0x00400000);
program.getMemory() program.getMemory()
.createInitializedBlock(".text", start, .createInitializedBlock(".text", start, new ByteArrayInputStream(arr("ebffc0")),
new ByteArrayInputStream(arr("ebffc0")), 3, monitor, false); 3, monitor, false);
} }
intoProject(program); intoProject(program);
@@ -654,7 +653,7 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
new AddressSet(start, start.addWrap(1))); new AddressSet(start, start.addWrap(1)));
dis.setInitialContext(DebuggerDisassemblerPlugin.deriveAlternativeDefaultContext( dis.setInitialContext(DebuggerDisassemblerPlugin.deriveAlternativeDefaultContext(
tb.language, new LanguageID("ARM:LE:32:v8T"), start)); tb.language, new LanguageID("ARM:LE:32:v8T"), start));
dis.applyToTyped(tb.trace.getProgramView(), TaskMonitor.DUMMY); dis.applyTo(tb.trace.getProgramView(), TaskMonitor.DUMMY);
} }
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@@ -715,11 +714,11 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
TraceGuestPlatform guest = TraceGuestPlatform guest =
Unique.assertOne(tb.trace.getPlatformManager().getGuestPlatforms()); Unique.assertOne(tb.trace.getPlatformManager().getGuestPlatforms());
try (Transaction tx = tb.startTransaction()) { try (Transaction tx = tb.startTransaction()) {
TraceDisassembleCommand dis = new TraceDisassembleCommand(guest, start, TraceDisassembleCommand dis =
new AddressSet(start, start.addWrap(1))); new TraceDisassembleCommand(guest, start, new AddressSet(start, start.addWrap(1)));
dis.setInitialContext(DebuggerDisassemblerPlugin.deriveAlternativeDefaultContext( dis.setInitialContext(DebuggerDisassemblerPlugin.deriveAlternativeDefaultContext(
guest.getLanguage(), new LanguageID("ARM:LE:32:v8T"), start)); guest.getLanguage(), new LanguageID("ARM:LE:32:v8T"), start));
dis.applyToTyped(tb.trace.getProgramView(), TaskMonitor.DUMMY); dis.applyTo(tb.trace.getProgramView(), TaskMonitor.DUMMY);
} }
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@@ -1,42 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.framework.cmd;
import ghidra.framework.model.DomainObject;
import ghidra.framework.model.UndoableDomainObject;
import ghidra.framework.plugintool.PluginTool;
import ghidra.util.task.TaskMonitor;
public abstract class TypedBackgroundCommand<T extends UndoableDomainObject>
extends BackgroundCommand {
public TypedBackgroundCommand(String name, boolean hasProgress, boolean canCancel,
boolean isModal) {
super(name, hasProgress, canCancel, isModal);
}
@Override
@SuppressWarnings("unchecked")
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
return applyToTyped((T) obj, monitor);
}
public abstract boolean applyToTyped(T obj, TaskMonitor monitor);
public void run(PluginTool tool, T obj) {
tool.executeBackgroundCommand(this, obj);
}
}
@@ -23,7 +23,6 @@ import ghidra.app.cmd.module.CreateDefaultTreeCmd;
import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin; import ghidra.app.plugin.ProgramPlugin;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.framework.plugintool.PluginInfo; import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.plugintool.util.PluginStatus;
@@ -53,7 +52,6 @@ import ghidra.util.task.TaskMonitor;
) )
//@formatter:on //@formatter:on
public class SampleProgramTreePlugin extends ProgramPlugin { public class SampleProgramTreePlugin extends ProgramPlugin {
private Listing listing;
/** /**
* Construct a new SampleProgramTreePlugin. * Construct a new SampleProgramTreePlugin.
@@ -90,8 +88,7 @@ public class SampleProgramTreePlugin extends ProgramPlugin {
* Method Modularize. * Method Modularize.
*/ */
private void modularize() { private void modularize() {
BackgroundCommand cmd = new ModularizeCommand(); ModularizeCommand cmd = new ModularizeCommand();
tool.executeBackgroundCommand(cmd, currentProgram); tool.executeBackgroundCommand(cmd, currentProgram);
} }
@@ -99,7 +96,7 @@ public class SampleProgramTreePlugin extends ProgramPlugin {
* Background command that will create the new tree and organize it. * Background command that will create the new tree and organize it.
* *
*/ */
class ModularizeCommand extends BackgroundCommand { static class ModularizeCommand extends BackgroundCommand<Program> {
private int fragment_count = 0; private int fragment_count = 0;
private String programTreeName = "Sample Tree"; private String programTreeName = "Sample Tree";
@@ -108,10 +105,9 @@ public class SampleProgramTreePlugin extends ProgramPlugin {
} }
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public boolean applyTo(Program program, TaskMonitor monitor) {
Program program = (Program) obj;
listing = program.getListing(); Listing listing = program.getListing();
createDefaultTreeView(program, programTreeName); createDefaultTreeView(program, programTreeName);
@@ -145,8 +141,8 @@ public class SampleProgramTreePlugin extends ProgramPlugin {
monitor.setMessage("Module " + start + " : " + mod_name); monitor.setMessage("Module " + start + " : " + mod_name);
ProgramModule mod = make_module(mod_name, frags); ProgramModule mod = make_module(listing, mod_name, frags);
makeFragment(start, end, "frag_" + fragment_count, mod); makeFragment(listing, start, end, "frag_" + fragment_count, mod);
fragment_count++; fragment_count++;
} }
@@ -156,24 +152,17 @@ public class SampleProgramTreePlugin extends ProgramPlugin {
private void createDefaultTreeView(Program program, String defaultTreeName) { private void createDefaultTreeView(Program program, String defaultTreeName) {
String treeName = defaultTreeName; String treeName = defaultTreeName;
int oneUp = 1; int oneUp = 1;
Listing listing = program.getListing();
while (listing.getRootModule(treeName) != null) { while (listing.getRootModule(treeName) != null) {
treeName = defaultTreeName + "_" + oneUp; treeName = defaultTreeName + "_" + oneUp;
oneUp++; oneUp++;
} }
CreateDefaultTreeCmd cmd = new CreateDefaultTreeCmd(defaultTreeName); CreateDefaultTreeCmd cmd = new CreateDefaultTreeCmd(defaultTreeName);
if (tool.execute(cmd, program)) { cmd.applyTo(program);
tool.setStatusInfo(cmd.getStatusMsg());
}
} }
/** private ProgramModule make_module(Listing listing, String moduleName,
* Method make_module. ProgramModule parent) {
* @param start
* @param entry_address
* @param prev_name
* @param code
*/
private ProgramModule make_module(String moduleName, ProgramModule parent) {
String modName = moduleName; String modName = moduleName;
int oneUp = 1; int oneUp = 1;
@@ -183,6 +172,7 @@ public class SampleProgramTreePlugin extends ProgramPlugin {
newMod = parent.createModule(modName); newMod = parent.createModule(modName);
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
// ignore
} }
modName = moduleName + "_" + oneUp; modName = moduleName + "_" + oneUp;
oneUp++; oneUp++;
@@ -190,19 +180,14 @@ public class SampleProgramTreePlugin extends ProgramPlugin {
return newMod; return newMod;
} }
/** private ProgramFragment makeFragment(Listing listing, Address start, Address end,
* Method make_frag. String fragmentName, ProgramModule parent) {
* @param start
* @param entry_address
* @param prev_name
*/
private ProgramFragment makeFragment(Address start, Address end, String fragmentName,
ProgramModule parent) {
try { try {
parent.createFragment(fragmentName); parent.createFragment(fragmentName);
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
// ignore
} }
ProgramFragment frag = listing.getFragment(programTreeName, fragmentName); ProgramFragment frag = listing.getFragment(programTreeName, fragmentName);
@@ -15,10 +15,12 @@
*/ */
package ghidra.app.cmd.analysis; package ghidra.app.cmd.analysis;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.cmd.disassemble.SetFlowOverrideCmd; import ghidra.app.cmd.disassemble.SetFlowOverrideCmd;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager; import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
@@ -26,14 +28,11 @@ import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import java.util.ArrayList;
import java.util.List;
/** /**
* Identifies functions to which Jump references exist and converts * Identifies functions to which Jump references exist and converts
* the associated branching instruction flow to a CALL-RETURN * the associated branching instruction flow to a CALL-RETURN
*/ */
public class SharedReturnAnalysisCmd extends BackgroundCommand { public class SharedReturnAnalysisCmd extends BackgroundCommand<Program> {
private AddressSetView set; private AddressSetView set;
private boolean assumeContiguousFunctions = false; private boolean assumeContiguousFunctions = false;
@@ -58,9 +57,7 @@ public class SharedReturnAnalysisCmd extends BackgroundCommand {
} }
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public boolean applyTo(Program program, TaskMonitor monitor) {
Program program = (Program) obj;
try { try {
@@ -180,8 +177,8 @@ public class SharedReturnAnalysisCmd extends BackgroundCommand {
} }
// if we have not passed lastFunctionAfter then no change to lastFunctionBefore // if we have not passed lastFunctionAfter then no change to lastFunctionBefore
if (functionBeforeSrc != null && if (functionBeforeSrc != null && (functionAfterSrc == Address.NO_ADDRESS ||
(functionAfterSrc == Address.NO_ADDRESS || srcAddr.compareTo(functionAfterSrc) < 0)) { srcAddr.compareTo(functionAfterSrc) < 0)) {
// we have not passed lastFunctionAfterSrc - no change to lastFunctionBeforeSrc // we have not passed lastFunctionAfterSrc - no change to lastFunctionBeforeSrc
} }
else { else {
@@ -276,7 +273,7 @@ public class SharedReturnAnalysisCmd extends BackgroundCommand {
} }
private boolean checkIfCouldHaveFallThruTo(Program program, Address location) { private boolean checkIfCouldHaveFallThruTo(Program program, Address location) {
Instruction instr= program.getListing().getInstructionAt(location); Instruction instr = program.getListing().getInstructionAt(location);
if (instr == null) { if (instr == null) {
return true; return true;
} }
@@ -342,43 +339,43 @@ public class SharedReturnAnalysisCmd extends BackgroundCommand {
} }
private void checkAllJumpReferences(Program program, TaskMonitor monitor) // private void checkAllJumpReferences(Program program, TaskMonitor monitor)
throws CancelledException { // throws CancelledException {
//
SymbolTable symbolTable = program.getSymbolTable(); // SymbolTable symbolTable = program.getSymbolTable();
//
InstructionIterator instructionIter = program.getListing().getInstructions(set, true); // InstructionIterator instructionIter = program.getListing().getInstructions(set, true);
while (instructionIter.hasNext()) { // while (instructionIter.hasNext()) {
monitor.checkCancelled(); // monitor.checkCancelled();
Instruction instr = instructionIter.next(); // Instruction instr = instructionIter.next();
FlowType ft = instr.getFlowType(); // FlowType ft = instr.getFlowType();
if (!ft.isJump()) { // if (!ft.isJump()) {
continue; // continue;
} // }
Reference ref = getSingleFlowReferenceFrom(instr); // Reference ref = getSingleFlowReferenceFrom(instr);
if (ref == null) { // if (ref == null) {
continue; // continue;
} // }
// if there is a function at this address, this is a thunk // // if there is a function at this address, this is a thunk
// Handle differently // // Handle differently
if (program.getFunctionManager().getFunctionAt(instr.getMinAddress()) != null) { // if (program.getFunctionManager().getFunctionAt(instr.getMinAddress()) != null) {
continue; // continue;
} // }
Symbol s = symbolTable.getPrimarySymbol(ref.getToAddress()); // Symbol s = symbolTable.getPrimarySymbol(ref.getToAddress());
if (s != null && s.getSymbolType() == SymbolType.FUNCTION) { // if (s != null && s.getSymbolType() == SymbolType.FUNCTION) {
if (instr.getFlowOverride() != FlowOverride.NONE) { // if (instr.getFlowOverride() != FlowOverride.NONE) {
continue; // continue;
} // }
SetFlowOverrideCmd cmd = // SetFlowOverrideCmd cmd =
new SetFlowOverrideCmd(instr.getMinAddress(), FlowOverride.CALL_RETURN); // new SetFlowOverrideCmd(instr.getMinAddress(), FlowOverride.CALL_RETURN);
cmd.applyTo(program); // cmd.applyTo(program);
} // }
} // }
} // }
private void processFunctionJumpReferences(Program program, Address entry, TaskMonitor monitor) private void processFunctionJumpReferences(Program program, Address entry, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
// since reference fixup will occur when flow override is done, // since reference fixup will occur when flow override is done,
// avoid concurrent modification during reference iterator use // avoid concurrent modification during reference iterator use
// by building list of jump references // by building list of jump references
@@ -388,7 +385,7 @@ public class SharedReturnAnalysisCmd extends BackgroundCommand {
} }
FunctionManager funcMgr = program.getFunctionManager(); FunctionManager funcMgr = program.getFunctionManager();
for (Reference ref : fnRefList) { for (Reference ref : fnRefList) {
monitor.checkCancelled(); monitor.checkCancelled();
Instruction instr = program.getListing().getInstructionAt(ref.getFromAddress()); Instruction instr = program.getListing().getInstructionAt(ref.getFromAddress());
@@ -399,15 +396,15 @@ public class SharedReturnAnalysisCmd extends BackgroundCommand {
if (checkRef == null) { if (checkRef == null) {
continue; continue;
} }
// if there is a function at this address, this is a thunk // if there is a function at this address, this is a thunk
// Handle differently // Handle differently
Address refInstrAddr = instr.getMinAddress(); Address refInstrAddr = instr.getMinAddress();
if (funcMgr.getFunctionAt(refInstrAddr) != null) { if (funcMgr.getFunctionAt(refInstrAddr) != null) {
continue; continue;
} }
// if this instruction is contained in the body of the function // if this instruction is contained in the body of the function
// then it is just an internal jump reference to the top of the // then it is just an internal jump reference to the top of the
// function // function
@@ -415,7 +412,7 @@ public class SharedReturnAnalysisCmd extends BackgroundCommand {
if (functionContaining != null && functionContaining.getEntryPoint().equals(entry)) { if (functionContaining != null && functionContaining.getEntryPoint().equals(entry)) {
continue; continue;
} }
if (checkRef.getToAddress().equals(ref.getToAddress())) { if (checkRef.getToAddress().equals(ref.getToAddress())) {
if (instr.getFlowOverride() != FlowOverride.NONE) { if (instr.getFlowOverride() != FlowOverride.NONE) {
continue; continue;
@@ -16,14 +16,13 @@
package ghidra.app.cmd.comments; package ghidra.app.cmd.comments;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
/** /**
* Command to append a specific type of comment on a code unit. * Command to append a specific type of comment on a code unit.
*/ */
public class AppendCommentCmd implements Command { public class AppendCommentCmd implements Command<Program> {
private Address address; private Address address;
private int commentType; private int commentType;
@@ -49,24 +48,17 @@ public class AppendCommentCmd implements Command {
cmdName = "Append Comment"; cmdName = "Append Comment";
} }
/**
* @see ghidra.framework.cmd.Command#getName()
*/
@Override @Override
public String getName() { public String getName() {
return cmdName; return cmdName;
} }
/**
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
CodeUnit cu = getCodeUnit((Program) obj); CodeUnit cu = getCodeUnit(program);
if (cu == null) { if (cu == null) {
message = message = "No Instruction or Data found for address " + address.toString() +
"No Instruction or Data found for address " + address.toString() + " Is this address valid?";
" Is this address valid?";
return false; return false;
} }
String previousComment = cu.getComment(commentType); String previousComment = cu.getComment(commentType);
@@ -95,9 +87,6 @@ public class AppendCommentCmd implements Command {
return cu; return cu;
} }
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/
@Override @Override
public String getStatusMsg() { public String getStatusMsg() {
return message; return message;
@@ -20,7 +20,6 @@ import java.util.List;
import ghidra.app.util.CodeUnitInfo; import ghidra.app.util.CodeUnitInfo;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Varnode; import ghidra.program.model.pcode.Varnode;
@@ -33,7 +32,7 @@ import ghidra.util.exception.InvalidInputException;
* Undoable edit for pasting code unit information at a location. * Undoable edit for pasting code unit information at a location.
* This class actually does the work of the "paste." * This class actually does the work of the "paste."
*/ */
public class CodeUnitInfoPasteCmd implements Command { public class CodeUnitInfoPasteCmd implements Command<Program> {
// TODO: should refactor to handle all variables in a consistent fashion // TODO: should refactor to handle all variables in a consistent fashion
@@ -48,6 +47,8 @@ public class CodeUnitInfoPasteCmd implements Command {
* Creates a new command for pasting comments/labels. * Creates a new command for pasting comments/labels.
* @param startAddr starting address for info * @param startAddr starting address for info
* @param infoList list of CodeUnitInfo objects that will be applied * @param infoList list of CodeUnitInfo objects that will be applied
* @param pasteLabels true if labels should be applied, else false
* @param pasteComments true if comments should be applied, else false
*/ */
public CodeUnitInfoPasteCmd(Address startAddr, List<CodeUnitInfo> infoList, boolean pasteLabels, public CodeUnitInfoPasteCmd(Address startAddr, List<CodeUnitInfo> infoList, boolean pasteLabels,
boolean pasteComments) { boolean pasteComments) {
@@ -65,19 +66,14 @@ public class CodeUnitInfoPasteCmd implements Command {
return "Paste Labels/Comments"; return "Paste Labels/Comments";
} }
/* (non-Javadoc)
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
Program program = (Program) obj;
SymbolTable symTable = program.getSymbolTable(); SymbolTable symTable = program.getSymbolTable();
Listing listing = program.getListing(); Listing listing = program.getListing();
boolean offCutExists = false; boolean offCutExists = false;
for (int i = 0; i < infoList.size(); i++) { for (CodeUnitInfo info : infoList) {
CodeUnitInfo info = infoList.get(i);
Address a = startAddr.add(info.getIndex()); Address a = startAddr.add(info.getIndex());
CodeUnit cu = listing.getCodeUnitAt(a); CodeUnit cu = listing.getCodeUnitAt(a);
if (cu == null) { if (cu == null) {
@@ -133,8 +129,8 @@ public class CodeUnitInfoPasteCmd implements Command {
function.setName(fnName, info.getPrimarySymbolSource()); function.setName(fnName, info.getPrimarySymbolSource());
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
messages.append("Could not set function name--duplicate name: " + fnName).append( messages.append("Could not set function name--duplicate name: " + fnName)
'\n'); .append('\n');
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
// shouldn't happen // shouldn't happen
@@ -175,8 +171,8 @@ public class CodeUnitInfoPasteCmd implements Command {
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
messages.append( messages.append(
"Could not set stack variable name--duplicate name: " + fnName).append( "Could not set stack variable name--duplicate name: " + fnName)
'\n'); .append('\n');
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
// shouldn't happen // shouldn't happen
@@ -204,8 +200,8 @@ public class CodeUnitInfoPasteCmd implements Command {
var.setName(varNames[i], varSources[i]); var.setName(varNames[i], varSources[i]);
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
messages.append( messages.append("Could not set variable name--duplicate name: " + fnName)
"Could not set variable name--duplicate name: " + fnName).append('\n'); .append('\n');
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
// shouldn't happen // shouldn't happen
@@ -219,8 +215,7 @@ public class CodeUnitInfoPasteCmd implements Command {
} }
private Variable findStackVar(Variable[] stackVars, int stackOffset, int firstUseOffset) { private Variable findStackVar(Variable[] stackVars, int stackOffset, int firstUseOffset) {
for (int k = 0; k < stackVars.length; k++) { for (Variable var : stackVars) {
Variable var = stackVars[k];
if (stackOffset == var.getStackOffset() && firstUseOffset == var.getFirstUseOffset()) { if (stackOffset == var.getStackOffset() && firstUseOffset == var.getFirstUseOffset()) {
return var; return var;
} }
@@ -229,8 +224,7 @@ public class CodeUnitInfoPasteCmd implements Command {
} }
private Variable findVar(Variable[] vars, Address storageAddr, int firstUseOffset) { private Variable findVar(Variable[] vars, Address storageAddr, int firstUseOffset) {
for (int k = 0; k < vars.length; k++) { for (Variable var : vars) {
Variable var = vars[k];
Varnode varnode = var.getVariableStorage().getFirstVarnode(); Varnode varnode = var.getVariableStorage().getFirstVarnode();
if (varnode != null && firstUseOffset == var.getFirstUseOffset() && if (varnode != null && firstUseOffset == var.getFirstUseOffset() &&
storageAddr.equals(varnode.getAddress())) { storageAddr.equals(varnode.getAddress())) {
@@ -277,8 +271,8 @@ public class CodeUnitInfoPasteCmd implements Command {
} }
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
messages.append("Could not set label name--duplicate name: " + primaryName).append( messages.append("Could not set label name--duplicate name: " + primaryName)
'\n'); .append('\n');
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
// should not happen // should not happen
@@ -359,12 +353,12 @@ public class CodeUnitInfoPasteCmd implements Command {
private String[] appendComment(String[] comment1, String[] comment2) { private String[] appendComment(String[] comment1, String[] comment2) {
// first check for duplicate comments // first check for duplicate comments
ArrayList<String> list = new ArrayList<String>(); ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < comment2.length; i++) { for (String element : comment2) {
list.add(comment2[i]); list.add(element);
} }
for (int i = 0; i < comment1.length; i++) { for (String element : comment1) {
for (int j = 0; j < list.size(); j++) { for (int j = 0; j < list.size(); j++) {
if (comment1[i].equals(list.get(j))) { if (element.equals(list.get(j))) {
list.remove(j); list.remove(j);
--j; --j;
} }
@@ -17,14 +17,13 @@ package ghidra.app.cmd.comments;
import ghidra.app.util.viewer.field.CommentUtils; import ghidra.app.util.viewer.field.CommentUtils;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
/** /**
* Command to set a specific type of comment on a code unit. * Command to set a specific type of comment on a code unit.
*/ */
public class SetCommentCmd implements Command { public class SetCommentCmd implements Command<Program> {
private Address address; private Address address;
private int commentType; private int commentType;
@@ -67,8 +66,7 @@ public class SetCommentCmd implements Command {
} }
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
Program program = (Program) obj;
CodeUnit cu = getCodeUnit(program); CodeUnit cu = getCodeUnit(program);
if (cu == null) { if (cu == null) {
message = "No Instruction or Data found for address " + address.toString() + message = "No Instruction or Data found for address " + address.toString() +
@@ -17,14 +17,13 @@ package ghidra.app.cmd.comments;
import ghidra.app.util.viewer.field.CommentUtils; import ghidra.app.util.viewer.field.CommentUtils;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
/** /**
* Command for editing and removing comments at an address. * Command for editing and removing comments at an address.
*/ */
public class SetCommentsCmd implements Command { public class SetCommentsCmd implements Command<Program> {
private Address address; private Address address;
private String preComment; private String preComment;
@@ -79,13 +78,8 @@ public class SetCommentsCmd implements Command {
return !oldValue.equals(newValue); return !oldValue.equals(newValue);
} }
/**
*
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
Program program = (Program) obj;
CodeUnit cu = getCodeUnit(program); CodeUnit cu = getCodeUnit(program);
if (cu != null) { if (cu != null) {
@@ -138,9 +132,6 @@ public class SetCommentsCmd implements Command {
return cu; return cu;
} }
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/
@Override @Override
public String getStatusMsg() { public String getStatusMsg() {
return msg; return msg;
@@ -16,8 +16,6 @@
package ghidra.app.cmd.data; package ghidra.app.cmd.data;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure; import ghidra.program.model.data.Structure;
@@ -26,128 +24,110 @@ import ghidra.program.model.listing.Program;
/** /**
* A base class to hold duplicate information for commands that create * A base class to hold duplicate information for commands that create
* structures. This class implements the logic of the * structures. This class implements the logic of the
* {@link #applyTo(DomainObject)} method so that child implementations need * {@link #applyTo(Program)} method so that child implementations need
* only to implement the abstract methods. * only to implement the abstract methods.
*
*
* @since Tracker Id 383
*/ */
public abstract class AbstractCreateStructureCmd implements Command { public abstract class AbstractCreateStructureCmd implements Command<Program> {
private String statusMessage;
private String structureName;
private DataType newDataType;
private Address structureAddress;
/**
* Initializes the this class to create a structure with the given name
* and address when the {@link #applyTo(DomainObject)} is called.
*
* @param name The name of the structure to create.
* @param address The address of the structure.
*/
/*package*/ AbstractCreateStructureCmd( String name, Address address ){
structureAddress = address;
structureName = name;
}
/**
* Applies this command to the given domain object.
* <p>
* This method is a Form Template method in that child subclasses do not
* need to override the method, but only need to implement the methods
* that this method calls.
*
* @param domainObject The domain object that is associated with this
* command
* @see Command#applyTo(DomainObject)
*/
public boolean applyTo(DomainObject domainObject) {
try {
Program program = (Program) domainObject;
Structure structure = createStructure( structureAddress, program );
setNewDataType( initializeStructureData( program, structure ) );
} catch (IllegalArgumentException iae) {
setStatusMsg( iae.getMessage() );
return false;
}
return true;
}
/**
* Child classes implement this method in order to create an instance
* of {@link Structure}.
*
* @param address The address of the structure.
* @param program The program of the structure.
* @return A new StructureInfo object that describes the new structure to
* be created.
* @throws IllegalArgumentException If the data at the given address is
* not valid for creating a structure.
*/
/*package*/ abstract Structure createStructure( Address address,
Program program )
throws IllegalArgumentException;
/**
* Initializes the structure that is represented by the provided
* <tt>structureInfo</tt> object. This involves populating the new
* structure with data and then returning the data type object that
* represents the newly created structure.
*
* @param structureInfo The structure info object that describes the newly
* created structure.
* @return The new data type that represents the created structure.
*/
/*package*/ abstract DataType initializeStructureData(
Program program, Structure structure );
/**
* Sets the new data type of this command.
*
* @param dataType The new data type.
*/
/*package*/ void setNewDataType( DataType dataType ){
newDataType = dataType;
}
/**
* Get the new structure data type which was created.
* @return new structure.
*/
public DataType getNewDataType() {
return newDataType;
}
/*package*/ Address getStructureAddress(){
return structureAddress;
}
/**
* Sets the value of the status message for this command
*
* @param message The value of the command.
*/
/*package*/ void setStatusMsg( String message ){
statusMessage = message;
}
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/
public String getStatusMsg(){
return statusMessage;
}
/*package*/ String getStructureName(){ private String statusMessage;
return structureName; private String structureName;
} private DataType newDataType;
private Address structureAddress;
/**
* @see ghidra.framework.cmd.Command#getName() /**
*/ * Initializes the this class to create a structure with the given name
public String getName(){ * and address when the {@link #applyTo(Program)} is called.
return "Create Structure"; *
} * @param name The name of the structure to create.
* @param address The address of the structure.
*/
/*package*/ AbstractCreateStructureCmd(String name, Address address) {
structureAddress = address;
structureName = name;
}
@Override
public boolean applyTo(Program program) {
try {
Structure structure = createStructure(structureAddress, program);
setNewDataType(initializeStructureData(program, structure));
}
catch (IllegalArgumentException iae) {
setStatusMsg(iae.getMessage());
return false;
}
return true;
}
/**
* Child classes implement this method in order to create an instance
* of {@link Structure}.
*
* @param address The address of the structure.
* @param program The program of the structure.
* @return A new StructureInfo object that describes the new structure to
* be created.
* @throws IllegalArgumentException If the data at the given address is
* not valid for creating a structure.
*/
/*package*/ abstract Structure createStructure(Address address, Program program)
throws IllegalArgumentException;
/**
* Initializes the structure that is represented by the provided
* <tt>structureInfo</tt> object. This involves populating the new
* structure with data and then returning the data type object that
* represents the newly created structure.
*
* @param program program to be modified
* @param structure The structure definition that describes the newly
* created structure.
* @return The new data type that represents the created structure.
*/
/*package*/ abstract DataType initializeStructureData(Program program, Structure structure);
/**
* Sets the new data type of this command.
*
* @param dataType The new data type.
*/
/*package*/ void setNewDataType(DataType dataType) {
newDataType = dataType;
}
/**
* Get the new structure data type which was created.
* @return new structure.
*/
public DataType getNewDataType() {
return newDataType;
}
/*package*/ Address getStructureAddress() {
return structureAddress;
}
/**
* Sets the value of the status message for this command
*
* @param message The value of the command.
*/
/*package*/ void setStatusMsg(String message) {
statusMessage = message;
}
@Override
public String getStatusMsg() {
return statusMessage;
}
/*package*/ String getStructureName() {
return structureName;
}
@Override
public String getName() {
return "Create Structure";
}
} }
@@ -16,7 +16,6 @@
package ghidra.app.cmd.data; package ghidra.app.cmd.data;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@@ -27,7 +26,7 @@ import ghidra.util.Msg;
* Command to create an array. All conflicting data will be cleared. * Command to create an array. All conflicting data will be cleared.
* *
*/ */
public class CreateArrayCmd implements Command { public class CreateArrayCmd implements Command<Program> {
private String msg; private String msg;
private Address addr; private Address addr;
private int numElements; private int numElements;
@@ -42,7 +41,7 @@ public class CreateArrayCmd implements Command {
* @param dt the dataType of the elements in the array to be created. * @param dt the dataType of the elements in the array to be created.
* @param elementLength the size of an element in the array. Only used for Dynamic * @param elementLength the size of an element in the array. Only used for Dynamic
* datatype <code>dt</code> when {@link Dynamic#canSpecifyLength()} returns true. * datatype <code>dt</code> when {@link Dynamic#canSpecifyLength()} returns true.
*/ */
public CreateArrayCmd(Address addr, int numElements, DataType dt, int elementLength) { public CreateArrayCmd(Address addr, int numElements, DataType dt, int elementLength) {
this.addr = addr; this.addr = addr;
this.numElements = numElements; this.numElements = numElements;
@@ -51,8 +50,7 @@ public class CreateArrayCmd implements Command {
} }
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
Program program = (Program)obj;
Listing listing = program.getListing(); Listing listing = program.getListing();
try { try {
ArrayDataType adt = new ArrayDataType(dataType, numElements, elementLength, ArrayDataType adt = new ArrayDataType(dataType, numElements, elementLength,
@@ -68,7 +66,8 @@ public class CreateArrayCmd implements Command {
} }
listing.clearCodeUnits(addr, endAddr, false); listing.clearCodeUnits(addr, endAddr, false);
listing.createData(addr, adt, adt.getLength()); listing.createData(addr, adt, adt.getLength());
} catch (AddressOverflowException e1) { }
catch (AddressOverflowException e1) {
msg = "Can't create data because length exceeds address space"; msg = "Can't create data because length exceeds address space";
return false; return false;
} }
@@ -81,7 +80,7 @@ public class CreateArrayCmd implements Command {
Msg.error(this, msg, e); Msg.error(this, msg, e);
return false; return false;
} }
return true; return true;
} }
@Override @Override
@@ -16,7 +16,6 @@
package ghidra.app.cmd.data; package ghidra.app.cmd.data;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@@ -27,13 +26,13 @@ import ghidra.util.Msg;
* within the targeted structure will be replaced with the new array component. * within the targeted structure will be replaced with the new array component.
* *
*/ */
public class CreateArrayInStructureCmd implements Command { public class CreateArrayInStructureCmd implements Command<Program> {
private String msg; private String msg;
private Address addr; private Address addr;
private int numElements; private int numElements;
private DataType dataType; private DataType dataType;
private int[] compPath; private int[] compPath;
// NOTE: This command does not currently handle Dynamic types whose length may // NOTE: This command does not currently handle Dynamic types whose length may
// be specified since no elementLength parameter exists. // be specified since no elementLength parameter exists.
@@ -49,9 +48,8 @@ public class CreateArrayInStructureCmd implements Command {
* @param compPath the target component path within the structure of an existing component where * @param compPath the target component path within the structure of an existing component where
* the array should be created. The component path is an array of integers where each integer * the array should be created. The component path is an array of integers where each integer
* is a component index of the component above it. * is a component index of the component above it.
*/ */
public CreateArrayInStructureCmd(Address addr, int numElements, DataType dt, public CreateArrayInStructureCmd(Address addr, int numElements, DataType dt, int[] compPath) {
int[] compPath) {
this.addr = addr; this.addr = addr;
this.numElements = numElements; this.numElements = numElements;
this.dataType = dt; this.dataType = dt;
@@ -59,8 +57,7 @@ public class CreateArrayInStructureCmd implements Command {
} }
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
Program program = (Program)obj;
Listing listing = program.getListing(); Listing listing = program.getListing();
Data data = listing.getDataContaining(addr); Data data = listing.getDataContaining(addr);
@@ -70,15 +67,15 @@ public class CreateArrayInStructureCmd implements Command {
return false; return false;
} }
int index = compData.getComponentIndex(); int index = compData.getComponentIndex();
int offset = compData.getParentOffset(); int offset = compData.getParentOffset();
DataType parentDataType = compData.getParent().getBaseDataType(); DataType parentDataType = compData.getParent().getBaseDataType();
if (!(parentDataType instanceof Structure)) { if (!(parentDataType instanceof Structure)) {
msg = "Data not in a structure"; msg = "Data not in a structure";
return false; return false;
} }
Structure struct = (Structure)parentDataType; Structure struct = (Structure) parentDataType;
DataType baseDt = dataType; DataType baseDt = dataType;
if (dataType instanceof TypeDef) { if (dataType instanceof TypeDef) {
@@ -90,7 +87,7 @@ public class CreateArrayInStructureCmd implements Command {
} }
try { try {
ArrayDataType adt = new ArrayDataType(dataType, numElements, dataType.getLength()); ArrayDataType adt = new ArrayDataType(dataType, numElements, dataType.getLength());
int length = adt.isZeroLength() ? 0 : adt.getLength(); int length = adt.isZeroLength() ? 0 : adt.getLength();
if (!struct.isPackingEnabled() && (offset + length) > struct.getLength()) { if (!struct.isPackingEnabled() && (offset + length) > struct.getLength()) {
msg = "Array too big for structure"; msg = "Array too big for structure";
@@ -108,20 +105,20 @@ public class CreateArrayInStructureCmd implements Command {
msg = "Unexpected error: " + e.toString(); msg = "Unexpected error: " + e.toString();
Msg.error(this, msg, e); Msg.error(this, msg, e);
return false; return false;
} }
return true; return true;
} }
private void clearStruct(Structure struct, int offset, int length) { private void clearStruct(Structure struct, int offset, int length) {
DataTypeComponent[] comps = struct.getDefinedComponents(); DataTypeComponent[] comps = struct.getDefinedComponents();
int endOffset = offset+length; int endOffset = offset + length;
for(int i=comps.length-1;i>=0;i--) { for (int i = comps.length - 1; i >= 0; i--) {
if (comps[i].getOffset() >= offset && comps[i].getOffset() < endOffset) { if (comps[i].getOffset() >= offset && comps[i].getOffset() < endOffset) {
struct.clearComponent(comps[i].getOrdinal()); struct.clearComponent(comps[i].getOrdinal());
} }
} }
} }
/** /**
* @see ghidra.framework.cmd.Command#getStatusMsg() * @see ghidra.framework.cmd.Command#getStatusMsg()
*/ */
@@ -16,7 +16,6 @@
package ghidra.app.cmd.data; package ghidra.app.cmd.data;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataUtilities; import ghidra.program.model.data.DataUtilities;
@@ -37,8 +36,7 @@ import ghidra.util.task.TaskMonitor;
* of a pointer, then a pointer to dataType will only be created if there are * of a pointer, then a pointer to dataType will only be created if there are
* enough undefined bytes following to make a pointer. * enough undefined bytes following to make a pointer.
*/ */
public class CreateDataBackgroundCmd extends BackgroundCommand { public class CreateDataBackgroundCmd extends BackgroundCommand<Program> {
private static final int EVENT_LIMIT = 1000;
private AddressSetView addrSet; private AddressSetView addrSet;
private DataType newDataType; private DataType newDataType;
@@ -76,12 +74,7 @@ public class CreateDataBackgroundCmd extends BackgroundCommand {
} }
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public boolean applyTo(Program program, TaskMonitor monitor) {
return doApplyTo(obj, monitor);
}
public boolean doApplyTo(DomainObject obj, TaskMonitor monitor) {
Program program = (Program) obj;
Listing listing = program.getListing(); Listing listing = program.getListing();
InstructionIterator iter = listing.getInstructions(addrSet, true); InstructionIterator iter = listing.getInstructions(addrSet, true);
if (iter.hasNext()) { if (iter.hasNext()) {
@@ -16,7 +16,6 @@
package ghidra.app.cmd.data; package ghidra.app.cmd.data;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataUtilities; import ghidra.program.model.data.DataUtilities;
@@ -33,7 +32,7 @@ import ghidra.program.model.listing.Program;
* *
* @see DataUtilities#createData(Program, Address, DataType, int, boolean, DataUtilities.ClearDataMode) * @see DataUtilities#createData(Program, Address, DataType, int, boolean, DataUtilities.ClearDataMode)
*/ */
public class CreateDataCmd implements Command { public class CreateDataCmd implements Command<Program> {
private Address addr; private Address addr;
private DataType newDataType; private DataType newDataType;
@@ -119,10 +118,9 @@ public class CreateDataCmd implements Command {
} }
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
try { try {
DataUtilities.createData((Program) obj, addr, newDataType, -1, stackPointers, DataUtilities.createData(program, addr, newDataType, -1, stackPointers, clearMode);
clearMode);
return true; return true;
} }
catch (Exception e) { catch (Exception e) {
@@ -16,7 +16,6 @@
package ghidra.app.cmd.data; package ghidra.app.cmd.data;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Data;
@@ -28,7 +27,7 @@ import ghidra.util.task.TaskMonitor;
* Background command to create data across a selection inside of a structure. * Background command to create data across a selection inside of a structure.
* *
*/ */
public class CreateDataInStructureBackgroundCmd extends BackgroundCommand { public class CreateDataInStructureBackgroundCmd extends BackgroundCommand<Program> {
// TODO: Not sure any of this will work for a packed structure which does not support // TODO: Not sure any of this will work for a packed structure which does not support
// offset-based component manipulation (see GP-3740) // offset-based component manipulation (see GP-3740)
@@ -81,9 +80,8 @@ public class CreateDataInStructureBackgroundCmd extends BackgroundCommand {
* @see ghidra.framework.cmd.BackgroundCommand#applyTo(ghidra.framework.model.DomainObject, ghidra.util.task.TaskMonitor) * @see ghidra.framework.cmd.BackgroundCommand#applyTo(ghidra.framework.model.DomainObject, ghidra.util.task.TaskMonitor)
*/ */
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public boolean applyTo(Program program, TaskMonitor monitor) {
Program program = (Program) obj;
Data data = program.getListing().getDefinedDataContaining(addr); Data data = program.getListing().getDefinedDataContaining(addr);
Data startData = data.getComponent(startPath); Data startData = data.getComponent(startPath);
if (startData == null) { if (startData == null) {
@@ -16,7 +16,6 @@
package ghidra.app.cmd.data; package ghidra.app.cmd.data;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Data;
@@ -25,7 +24,7 @@ import ghidra.program.model.listing.Program;
/** /**
* Command to Create data inside of a structure. * Command to Create data inside of a structure.
*/ */
public class CreateDataInStructureCmd implements Command { public class CreateDataInStructureCmd implements Command<Program> {
// TODO: Not sure any of this will work for a packed structure which does not support // TODO: Not sure any of this will work for a packed structure which does not support
// offset-based component manipulation (see GP-3740) // offset-based component manipulation (see GP-3740)
@@ -69,12 +68,8 @@ public class CreateDataInStructureCmd implements Command {
this.stackPointers = stackPointers; this.stackPointers = stackPointers;
} }
/**
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
Program program = (Program) obj;
Data data = program.getListing().getDefinedDataContaining(addr); Data data = program.getListing().getDefinedDataContaining(addr);
Data dataComp = data.getComponent(componentPath); Data dataComp = data.getComponent(componentPath);
if (dataComp == null) { if (dataComp == null) {
@@ -142,17 +137,11 @@ public class CreateDataInStructureCmd implements Command {
return true; return true;
} }
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/
@Override @Override
public String getStatusMsg() { public String getStatusMsg() {
return msg; return msg;
} }
/**
* @see ghidra.framework.cmd.Command#getName()
*/
@Override @Override
public String getName() { public String getName() {
return "Create " + newDataType.getDisplayName() + " component"; return "Create " + newDataType.getDisplayName() + " component";
@@ -16,7 +16,6 @@
package ghidra.app.cmd.data; package ghidra.app.cmd.data;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataUtilities.ClearDataMode; import ghidra.program.model.data.DataUtilities.ClearDataMode;
@@ -27,7 +26,7 @@ import ghidra.program.model.util.CodeUnitInsertionException;
* Command to create a String and optionally label it. * Command to create a String and optionally label it.
* *
*/ */
public class CreateStringCmd implements Command { public class CreateStringCmd implements Command<Program> {
private final Address addr; private final Address addr;
private final AbstractStringDataType stringDataType; private final AbstractStringDataType stringDataType;
private int length = -1; private int length = -1;
@@ -39,6 +38,14 @@ public class CreateStringCmd implements Command {
: (length > 0) ? new StringDataType() : new TerminatedStringDataType(); : (length > 0) ? new StringDataType() : new TerminatedStringDataType();
} }
/**
* Construct command for creating string Data
* @param addr address where string should be created.
* @param stringDataType string datatype
* @param length maximum string length (treatment is specific to specified datatype).
* @param clearMode {@link ClearDataMode} which indicates how existing Data conflicts
* should be handled.
*/
public CreateStringCmd(Address addr, AbstractStringDataType stringDataType, int length, public CreateStringCmd(Address addr, AbstractStringDataType stringDataType, int length,
ClearDataMode clearMode) { ClearDataMode clearMode) {
this.addr = addr; this.addr = addr;
@@ -48,41 +55,49 @@ public class CreateStringCmd implements Command {
} }
/** /**
* Constructs a new command for creating strings. * Construct command for creating fixed-length ASCII or Unicode string Data
* @param addr address where string should be created.
* @param length byte-length of string
* @param unicode if true Unicode string will be created, else ASCII
* @param clearMode {@link ClearDataMode} which indicates how existing Data conflicts
* should be handled.
*/ */
public CreateStringCmd(Address addr, int length, boolean unicode, ClearDataMode clearMode) { public CreateStringCmd(Address addr, int length, boolean unicode, ClearDataMode clearMode) {
this(addr, getStringDataType(unicode, length), length, clearMode); this(addr, getStringDataType(unicode, length), length, clearMode);
} }
/** /**
* Constructs a new command for creating strings. * Construct command for creating fixed-length ASCII or Unicode string Data.
* Current Data at addr will be cleared if it already exists.
* @param addr address where string should be created.
* @param length byte-length of string
* @param unicode if true Unicode string will be created, else ASCII
*/ */
public CreateStringCmd(Address addr, int length, boolean unicode) { public CreateStringCmd(Address addr, int length, boolean unicode) {
this(addr, getStringDataType(unicode, length), length, ClearDataMode.CLEAR_SINGLE_DATA); this(addr, getStringDataType(unicode, length), length, ClearDataMode.CLEAR_SINGLE_DATA);
} }
/** /**
* Constructs a new command for creating strings. * Construct command for creating null-terminated ASCII string Data.
* Current Data at addr will be cleared if it already exists.
* @param addr address where string should be created.
*/ */
public CreateStringCmd(Address addr) { public CreateStringCmd(Address addr) {
this(addr, -1, false); this(addr, -1, false);
} }
/** /**
* Constructs a new command for creating strings. * Construct command for creating fixed-length ASCII string Data.
* Current Data at addr will be cleared if it already exists.
* @param addr address where string should be created.
* @param length byte-length of string
*/ */
public CreateStringCmd(Address addr, int length) { public CreateStringCmd(Address addr, int length) {
this(addr, length, false); this(addr, length, false);
} }
/**
*
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
Program program = (Program) obj;
try { try {
DataUtilities.createData(program, addr, stringDataType, length, clearMode); DataUtilities.createData(program, addr, stringDataType, length, clearMode);
} }
@@ -94,17 +109,11 @@ public class CreateStringCmd implements Command {
return true; return true;
} }
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/
@Override @Override
public String getStatusMsg() { public String getStatusMsg() {
return msg; return msg;
} }
/**
* @see ghidra.framework.cmd.Command#getName()
*/
@Override @Override
public String getName() { public String getName() {
return "Create String"; return "Create String";
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,7 +15,9 @@
*/ */
package ghidra.app.cmd.data; package ghidra.app.cmd.data;
import ghidra.framework.model.DomainObject; import java.util.ArrayList;
import java.util.Collections;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@@ -24,124 +25,120 @@ import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceManager; import ghidra.program.model.symbol.ReferenceManager;
import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.program.model.util.CodeUnitInsertionException;
import java.util.ArrayList;
/** /**
* Command to create a structure. * Command to create a structure.
*/ */
public class CreateStructureCmd extends AbstractCreateStructureCmd{ public class CreateStructureCmd extends AbstractCreateStructureCmd {
private int structureDataLength; private int structureDataLength;
private Structure structure; private Structure structure;
/**
* Constructs a new command for creating a new structure and applying it to
* the browser. This method simply calls
* {@link #CreateStructureCmd(String, Address, int)} with
* {@link ghidra.program.model.data.StructureFactory#DEFAULT_STRUCTURE_NAME} as the name of the structure.
*
* @param address the address at which to create the new structure.
* @param length the number of undefined bytes to consume in the new
* structure.
*/
public CreateStructureCmd( Address address, int length ){
this( StructureFactory.DEFAULT_STRUCTURE_NAME, address, length );
}
/**
* Constructs a new command for creating a new structure and applying it to
* the browser.
* @param name The name of the new structure to create.
* @param address the address at which to create the new structure.
* @param length the number of undefined bytes to consume in the new
* structure.
*/
public CreateStructureCmd( String name, Address address, int length ) {
super( name, address );
structureDataLength = length;
}
/**
* Creates a new structure by using the provided structure and attaching
* it to the program passed in the {@link #applyTo(DomainObject)} method.
*
* @param newStructure The new structure to attach to the program
* provided in the {@link #applyTo(DomainObject)} method.
* @param address the address at which to create the new structure.
*/
public CreateStructureCmd( Structure newStructure, Address address ){
super( newStructure.getName(), address );
structure = newStructure;
structureDataLength = structure.getLength();
}
/*
* @see AbstractCreateStructureCmd#createStructure(Address, Program)
*/
@Override
Structure createStructure( Address address,
Program program ){
if ( structure == null ){ /**
structure = * Constructs a new command for creating a new structure and applying it to
StructureFactory.createStructureDataType( program, address, * the browser. This method simply calls
structureDataLength, getStructureName(), true ); * {@link #CreateStructureCmd(String, Address, int)} with
} * {@link ghidra.program.model.data.StructureFactory#DEFAULT_STRUCTURE_NAME} as the name of the structure.
*
return structure; * @param address the address at which to create the new structure.
} * @param length the number of undefined bytes to consume in the new
* structure.
/* */
* @see AbstractCreateStructureCmd#initializeStructureData(Program, Structure) public CreateStructureCmd(Address address, int length) {
*/ this(StructureFactory.DEFAULT_STRUCTURE_NAME, address, length);
@Override }
DataType initializeStructureData( Program program, Structure localStructure ){
Listing listing = program.getListing();
Address endAddress;
try {
endAddress = getStructureAddress().addNoWrap(structureDataLength - 1);
} catch (AddressOverflowException e1){
throw new IllegalArgumentException(
"Can't create structure because length exceeds address " +
"space" + structureDataLength );
}
ReferenceManager refMgr = program.getReferenceManager();
Reference[] refs = findExistingRefs( refMgr, program.getAddressFactory(), getStructureAddress(),
endAddress );
listing.clearCodeUnits( getStructureAddress(), endAddress, false );
Data data = null;
try{
listing.createData(getStructureAddress(), localStructure,
localStructure.getLength());
refMgr.removeAllReferencesFrom( getStructureAddress(), endAddress );
addRefs( program, refMgr, refs );
data = listing.getDataAt( getStructureAddress() );
} catch(CodeUnitInsertionException e){
throw new IllegalArgumentException( e.getMessage() );
}
return data.getDataType();
}
private Reference[] findExistingRefs(ReferenceManager refMgr, AddressFactory af, Address start, Address end) { /**
ArrayList<Reference> list = new ArrayList<Reference>(); * Constructs a new command for creating a new structure and applying it to
AddressIterator it = refMgr.getReferenceSourceIterator(new AddressSet(start, end), true); * the browser.
while(it.hasNext()) { * @param name The name of the new structure to create.
Address addr = it.next(); * @param address the address at which to create the new structure.
Reference[] refs = refMgr.getReferencesFrom(addr); * @param length the number of undefined bytes to consume in the new
for(int i=0;i<refs.length;i++) { * structure.
list.add(refs[i]); */
} public CreateStructureCmd(String name, Address address, int length) {
} super(name, address);
Reference[] refList = new Reference[list.size()]; structureDataLength = length;
return list.toArray(refList); }
}
/**
private void addRefs(Program p, ReferenceManager refMgr, Reference[] refs) { * Creates a new structure by using the provided structure and attaching
for(int i=0;i<refs.length;i++) { * it to the program passed in the {@link #applyTo(Program)} method.
refMgr.addReference(refs[i]); *
} * @param newStructure The new structure to attach to the program
} * provided in the {@link #applyTo(Program)} method.
* @param address the address at which to create the new structure.
*/
public CreateStructureCmd(Structure newStructure, Address address) {
super(newStructure.getName(), address);
structure = newStructure;
structureDataLength = structure.getLength();
}
/*
* @see AbstractCreateStructureCmd#createStructure(Address, Program)
*/
@Override
Structure createStructure(Address address, Program program) {
if (structure == null) {
structure = StructureFactory.createStructureDataType(program, address,
structureDataLength, getStructureName(), true);
}
return structure;
}
/*
* @see AbstractCreateStructureCmd#initializeStructureData(Program, Structure)
*/
@Override
DataType initializeStructureData(Program program, Structure localStructure) {
Listing listing = program.getListing();
Address endAddress;
try {
endAddress = getStructureAddress().addNoWrap(structureDataLength - 1);
}
catch (AddressOverflowException e1) {
throw new IllegalArgumentException(
"Can't create structure because length exceeds address " + "space" +
structureDataLength);
}
ReferenceManager refMgr = program.getReferenceManager();
Reference[] refs = findExistingRefs(refMgr, program.getAddressFactory(),
getStructureAddress(), endAddress);
listing.clearCodeUnits(getStructureAddress(), endAddress, false);
Data data = null;
try {
listing.createData(getStructureAddress(), localStructure, localStructure.getLength());
refMgr.removeAllReferencesFrom(getStructureAddress(), endAddress);
addRefs(program, refMgr, refs);
data = listing.getDataAt(getStructureAddress());
}
catch (CodeUnitInsertionException e) {
throw new IllegalArgumentException(e.getMessage());
}
return data.getDataType();
}
private Reference[] findExistingRefs(ReferenceManager refMgr, AddressFactory af, Address start,
Address end) {
ArrayList<Reference> list = new ArrayList<Reference>();
AddressIterator it = refMgr.getReferenceSourceIterator(new AddressSet(start, end), true);
while (it.hasNext()) {
Address addr = it.next();
Reference[] refs = refMgr.getReferencesFrom(addr);
Collections.addAll(list, refs);
}
Reference[] refList = new Reference[list.size()];
return list.toArray(refList);
}
private void addRefs(Program p, ReferenceManager refMgr, Reference[] refs) {
for (Reference ref : refs) {
refMgr.addReference(ref);
}
}
} }
@@ -24,97 +24,93 @@ import ghidra.program.model.listing.Program;
* Command to create a structure inside of another structure. * Command to create a structure inside of another structure.
* *
*/ */
public class CreateStructureInStructureCmd extends AbstractCreateStructureCmd{ public class CreateStructureInStructureCmd extends AbstractCreateStructureCmd {
private int[] fromPath; private int[] fromPath;
private int[] toPath; private int[] toPath;
private Structure structure; private Structure structure;
/**
* Constructs a new command for creating structures inside other structures.
* @param address the address of the outer-most structure.
* @param fromPath the componentPath of the first component to be consumed in
* the new structure.
* @param toPath the componentPath of the second component to be consumed in the
* the new structure.
*/
public CreateStructureInStructureCmd( Address address, int[] fromPath, int[] toPath ){
this( StructureFactory.DEFAULT_STRUCTURE_NAME, address, fromPath, toPath );
}
/** /**
* Constructs a new command for creating structures inside other structures. * Constructs a new command for creating structures inside other structures.
* * @param address the address of the outer-most structure.
* @param name The name of the structure. * @param fromPath the componentPath of the first component to be consumed in
* the new structure.
* @param toPath the componentPath of the second component to be consumed in the
* the new structure.
*/
public CreateStructureInStructureCmd(Address address, int[] fromPath, int[] toPath) {
this(StructureFactory.DEFAULT_STRUCTURE_NAME, address, fromPath, toPath);
}
/**
* Constructs a new command for creating structures inside other structures.
*
* @param name The name of the structure.
* @param addr the address of the outer-most structure. * @param addr the address of the outer-most structure.
* @param fromPath the componentPath of the first component to be consumed in * @param fromPath the componentPath of the first component to be consumed in
* the new structure. * the new structure.
* @param toPath the componentPath of the second component to be consumed in the * @param toPath the componentPath of the second component to be consumed in the
* the new structure. * the new structure.
*/ */
public CreateStructureInStructureCmd( String name, Address addr, int[] fromPath, int[] toPath){ public CreateStructureInStructureCmd(String name, Address addr, int[] fromPath, int[] toPath) {
super( name, addr ); super(name, addr);
this.fromPath = fromPath; this.fromPath = fromPath;
this.toPath = toPath; this.toPath = toPath;
} }
public CreateStructureInStructureCmd( Structure newStructure, public CreateStructureInStructureCmd(Structure newStructure, Address address, int[] fromPath,
Address address, int[] fromPath, int[] toPath ){ int[] toPath) {
this( address, fromPath, toPath ); this(address, fromPath, toPath);
structure = newStructure; structure = newStructure;
} }
/*
* @see AbstractCreateStructureCmd#createStructure(Address, Program)
*/
/*package*/ @Override
Structure createStructure( Address address,
Program program ){
if ( structure == null ){
structure = StructureFactory.createStructureDataTypeInStrucuture(
program, address, fromPath, toPath, getStructureName(), true );
}
return structure;
}
/*
* @see AbstractCreateStructureCmd#initializeStructureData(StructureInfo)
*/
/*package*/ @Override
DataType initializeStructureData( Program program, Structure localStructure ){
Data data = program.getListing().getDataContaining(
getStructureAddress() );
Data comp1 = data.getComponent( fromPath );
Data comp2 = data.getComponent(toPath);
int dataLength = (comp2.getParentOffset() + comp2.getLength())
- comp1.getParentOffset();
DataType parentDataType = comp1.getParent().getBaseDataType();
if ( !(parentDataType instanceof Structure) ){
throw new IllegalArgumentException(
"Data not in a structure");
}
Structure originalStructure = (Structure) parentDataType;
// clear and initialize the original structure and then get the new
// data
clearStruct(originalStructure, comp1.getParentOffset(), dataLength );
originalStructure.replace(comp1.getComponentIndex(),
localStructure, localStructure.getLength());
comp1 = data.getComponent( fromPath );
return comp1.getDataType();
}
private void clearStruct(Structure struct, int offset, int length) { /*
DataTypeComponent[] comps = struct.getDefinedComponents(); * @see AbstractCreateStructureCmd#createStructure(Address, Program)
int endOffset = offset+length; */
for(int i=comps.length-1;i>=0;i--) { /*package*/ @Override
if (comps[i].getOffset() >= offset && comps[i].getOffset() < endOffset) { Structure createStructure(Address address, Program program) {
struct.clearComponent(comps[i].getOrdinal());
} if (structure == null) {
} structure = StructureFactory.createStructureDataTypeInStrucuture(program, address,
} fromPath, toPath, getStructureName(), true);
}
return structure;
}
/*
* @see AbstractCreateStructureCmd#initializeStructureData(StructureInfo)
*/
/*package*/ @Override
DataType initializeStructureData(Program program, Structure localStructure) {
Data data = program.getListing().getDataContaining(getStructureAddress());
Data comp1 = data.getComponent(fromPath);
Data comp2 = data.getComponent(toPath);
int dataLength = (comp2.getParentOffset() + comp2.getLength()) - comp1.getParentOffset();
DataType parentDataType = comp1.getParent().getBaseDataType();
if (!(parentDataType instanceof Structure)) {
throw new IllegalArgumentException("Data not in a structure");
}
Structure originalStructure = (Structure) parentDataType;
// clear and initialize the original structure and then get the new
// data
clearStruct(originalStructure, comp1.getParentOffset(), dataLength);
originalStructure.replace(comp1.getComponentIndex(), localStructure,
localStructure.getLength());
comp1 = data.getComponent(fromPath);
return comp1.getDataType();
}
private void clearStruct(Structure struct, int offset, int length) {
DataTypeComponent[] comps = struct.getDefinedComponents();
int endOffset = offset + length;
for (int i = comps.length - 1; i >= 0; i--) {
if (comps[i].getOffset() >= offset && comps[i].getOffset() < endOffset) {
struct.clearComponent(comps[i].getOrdinal());
}
}
}
} }
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,22 +16,21 @@
package ghidra.app.cmd.data; package ghidra.app.cmd.data;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.data.DataTypeComponent; import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
/** /**
* Command to rename a component in a data type. * Command to rename a component in a data type.
* *
*/ */
public class RenameDataFieldCmd implements Command { public class RenameDataFieldCmd implements Command<Program> {
private DataTypeComponent comp; private DataTypeComponent comp;
private String newName; private String newName;
private String statusMsg = ""; private String statusMsg = "";
/** /**
* Construct a new RenameDataFieldCmd. * Construct a new RenameDataFieldCmd.
* @param comp component in data type to be renamed * @param comp component in data type to be renamed
@@ -43,11 +41,8 @@ public class RenameDataFieldCmd implements Command {
this.newName = newName; this.newName = newName;
} }
/* @Override
* (non-Javadoc) public boolean applyTo(Program program) {
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
public boolean applyTo(DomainObject obj) {
if (comp == null) { if (comp == null) {
statusMsg = "Null data type"; statusMsg = "Null data type";
return false; return false;
@@ -55,7 +50,8 @@ public class RenameDataFieldCmd implements Command {
try { try {
comp.setFieldName(newName); comp.setFieldName(newName);
return true; return true;
} catch(DuplicateNameException e) { }
catch (DuplicateNameException e) {
statusMsg = "Type name already exists: " + newName; statusMsg = "Type name already exists: " + newName;
} }
return false; return false;
@@ -65,6 +61,7 @@ public class RenameDataFieldCmd implements Command {
* (non-Javadoc) * (non-Javadoc)
* @see ghidra.framework.cmd.Command#getStatusMsg() * @see ghidra.framework.cmd.Command#getStatusMsg()
*/ */
@Override
public String getStatusMsg() { public String getStatusMsg() {
return statusMsg; return statusMsg;
} }
@@ -73,6 +70,7 @@ public class RenameDataFieldCmd implements Command {
* (non-Javadoc) * (non-Javadoc)
* @see ghidra.framework.cmd.Command#getName() * @see ghidra.framework.cmd.Command#getName()
*/ */
@Override
public String getName() { public String getName() {
return "Rename Data Field"; return "Rename Data Field";
} }
@@ -15,7 +15,8 @@
*/ */
package ghidra.app.cmd.disassemble; package ghidra.app.cmd.disassemble;
import ghidra.framework.model.DomainObject; import java.math.BigInteger;
import ghidra.program.disassemble.DisassemblerContextImpl; import ghidra.program.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
@@ -24,8 +25,6 @@ import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import java.math.BigInteger;
/** /**
* Command object for performing Arm/Thumb disassembly * Command object for performing Arm/Thumb disassembly
*/ */
@@ -70,8 +69,7 @@ public class ArmDisassembleCommand extends DisassembleCommand {
} }
@Override @Override
synchronized public boolean applyTo(DomainObject obj, TaskMonitor monitor) { synchronized public boolean applyTo(Program program, TaskMonitor monitor) {
Program program = (Program) obj;
disassemblyPerformed = false; disassemblyPerformed = false;
unalignedStart = false; unalignedStart = false;
@@ -17,10 +17,10 @@ package ghidra.app.cmd.disassemble;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager; import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.program.disassemble.*; import ghidra.program.disassemble.*;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
@@ -30,7 +30,7 @@ import ghidra.util.task.TaskMonitor;
/** /**
* Command object for performing disassembly * Command object for performing disassembly
*/ */
public class DisassembleCommand extends BackgroundCommand { public class DisassembleCommand extends BackgroundCommand<Program> {
protected AddressSetView startSet; protected AddressSetView startSet;
protected boolean useDefaultRepeatPatternBehavior = false; protected boolean useDefaultRepeatPatternBehavior = false;
@@ -78,6 +78,8 @@ public class DisassembleCommand extends BackgroundCommand {
* @param startSet set of addresses to be the start of a disassembly. The Command object will * @param startSet set of addresses to be the start of a disassembly. The Command object will
* attempt to start a disassembly at each address in this set. * attempt to start a disassembly at each address in this set.
* @param restrictedSet addresses that can be disassembled. a null set implies no restrictions * @param restrictedSet addresses that can be disassembled. a null set implies no restrictions
* @param followFlow follow all flows within restricted set if true, otherwise limit to using
* startSet for flows.
*/ */
public DisassembleCommand(AddressSetView startSet, AddressSetView restrictedSet, public DisassembleCommand(AddressSetView startSet, AddressSetView restrictedSet,
boolean followFlow) { boolean followFlow) {
@@ -125,7 +127,7 @@ public class DisassembleCommand extends BackgroundCommand {
* Set code analysis enablement. By default new instructions will be submitted for * Set code analysis enablement. By default new instructions will be submitted for
* auto-analysis. * auto-analysis.
* *
* @param enable * @param enable true if incremental code analysis should be done, else false to prevent this.
*/ */
public void enableCodeAnalysis(boolean enable) { public void enableCodeAnalysis(boolean enable) {
this.enableAnalysis = enable; this.enableAnalysis = enable;
@@ -150,8 +152,7 @@ public class DisassembleCommand extends BackgroundCommand {
} }
@Override @Override
synchronized public boolean applyTo(DomainObject obj, TaskMonitor monitor) { synchronized public boolean applyTo(Program program, TaskMonitor monitor) {
Program program = (Program) obj;
return doDisassembly(monitor, program, program.getLanguage().getInstructionAlignment()); return doDisassembly(monitor, program, program.getLanguage().getInstructionAlignment());
} }
@@ -317,7 +318,7 @@ public class DisassembleCommand extends BackgroundCommand {
* *
* @param disassembler disassembler to use * @param disassembler disassembler to use
* @param seedSet set of addresses to be disassembled * @param seedSet set of addresses to be disassembled
* @param mgr * @param mgr auto analysis manager
* *
* @return addresses actually disassembled * @return addresses actually disassembled
*/ */
@@ -17,7 +17,6 @@ package ghidra.app.cmd.disassemble;
import java.math.BigInteger; import java.math.BigInteger;
import ghidra.framework.model.DomainObject;
import ghidra.program.disassemble.DisassemblerContextImpl; import ghidra.program.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
@@ -70,8 +69,7 @@ public class Hcs12DisassembleCommand extends DisassembleCommand {
} }
@Override @Override
synchronized public boolean applyTo(DomainObject obj, TaskMonitor monitor) { synchronized public boolean applyTo(Program program, TaskMonitor monitor) {
Program program = (Program) obj;
disassemblyPerformed = false; disassemblyPerformed = false;
unalignedStart = false; unalignedStart = false;
@@ -17,7 +17,6 @@ package ghidra.app.cmd.disassemble;
import java.math.BigInteger; import java.math.BigInteger;
import ghidra.framework.model.DomainObject;
import ghidra.program.disassemble.DisassemblerContextImpl; import ghidra.program.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
@@ -75,8 +74,7 @@ public class MipsDisassembleCommand extends DisassembleCommand {
} }
@Override @Override
synchronized public boolean applyTo(DomainObject obj, TaskMonitor monitor) { synchronized public boolean applyTo(Program program, TaskMonitor monitor) {
Program program = (Program) obj;
disassemblyPerformed = false; disassemblyPerformed = false;
unalignedStart = false; unalignedStart = false;
@@ -90,7 +88,7 @@ public class MipsDisassembleCommand extends DisassembleCommand {
setStatusMsg("MIPS16 mode not supported"); setStatusMsg("MIPS16 mode not supported");
return false; return false;
} }
return super.applyTo(obj, monitor); return super.applyTo(program, monitor);
} }
RegisterValue m16modeValue = RegisterValue m16modeValue =
@@ -17,7 +17,6 @@ package ghidra.app.cmd.disassemble;
import java.math.BigInteger; import java.math.BigInteger;
import ghidra.framework.model.DomainObject;
import ghidra.program.disassemble.DisassemblerContextImpl; import ghidra.program.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
@@ -77,8 +76,7 @@ public class PowerPCDisassembleCommand extends DisassembleCommand {
} }
@Override @Override
synchronized public boolean applyTo(DomainObject obj, TaskMonitor monitor) { synchronized public boolean applyTo(Program program, TaskMonitor monitor) {
Program program = (Program) obj;
disassemblyPerformed = false; disassemblyPerformed = false;
unalignedStart = false; unalignedStart = false;
@@ -92,7 +90,7 @@ public class PowerPCDisassembleCommand extends DisassembleCommand {
setStatusMsg("PowerISA VLE mode not supported"); setStatusMsg("PowerISA VLE mode not supported");
return false; return false;
} }
return super.applyTo(obj, monitor); return super.applyTo(program, monitor);
} }
RegisterValue vlemodeValue = RegisterValue vlemodeValue =
@@ -16,14 +16,13 @@
package ghidra.app.cmd.disassemble; package ghidra.app.cmd.disassemble;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.program.disassemble.ReDisassembler; import ghidra.program.disassemble.ReDisassembler;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class ReDisassembleCommand extends BackgroundCommand { public class ReDisassembleCommand extends BackgroundCommand<Program> {
private final Address seed; private final Address seed;
public ReDisassembleCommand(Address seed) { public ReDisassembleCommand(Address seed) {
@@ -31,8 +30,8 @@ public class ReDisassembleCommand extends BackgroundCommand {
} }
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public boolean applyTo(Program program, TaskMonitor monitor) {
ReDisassembler dis = new ReDisassembler((Program) obj); ReDisassembler dis = new ReDisassembler(program);
try { try {
dis.disasemble(seed, monitor); dis.disasemble(seed, monitor);
return true; return true;
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,7 +16,6 @@
package ghidra.app.cmd.disassemble; package ghidra.app.cmd.disassemble;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView; import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@@ -26,7 +24,7 @@ import ghidra.util.task.TaskMonitor;
/** /**
* Command for setting the fallthrough property on an instruction. * Command for setting the fallthrough property on an instruction.
*/ */
public class SetFlowOverrideCmd extends BackgroundCommand { public class SetFlowOverrideCmd extends BackgroundCommand<Program> {
Address instAddr; Address instAddr;
AddressSetView set; AddressSetView set;
FlowOverride flowOverride; FlowOverride flowOverride;
@@ -60,9 +58,7 @@ public class SetFlowOverrideCmd extends BackgroundCommand {
} }
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public boolean applyTo(Program program, TaskMonitor monitor) {
Program program = (Program) obj;
if (set != null) { if (set != null) {
int cnt = 0; int cnt = 0;
@@ -19,10 +19,10 @@ import java.math.BigInteger;
import javax.help.UnsupportedOperationException; import javax.help.UnsupportedOperationException;
import ghidra.framework.model.DomainObject;
import ghidra.program.disassemble.DisassemblerContextImpl; import ghidra.program.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.ProgramContext; import ghidra.program.model.listing.ProgramContext;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@@ -91,8 +91,7 @@ public class X86_64DisassembleCommand extends DisassembleCommand {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public static AddressSet alignSet(int alignment, AddressSetView set) public static AddressSet alignSet(int alignment, AddressSetView set) {
throws CancelledException {
AddressSet result = new AddressSet(); AddressSet result = new AddressSet();
for (AddressRange range : set) { for (AddressRange range : set) {
Address min = range.getMinAddress(); Address min = range.getMinAddress();
@@ -115,8 +114,7 @@ public class X86_64DisassembleCommand extends DisassembleCommand {
} }
@Override @Override
synchronized public boolean applyTo(DomainObject obj, TaskMonitor monitor) { synchronized public boolean applyTo(Program program, TaskMonitor monitor) {
Program program = (Program) obj;
disassemblyPerformed = false; disassemblyPerformed = false;
unalignedStart = false; unalignedStart = false;
@@ -130,8 +128,8 @@ public class X86_64DisassembleCommand extends DisassembleCommand {
languageError = "Requires x86:LE:64:default"; languageError = "Requires x86:LE:64:default";
return false; return false;
} }
RegisterValue ctx = new RegisterValue(context.getBaseContextRegister()) RegisterValue ctx = new RegisterValue(context.getBaseContextRegister()).assign(longModeReg,
.assign(longModeReg, size32Mode ? BigInteger.ZERO : BigInteger.ONE); size32Mode ? BigInteger.ZERO : BigInteger.ONE);
super.setInitialContext(ctx); super.setInitialContext(ctx);
@@ -16,13 +16,12 @@
package ghidra.app.cmd.equate; package ghidra.app.cmd.equate;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Equate; import ghidra.program.model.symbol.Equate;
import ghidra.program.model.symbol.EquateTable; import ghidra.program.model.symbol.EquateTable;
public class ClearEquateCmd implements Command { public class ClearEquateCmd implements Command<Program> {
private String equateName; private String equateName;
private Address addr; private Address addr;
@@ -42,8 +41,8 @@ public class ClearEquateCmd implements Command {
} }
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
EquateTable equateTable = ((Program) obj).getEquateTable(); EquateTable equateTable = program.getEquateTable();
Equate equate = equateTable.getEquate(equateName); Equate equate = equateTable.getEquate(equateName);
clearEquate(equate, equateTable); clearEquate(equate, equateTable);
@@ -16,7 +16,6 @@
package ghidra.app.cmd.equate; package ghidra.app.cmd.equate;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Equate; import ghidra.program.model.symbol.Equate;
@@ -27,7 +26,7 @@ import ghidra.util.exception.InvalidInputException;
/** /**
* Command for setting an equate at a location. * Command for setting an equate at a location.
*/ */
public class SetEquateCmd implements Command { public class SetEquateCmd implements Command<Program> {
private String equateName; private String equateName;
private Address addr; private Address addr;
@@ -52,24 +51,19 @@ public class SetEquateCmd implements Command {
this.equateValue = equateValue; this.equateValue = equateValue;
} }
/**
* The name of the edit action.
*/
@Override @Override
public String getName() { public String getName() {
return "Set Equate"; return "Set Equate";
} }
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
EquateTable equateTable = ((Program) obj).getEquateTable(); EquateTable equateTable = program.getEquateTable();
equate = equateTable.getEquate(equateName); equate = equateTable.getEquate(equateName);
if (existsWithDifferentValue(equate)) { if (existsWithDifferentValue(equate)) {
msg = msg = "Equate named " + equateName + " already exists with value of " +
"Equate named " + equateName + " already exists with value of " + equate.getValue() + ".";
equate.getValue() + ".";
return false; return false;
} }
@@ -101,9 +95,6 @@ public class SetEquateCmd implements Command {
return equate; return equate;
} }
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/
@Override @Override
public String getStatusMsg() { public String getStatusMsg() {
return msg; return msg;
@@ -16,17 +16,14 @@
package ghidra.app.cmd.function; package ghidra.app.cmd.function;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.*;
import ghidra.program.model.listing.FunctionManager;
/** /**
* Command for assigning a tag to a function. Executing this will pop up a dialog * Command for assigning a tag to a function. Executing this will pop up a dialog
* allowing the user to assign tags to a function. * allowing the user to assign tags to a function.
*/ */
public class AddFunctionTagCmd implements Command { public class AddFunctionTagCmd implements Command<Program> {
private Address entryPoint; private Address entryPoint;
private String tagName; private String tagName;
@@ -44,8 +41,7 @@ public class AddFunctionTagCmd implements Command {
} }
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
ProgramDB program = (ProgramDB) obj;
FunctionManager functionManager = program.getFunctionManager(); FunctionManager functionManager = program.getFunctionManager();
Function function = functionManager.getFunctionAt(entryPoint); Function function = functionManager.getFunctionAt(entryPoint);
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,12 +23,16 @@ import ghidra.util.exception.InvalidInputException;
/** /**
* A command to create a new function memory parameter. * A command to create a new function memory parameter.
*
* @deprecated function signatures should be modified in their entirety using
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
*/ */
@Deprecated(since = "11.1")
public class AddMemoryParameterCommand extends AddParameterCommand { public class AddMemoryParameterCommand extends AddParameterCommand {
private Address memAddr; private final Address memAddr;
private String name; private final String name;
private DataType dataType; private final DataType dataType;
public AddMemoryParameterCommand(Function function, Address memAddr, String name, public AddMemoryParameterCommand(Function function, Address memAddr, String name,
DataType dataType, int ordinal, SourceType source) { DataType dataType, int ordinal, SourceType source) {
@@ -37,7 +40,6 @@ public class AddMemoryParameterCommand extends AddParameterCommand {
this.memAddr = memAddr; this.memAddr = memAddr;
this.name = name; this.name = name;
this.dataType = dataType; this.dataType = dataType;
this.ordinal = ordinal;
} }
@Override @Override
@@ -45,9 +47,6 @@ public class AddMemoryParameterCommand extends AddParameterCommand {
return new ParameterImpl(name, dataType, memAddr, program); return new ParameterImpl(name, dataType, memAddr, program);
} }
/**
* @see ghidra.framework.cmd.Command#getName()
*/
@Override @Override
public String getName() { public String getName() {
return "Create Memory Parameter"; return "Create Memory Parameter";
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,7 +16,6 @@
package ghidra.app.cmd.function; package ghidra.app.cmd.function;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@@ -28,8 +26,8 @@ import ghidra.util.exception.InvalidInputException;
/** /**
* Command to add a memory variable to a function. * Command to add a memory variable to a function.
*/ */
public class AddMemoryVarCmd implements Command { public class AddMemoryVarCmd implements Command<Program> {
private Program program;
private Address memAddr; private Address memAddr;
private Address firstUseAddr; private Address firstUseAddr;
private String name; private String name;
@@ -68,13 +66,8 @@ public class AddMemoryVarCmd implements Command {
this.source = source; this.source = source;
} }
/**
*
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
program = (Program) obj;
Function f = program.getListing().getFunctionContaining(firstUseAddr); Function f = program.getListing().getFunctionContaining(firstUseAddr);
if (f == null) { if (f == null) {
@@ -100,17 +93,11 @@ public class AddMemoryVarCmd implements Command {
return true; return true;
} }
/**
* @see ghidra.framework.cmd.Command#getName()
*/
@Override @Override
public String getName() { public String getName() {
return "Create Memory Variable"; return "Create Memory Variable";
} }
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/
@Override @Override
public String getStatusMsg() { public String getStatusMsg() {
return errMsg; return errMsg;
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,7 +16,6 @@
package ghidra.app.cmd.function; package ghidra.app.cmd.function;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
@@ -29,17 +27,23 @@ import ghidra.util.exception.InvalidInputException;
* Note: If no ordinal is provided to this class at construction time, then * Note: If no ordinal is provided to this class at construction time, then
* the ordinal of hte given parameter will be used. * the ordinal of hte given parameter will be used.
* *
* @see AddRegisterParameterCommand
* @see AddStackParameterCommand
* @see AddMemoryParameterCommand
* *
* @see ghidra.app.cmd.function.AddRegisterParameterCommand * @deprecated function signatures should be modified in their entirety using
* @see ghidra.app.cmd.function.AddStackParameterCommand * either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
*/ */
public class AddParameterCommand implements Command { @Deprecated(since = "11.1")
public class AddParameterCommand implements Command<Program> {
protected final Function function;
protected final int ordinal;
protected final SourceType source;
private final Parameter parameter;
protected Function function;
protected Parameter parameter;
protected String statusMessage; protected String statusMessage;
protected int ordinal;
protected SourceType source;
public AddParameterCommand(Function function, Parameter parameter, int ordinal, public AddParameterCommand(Function function, Parameter parameter, int ordinal,
SourceType source) { SourceType source) {
@@ -49,31 +53,32 @@ public class AddParameterCommand implements Command {
this.source = source; this.source = source;
} }
// // lets this be usable by code that already has a parameter
// public AddParameterCommand(Function function, Parameter parameter) {
// this(function, parameter, parameter.getOrdinal());
// }
// allows subclasses to use this class without having to already have // allows subclasses to use this class without having to already have
// a parameter created // a parameter created
protected AddParameterCommand(Function function, int ordinal, SourceType source) { protected AddParameterCommand(Function function, int ordinal, SourceType source) {
this(function, null, ordinal, source); this(function, null, ordinal, source);
} }
/**
* Get parameter to be added
* @param program target program
* @return parameter to be added
* @throws InvalidInputException if unable to generate parameter due to invalid data
*/
protected Parameter getParameter(Program program) throws InvalidInputException { protected Parameter getParameter(Program program) throws InvalidInputException {
return parameter; return parameter;
} }
/**
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
@Override @Override
public boolean applyTo(DomainObject obj) { public final boolean applyTo(Program program) {
if (program != function.getProgram()) {
throw new AssertionError("Program instance mismatch");
}
String name = null; String name = null;
try { try {
Parameter parameter2add = getParameter((Program) obj); Parameter param = getParameter(program);
name = parameter2add.getName(); name = param.getName();
if (function.insertParameter(ordinal, parameter2add, source) == null) { if (function.insertParameter(ordinal, param, source) == null) {
statusMessage = "Create parameter failed"; statusMessage = "Create parameter failed";
return false; return false;
} }
@@ -102,17 +107,11 @@ public class AddParameterCommand implements Command {
return true; return true;
} }
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/
@Override @Override
public String getStatusMsg() { public String getStatusMsg() {
return statusMessage; return statusMessage;
} }
/**
* @see ghidra.framework.cmd.Command#getName()
*/
@Override @Override
public String getName() { public String getName() {
return "Add Parameter Command"; return "Add Parameter Command";
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -25,14 +24,15 @@ import ghidra.util.exception.InvalidInputException;
/** /**
* A command to create a new function register parameter. * A command to create a new function register parameter.
* *
* * @deprecated function signatures should be modified in their entirety using
* @since Tracker Id 526 * either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
*/ */
@Deprecated(since = "11.1")
public class AddRegisterParameterCommand extends AddParameterCommand { public class AddRegisterParameterCommand extends AddParameterCommand {
private Register register; private final Register register;
private String name; private final String name;
private DataType dataType; private final DataType dataType;
public AddRegisterParameterCommand(Function function, Register register, String name, public AddRegisterParameterCommand(Function function, Register register, String name,
DataType dataType, int ordinal, SourceType source) { DataType dataType, int ordinal, SourceType source) {
@@ -40,7 +40,6 @@ public class AddRegisterParameterCommand extends AddParameterCommand {
this.register = register; this.register = register;
this.name = name; this.name = name;
this.dataType = dataType; this.dataType = dataType;
this.ordinal = ordinal;
} }
@Override @Override
@@ -48,9 +47,6 @@ public class AddRegisterParameterCommand extends AddParameterCommand {
return new ParameterImpl(name, dataType, register, program); return new ParameterImpl(name, dataType, register, program);
} }
/**
* @see ghidra.framework.cmd.Command#getName()
*/
@Override @Override
public String getName() { public String getName() {
return "Create Register Parameter"; return "Create Register Parameter";
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,7 +16,6 @@
package ghidra.app.cmd.function; package ghidra.app.cmd.function;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
@@ -30,9 +28,8 @@ import ghidra.util.exception.InvalidInputException;
* Command to add a register variable to a function. * Command to add a register variable to a function.
* *
*/ */
public class AddRegisterVarCmd implements Command { public class AddRegisterVarCmd implements Command<Program> {
private Program program;
private Address addr; private Address addr;
private Register reg; private Register reg;
private String name; private String name;
@@ -71,13 +68,8 @@ public class AddRegisterVarCmd implements Command {
this.source = source; this.source = source;
} }
/**
*
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
@Override @Override
public boolean applyTo(DomainObject obj) { public boolean applyTo(Program program) {
program = (Program) obj;
Function f = program.getListing().getFunctionContaining(addr); Function f = program.getListing().getFunctionContaining(addr);
if (f == null) { if (f == null) {
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,14 +23,15 @@ import ghidra.util.exception.InvalidInputException;
/** /**
* A command to create a new function stack parameter. * A command to create a new function stack parameter.
* *
* * @deprecated function signatures should be modified in their entirety using
* @since Tracker Id 526 * either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
*/ */
@Deprecated(since = "11.1")
public class AddStackParameterCommand extends AddParameterCommand { public class AddStackParameterCommand extends AddParameterCommand {
private int stackOffset; private final int stackOffset;
private String name; private final String name;
private DataType dataType; private final DataType dataType;
public AddStackParameterCommand(Function function, int stackOffset, String name, public AddStackParameterCommand(Function function, int stackOffset, String name,
DataType dataType, int ordinal, SourceType source) { DataType dataType, int ordinal, SourceType source) {
@@ -39,8 +39,6 @@ public class AddStackParameterCommand extends AddParameterCommand {
this.stackOffset = stackOffset; this.stackOffset = stackOffset;
this.name = name; this.name = name;
this.dataType = dataType; this.dataType = dataType;
this.ordinal = ordinal;
this.source = source;
} }
@Override @Override

Some files were not shown because too many files have changed in this diff Show More