mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
GP-3351: Purge TraceFunctionSymbol and related interfaces, impls, tables, etc.
This commit is contained in:
parent
bece81176e
commit
eeaa3486b8
50 changed files with 520 additions and 7068 deletions
|
@ -404,11 +404,6 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
|||
return !mode.canEdit(current);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamicListing() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWindowGroup() {
|
||||
//TODO: Overriding this to align disconnected providers
|
||||
|
|
|
@ -102,9 +102,9 @@ public enum DebuggerPcodeUtils {
|
|||
* TODO: This may break things that check for the absence of a symbol
|
||||
*
|
||||
* I don't think it'll affect expressions, but it could later affect user Sleigh
|
||||
* libraries than an expression might like to use. The better approach would be
|
||||
* to incorporate a better error message into the Sleigh compiler, but it won't
|
||||
* always know the use case for a clear message.
|
||||
* libraries than an expression might like to use. The better approach would be to
|
||||
* incorporate a better error message into the Sleigh compiler, but it won't always
|
||||
* know the use case for a clear message.
|
||||
*/
|
||||
throw new SleighException("Unknown register or label: '" + nm + "'");
|
||||
}
|
||||
|
@ -114,9 +114,7 @@ public enum DebuggerPcodeUtils {
|
|||
protected SleighSymbol findUserSymbol(String nm) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
long snap = coordinates.getSnap();
|
||||
for (TraceSymbol symbol : trace.getSymbolManager()
|
||||
.labelsAndFunctions()
|
||||
.getNamed(nm)) {
|
||||
for (TraceSymbol symbol : trace.getSymbolManager().labels().getNamed(nm)) {
|
||||
if (symbol instanceof TraceSymbolWithLifespan lifeSym &&
|
||||
!lifeSym.getLifespan().contains(snap)) {
|
||||
continue;
|
||||
|
|
|
@ -224,11 +224,9 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferMixin {
|
|||
@Override
|
||||
default Symbol[] getSymbols() {
|
||||
try (LockHold hold = getTrace().lockRead()) {
|
||||
Collection<? extends TraceSymbol> at =
|
||||
getTrace().getSymbolManager()
|
||||
.labelsAndFunctions()
|
||||
.getAt(getStartSnap(), getThread(),
|
||||
getAddress(), true);
|
||||
Collection<? extends TraceSymbol> at = getTrace().getSymbolManager()
|
||||
.labels()
|
||||
.getAt(getStartSnap(), getThread(), getAddress(), true);
|
||||
return at.toArray(new TraceSymbol[at.size()]);
|
||||
}
|
||||
}
|
||||
|
@ -236,11 +234,9 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferMixin {
|
|||
@Override
|
||||
default Symbol getPrimarySymbol() {
|
||||
try (LockHold hold = getTrace().lockRead()) {
|
||||
Collection<? extends TraceSymbol> at =
|
||||
getTrace().getSymbolManager()
|
||||
.labelsAndFunctions()
|
||||
.getAt(getStartSnap(), getThread(),
|
||||
getAddress(), true);
|
||||
Collection<? extends TraceSymbol> at = getTrace().getSymbolManager()
|
||||
.labels()
|
||||
.getAt(getStartSnap(), getThread(), getAddress(), true);
|
||||
if (at.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ import ghidra.trace.database.DBTrace;
|
|||
import ghidra.trace.database.guest.InternalTracePlatform;
|
||||
import ghidra.trace.database.listing.UndefinedDBTraceData;
|
||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||
import ghidra.trace.database.symbol.DBTraceFunctionSymbol;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.listing.*;
|
||||
|
@ -45,7 +44,6 @@ import ghidra.trace.model.memory.TraceMemoryRegion;
|
|||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.program.TraceProgramViewListing;
|
||||
import ghidra.trace.model.property.TracePropertyMapOperations;
|
||||
import ghidra.trace.model.symbol.TraceFunctionSymbol;
|
||||
import ghidra.trace.util.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.AddressIteratorAdapter;
|
||||
|
@ -867,13 +865,13 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
|||
}
|
||||
|
||||
@Override
|
||||
public TraceFunctionSymbol createFunction(String name, Address entryPoint, AddressSetView body,
|
||||
public Function createFunction(String name, Address entryPoint, AddressSetView body,
|
||||
SourceType source) throws InvalidInputException, OverlappingFunctionException {
|
||||
return program.functionManager.createFunction(name, entryPoint, body, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceFunctionSymbol createFunction(String name, Namespace nameSpace, Address entryPoint,
|
||||
public Function createFunction(String name, Namespace nameSpace, Address entryPoint,
|
||||
AddressSetView body, SourceType source)
|
||||
throws InvalidInputException, OverlappingFunctionException {
|
||||
return program.functionManager.createFunction(name, nameSpace, entryPoint, body, source);
|
||||
|
@ -891,22 +889,12 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
|||
|
||||
@Override
|
||||
public List<Function> getGlobalFunctions(String name) {
|
||||
return new ArrayList<>(program.trace.getSymbolManager().functions().getGlobalsNamed(name));
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Function> getFunctions(String namespace, String name) {
|
||||
// NOTE: This implementation allows namespaces to contain the separator symbol
|
||||
List<Function> result = new ArrayList<>();
|
||||
for (DBTraceFunctionSymbol func : program.trace.getSymbolManager()
|
||||
.functions()
|
||||
.getNamed(
|
||||
name)) {
|
||||
if (namespace.equals(func.getParentNamespace().getName(true))) {
|
||||
result.add(func);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -916,7 +904,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
|||
|
||||
@Override
|
||||
public FunctionIterator getExternalFunctions() {
|
||||
return program.functionManager.getExternalFunctions();
|
||||
return EmptyFunctionIterator.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,10 +47,10 @@ import ghidra.trace.database.*;
|
|||
import ghidra.trace.database.listing.DBTraceCodeSpace;
|
||||
import ghidra.trace.database.listing.DBTraceDefinedUnitsView;
|
||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||
import ghidra.trace.database.symbol.DBTraceFunctionSymbolView;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.Trace.*;
|
||||
import ghidra.trace.model.TraceTimeViewport.*;
|
||||
import ghidra.trace.model.TraceTimeViewport.Occlusion;
|
||||
import ghidra.trace.model.TraceTimeViewport.RangeQueryOcclusion;
|
||||
import ghidra.trace.model.bookmark.TraceBookmark;
|
||||
import ghidra.trace.model.bookmark.TraceBookmarkType;
|
||||
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||
|
@ -129,22 +129,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
listenFor(TraceDataTypeChangeType.RENAMED, this::dataTypeRenamed);
|
||||
listenFor(TraceDataTypeChangeType.DELETED, this::dataTypeDeleted);
|
||||
|
||||
listenFor(TraceFunctionChangeType.CHANGED, this::functionChanged);
|
||||
listenFor(TraceFunctionChangeType.CHANGED_PURGE, this::functionChangedPurge);
|
||||
listenFor(TraceFunctionChangeType.CHANGED_INLINE, this::functionChangedInline);
|
||||
listenFor(TraceFunctionChangeType.CHANGED_NORETURN, this::functionChangedNoReturn);
|
||||
listenFor(TraceFunctionChangeType.CHANGED_CALL_FIXUP, this::functionChangedCallFixup);
|
||||
listenFor(TraceFunctionChangeType.CHANGED_RETURN, this::functionChangedReturn);
|
||||
listenFor(TraceFunctionChangeType.CHANGED_PARAMETERS, this::functionChangedParameters);
|
||||
listenFor(TraceFunctionChangeType.CHANGED_THUNK, this::functionChangedThunk);
|
||||
listenFor(TraceFunctionChangeType.CHANGED_BODY, this::functionChangedBody);
|
||||
listenFor(TraceFunctionChangeType.TAG_APPLIED, this::functionChangedTagApplied);
|
||||
listenFor(TraceFunctionChangeType.TAG_REMOVED, this::functionChangedTagRemoved);
|
||||
|
||||
listenFor(TraceFunctionTagChangeType.ADDED, this::functionTagAdded);
|
||||
listenFor(TraceFunctionTagChangeType.CHANGED, this::functionTagChanged);
|
||||
listenFor(TraceFunctionTagChangeType.DELETED, this::functionTagDeleted);
|
||||
|
||||
listenFor(TraceInstructionChangeType.FLOW_OVERRIDE_CHANGED,
|
||||
this::instructionFlowOverrideChanged);
|
||||
listenFor(TraceInstructionChangeType.FALL_THROUGH_OVERRIDE_CHANGED,
|
||||
|
@ -465,107 +449,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
null, null, oldPath, newIsNull));
|
||||
}
|
||||
|
||||
private void gatherThunksTo(Collection<TraceFunctionSymbol> into,
|
||||
TraceFunctionSymbol function) {
|
||||
into.add(function);
|
||||
for (Address address : function.getFunctionThunkAddresses()) {
|
||||
TraceFunctionSymbol thunkTo = functionManager.getFunctionAt(address);
|
||||
if (thunkTo != null) {
|
||||
gatherThunksTo(into, thunkTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<TraceFunctionSymbol> gatherThunksTo(TraceFunctionSymbol function) {
|
||||
List<TraceFunctionSymbol> result = new ArrayList<>();
|
||||
gatherThunksTo(result, function);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void functionChangedGeneric(TraceAddressSpace space, TraceFunctionSymbol function,
|
||||
int type, int subType) {
|
||||
DomainObjectEventQueues queues = isFunctionVisible(space, function);
|
||||
if (queues == null) {
|
||||
return;
|
||||
}
|
||||
for (TraceFunctionSymbol f : gatherThunksTo(function)) {
|
||||
queues.fireEvent(new ProgramChangeRecord(type, subType, f.getEntryPoint(),
|
||||
f.getEntryPoint(), f, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
private void functionChanged(TraceAddressSpace space, TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED, 0);
|
||||
}
|
||||
|
||||
private void functionChangedPurge(TraceAddressSpace space, TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED,
|
||||
ChangeManager.FUNCTION_CHANGED_PURGE);
|
||||
}
|
||||
|
||||
private void functionChangedInline(TraceAddressSpace space, TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED,
|
||||
ChangeManager.FUNCTION_CHANGED_INLINE);
|
||||
}
|
||||
|
||||
private void functionChangedNoReturn(TraceAddressSpace space,
|
||||
TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED,
|
||||
ChangeManager.FUNCTION_CHANGED_NORETURN);
|
||||
}
|
||||
|
||||
private void functionChangedCallFixup(TraceAddressSpace space,
|
||||
TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED,
|
||||
ChangeManager.FUNCTION_CHANGED_CALL_FIXUP);
|
||||
}
|
||||
|
||||
private void functionChangedReturn(TraceAddressSpace space, TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED,
|
||||
ChangeManager.FUNCTION_CHANGED_RETURN);
|
||||
}
|
||||
|
||||
private void functionChangedParameters(TraceAddressSpace space,
|
||||
TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED,
|
||||
ChangeManager.FUNCTION_CHANGED_PARAMETERS);
|
||||
}
|
||||
|
||||
private void functionChangedThunk(TraceAddressSpace space, TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED,
|
||||
ChangeManager.FUNCTION_CHANGED_THUNK);
|
||||
}
|
||||
|
||||
private void functionChangedBody(TraceAddressSpace space, TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_BODY_CHANGED, 0);
|
||||
}
|
||||
|
||||
private void functionChangedTagApplied(TraceAddressSpace space,
|
||||
TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_TAG_ADDED_TO_FUNCTION, 0);
|
||||
}
|
||||
|
||||
private void functionChangedTagRemoved(TraceAddressSpace space,
|
||||
TraceFunctionSymbol function) {
|
||||
functionChangedGeneric(space, function, ChangeManager.DOCR_TAG_REMOVED_FROM_FUNCTION,
|
||||
0);
|
||||
}
|
||||
|
||||
private void functionTagAdded(FunctionTag tag) {
|
||||
fireEventAllViews(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_TAG_CREATED, null,
|
||||
null, tag, null, null));
|
||||
}
|
||||
|
||||
private void functionTagChanged(FunctionTag tag) {
|
||||
fireEventAllViews(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_TAG_CHANGED, null,
|
||||
null, tag, null, null));
|
||||
}
|
||||
|
||||
private void functionTagDeleted(FunctionTag tag) {
|
||||
fireEventAllViews(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_TAG_DELETED, null,
|
||||
null, tag, null, null));
|
||||
}
|
||||
|
||||
private void instructionFlowOverrideChanged(TraceAddressSpace space,
|
||||
TraceInstruction instruction, FlowOverride oldOverride, FlowOverride newOverride) {
|
||||
DomainObjectEventQueues queues = isCodeVisible(space, instruction);
|
||||
|
@ -667,39 +550,12 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
null, null, id, null, null));
|
||||
}
|
||||
|
||||
private void checkVariableFunctionChanged(TraceAddressSpace space, TraceSymbol symbol) {
|
||||
if (!(symbol instanceof TraceVariableSymbol)) {
|
||||
return;
|
||||
}
|
||||
TraceFunctionSymbol function = ((TraceVariableSymbol) symbol).getFunction();
|
||||
if (function == null) {
|
||||
return;
|
||||
}
|
||||
int subType = symbol instanceof TraceParameterSymbol ? //
|
||||
ChangeManager.FUNCTION_CHANGED_PARAMETERS : 0;
|
||||
for (TraceFunctionSymbol f : gatherThunksTo(function)) {
|
||||
// NOTE: Should probably not see functions in register views anyway...
|
||||
DomainObjectEventQueues queues = getEventQueues(space);
|
||||
if (queues == null) {
|
||||
continue;
|
||||
}
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_CHANGED,
|
||||
subType, f.getEntryPoint(), f.getEntryPoint(), f, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
private void symbolAdded(TraceAddressSpace space, TraceSymbol symbol) {
|
||||
DomainObjectEventQueues queues = isSymbolVisible(space, symbol);
|
||||
if (queues == null) {
|
||||
return;
|
||||
}
|
||||
fireSymbolAdded(queues, symbol);
|
||||
if (symbol instanceof TraceFunctionSymbol) {
|
||||
TraceFunctionSymbol function = (TraceFunctionSymbol) symbol;
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_ADDED,
|
||||
function.getEntryPoint(), function.getEntryPoint(), function, null, null));
|
||||
}
|
||||
checkVariableFunctionChanged(space, symbol);
|
||||
}
|
||||
|
||||
public void fireSymbolAdded(DomainObjectEventQueues queues, TraceSymbol symbol) {
|
||||
|
@ -714,7 +570,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
}
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_SOURCE_CHANGED,
|
||||
symbol.getAddress(), symbol.getAddress(), symbol, null, null));
|
||||
checkVariableFunctionChanged(space, symbol);
|
||||
}
|
||||
|
||||
private void symbolSetAsPrimary(TraceAddressSpace space, TraceSymbol symbol,
|
||||
|
@ -731,7 +586,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
assert oldQueues == newQueues || oldQueues == null;
|
||||
newQueues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_SET_AS_PRIMARY,
|
||||
symbol.getAddress(), symbol.getAddress(), null, oldPrimary, newPrimary));
|
||||
checkVariableFunctionChanged(space, symbol);
|
||||
}
|
||||
|
||||
private void symbolRenamed(TraceAddressSpace space, TraceSymbol symbol, String oldName,
|
||||
|
@ -742,7 +596,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
}
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_RENAMED,
|
||||
symbol.getAddress(), symbol.getAddress(), symbol, oldName, newName));
|
||||
checkVariableFunctionChanged(space, symbol);
|
||||
}
|
||||
|
||||
private void symbolParentChanged(TraceAddressSpace space, TraceSymbol symbol,
|
||||
|
@ -753,7 +606,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
}
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_SCOPE_CHANGED,
|
||||
symbol.getAddress(), symbol.getAddress(), symbol, oldParent, newParent));
|
||||
checkVariableFunctionChanged(space, symbol);
|
||||
}
|
||||
|
||||
private void symbolAssociationAdded(TraceAddressSpace space, TraceSymbol symbol,
|
||||
|
@ -786,7 +638,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
}
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_ADDRESS_CHANGED,
|
||||
oldAddress, oldAddress, symbol, oldAddress, newAddress));
|
||||
checkVariableFunctionChanged(space, symbol);
|
||||
}
|
||||
|
||||
private void symbolLifespanChanged(TraceAddressSpace space, TraceSymbolWithLifespan symbol,
|
||||
|
@ -799,20 +650,9 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
boolean inNew = isSymbolWithLifespanVisible(symbol, newSpan);
|
||||
if (inOld && !inNew) {
|
||||
fireSymbolRemoved(queues, symbol);
|
||||
if (symbol instanceof TraceFunctionSymbol) {
|
||||
TraceFunctionSymbol function = (TraceFunctionSymbol) symbol;
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_REMOVED,
|
||||
function.getEntryPoint(), function.getEntryPoint(), function,
|
||||
function.getBody(), null));
|
||||
}
|
||||
}
|
||||
if (!inOld && inNew) {
|
||||
fireSymbolAdded(queues, symbol);
|
||||
if (symbol instanceof TraceFunctionSymbol) {
|
||||
TraceFunctionSymbol function = (TraceFunctionSymbol) symbol;
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_ADDED,
|
||||
function.getEntryPoint(), function.getEntryPoint(), function, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -822,13 +662,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
return;
|
||||
}
|
||||
fireSymbolRemoved(queues, symbol);
|
||||
if (symbol instanceof TraceFunctionSymbol) {
|
||||
TraceFunctionSymbol function = (TraceFunctionSymbol) symbol;
|
||||
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_REMOVED,
|
||||
function.getEntryPoint(), function.getEntryPoint(), function,
|
||||
function.getBody(), null));
|
||||
}
|
||||
checkVariableFunctionChanged(space, symbol);
|
||||
}
|
||||
|
||||
protected void fireSymbolRemoved(DomainObjectEventQueues queues, TraceSymbol symbol) {
|
||||
|
@ -1775,51 +1608,8 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
return getEventQueues(space);
|
||||
}
|
||||
|
||||
protected Occlusion<TraceFunctionSymbol> getFunctionOcclusion(TraceFunctionSymbol func) {
|
||||
return new QueryOcclusion<>() {
|
||||
DBTraceFunctionSymbolView functions = trace.getSymbolManager().functions();
|
||||
AddressSetView body = func.getBody();
|
||||
|
||||
@Override
|
||||
public Iterable<? extends TraceFunctionSymbol> query(AddressRange range,
|
||||
Lifespan span) {
|
||||
// NB. No functions in register space!
|
||||
return functions.getIntersecting(Lifespan.at(span.lmax()), null, range, false);
|
||||
}
|
||||
|
||||
public boolean itemOccludes(AddressRange range, TraceFunctionSymbol f) {
|
||||
return body.intersects(f.getBody());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(AddressSet remains, TraceFunctionSymbol t) {
|
||||
remains.delete(t.getBody());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected boolean isFunctionVisible(TraceFunctionSymbol function, Lifespan lifespan) {
|
||||
AddressSetView body = function.getBody();
|
||||
AddressRange bodySpan = new AddressRangeImpl(body.getMinAddress(), body.getMaxAddress());
|
||||
return viewport.isCompletelyVisible(bodySpan, function.getLifespan(), function,
|
||||
getFunctionOcclusion(function));
|
||||
}
|
||||
|
||||
protected DomainObjectEventQueues isFunctionVisible(TraceAddressSpace space,
|
||||
TraceFunctionSymbol function) {
|
||||
DomainObjectEventQueues queues = getEventQueues(space);
|
||||
if (queues == null) {
|
||||
return null;
|
||||
}
|
||||
return isFunctionVisible(function, function.getLifespan()) ? queues : null;
|
||||
}
|
||||
|
||||
protected boolean isSymbolWithLifespanVisible(TraceSymbolWithLifespan symbol,
|
||||
Lifespan lifespan) {
|
||||
if (symbol instanceof TraceFunctionSymbol) {
|
||||
TraceFunctionSymbol func = (TraceFunctionSymbol) symbol;
|
||||
return isFunctionVisible(func, lifespan);
|
||||
}
|
||||
if (!viewport.containsAnyUpper(lifespan)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1832,14 +1622,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
if (queues == null) {
|
||||
return null;
|
||||
}
|
||||
if (symbol instanceof TraceVariableSymbol) {
|
||||
TraceVariableSymbol var = (TraceVariableSymbol) symbol;
|
||||
TraceFunctionSymbol func = var.getFunction();
|
||||
if (func == null) {
|
||||
return queues;
|
||||
}
|
||||
return isFunctionVisible(space, func);
|
||||
}
|
||||
if (!(symbol instanceof TraceSymbolWithLifespan)) {
|
||||
return queues;
|
||||
}
|
||||
|
|
|
@ -15,28 +15,20 @@
|
|||
*/
|
||||
package ghidra.trace.database.program;
|
||||
|
||||
import static ghidra.lifecycle.Unfinished.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import generic.NestedIterator;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.lang.PrototypeModel;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.symbol.*;
|
||||
import ghidra.trace.model.Lifespan;
|
||||
import ghidra.trace.model.listing.TraceData;
|
||||
import ghidra.trace.model.symbol.TraceFunctionSymbol;
|
||||
import ghidra.trace.database.symbol.DBTraceNamespaceSymbol;
|
||||
import ghidra.trace.util.EmptyFunctionIterator;
|
||||
import ghidra.trace.util.WrappingFunctionIterator;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -44,12 +36,10 @@ import ghidra.util.task.TaskMonitor;
|
|||
public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
||||
|
||||
protected final DBTraceProgramView program;
|
||||
protected final DBTraceFunctionSymbolView functions;
|
||||
protected final DBTraceNamespaceSymbol global;
|
||||
|
||||
public DBTraceProgramViewFunctionManager(DBTraceProgramView program) {
|
||||
this.program = program;
|
||||
this.functions = program.trace.getSymbolManager().functions();
|
||||
this.global = program.trace.getSymbolManager().getGlobalNamespace();
|
||||
}
|
||||
|
||||
|
@ -60,135 +50,69 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
|||
|
||||
@Override
|
||||
public FunctionTagManager getFunctionTagManager() {
|
||||
return TODO();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getCallingConventionNames() {
|
||||
return functions.getCallingConventionNames();
|
||||
return Stream.of(program.trace.getBaseCompilerSpec().getCallingConventions())
|
||||
.map(PrototypeModel::getName)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrototypeModel getDefaultCallingConvention() {
|
||||
return functions.getDefaultCallingConvention();
|
||||
return program.trace.getBaseCompilerSpec().getDefaultCallingConvention();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrototypeModel getCallingConvention(String name) {
|
||||
return functions.getCallingConvention(name);
|
||||
return program.trace.getBaseCompilerSpec().getCallingConvention(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceFunctionSymbol createFunction(String name, Address entryPoint, AddressSetView body,
|
||||
public Function createFunction(String name, Address entryPoint, AddressSetView body,
|
||||
SourceType source) throws InvalidInputException, OverlappingFunctionException {
|
||||
return functions.create(program.snap, entryPoint, body, name, null, global, source);
|
||||
}
|
||||
|
||||
protected static DBTraceNamespaceSymbol validateParent(Namespace nameSpace) {
|
||||
if (!(nameSpace instanceof DBTraceNamespaceSymbol)) {
|
||||
throw new IllegalArgumentException("Given namespace is not part of this trace");
|
||||
}
|
||||
return (DBTraceNamespaceSymbol) nameSpace;
|
||||
}
|
||||
|
||||
protected static DBTraceFunctionSymbol validateThunked(Function thunked) {
|
||||
if (!(thunked instanceof DBTraceFunctionSymbol)) {
|
||||
throw new IllegalArgumentException("Given thunked function is not part of this trace");
|
||||
}
|
||||
return (DBTraceFunctionSymbol) thunked;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceFunctionSymbol createFunction(String name, Namespace nameSpace, Address entryPoint,
|
||||
public Function createFunction(String name, Namespace nameSpace, Address entryPoint,
|
||||
AddressSetView body, SourceType source)
|
||||
throws InvalidInputException, OverlappingFunctionException {
|
||||
return functions.create(program.snap, entryPoint, body, name, null,
|
||||
validateParent(nameSpace), source);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceFunctionSymbol createThunkFunction(String name, Namespace nameSpace,
|
||||
Address entryPoint, AddressSetView body, Function thunkedFunction, SourceType source)
|
||||
public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint,
|
||||
AddressSetView body, Function thunkedFunction, SourceType source)
|
||||
throws OverlappingFunctionException {
|
||||
try {
|
||||
return functions.create(program.snap, entryPoint, body, name,
|
||||
validateThunked(thunkedFunction), validateParent(nameSpace), source);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// TODO: Why not just declare this as thrown???
|
||||
throw new RuntimeException("Unexpected for default named function", e);
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFunctionCount() {
|
||||
return functions.size(false); // NOTE: May include those not at this snap
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeFunction(Address entryPoint) {
|
||||
try (LockHold hold = program.trace.lockWrite()) {
|
||||
TraceFunctionSymbol at = getFunctionAt(entryPoint);
|
||||
if (at == null) {
|
||||
return false;
|
||||
}
|
||||
at.delete();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceFunctionSymbol getFunctionAt(Address entryPoint) {
|
||||
if (!entryPoint.getAddressSpace().isMemorySpace()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (long s : program.viewport.getOrderedSnaps()) {
|
||||
// NOTE: There ought only to be one, since no overlaps allowed.
|
||||
for (TraceFunctionSymbol at : functions.getAt(s, null, entryPoint, false)) {
|
||||
if (entryPoint.equals(at.getEntryPoint())) {
|
||||
return at;
|
||||
}
|
||||
else {
|
||||
return null; // Anything below is occluded by the found function
|
||||
}
|
||||
}
|
||||
}
|
||||
public Function getFunctionAt(Address entryPoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceFunctionSymbol getReferencedFunction(Address address) {
|
||||
if (!address.getAddressSpace().isMemorySpace()) {
|
||||
return null;
|
||||
}
|
||||
TraceFunctionSymbol found = getFunctionAt(address);
|
||||
if (found != null) {
|
||||
return found;
|
||||
}
|
||||
TraceData data =
|
||||
program.getTopCode(address, (space, s) -> space.data().getContaining(s, address));
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
DBTraceReference ref = program.trace.getReferenceManager()
|
||||
.getPrimaryReferenceFrom(data.getStartSnap(), address, 0);
|
||||
return ref == null ? null : getFunctionAt(ref.getToAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceFunctionSymbol getFunctionContaining(Address addr) {
|
||||
// NOTE: There ought only to be one, since no overlaps allowed.
|
||||
for (TraceFunctionSymbol at : functions.getAt(program.snap, null, addr, false)) {
|
||||
return at;
|
||||
}
|
||||
public Function getReferencedFunction(Address address) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Iterator<? extends DBTraceFunctionSymbol> getFunctionsInRange(AddressRange range,
|
||||
boolean forward) {
|
||||
return functions.getIntersecting(Lifespan.at(program.snap), null, range, false,
|
||||
forward).iterator();
|
||||
@Override
|
||||
public Function getFunctionContaining(Address addr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -198,52 +122,27 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
|||
|
||||
@Override
|
||||
public FunctionIterator getFunctions(Address start, boolean forward) {
|
||||
return getFunctions(DBTraceUtils.getAddressSet(program.getAddressFactory(), start, forward),
|
||||
forward);
|
||||
return EmptyFunctionIterator.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionIterator getFunctions(AddressSetView asv, boolean forward) {
|
||||
return new WrappingFunctionIterator(
|
||||
NestedIterator.start(asv.iterator(forward), rng -> getFunctionsInRange(rng, forward)),
|
||||
f -> {
|
||||
if (!asv.contains(f.getEntryPoint())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return EmptyFunctionIterator.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionIterator getFunctionsNoStubs(boolean forward) {
|
||||
return getFunctionsNoStubs(program.getAddressFactory().getAddressSet(), forward);
|
||||
return EmptyFunctionIterator.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionIterator getFunctionsNoStubs(Address start, boolean forward) {
|
||||
return getFunctionsNoStubs(
|
||||
DBTraceUtils.getAddressSet(program.getAddressFactory(), start, forward), forward);
|
||||
return EmptyFunctionIterator.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionIterator getFunctionsNoStubs(AddressSetView asv, boolean forward) {
|
||||
return new WrappingFunctionIterator(
|
||||
NestedIterator.start(asv.iterator(forward), rng -> getFunctionsInRange(rng, forward)),
|
||||
f -> {
|
||||
if (f.isThunk()) {
|
||||
return false;
|
||||
}
|
||||
if (!asv.contains(f.getEntryPoint())) {
|
||||
return false;
|
||||
}
|
||||
if (program.trace.getCodeManager()
|
||||
.instructions()
|
||||
.getAt(program.snap,
|
||||
f.getEntryPoint()) == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return EmptyFunctionIterator.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -253,8 +152,7 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
|||
|
||||
@Override
|
||||
public boolean isInFunction(Address addr) {
|
||||
// TODO: Could use idMap directly to avoid loading the function
|
||||
return getFunctionContaining(addr) != null;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -266,12 +164,7 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
|||
@Override
|
||||
public void deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
Iterator<? extends DBTraceFunctionSymbol> it =
|
||||
getFunctionsInRange(new AddressRangeImpl(startAddr, endAddr), true);
|
||||
while (it.hasNext()) {
|
||||
monitor.checkCancelled();
|
||||
it.next().delete();
|
||||
}
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -287,28 +180,22 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
|||
|
||||
@Override
|
||||
public void invalidateCache(boolean all) {
|
||||
throw new UnsupportedOperationException();
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Function> getFunctionsOverlapping(AddressSetView set) {
|
||||
return new WrappingFunctionIterator(
|
||||
NestedIterator.start(set.iterator(true), rng -> getFunctionsInRange(rng, true)));
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable getReferencedVariable(Address instrAddr, Address storageAddr, int size,
|
||||
boolean isRead) {
|
||||
TraceFunctionSymbol function = getFunctionContaining(instrAddr);
|
||||
if (function == null) {
|
||||
return null;
|
||||
}
|
||||
return DBTraceFunctionSymbolView.getReferencedVariable(function, instrAddr, storageAddr,
|
||||
size, isRead, program.language);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceFunctionSymbol getFunction(long key) {
|
||||
return functions.getByKey(key);
|
||||
public Function getFunction(long key) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,14 +144,9 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
}
|
||||
|
||||
protected <T extends TraceSymbol> T requireVisible(T sym) {
|
||||
if (!(sym instanceof TraceSymbolWithLifespan)) {
|
||||
if (!(sym instanceof TraceSymbolWithLifespan wl)) {
|
||||
return sym;
|
||||
}
|
||||
if (sym instanceof TraceFunctionSymbol) {
|
||||
TraceFunctionSymbol function = (TraceFunctionSymbol) sym;
|
||||
return program.isFunctionVisible(function, function.getLifespan()) ? sym : null;
|
||||
}
|
||||
TraceSymbolWithLifespan wl = (TraceSymbolWithLifespan) sym;
|
||||
if (program.viewport.containsAnyUpper(wl.getLifespan())) {
|
||||
return sym;
|
||||
}
|
||||
|
@ -210,9 +205,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
TraceNamespaceSymbol parent = assertTraceNamespace(namespace);
|
||||
try (LockHold hold = program.trace.lockRead()) {
|
||||
List<Symbol> result = new ArrayList<>();
|
||||
for (TraceSymbol sym : symbolManager.labelsAndFunctions()
|
||||
.getChildrenNamed(name,
|
||||
parent)) {
|
||||
for (TraceSymbol sym : symbolManager.labels().getChildrenNamed(name, parent)) {
|
||||
if (requireVisible(sym) != null) {
|
||||
result.add(sym);
|
||||
}
|
||||
|
@ -239,17 +232,17 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
|
||||
@Override
|
||||
public Symbol getParameterSymbol(String name, Namespace namespace) {
|
||||
return symbolManager.parameters().getChildNamed(name, assertTraceNamespace(namespace));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol getLocalVariableSymbol(String name, Namespace namespace) {
|
||||
return symbolManager.localVariables().getChildNamed(name, assertTraceNamespace(namespace));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol getVariableSymbol(String name, Function function) {
|
||||
return symbolManager.allVariables().getChildNamed(name, assertTraceNamespace(function));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -279,7 +272,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
public Symbol getPrimarySymbol(Address addr) {
|
||||
try (LockHold hold = program.trace.lockRead()) {
|
||||
Collection<? extends TraceSymbol> at =
|
||||
symbolManager.labelsAndFunctions().getAt(program.snap, null, addr, true);
|
||||
symbolManager.labels().getAt(program.snap, null, addr, true);
|
||||
if (at.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -291,7 +284,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
public Symbol[] getSymbols(Address addr) {
|
||||
try (LockHold hold = program.trace.lockRead()) {
|
||||
Collection<? extends TraceSymbol> at =
|
||||
symbolManager.labelsAndFunctions().getAt(program.snap, null, addr, true);
|
||||
symbolManager.labels().getAt(program.snap, null, addr, true);
|
||||
return at.toArray(new Symbol[at.size()]);
|
||||
}
|
||||
}
|
||||
|
@ -307,7 +300,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
public Symbol[] getUserSymbols(Address addr) {
|
||||
try (LockHold hold = program.trace.lockRead()) {
|
||||
Collection<? extends TraceSymbol> at =
|
||||
symbolManager.labelsAndFunctions().getAt(program.snap, null, addr, false);
|
||||
symbolManager.labels().getAt(program.snap, null, addr, false);
|
||||
return at.toArray(new Symbol[at.size()]);
|
||||
}
|
||||
}
|
||||
|
@ -331,10 +324,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
@Override
|
||||
public boolean hasSymbol(Address addr) {
|
||||
if (addr.isMemoryAddress()) {
|
||||
return symbolManager.labelsAndFunctions().hasAt(program.snap, null, addr, true);
|
||||
}
|
||||
if (addr.getAddressSpace().isRegisterSpace() || addr.isStackAddress()) {
|
||||
return symbolManager.allVariables().hasAt(addr, true);
|
||||
return symbolManager.labels().hasAt(program.snap, null, addr, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -360,23 +350,6 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
.getIntersecting(Lifespan.at(program.snap), null, range, true, forward)
|
||||
.iterator();
|
||||
}
|
||||
if (type == SymbolType.FUNCTION) {
|
||||
return symbolManager.functions()
|
||||
.getIntersecting(Lifespan.at(program.snap), null, range, true, forward)
|
||||
.iterator();
|
||||
}
|
||||
}
|
||||
if (range.getAddressSpace().isRegisterSpace() ||
|
||||
range.getAddressSpace().isStackSpace()) {
|
||||
if (type == SymbolType.PARAMETER) {
|
||||
return symbolManager.parameters().getIntersecting(range, true).iterator();
|
||||
}
|
||||
if (type == SymbolType.LOCAL_VAR) {
|
||||
return symbolManager.localVariables().getIntersecting(range, true).iterator();
|
||||
}
|
||||
if (type == SymbolType.GLOBAL_VAR) {
|
||||
return symbolManager.globalVariables().getIntersecting(range, true).iterator();
|
||||
}
|
||||
}
|
||||
return Collections.emptyIterator();
|
||||
}));
|
||||
|
@ -437,8 +410,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
|
||||
@Override
|
||||
public SymbolIterator getSymbolIterator(Address startAddr, boolean forward) {
|
||||
return new SymbolIteratorAdapter(getSymbolIteratorAtMySnap(
|
||||
symbolManager.labelsAndFunctions(),
|
||||
return new SymbolIteratorAdapter(getSymbolIteratorAtMySnap(symbolManager.labels(),
|
||||
DBTraceUtils.getAddressSet(program.language.getAddressFactory(), startAddr, forward),
|
||||
true, forward));
|
||||
}
|
||||
|
@ -456,7 +428,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
@Override
|
||||
public SymbolIterator getPrimarySymbolIterator(AddressSetView asv, boolean forward) {
|
||||
return new PrimarySymbolIterator(NestedIterator.start(asv.iterator(forward),
|
||||
range -> symbolManager.labelsAndFunctions()
|
||||
range -> symbolManager.labels()
|
||||
.getIntersecting(Lifespan.at(program.snap), null, range, true, forward)
|
||||
.iterator()));
|
||||
}
|
||||
|
@ -501,20 +473,13 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
// NOTE: Currently, traces do not allow namespaces to have arbitrary bodies.
|
||||
// Instead, their bodies are the union of addresses of their descendants.
|
||||
if (addr.isMemoryAddress()) {
|
||||
for (TraceSymbol sym : symbolManager.labelsAndFunctions()
|
||||
.getAt(program.snap, null,
|
||||
addr, true)) {
|
||||
for (TraceSymbol sym : symbolManager.labels().getAt(program.snap, null, addr, true)) {
|
||||
if (sym instanceof TraceNamespaceSymbol /* Function */) {
|
||||
return (TraceNamespaceSymbol) sym;
|
||||
}
|
||||
return sym.getParentNamespace();
|
||||
}
|
||||
}
|
||||
if (addr.getAddressSpace().isRegisterSpace() || addr.isStackAddress()) {
|
||||
for (TraceSymbol sym : symbolManager.allVariables().getAt(addr, true)) {
|
||||
return sym.getParentNamespace();
|
||||
}
|
||||
}
|
||||
return symbolManager.getGlobalNamespace();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,396 +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.trace.database.symbol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.AbstractFloatDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.trace.database.symbol.DBTraceSymbolManager.DBTraceVariableStorageEntry;
|
||||
import ghidra.trace.model.Trace.TraceSymbolChangeType;
|
||||
import ghidra.trace.model.symbol.TraceVariableSymbol;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.database.DBCachedObjectStore;
|
||||
import ghidra.util.database.DBObjectColumn;
|
||||
import ghidra.util.database.annot.DBAnnotatedColumn;
|
||||
import ghidra.util.database.annot.DBAnnotatedField;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* TODO: Document me
|
||||
*
|
||||
* TODO: Somehow, this is supposed to generate {@link TraceSymbolChangeType#ADDRESS_CHANGED}. Find
|
||||
* out how and be sure to implement it.
|
||||
*/
|
||||
public abstract class AbstractDBTraceVariableSymbol extends AbstractDBTraceSymbol
|
||||
implements TraceVariableSymbol {
|
||||
|
||||
static final String DATATYPE_COLUMN_NAME = "DataType";
|
||||
static final String STORAGE_COLUMN_NAME = "Storage";
|
||||
static final String COMMENT_COLUMN_NAME = "Comment";
|
||||
|
||||
@DBAnnotatedColumn(DATATYPE_COLUMN_NAME)
|
||||
static DBObjectColumn DATATYPE_COLUMN;
|
||||
@DBAnnotatedColumn(STORAGE_COLUMN_NAME)
|
||||
static DBObjectColumn STORAGE_COLUMN;
|
||||
@DBAnnotatedColumn(COMMENT_COLUMN_NAME)
|
||||
static DBObjectColumn COMMENT_COLUMN;
|
||||
|
||||
@DBAnnotatedField(column = DATATYPE_COLUMN_NAME)
|
||||
private long dataTypeID;
|
||||
@DBAnnotatedField(column = STORAGE_COLUMN_NAME)
|
||||
private int storageID;
|
||||
@DBAnnotatedField(column = COMMENT_COLUMN_NAME)
|
||||
private String comment;
|
||||
|
||||
protected DataType dataType;
|
||||
protected VariableStorage storage;
|
||||
protected Address address;
|
||||
|
||||
public AbstractDBTraceVariableSymbol(DBTraceSymbolManager manager, DBCachedObjectStore<?> store,
|
||||
DBRecord record) {
|
||||
super(manager, store, record);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fresh(boolean created) throws IOException {
|
||||
super.fresh(created);
|
||||
if (created) {
|
||||
return;
|
||||
}
|
||||
dataType = manager.dataTypeManager.getDataType(dataTypeID);
|
||||
DBTraceVariableStorageEntry storageEntry = manager.storageStore.getObjectAt(storageID);
|
||||
if (storageEntry == null) {
|
||||
throw new IOException(
|
||||
"Database is corrupt. Cannot find VariableStorage entry " + storageID);
|
||||
}
|
||||
storage = storageEntry.getStorage();
|
||||
address = AddressSpace.VARIABLE_SPACE.getAddress(storageID);
|
||||
}
|
||||
|
||||
protected void set(String name, DBTraceNamespaceSymbol parent, DataType dt,
|
||||
VariableStorage storage, SourceType source) {
|
||||
super.set(name, parent, source);
|
||||
this.dataTypeID = manager.dataTypeManager.getResolvedID(dt);
|
||||
this.dataType = manager.dataTypeManager.getDataType(dataTypeID);
|
||||
this.storageID = manager.findOrRecordVariableStorage(storage);
|
||||
update(DATATYPE_COLUMN, STORAGE_COLUMN);
|
||||
|
||||
this.storage = storage;
|
||||
this.address = AddressSpace.VARIABLE_SPACE.getAddress(storageID);
|
||||
}
|
||||
|
||||
protected VariableStorage adjustStorage(VariableStorage s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return String.format("[%s %s@%s]", getDataType().getName(), getName(),
|
||||
getVariableStorage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddress() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol getSymbol() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return getDataType().getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
VariableStorage s = getVariableStorage(); // Overridden by DBTraceParameterSymbol
|
||||
if (!s.isValid()) {
|
||||
return false;
|
||||
}
|
||||
if (dataType instanceof AbstractFloatDataType) {
|
||||
return true;
|
||||
}
|
||||
// NOTE: Use getDataType(), since storage may force indirection (pointer)
|
||||
return s.size() == getDataType().getLength();
|
||||
}
|
||||
}
|
||||
|
||||
protected void doSetDataType(DataType dt) {
|
||||
this.dataTypeID = manager.dataTypeManager.getResolvedID(dt);
|
||||
this.dataType = manager.dataTypeManager.getDataType(dataTypeID);
|
||||
update(DATATYPE_COLUMN);
|
||||
}
|
||||
|
||||
protected void doSetStorage(VariableStorage s) {
|
||||
this.storage = s;
|
||||
update(STORAGE_COLUMN);
|
||||
}
|
||||
|
||||
// NOTE: Must have the write lock
|
||||
protected void doSetStorageAndDataType(VariableStorage s, DataType dt) {
|
||||
doSetDataType(dt);
|
||||
doSetStorage(adjustStorage(s));
|
||||
}
|
||||
|
||||
protected void doUpdatesAfterSetDataType() {
|
||||
// Extension point
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataType(DataType dt, VariableStorage s, boolean force, SourceType source)
|
||||
throws InvalidInputException {
|
||||
s = adjustStorage(s);
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
dt = VariableUtilities.checkDataType(dt, false, getLength(), getProgram());
|
||||
// NOTE: UNASSIGNED passes through
|
||||
DBTraceFunctionSymbol function = getFunction();
|
||||
s = VariableUtilities.checkStorage(function, s, dt, force);
|
||||
VariableUtilities.checkVariableConflict(function, this, s, force);
|
||||
doSetStorageAndDataType(s, dt);
|
||||
doUpdatesAfterSetDataType();
|
||||
}
|
||||
}
|
||||
|
||||
protected VariableStorage doDeriveStorageForSetDataType(DataType dt, boolean alignStack,
|
||||
boolean force) throws InvalidInputException {
|
||||
try {
|
||||
VariableStorage s = VariableUtilities.resizeStorage(getVariableStorage(), dt,
|
||||
alignStack, getFunction());
|
||||
VariableUtilities.checkStorage(s, dt, force);
|
||||
VariableUtilities.checkVariableConflict(getFunction(), this, s, force);
|
||||
return s;
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
if (!force) {
|
||||
throw e;
|
||||
}
|
||||
return VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataType(DataType dt, boolean alignStack, boolean force, SourceType source)
|
||||
throws InvalidInputException {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
dt = VariableUtilities.checkDataType(dt, false, getLength(), getProgram());
|
||||
VariableStorage s = doDeriveStorageForSetDataType(dt, alignStack, force);
|
||||
doSetStorageAndDataType(s, dt);
|
||||
doUpdatesAfterSetDataType();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataType(DataType dt, SourceType source) throws InvalidInputException {
|
||||
setDataType(dt, true, false, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract DBTraceFunctionSymbol getFunction();
|
||||
|
||||
@Override
|
||||
public void setComment(String comment) {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
this.comment = comment;
|
||||
update(COMMENT_COLUMN);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return comment;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableStorage getVariableStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Varnode getFirstStorageVarnode() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? null : s.getFirstVarnode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Varnode getLastStorageVarnode() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? null : s.getLastVarnode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStackVariable() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? false : s.isStackStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStackStorage() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? false : s.hasStackStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegisterVariable() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? false : s.isRegisterStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Register getRegister() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? null : s.getRegister();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Register> getRegisters() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? null : s.getRegisters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getMinAddress() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? null : s.getMinAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStackOffset() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
if (s == null) {
|
||||
throw new UnsupportedOperationException("Variable has no storage");
|
||||
}
|
||||
return s.getStackOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMemoryVariable() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? false : s.isMemoryStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUniqueVariable() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? false : s.isHashStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompoundVariable() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? false : s.isCompoundStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAssignedStorage() {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? false : !s.isUnassignedStorage();
|
||||
}
|
||||
|
||||
protected static boolean doHasCustomStorage(Variable v) {
|
||||
Function f = v.getFunction();
|
||||
return f == null || f.hasCustomVariableStorage();
|
||||
}
|
||||
|
||||
public static boolean areEquivalent(Variable v1, Variable v2) {
|
||||
if (v1 == null && v2 == null) {
|
||||
return true;
|
||||
}
|
||||
if (v1 == null || v2 == null) {
|
||||
return false;
|
||||
}
|
||||
if (v1 == v2) {
|
||||
return true;
|
||||
}
|
||||
if ((v1 instanceof Parameter) != (v2 instanceof Parameter)) {
|
||||
return false;
|
||||
}
|
||||
if (v1 instanceof Parameter) {
|
||||
Parameter p1 = (Parameter) v1;
|
||||
Parameter p2 = (Parameter) v2;
|
||||
if (p1.getOrdinal() != p2.getOrdinal()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (v1.getFirstUseOffset() != v2.getFirstUseOffset()) {
|
||||
return false;
|
||||
}
|
||||
boolean eitherCustom = doHasCustomStorage(v1) || doHasCustomStorage(v2);
|
||||
if (eitherCustom && !Objects.equals(v1.getVariableStorage(), v2.getVariableStorage())) {
|
||||
return false;
|
||||
}
|
||||
if (!DataTypeUtilities.isSameOrEquivalentDataType(v1.getDataType(), v2.getDataType())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEquivalent(Variable variable) {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return areEquivalent(this, variable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Variable that) {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return VariableUtilities.compare(this, that);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
DBTraceFunctionSymbol function = getFunction();
|
||||
if (function != null) {
|
||||
function.doDeleteVariable(this);
|
||||
}
|
||||
return super.delete();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,329 +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.trace.database.symbol;
|
||||
|
||||
import static ghidra.lifecycle.Unfinished.TODO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import ghidra.lifecycle.Unfinished;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
public class DBTraceFunctionStackFrame implements StackFrame, Unfinished {
|
||||
protected final DBTraceFunctionSymbol function;
|
||||
protected Variable[] variables;
|
||||
protected boolean growsNegative;
|
||||
protected boolean valid;
|
||||
|
||||
public DBTraceFunctionStackFrame(DBTraceFunctionSymbol function) {
|
||||
this.function = function;
|
||||
this.growsNegative = function.getTrace().getBaseCompilerSpec().stackGrowsNegative();
|
||||
this.valid = false;
|
||||
}
|
||||
|
||||
protected synchronized boolean checkIsValid() {
|
||||
if (!function.isDeleted()) {
|
||||
if (!valid) {
|
||||
growsNegative = function.getTrace().getBaseCompilerSpec().stackGrowsNegative();
|
||||
variables = function.getVariables(VariableFilter.COMPOUND_STACK_VARIABLE_FILTER);
|
||||
Arrays.sort(variables, StackVariableComparator.get());
|
||||
valid = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceFunctionSymbol getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFrameSize() {
|
||||
try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) {
|
||||
return getParameterSize() + getLocalSize();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalSize() {
|
||||
try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) {
|
||||
checkIsValid();
|
||||
|
||||
Integer base = VariableUtilities.getBaseStackParamOffset(function);
|
||||
int baseOffset = base == null ? 0 : base.intValue();
|
||||
|
||||
if (growsNegative) {
|
||||
if (variables.length == 0) {
|
||||
return baseOffset;
|
||||
}
|
||||
Variable v = variables[0];
|
||||
if (!(v instanceof LocalVariable)) {
|
||||
return baseOffset;
|
||||
}
|
||||
int offset = Math.max(0, (int) v.getLastStorageVarnode().getOffset());
|
||||
return baseOffset - offset;
|
||||
}
|
||||
// else Positive growth
|
||||
if (variables.length == 0) {
|
||||
return -baseOffset;
|
||||
}
|
||||
Variable v = variables[variables.length - 1];
|
||||
if (!(v instanceof LocalVariable)) {
|
||||
return -baseOffset;
|
||||
}
|
||||
Varnode stackVarnode = v.getLastStorageVarnode();
|
||||
int len = stackVarnode.getSize();
|
||||
int offset = Math.max(0, (int) stackVarnode.getOffset());
|
||||
return offset - baseOffset + len;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParameterSize() {
|
||||
try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) {
|
||||
checkIsValid();
|
||||
|
||||
Integer base = VariableUtilities.getBaseStackParamOffset(function);
|
||||
int baseOffset = base == null ? 0 : base.intValue();
|
||||
|
||||
if (growsNegative) {
|
||||
if (variables.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
Variable v = variables[variables.length - 1];
|
||||
if (!(v instanceof Parameter)) {
|
||||
return 0;
|
||||
}
|
||||
Varnode stackVarnode = v.getLastStorageVarnode();
|
||||
int len = stackVarnode.getSize();
|
||||
int offset = (int) stackVarnode.getOffset();
|
||||
return offset - baseOffset + len;
|
||||
}
|
||||
// else Positive growth
|
||||
if (variables.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
Variable v = variables[0];
|
||||
if (!(v instanceof Parameter)) {
|
||||
return 0;
|
||||
}
|
||||
int offset = (int) v.getLastStorageVarnode().getOffset();
|
||||
return baseOffset - offset;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParameterOffset() {
|
||||
Integer base = VariableUtilities.getBaseStackParamOffset(function);
|
||||
return base == null ? UNKNOWN_PARAM_OFFSET : base.intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParameterOffset(int offset) {
|
||||
Integer base = VariableUtilities.getBaseStackParamOffset(function);
|
||||
if (base == null) {
|
||||
return false;
|
||||
}
|
||||
if (growsNegative) {
|
||||
return offset >= base.intValue();
|
||||
}
|
||||
return offset < base.intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocalSize(int size) {
|
||||
// TODO: Is this ever called?
|
||||
TODO();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReturnAddressOffset(int offset) {
|
||||
function.setReturnAddressOffset(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReturnAddressOffset() {
|
||||
return function.getReturnAddressOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable getVariableContaining(int offset) {
|
||||
try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) {
|
||||
int index = Arrays.binarySearch(variables, offset, StackVariableComparator.get());
|
||||
if (index >= 0) {
|
||||
return variables[index];
|
||||
}
|
||||
/**
|
||||
* index is -insertionPoint - 1 insertionPoint is index of first element greater than
|
||||
* the key, i.e., where it would be inserted. We want the last element less than they
|
||||
* key
|
||||
*/
|
||||
index = -index - 2;
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
// We have the preceding variable. See if it contains the offset.
|
||||
Variable var = variables[index];
|
||||
Varnode stackVarnode = var.getLastStorageVarnode();
|
||||
int varOffset = (int) stackVarnode.getOffset();
|
||||
if (offset < varOffset + stackVarnode.getSize()) {
|
||||
return var;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractDBTraceVariableSymbol createVariable(String name, int offset, DataType dataType,
|
||||
SourceType source) throws DuplicateNameException, InvalidInputException {
|
||||
try (LockHold hold = LockHold.lock(function.manager.lock.writeLock())) {
|
||||
checkIsValid();
|
||||
if (dataType != null) {
|
||||
dataType = dataType.clone(function.getTrace().getDataTypeManager());
|
||||
}
|
||||
Variable var = new LocalVariableImpl(name, dataType, offset, function.getProgram());
|
||||
AbstractDBTraceVariableSymbol result;
|
||||
if (isParameterOffset(offset)) {
|
||||
// Compute ordinal
|
||||
int ordinal = function.getParameterCount();
|
||||
Parameter[] params = getParameters();
|
||||
if (growsNegative) {
|
||||
for (int i = params.length - 1; i >= 0; i--) {
|
||||
Parameter p = params[i];
|
||||
if (offset <= p.getLastStorageVarnode().getOffset()) {
|
||||
ordinal = p.getOrdinal();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
Parameter p = params[i];
|
||||
if (offset <= p.getLastStorageVarnode().getOffset()) {
|
||||
ordinal = p.getOrdinal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = function.insertParameter(ordinal, var, source);
|
||||
}
|
||||
else {
|
||||
result = function.addLocalVariable(var, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: The original implementation tries to implicitly enable custom storage if:
|
||||
*
|
||||
* 1) We're inserting a parameter,
|
||||
*
|
||||
* 2) Custom storage is not already enabled, and
|
||||
*
|
||||
* 3) The variable would not be stored where specified without custom storage
|
||||
*
|
||||
* Unless it is required or jarring to the user, I'm going to forego this rule. Let the
|
||||
* user manually enable custom storage if precise parameter placement via this method is
|
||||
* desired.
|
||||
*
|
||||
* The issue in the original implementation is: It detects (3) by inserting the variable
|
||||
* and then checking where it was assigned storage. By this time, the function will have
|
||||
* already re-assigned the other variables' storage. Despite that, the method re-assigns
|
||||
* the new variable to the desired storage. This may leave the others in an unexpected
|
||||
* or bad state.
|
||||
*
|
||||
* Perhaps it can be fixed: Instead of re-assigning the storage, deleting the new
|
||||
* parameter, enable custom storage, and then re-insert the desired parameter.
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearVariable(int offset) {
|
||||
try (LockHold hold = LockHold.lock(function.manager.lock.writeLock())) {
|
||||
checkIsValid();
|
||||
Variable var = getVariableContaining(offset);
|
||||
/**
|
||||
* TODO: The original implementation implicitly enables custom storage if:
|
||||
*
|
||||
* 1) A variable exists at the given offset, and
|
||||
*
|
||||
* 2) Custom storage is not already enabled
|
||||
*
|
||||
* Unless it is required or jarring to the user, I'm going to forego this rule. Let the
|
||||
* user manually enable custom storage if precise parameter placement via this method is
|
||||
* desired.
|
||||
*/
|
||||
if (var != null) {
|
||||
function.removeVariable(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable[] getStackVariables() {
|
||||
try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) {
|
||||
checkIsValid();
|
||||
return Arrays.copyOf(variables, variables.length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameter[] getParameters() {
|
||||
try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) {
|
||||
checkIsValid();
|
||||
ArrayList<Parameter> list = new ArrayList<Parameter>();
|
||||
for (Variable v : variables) {
|
||||
if (v instanceof Parameter) {
|
||||
list.add((Parameter) v);
|
||||
}
|
||||
}
|
||||
return list.toArray(new Parameter[list.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalVariable[] getLocals() {
|
||||
try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) {
|
||||
checkIsValid();
|
||||
ArrayList<LocalVariable> list = new ArrayList<LocalVariable>();
|
||||
for (Variable v : variables) {
|
||||
if (v instanceof LocalVariable) {
|
||||
list.add((LocalVariable) v);
|
||||
}
|
||||
}
|
||||
return list.toArray(new LocalVariable[list.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean growsNegative() {
|
||||
try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) {
|
||||
return growsNegative;
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void invalidate() {
|
||||
valid = false;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,260 +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.trace.database.symbol;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.database.symbol.OverlappingNamespaceException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.trace.database.program.DBTraceProgramView;
|
||||
import ghidra.trace.model.Lifespan;
|
||||
import ghidra.trace.model.Trace.TraceSymbolChangeType;
|
||||
import ghidra.trace.model.symbol.*;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
public class DBTraceFunctionSymbolView
|
||||
extends AbstractDBTraceSymbolSingleTypeWithLocationView<DBTraceFunctionSymbol>
|
||||
implements TraceFunctionSymbolView {
|
||||
protected static final PrototypeModel[] EMPTY_MODEL_LIST = new PrototypeModel[] {};
|
||||
|
||||
protected static void assertProperSpace(AddressSpace expected, AddressSetView body) {
|
||||
if (!expected.isMemorySpace()) {
|
||||
throw new IllegalArgumentException("Function must be in memory space");
|
||||
}
|
||||
for (AddressRange rng : body) {
|
||||
if (rng.getAddressSpace() != expected) {
|
||||
throw new IllegalArgumentException(
|
||||
"Function body must be in same space as entry point");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DBTraceFunctionSymbolView(DBTraceSymbolManager manager) {
|
||||
super(manager, SymbolType.FUNCTION.getID(), manager.functionStore);
|
||||
}
|
||||
|
||||
protected DBTraceNamespaceSymbol doValidateParentAndEntry(DBTraceNamespaceSymbol proposed,
|
||||
Address entryPoint) {
|
||||
if (proposed == null) {
|
||||
return manager.globalNamespace;
|
||||
}
|
||||
DBTraceProgramView program = manager.trace.getProgramView();
|
||||
if (!SymbolType.FUNCTION.isValidAddress(program, entryPoint)) {
|
||||
throw new IllegalArgumentException("Invalid function entry point: " + entryPoint);
|
||||
}
|
||||
if (!SymbolType.FUNCTION.isValidParent(program, proposed, entryPoint, false)) {
|
||||
throw new IllegalArgumentException("Invalid function namespace: " + proposed);
|
||||
}
|
||||
|
||||
return proposed;
|
||||
}
|
||||
|
||||
protected SourceType doValidateSource(SourceType proposed, String name, Address entryPoint) {
|
||||
if (!SymbolType.FUNCTION.isValidSourceType(proposed, entryPoint)) {
|
||||
throw new IllegalArgumentException("Invalid function source type: " + proposed);
|
||||
}
|
||||
return proposed;
|
||||
}
|
||||
|
||||
protected String doValidateName(String proposed, Address entryPoint, SourceType source)
|
||||
throws InvalidInputException {
|
||||
if (source == SourceType.DEFAULT) {
|
||||
return "";
|
||||
}
|
||||
// TODO: Do entryPoint and source no longer matter? (see commit 898da2b)
|
||||
SymbolUtilities.validateName(proposed);
|
||||
return proposed;
|
||||
}
|
||||
|
||||
protected void assertNotOverlapping(DBTraceFunctionSymbol exclude, Address entryPoint,
|
||||
Lifespan span, AddressSetView proposedBody) throws OverlappingFunctionException {
|
||||
for (AddressRange rng : proposedBody) {
|
||||
for (DBTraceFunctionSymbol overlap : manager.functions.getIntersecting(span, null, rng,
|
||||
false, true)) {
|
||||
if (overlap != exclude) {
|
||||
throw new OverlappingFunctionException(entryPoint,
|
||||
new OverlappingNamespaceException(rng.getMinAddress(),
|
||||
rng.getMaxAddress()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceFunctionSymbol add(Lifespan lifespan, Address entryPoint, AddressSetView body,
|
||||
String name, TraceFunctionSymbol thunked, TraceNamespaceSymbol parent,
|
||||
SourceType source) throws InvalidInputException, OverlappingFunctionException {
|
||||
if (name == null || name.length() == 0 || SymbolUtilities.isReservedDynamicLabelName(name,
|
||||
manager.trace.getBaseAddressFactory())) {
|
||||
source = SourceType.DEFAULT;
|
||||
name = "";
|
||||
}
|
||||
else {
|
||||
DBTraceSymbolManager.assertValidName(name);
|
||||
}
|
||||
if (!"".equals(name) && source == SourceType.DEFAULT) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot create DEFAULT function with non-default name");
|
||||
}
|
||||
if (!body.contains(entryPoint)) {
|
||||
throw new IllegalArgumentException("Function body must contain the entry point");
|
||||
}
|
||||
assertProperSpace(entryPoint.getAddressSpace(), body);
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
DBTraceNamespaceSymbol dbnsParent =
|
||||
parent == null ? null : manager.assertIsMine((Namespace) parent);
|
||||
manager.assertValidThreadAddress(null, entryPoint);
|
||||
DBTraceFunctionSymbol dbThunked =
|
||||
thunked == null ? null : manager.assertIsMine((Function) thunked);
|
||||
|
||||
if (manager.trace.getCodeManager()
|
||||
.definedData()
|
||||
.getAt(lifespan.lmin(), entryPoint) != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Function entry point cannot be at defined data");
|
||||
}
|
||||
|
||||
if (dbThunked != null && name.equals(dbThunked.getName())) {
|
||||
source = SourceType.DEFAULT;
|
||||
name = "";
|
||||
}
|
||||
|
||||
assertNotOverlapping(null, entryPoint, lifespan, body);
|
||||
dbnsParent = doValidateParentAndEntry(dbnsParent, entryPoint);
|
||||
source = doValidateSource(source, name, entryPoint);
|
||||
name = doValidateName(name, entryPoint, source);
|
||||
|
||||
DBTraceLabelSymbol toPromote = manager.labels.getChildWithNameAt(name,
|
||||
lifespan.lmin(), null, entryPoint, dbnsParent);
|
||||
if (toPromote != null && toPromote.getLifespan().equals(lifespan)) {
|
||||
toPromote.delete();
|
||||
}
|
||||
|
||||
DBTraceFunctionSymbol function = store.create();
|
||||
function.set(lifespan, entryPoint, name, dbThunked, dbnsParent, source);
|
||||
function.doCreateReturnParameter();
|
||||
for (AddressRange rng : body) {
|
||||
manager.putID(lifespan, null, rng, function.getID());
|
||||
}
|
||||
|
||||
cacheForAt.notifyNewEntries(lifespan, body, function);
|
||||
|
||||
manager.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceSymbolChangeType.ADDED, null, function));
|
||||
return function;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getCallingConventionNames() {
|
||||
return manager.dataTypeManager.getDefinedCallingConventionNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrototypeModel getDefaultCallingConvention() {
|
||||
return manager.dataTypeManager.getDefaultCallingConvention();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrototypeModel getCallingConvention(String name) {
|
||||
return manager.dataTypeManager.getCallingConvention(name);
|
||||
}
|
||||
|
||||
// TODO: Move this into a FunctionUtilities class?
|
||||
public static Variable getReferencedVariable(Function function, Address instrAddr,
|
||||
Address storageAddr, int size, boolean isRead, Language language) {
|
||||
Variable variables[] = function.getAllVariables();
|
||||
|
||||
Parameter paramCandidate = null;
|
||||
List<Variable> localCandidates = null;
|
||||
Variable firstCandidate = null;
|
||||
|
||||
size = Math.min(1, size);
|
||||
Register register = language.getRegister(storageAddr, size);
|
||||
|
||||
for (Variable var : variables) {
|
||||
VariableStorage varStorage = var.getVariableStorage();
|
||||
|
||||
// TODO: It seems this check will miss intersection if storageAddr precedes the
|
||||
// variable, but size is large enough to intersect.
|
||||
if ((register != null && varStorage.intersects(register)) ||
|
||||
(register == null && varStorage.contains(storageAddr))) {
|
||||
|
||||
if (var instanceof Parameter) {
|
||||
paramCandidate = (Parameter) var;
|
||||
}
|
||||
else if (firstCandidate != null) {
|
||||
if (localCandidates == null) {
|
||||
localCandidates = new ArrayList<>();
|
||||
localCandidates.add(firstCandidate);
|
||||
}
|
||||
localCandidates.add(var);
|
||||
}
|
||||
else {
|
||||
firstCandidate = var;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int useOffset = (int) instrAddr.subtract(function.getEntryPoint());
|
||||
if (isRead) {
|
||||
if (useOffset == 0) {
|
||||
return paramCandidate;
|
||||
}
|
||||
--useOffset;
|
||||
}
|
||||
if (useOffset < 0) {
|
||||
// A bit of a hack to deal with negative offsets (from function entry)
|
||||
useOffset = Integer.MAX_VALUE - useOffset;
|
||||
}
|
||||
|
||||
if (localCandidates == null) {
|
||||
if (firstCandidate != null) {
|
||||
int varFirstUse = firstCandidate.getFirstUseOffset();
|
||||
if (varFirstUse < 0) {
|
||||
varFirstUse = Integer.MAX_VALUE - varFirstUse;
|
||||
}
|
||||
if (varFirstUse <= useOffset) {
|
||||
return firstCandidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Variable bestVar = null;
|
||||
int bestFirstUse = 0;
|
||||
for (Variable var : localCandidates) {
|
||||
int varFirstUse = var.getFirstUseOffset();
|
||||
if (varFirstUse < 0) {
|
||||
varFirstUse = Integer.MAX_VALUE - varFirstUse;
|
||||
}
|
||||
if (varFirstUse <= useOffset && (bestVar == null || bestFirstUse < varFirstUse)) {
|
||||
bestVar = var;
|
||||
bestFirstUse = varFirstUse;
|
||||
}
|
||||
}
|
||||
if (bestVar == null) {
|
||||
bestVar = paramCandidate;
|
||||
}
|
||||
return bestVar;
|
||||
}
|
||||
}
|
|
@ -1,66 +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.trace.database.symbol;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.trace.model.symbol.TraceGlobalVariableSymbol;
|
||||
import ghidra.util.database.DBCachedObjectStore;
|
||||
import ghidra.util.database.annot.DBAnnotatedObjectInfo;
|
||||
|
||||
@DBAnnotatedObjectInfo(version = 0)
|
||||
public class DBTraceGlobalVariableSymbol extends AbstractDBTraceVariableSymbol
|
||||
implements TraceGlobalVariableSymbol {
|
||||
static final String TABLE_NAME = "GlobalVars";
|
||||
|
||||
public DBTraceGlobalVariableSymbol(DBTraceSymbolManager manager, DBCachedObjectStore<?> store,
|
||||
DBRecord record) {
|
||||
super(manager, store, record);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getSymbolType() {
|
||||
return SymbolType.GLOBAL_VAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceFunctionSymbol getFunction() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddress() {
|
||||
// TODO: Reference implementation in Program is not complete. If ever, make this similar.
|
||||
return getVariableStorage().getRegister().getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setPrimary() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimary() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstUseOffset() {
|
||||
// TODO: Reference implementation in Program is not complete. If ever, make this similar.
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,28 +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.trace.database.symbol;
|
||||
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.trace.model.symbol.TraceGlobalVariableSymbolView;
|
||||
|
||||
public class DBTraceGlobalVariableSymbolView
|
||||
extends AbstractDBTraceSymbolSingleTypeWithAddressView<DBTraceGlobalVariableSymbol>
|
||||
implements TraceGlobalVariableSymbolView {
|
||||
|
||||
public DBTraceGlobalVariableSymbolView(DBTraceSymbolManager manager) {
|
||||
super(manager, SymbolType.GLOBAL_VAR.getID(), manager.globalVarStore);
|
||||
}
|
||||
}
|
|
@ -240,11 +240,6 @@ public class DBTraceLabelSymbol extends AbstractDBTraceSymbol
|
|||
public boolean setPrimary() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
AddressRangeImpl range = new AddressRangeImpl(address, address);
|
||||
if (!manager.functions.getIntersecting(lifespan, thread, range, false,
|
||||
true).isEmpty()) {
|
||||
// Labels cannot supersede a function
|
||||
return false;
|
||||
}
|
||||
boolean result = doSetPrimary(true);
|
||||
if (!result) {
|
||||
return false;
|
||||
|
|
|
@ -1,123 +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.trace.database.symbol;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.trace.model.Trace.TraceFunctionChangeType;
|
||||
import ghidra.trace.model.symbol.TraceLocalVariableSymbol;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.database.DBCachedObjectStore;
|
||||
import ghidra.util.database.DBObjectColumn;
|
||||
import ghidra.util.database.annot.*;
|
||||
|
||||
@DBAnnotatedObjectInfo(version = 0)
|
||||
public class DBTraceLocalVariableSymbol extends AbstractDBTraceVariableSymbol
|
||||
implements TraceLocalVariableSymbol {
|
||||
static final String TABLE_NAME = "LocalVars";
|
||||
|
||||
static final String FIRST_USE_COLUMN_NAME = "FirstUse";
|
||||
|
||||
@DBAnnotatedColumn(FIRST_USE_COLUMN_NAME)
|
||||
static DBObjectColumn FIRST_USE_COLUMN;
|
||||
|
||||
@DBAnnotatedField(column = FIRST_USE_COLUMN_NAME)
|
||||
int firstUseOffset;
|
||||
|
||||
public DBTraceLocalVariableSymbol(DBTraceSymbolManager manager, DBCachedObjectStore<?> store,
|
||||
DBRecord record) {
|
||||
super(manager, store, record);
|
||||
}
|
||||
|
||||
protected void set(String name, DBTraceFunctionSymbol function, DataType dt,
|
||||
VariableStorage storage, int firstUseOffset, SourceType source) {
|
||||
super.set(name, function, dt, storage, source);
|
||||
this.firstUseOffset = firstUseOffset;
|
||||
update(FIRST_USE_COLUMN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getSymbolType() {
|
||||
return SymbolType.LOCAL_VAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceFunctionSymbol getParentNamespace() {
|
||||
return (DBTraceFunctionSymbol) super.getParentNamespace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceFunctionSymbol getParentSymbol() {
|
||||
return (DBTraceFunctionSymbol) super.getParentSymbol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceFunctionSymbol getFunction() {
|
||||
return getParentSymbol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setPrimary() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimary() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setFirstUseOffset(int firstUseOffset) {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
if (this.firstUseOffset == firstUseOffset) {
|
||||
return true; // ineffective, but successful
|
||||
}
|
||||
this.firstUseOffset = firstUseOffset;
|
||||
update(FIRST_USE_COLUMN);
|
||||
}
|
||||
manager.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, getSpace(), getFunction()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstUseOffset() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return firstUseOffset;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doUpdatesAfterSetDataType() {
|
||||
super.doUpdatesAfterSetDataType();
|
||||
manager.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, getSpace(), getFunction()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
if (super.delete()) {
|
||||
manager.trace.setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED,
|
||||
getSpace(), getFunction()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,28 +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.trace.database.symbol;
|
||||
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.trace.model.symbol.TraceLocalVariableSymbolView;
|
||||
|
||||
public class DBTraceLocalVariableSymbolView
|
||||
extends AbstractDBTraceSymbolSingleTypeWithAddressView<DBTraceLocalVariableSymbol>
|
||||
implements TraceLocalVariableSymbolView {
|
||||
|
||||
public DBTraceLocalVariableSymbolView(DBTraceSymbolManager manager) {
|
||||
super(manager, SymbolType.LOCAL_VAR.getID(), manager.localVarStore);
|
||||
}
|
||||
}
|
|
@ -1,220 +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.trace.database.symbol;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.trace.model.Trace.TraceFunctionChangeType;
|
||||
import ghidra.trace.model.symbol.TraceParameterSymbol;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.database.DBCachedObjectStore;
|
||||
import ghidra.util.database.DBObjectColumn;
|
||||
import ghidra.util.database.annot.*;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
@DBAnnotatedObjectInfo(version = 0)
|
||||
public class DBTraceParameterSymbol extends AbstractDBTraceVariableSymbol
|
||||
implements TraceParameterSymbol {
|
||||
static final String TABLE_NAME = "Parameters";
|
||||
|
||||
static final String ORDINAL_COLUMN_NAME = "Ordinal";
|
||||
|
||||
@DBAnnotatedColumn(ORDINAL_COLUMN_NAME)
|
||||
static DBObjectColumn ORDINAL_COLUMN;
|
||||
|
||||
@DBAnnotatedField(column = ORDINAL_COLUMN_NAME)
|
||||
int ordinal;
|
||||
|
||||
// This is transient, when the function does not use custom parameter storage.
|
||||
// It is unused if the function uses custom storage.
|
||||
protected VariableStorage dynamicStorage = VariableStorage.UNASSIGNED_STORAGE;
|
||||
|
||||
public DBTraceParameterSymbol(DBTraceSymbolManager manager, DBCachedObjectStore<?> store,
|
||||
DBRecord record) {
|
||||
super(manager, store, record);
|
||||
}
|
||||
|
||||
protected void set(String name, DBTraceFunctionSymbol function, DataType dt,
|
||||
VariableStorage storage, int ordinal, SourceType source) {
|
||||
super.set(name, function, dt, storage, source);
|
||||
this.ordinal = ordinal;
|
||||
update(ORDINAL_COLUMN);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected VariableStorage adjustStorage(VariableStorage s) {
|
||||
if (!getFunction().hasCustomVariableStorage()) {
|
||||
return VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
return super.adjustStorage(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolType getSymbolType() {
|
||||
return SymbolType.PARAMETER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pair<String, SourceType> validateNameAndSource(String newName, SourceType newSource)
|
||||
throws InvalidInputException {
|
||||
if (newSource == SourceType.DEFAULT || newName == null || "".equals(newName) ||
|
||||
SymbolUtilities.isDefaultParameterName(newName)) {
|
||||
return new ImmutablePair<>("", SourceType.DEFAULT);
|
||||
}
|
||||
return new ImmutablePair<>(newName, newSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (getSource() == SourceType.DEFAULT && ordinal != -1) {
|
||||
return SymbolUtilities.getDefaultParamName(ordinal);
|
||||
}
|
||||
return super.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceFunctionSymbol getParentNamespace() {
|
||||
return (DBTraceFunctionSymbol) super.getParentNamespace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceFunctionSymbol getParentSymbol() {
|
||||
return (DBTraceFunctionSymbol) super.getParentSymbol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceFunctionSymbol getFunction() {
|
||||
return getParentSymbol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setPrimary() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimary() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableStorage getVariableStorage() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
if (!getFunction().hasCustomVariableStorage()) {
|
||||
return dynamicStorage;
|
||||
}
|
||||
return super.getVariableStorage();
|
||||
}
|
||||
}
|
||||
|
||||
// Internal
|
||||
public void setOrdinal(int ordinal) {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
this.ordinal = ordinal;
|
||||
update(ORDINAL_COLUMN);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrdinal() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return ordinal;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoParameter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoParameterType getAutoParameterType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForcedIndirect() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
VariableStorage s = getVariableStorage();
|
||||
return s == null ? false : s.isForcedIndirect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return manager.checkIndirection(getVariableStorage(), getFormalDataType());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getFormalDataType() {
|
||||
return super.getDataType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstUseOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void doSetDynamicStorage(VariableStorage s) {
|
||||
assert !getFunction().hasCustomVariableStorage();
|
||||
this.dynamicStorage = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doUpdatesAfterSetDataType() {
|
||||
super.doUpdatesAfterSetDataType();
|
||||
DBTraceFunctionSymbol function = getFunction();
|
||||
if (!function.hasCustomVariableStorage()) {
|
||||
function.doUpdateParametersAndReturn();
|
||||
}
|
||||
function.doUpdateSignatureSourceAfterVariableChange(getSource(), getDataType());
|
||||
if (ordinal == Parameter.RETURN_ORIDINAL) {
|
||||
manager.trace.setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED_RETURN,
|
||||
getSpace(), getFunction()));
|
||||
}
|
||||
else {
|
||||
manager.trace.setChanged(new TraceChangeRecord<>(
|
||||
TraceFunctionChangeType.CHANGED_PARAMETERS, getSpace(), getFunction()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected VariableStorage doDeriveStorageForSetDataType(DataType dt, boolean alignStack,
|
||||
boolean force) throws InvalidInputException {
|
||||
if (!getFunction().hasCustomVariableStorage()) {
|
||||
return VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
return super.doDeriveStorageForSetDataType(dt, alignStack, force);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
if (super.delete()) {
|
||||
manager.trace.setChanged(new TraceChangeRecord<>(
|
||||
TraceFunctionChangeType.CHANGED_PARAMETERS, getSpace(), getFunction()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,28 +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.trace.database.symbol;
|
||||
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.trace.model.symbol.TraceParameterSymbolView;
|
||||
|
||||
public class DBTraceParameterSymbolView
|
||||
extends AbstractDBTraceSymbolSingleTypeWithAddressView<DBTraceParameterSymbol>
|
||||
implements TraceParameterSymbolView {
|
||||
|
||||
public DBTraceParameterSymbolView(DBTraceSymbolManager manager) {
|
||||
super(manager, SymbolType.PARAMETER.getID(), manager.parameterStore);
|
||||
}
|
||||
}
|
|
@ -151,25 +151,7 @@ public class DBTraceReference implements TraceReference {
|
|||
return;
|
||||
}
|
||||
Address toAddress = getToAddress();
|
||||
if (dbSym instanceof AbstractDBTraceVariableSymbol) {
|
||||
AbstractDBTraceVariableSymbol varSym = (AbstractDBTraceVariableSymbol) dbSym;
|
||||
// Variables' lifespans are governed by the parent function.
|
||||
// Globals span all time.
|
||||
DBTraceNamespaceSymbol parent = varSym.getParentNamespace();
|
||||
if (parent instanceof TraceSymbolWithLifespan) {
|
||||
TraceSymbolWithLifespan symWl = (TraceSymbolWithLifespan) parent;
|
||||
if (!symWl.getLifespan().intersects(getLifespan())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Associated symbol and reference must have connected lifespans");
|
||||
}
|
||||
}
|
||||
if (!varSym.getVariableStorage().contains(toAddress)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Variable symbol storage of '%s' must contain Reference's to address (%s)",
|
||||
varSym.getName(), toAddress));
|
||||
}
|
||||
}
|
||||
else if (!Objects.equals(symbol.getAddress(), toAddress)) {
|
||||
if (!Objects.equals(symbol.getAddress(), toAddress)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Symbol address (%s) of '%s' must match Reference's to address (%s)",
|
||||
symbol.getAddress(), symbol.getName(), toAddress));
|
||||
|
|
|
@ -21,10 +21,12 @@ import java.util.*;
|
|||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
import db.*;
|
||||
import ghidra.lifecycle.Internal;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.DBTraceManager;
|
||||
|
@ -37,7 +39,6 @@ import ghidra.trace.database.space.DBTraceSpaceKey;
|
|||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.Lifespan;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.Trace.TraceFunctionTagChangeType;
|
||||
import ghidra.trace.model.Trace.TraceSymbolChangeType;
|
||||
import ghidra.trace.model.symbol.*;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
@ -93,164 +94,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
}
|
||||
}
|
||||
|
||||
@DBAnnotatedObjectInfo(version = 0)
|
||||
public static class DBTraceFunctionTag extends DBAnnotatedObject implements FunctionTag {
|
||||
|
||||
static final String TABLE_NAME = "FunctionTags";
|
||||
|
||||
static final String NAME_COLUMN_NAME = "Name";
|
||||
static final String COMMENT_COLUMN_NAME = "Comment";
|
||||
|
||||
@DBAnnotatedColumn(NAME_COLUMN_NAME)
|
||||
static DBObjectColumn NAME_COLUMN;
|
||||
@DBAnnotatedColumn(COMMENT_COLUMN_NAME)
|
||||
static DBObjectColumn COMMENT_COLUMN;
|
||||
|
||||
@DBAnnotatedField(column = NAME_COLUMN_NAME, indexed = true)
|
||||
String name;
|
||||
@DBAnnotatedField(column = COMMENT_COLUMN_NAME)
|
||||
String comment;
|
||||
|
||||
protected final DBTraceSymbolManager manager;
|
||||
|
||||
public DBTraceFunctionTag(DBTraceSymbolManager manager, DBCachedObjectStore<?> store,
|
||||
DBRecord record) {
|
||||
super(store, record);
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
protected void set(String name, String comment) {
|
||||
this.name = name;
|
||||
this.comment = comment;
|
||||
update(NAME_COLUMN, COMMENT_COLUMN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof FunctionTag)) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
FunctionTag that = (FunctionTag) obj;
|
||||
if (!Objects.equals(this.getName(), that.getName())) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.getComment(), that.getComment())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FunctionTag o) {
|
||||
int result;
|
||||
result = this.getName().compareToIgnoreCase(o.getName());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = this.getComment().compareToIgnoreCase(o.getComment());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return comment;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
this.name = name;
|
||||
update(NAME_COLUMN);
|
||||
}
|
||||
manager.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceFunctionTagChangeType.CHANGED, null, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComment(String comment) {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
this.comment = comment;
|
||||
update(COMMENT_COLUMN);
|
||||
}
|
||||
manager.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceFunctionTagChangeType.CHANGED, null, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||
for (DBTraceFunctionTagMapping mapping : manager.tagMappingsByTag.get(key)) {
|
||||
manager.tagMappingStore.delete(mapping);
|
||||
}
|
||||
manager.tagStore.delete(this);
|
||||
}
|
||||
manager.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceFunctionTagChangeType.DELETED, null, this));
|
||||
}
|
||||
}
|
||||
|
||||
@DBAnnotatedObjectInfo(version = 0)
|
||||
public static class DBTraceFunctionTagMapping extends DBAnnotatedObject {
|
||||
|
||||
static final String TABLE_NAME = "FunctionTagMappings";
|
||||
|
||||
static final String FUNCTION_COLUMN_NAME = "Function";
|
||||
static final String TAG_COLUMN_NAME = "Tag";
|
||||
|
||||
@DBAnnotatedColumn(FUNCTION_COLUMN_NAME)
|
||||
static DBObjectColumn FUNCTION_COLUMN;
|
||||
@DBAnnotatedColumn(TAG_COLUMN_NAME)
|
||||
static DBObjectColumn TAG_COLUMN;
|
||||
|
||||
@DBAnnotatedField(column = FUNCTION_COLUMN_NAME, indexed = true)
|
||||
private long functionKey;
|
||||
@DBAnnotatedField(column = TAG_COLUMN_NAME, indexed = true)
|
||||
private long tagKey;
|
||||
|
||||
public DBTraceFunctionTagMapping(DBCachedObjectStore<?> store, DBRecord record) {
|
||||
super(store, record);
|
||||
}
|
||||
|
||||
protected void set(DBTraceFunctionSymbol function, DBTraceFunctionTag tag) {
|
||||
this.functionKey = function.getKey();
|
||||
this.tagKey = tag.getKey();
|
||||
update(FUNCTION_COLUMN, TAG_COLUMN);
|
||||
}
|
||||
|
||||
public long getFunctionKey() {
|
||||
return functionKey;
|
||||
}
|
||||
|
||||
public long getTagKey() {
|
||||
return tagKey;
|
||||
}
|
||||
}
|
||||
|
||||
public static class VariableStorageDBFieldCodec extends
|
||||
AbstractDBFieldCodec<VariableStorage, DBTraceVariableStorageEntry, StringField> {
|
||||
|
||||
|
@ -351,25 +194,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
CLASS {
|
||||
@Override
|
||||
boolean isValidParent(DBTraceNamespaceSymbol parent) {
|
||||
return isNoFunctionAncestor(parent);
|
||||
}
|
||||
},
|
||||
FUNCTION {
|
||||
@Override
|
||||
boolean isValidParent(DBTraceNamespaceSymbol parent) {
|
||||
return isNoFunctionAncestor(parent);
|
||||
}
|
||||
},
|
||||
PARAMETER {
|
||||
@Override
|
||||
boolean isValidParent(DBTraceNamespaceSymbol parent) {
|
||||
return parent instanceof Function;
|
||||
}
|
||||
},
|
||||
LOCAL_VAR {
|
||||
@Override
|
||||
boolean isValidParent(DBTraceNamespaceSymbol parent) {
|
||||
return parent instanceof Function;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
GLOBAL_VAR {
|
||||
|
@ -382,15 +207,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
public static final List<MySymbolTypes> VALUES = List.of(values());
|
||||
|
||||
abstract boolean isValidParent(DBTraceNamespaceSymbol parent);
|
||||
|
||||
boolean isNoFunctionAncestor(DBTraceNamespaceSymbol parent) {
|
||||
for (DBTraceNamespaceSymbol p = parent; p != null; p = p.parent) {
|
||||
if (p instanceof Function) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected final DBTrace trace;
|
||||
|
@ -401,41 +217,23 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
|
||||
protected final DBTraceAddressSnapRangePropertyMap<Long, DBTraceSymbolIDEntry> idMap;
|
||||
|
||||
protected final DBCachedObjectStore<DBTraceFunctionTag> tagStore;
|
||||
protected final DBCachedObjectIndex<String, DBTraceFunctionTag> tagsByName;
|
||||
|
||||
protected final DBCachedObjectStore<DBTraceFunctionTagMapping> tagMappingStore;
|
||||
protected final DBCachedObjectIndex<Long, DBTraceFunctionTagMapping> tagMappingsByFunc;
|
||||
protected final DBCachedObjectIndex<Long, DBTraceFunctionTagMapping> tagMappingsByTag;
|
||||
|
||||
// NB. This is unused since the purging of trace function symbols
|
||||
// In theory, may get used by global variables.
|
||||
protected final DBCachedObjectStore<DBTraceVariableStorageEntry> storageStore;
|
||||
protected final DBCachedObjectIndex<VariableStorage, DBTraceVariableStorageEntry> storageByStorage;
|
||||
|
||||
protected final DBCachedObjectStore<DBTraceLabelSymbol> labelStore;
|
||||
protected final DBCachedObjectStore<DBTraceNamespaceSymbol> namespaceStore;
|
||||
protected final DBCachedObjectStore<DBTraceClassSymbol> classStore;
|
||||
protected final DBCachedObjectStore<DBTraceFunctionSymbol> functionStore;
|
||||
protected final DBCachedObjectIndex<Long, DBTraceFunctionSymbol> functionsByThunked;
|
||||
protected final DBCachedObjectStore<DBTraceParameterSymbol> parameterStore;
|
||||
protected final DBCachedObjectStore<DBTraceLocalVariableSymbol> localVarStore;
|
||||
// Seems only for "global register" variables
|
||||
protected final DBCachedObjectStore<DBTraceGlobalVariableSymbol> globalVarStore;
|
||||
protected final DBTraceNamespaceSymbol globalNamespace;
|
||||
|
||||
protected final DBTraceLabelSymbolView labels;
|
||||
protected final DBTraceNamespaceSymbolView namespaces;
|
||||
protected final DBTraceClassSymbolView classes;
|
||||
protected final DBTraceFunctionSymbolView functions;
|
||||
protected final DBTraceParameterSymbolView parameters;
|
||||
protected final DBTraceLocalVariableSymbolView localVars;
|
||||
protected final DBTraceGlobalVariableSymbolView globalVars;
|
||||
|
||||
protected final DBTraceSymbolMultipleTypesView<? extends DBTraceNamespaceSymbol> allNamespaces;
|
||||
protected final DBTraceSymbolMultipleTypesNoDuplicatesView<? extends DBTraceNamespaceSymbol> uniqueNamespaces;
|
||||
protected final DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView<? extends AbstractDBTraceVariableSymbol> allLocals;
|
||||
protected final DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView<?> allVariables;
|
||||
protected final DBTraceSymbolMultipleTypesWithLocationView<?> labelsAndFunctions;
|
||||
protected final DBTraceSymbolMultipleTypesNoDuplicatesView<?> notLabelsNorFunctions;
|
||||
protected final DBTraceSymbolMultipleTypesNoDuplicatesView<?> notLabels;
|
||||
protected final DBTraceSymbolMultipleTypesView<?> allSymbols;
|
||||
|
||||
protected final Map<Byte, AbstractDBTraceSymbolSingleTypeView<?>> symbolViews = new HashMap<>();
|
||||
|
@ -457,17 +255,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
baseLanguage, trace, threadManager, DBTraceSymbolIDEntry.class,
|
||||
DBTraceSymbolIDEntry::new);
|
||||
|
||||
tagStore = factory.getOrCreateCachedStore(DBTraceFunctionTag.TABLE_NAME,
|
||||
DBTraceFunctionTag.class, (s, r) -> new DBTraceFunctionTag(this, s, r), true);
|
||||
tagsByName = tagStore.getIndex(String.class, DBTraceFunctionTag.NAME_COLUMN);
|
||||
|
||||
tagMappingStore = factory.getOrCreateCachedStore(DBTraceFunctionTagMapping.TABLE_NAME,
|
||||
DBTraceFunctionTagMapping.class, DBTraceFunctionTagMapping::new, true);
|
||||
tagMappingsByFunc =
|
||||
tagMappingStore.getIndex(long.class, DBTraceFunctionTagMapping.FUNCTION_COLUMN);
|
||||
tagMappingsByTag =
|
||||
tagMappingStore.getIndex(long.class, DBTraceFunctionTagMapping.TAG_COLUMN);
|
||||
|
||||
storageStore = factory.getOrCreateCachedStore(DBTraceVariableStorageEntry.TABLE_NAME,
|
||||
DBTraceVariableStorageEntry.class,
|
||||
(s, r) -> new DBTraceVariableStorageEntry(this, s, r), true);
|
||||
|
@ -480,18 +267,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
DBTraceNamespaceSymbol.class, (s, r) -> new DBTraceNamespaceSymbol(this, s, r), true);
|
||||
classStore = factory.getOrCreateCachedStore(DBTraceClassSymbol.TABLE_NAME,
|
||||
DBTraceClassSymbol.class, (s, r) -> new DBTraceClassSymbol(this, s, r), true);
|
||||
functionStore = factory.getOrCreateCachedStore(DBTraceFunctionSymbol.TABLE_NAME,
|
||||
DBTraceFunctionSymbol.class, (s, r) -> new DBTraceFunctionSymbol(this, s, r), true);
|
||||
functionsByThunked =
|
||||
functionStore.getIndex(long.class, DBTraceFunctionSymbol.THUNKED_COLUMN);
|
||||
parameterStore = factory.getOrCreateCachedStore(DBTraceParameterSymbol.TABLE_NAME,
|
||||
DBTraceParameterSymbol.class, (s, r) -> new DBTraceParameterSymbol(this, s, r), true);
|
||||
localVarStore = factory.getOrCreateCachedStore(DBTraceLocalVariableSymbol.TABLE_NAME,
|
||||
DBTraceLocalVariableSymbol.class, (s, r) -> new DBTraceLocalVariableSymbol(this, s, r),
|
||||
true);
|
||||
globalVarStore = factory.getOrCreateCachedStore(DBTraceGlobalVariableSymbol.TABLE_NAME,
|
||||
DBTraceGlobalVariableSymbol.class,
|
||||
(s, r) -> new DBTraceGlobalVariableSymbol(this, s, r), true);
|
||||
|
||||
globalNamespace = getOrCreateGlobalNamespace();
|
||||
|
||||
|
@ -499,25 +274,13 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
labels = putInMap(new DBTraceLabelSymbolView(this));
|
||||
namespaces = putInMap(new DBTraceNamespaceSymbolView(this));
|
||||
classes = putInMap(new DBTraceClassSymbolView(this));
|
||||
functions = putInMap(new DBTraceFunctionSymbolView(this));
|
||||
parameters = putInMap(new DBTraceParameterSymbolView(this));
|
||||
localVars = putInMap(new DBTraceLocalVariableSymbolView(this));
|
||||
globalVars = putInMap(new DBTraceGlobalVariableSymbolView(this));
|
||||
|
||||
allNamespaces = new DBTraceSymbolMultipleTypesView<>(this, namespaces, classes, functions);
|
||||
allNamespaces = new DBTraceSymbolMultipleTypesView<>(this, namespaces, classes);
|
||||
uniqueNamespaces =
|
||||
new DBTraceSymbolMultipleTypesNoDuplicatesView<>(this, namespaces, classes);
|
||||
allLocals = new DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView<>(this, parameters,
|
||||
localVars);
|
||||
allVariables = new DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView<>(this, parameters,
|
||||
localVars, globalVars);
|
||||
labelsAndFunctions = new DBTraceSymbolMultipleTypesWithLocationView<AbstractDBTraceSymbol>(
|
||||
this, labels, functions);
|
||||
notLabelsNorFunctions = new DBTraceSymbolMultipleTypesNoDuplicatesView<>(this, namespaces,
|
||||
classes, parameters, localVars, globalVars);
|
||||
allSymbols = new DBTraceSymbolMultipleTypesView<>(this, labels, namespaces, classes,
|
||||
functions, parameters, localVars, globalVars);
|
||||
|
||||
notLabels =
|
||||
new DBTraceSymbolMultipleTypesNoDuplicatesView<>(this, namespaces, classes);
|
||||
allSymbols = new DBTraceSymbolMultipleTypesView<>(this, labels, namespaces, classes);
|
||||
}
|
||||
|
||||
protected DataType checkIndirection(VariableStorage s, DataType formal) {
|
||||
|
@ -595,8 +358,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
|
||||
// Internal
|
||||
public void replaceDataTypes(long oldID, long newID) {
|
||||
// TODO Auto-generated method stub
|
||||
// DataTypes of Function returns, params, locals, globalRegs
|
||||
// Would apply to functions and variables, but those are not supported.
|
||||
}
|
||||
|
||||
protected void assertValidThreadAddress(TraceThread thread, Address address) {
|
||||
|
@ -644,26 +406,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
return classes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceFunctionSymbolView functions() {
|
||||
return functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceParameterSymbolView parameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceLocalVariableSymbolView localVariables() {
|
||||
return localVars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceGlobalVariableSymbolView globalVariables() {
|
||||
return globalVars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceSymbolView<? extends DBTraceNamespaceSymbol> allNamespaces() {
|
||||
return allNamespaces;
|
||||
|
@ -674,23 +416,8 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
}
|
||||
|
||||
@Override
|
||||
public TraceSymbolWithAddressNoDuplicatesView<? extends AbstractDBTraceVariableSymbol> allLocals() {
|
||||
return allLocals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceSymbolWithAddressNoDuplicatesView<? extends AbstractDBTraceSymbol> allVariables() {
|
||||
return allVariables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceSymbolWithLocationView<? extends AbstractDBTraceSymbol> labelsAndFunctions() {
|
||||
return labelsAndFunctions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceSymbolNoDuplicatesView<? extends AbstractDBTraceSymbol> notLabelsNorFunctions() {
|
||||
return notLabelsNorFunctions;
|
||||
public TraceSymbolNoDuplicatesView<? extends AbstractDBTraceSymbol> notLabels() {
|
||||
return notLabels;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -700,10 +427,9 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
|
||||
// Internal
|
||||
public DBTraceNamespaceSymbol checkIsMine(Namespace ns) {
|
||||
if (!(ns instanceof DBTraceNamespaceSymbol)) {
|
||||
if (!(ns instanceof DBTraceNamespaceSymbol dbns)) {
|
||||
return null;
|
||||
}
|
||||
DBTraceNamespaceSymbol dbns = (DBTraceNamespaceSymbol) ns;
|
||||
if (dbns.manager != this) {
|
||||
return null;
|
||||
}
|
||||
|
@ -713,13 +439,8 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
if (namespaceStore.contains(dbns)) {
|
||||
return dbns;
|
||||
}
|
||||
if (dbns instanceof DBTraceClassSymbol) {
|
||||
if (classStore.contains((DBTraceClassSymbol) dbns)) {
|
||||
return dbns;
|
||||
}
|
||||
}
|
||||
if (dbns instanceof DBTraceFunctionSymbol) {
|
||||
if (functionStore.contains((DBTraceFunctionSymbol) dbns)) {
|
||||
if (dbns instanceof DBTraceClassSymbol dbcs) {
|
||||
if (classStore.contains(dbcs)) {
|
||||
return dbns;
|
||||
}
|
||||
}
|
||||
|
@ -728,10 +449,9 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
|
||||
// Internal
|
||||
public AbstractDBTraceSymbol checkIsMine(Symbol symbol) {
|
||||
if (!(symbol instanceof AbstractDBTraceSymbol)) {
|
||||
if (!(symbol instanceof AbstractDBTraceSymbol dbSym)) {
|
||||
return null;
|
||||
}
|
||||
AbstractDBTraceSymbol dbSym = (AbstractDBTraceSymbol) symbol;
|
||||
if (dbSym.manager != this) {
|
||||
return null;
|
||||
}
|
||||
|
@ -750,25 +470,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
return dbSym;
|
||||
}
|
||||
|
||||
// Internal
|
||||
public DBTraceFunctionSymbol checkIsMine(Function function) {
|
||||
if (!(function instanceof DBTraceFunctionSymbol)) {
|
||||
return null;
|
||||
}
|
||||
DBTraceFunctionSymbol dbFunc = (DBTraceFunctionSymbol) function;
|
||||
if (dbFunc.manager != this) {
|
||||
return null;
|
||||
}
|
||||
if (dbFunc.isDeleted()) {
|
||||
return null;
|
||||
}
|
||||
if (functionStore.contains(dbFunc)) {
|
||||
return dbFunc;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Internal
|
||||
@Internal
|
||||
public DBTraceNamespaceSymbol assertIsMine(Namespace ns) {
|
||||
DBTraceNamespaceSymbol dbns = checkIsMine(ns);
|
||||
if (dbns == null) {
|
||||
|
@ -777,7 +479,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
return dbns;
|
||||
}
|
||||
|
||||
// Internal
|
||||
@Internal
|
||||
public AbstractDBTraceSymbol assertIsMine(Symbol symbol) {
|
||||
AbstractDBTraceSymbol dbSym = checkIsMine(symbol);
|
||||
if (dbSym == null) {
|
||||
|
@ -786,15 +488,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
return dbSym;
|
||||
}
|
||||
|
||||
// Internal
|
||||
public DBTraceFunctionSymbol assertIsMine(Function function) {
|
||||
DBTraceFunctionSymbol dbFunc = checkIsMine(function);
|
||||
if (dbFunc == null) {
|
||||
throw new IllegalArgumentException("Given function is not in this trace");
|
||||
}
|
||||
return dbFunc;
|
||||
}
|
||||
|
||||
protected static void assertValidName(String name) throws InvalidInputException {
|
||||
if (name == null || name.length() == 0 || !name.matches("\\p{Graph}+")) {
|
||||
throw new InvalidInputException(name);
|
||||
|
@ -802,8 +495,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks for duplicate names, allowing {@link SymbolType#LABEL} and
|
||||
* {@link SymbolType#FUNCTION}.
|
||||
* Checks for duplicate names, allowing {@link SymbolType#LABEL}
|
||||
*
|
||||
* @param name the proposed name
|
||||
* @param parent the parent namespace
|
||||
|
@ -811,7 +503,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
*/
|
||||
protected void assertUniqueName(String name, DBTraceNamespaceSymbol parent)
|
||||
throws DuplicateNameException {
|
||||
for (AbstractDBTraceSymbol symbol : notLabelsNorFunctions.getChildren(parent)) {
|
||||
for (AbstractDBTraceSymbol symbol : notLabels.getChildren(parent)) {
|
||||
if (name.equals(symbol.name)) {
|
||||
throw new DuplicateNameException(name);
|
||||
}
|
||||
|
@ -866,8 +558,8 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
TraceThread thread, Address address, String name, DBTraceNamespaceSymbol parent)
|
||||
throws DuplicateNameException {
|
||||
if (address.isMemoryAddress()) {
|
||||
for (AbstractDBTraceSymbol duplicate : labelsAndFunctions.getIntersecting(lifespan,
|
||||
thread, new AddressRangeImpl(address, address), false, true)) {
|
||||
for (AbstractDBTraceSymbol duplicate : labels.getIntersecting(lifespan, thread,
|
||||
new AddressRangeImpl(address, address), false, true)) {
|
||||
if (duplicate == exclude) {
|
||||
continue;
|
||||
}
|
||||
|
@ -885,8 +577,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
|||
|
||||
protected void assertNotDuplicate(AbstractDBTraceSymbol exclude, String name,
|
||||
DBTraceNamespaceSymbol parent) throws DuplicateNameException {
|
||||
for (AbstractDBTraceSymbol duplicate : notLabelsNorFunctions.getChildrenNamed(name,
|
||||
parent)) {
|
||||
for (AbstractDBTraceSymbol duplicate : notLabels.getChildrenNamed(name, parent)) {
|
||||
if (duplicate == exclude) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -229,44 +229,6 @@ public interface Trace extends DataTypeManagerDomainObject {
|
|||
new TraceDataTypeChangeType<>();
|
||||
}
|
||||
|
||||
public static final class TraceFunctionChangeType<U>
|
||||
extends DefaultTraceChangeType<TraceFunctionSymbol, U> {
|
||||
// NOTE: ADDED/DELETED/LIFESPAN_CHANGED are SymbolChangeTypes
|
||||
public static final TraceFunctionChangeType<Void> CHANGED = new TraceFunctionChangeType<>();
|
||||
public static final TraceFunctionChangeType<Integer> CHANGED_PURGE =
|
||||
new TraceFunctionChangeType<>();
|
||||
public static final TraceFunctionChangeType<Boolean> CHANGED_INLINE =
|
||||
new TraceFunctionChangeType<>();
|
||||
public static final TraceFunctionChangeType<Boolean> CHANGED_NORETURN =
|
||||
new TraceFunctionChangeType<>();
|
||||
public static final TraceFunctionChangeType<String> CHANGED_CALL_FIXUP =
|
||||
new TraceFunctionChangeType<>();
|
||||
public static final TraceFunctionChangeType<Void> CHANGED_RETURN =
|
||||
new TraceFunctionChangeType<>();
|
||||
public static final TraceFunctionChangeType<Void> CHANGED_PARAMETERS =
|
||||
new TraceFunctionChangeType<>();
|
||||
public static final TraceFunctionChangeType<TraceFunctionSymbol> CHANGED_THUNK =
|
||||
new TraceFunctionChangeType<>();
|
||||
public static final TraceFunctionChangeType<AddressSetView> CHANGED_BODY =
|
||||
new TraceFunctionChangeType<>();
|
||||
public static final TraceFunctionChangeType<FunctionTag> TAG_APPLIED =
|
||||
new TraceFunctionChangeType<>();
|
||||
public static final TraceFunctionChangeType<FunctionTag> TAG_REMOVED =
|
||||
new TraceFunctionChangeType<>();
|
||||
// TODO: VARIABLE_REFERENCE_ADDED? Or would these be reported by ref manager?
|
||||
// TODO: VARIABLE_REFERENCE_DELETED? Or would these be reported by ref manager?
|
||||
}
|
||||
|
||||
public static final class TraceFunctionTagChangeType<U>
|
||||
extends DefaultTraceChangeType<FunctionTag, U> {
|
||||
public static final TraceFunctionTagChangeType<Void> ADDED =
|
||||
new TraceFunctionTagChangeType<>();
|
||||
public static final TraceFunctionTagChangeType<Void> CHANGED =
|
||||
new TraceFunctionTagChangeType<>();
|
||||
public static final TraceFunctionTagChangeType<Void> DELETED =
|
||||
new TraceFunctionTagChangeType<>();
|
||||
}
|
||||
|
||||
public static final class TraceInstructionChangeType<U>
|
||||
extends DefaultTraceChangeType<TraceInstruction, U> {
|
||||
public static final TraceInstructionChangeType<FlowOverride> FLOW_OVERRIDE_CHANGED =
|
||||
|
|
|
@ -17,6 +17,9 @@ package ghidra.trace.model.symbol;
|
|||
|
||||
import ghidra.program.model.listing.GhidraClass;
|
||||
|
||||
/**
|
||||
* A trace class symbol
|
||||
*/
|
||||
public interface TraceClassSymbol extends TraceNamespaceSymbol, GhidraClass {
|
||||
|
||||
// Nothing to add.
|
||||
}
|
||||
|
|
|
@ -19,8 +19,21 @@ import ghidra.program.model.symbol.SourceType;
|
|||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* The class symbol view.
|
||||
*/
|
||||
public interface TraceClassSymbolView extends TraceSymbolNoDuplicatesView<TraceClassSymbol> {
|
||||
|
||||
/**
|
||||
* Add a new class symbol.
|
||||
*
|
||||
* @param name the name of the class
|
||||
* @param parent the parent namespace
|
||||
* @param source the source
|
||||
* @return the new class symbol
|
||||
* @throws DuplicateNameException if the name is duplicated in the parent namespace
|
||||
* @throws InvalidInputException if the name is not valid
|
||||
* @throws IllegalArgumentException if some other argument is not valid
|
||||
*/
|
||||
TraceClassSymbol add(String name, TraceNamespaceSymbol parent, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException, IllegalArgumentException;
|
||||
}
|
||||
|
|
|
@ -1,81 +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.trace.model.symbol;
|
||||
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
public interface TraceFunctionSymbol
|
||||
extends TraceNamespaceSymbol, TraceSymbolWithLifespan, Function {
|
||||
|
||||
// TODO: If possible, remove the DuplicateNameException on these three methods.
|
||||
/*
|
||||
@Override
|
||||
void setName(String newName, SourceType source) throws InvalidInputException;
|
||||
|
||||
@Override
|
||||
void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source)
|
||||
throws InvalidInputException, CircularDependencyException;
|
||||
|
||||
@Override
|
||||
void setNamespace(Namespace newNamespace)
|
||||
throws InvalidInputException, CircularDependencyException;
|
||||
*/
|
||||
|
||||
@Override
|
||||
TraceParameterSymbol getReturn();
|
||||
|
||||
@Override
|
||||
TraceParameterSymbol addParameter(Variable var, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException;
|
||||
|
||||
@Override
|
||||
TraceParameterSymbol insertParameter(int ordinal, Variable var, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException;
|
||||
|
||||
@Override
|
||||
Parameter getParameter(int ordinal);
|
||||
|
||||
@Override
|
||||
Parameter moveParameter(int fromOrdinal, int toOrdinal) throws InvalidInputException;
|
||||
|
||||
@Override
|
||||
Parameter[] getParameters();
|
||||
|
||||
@Override
|
||||
Parameter[] getParameters(VariableFilter filter);
|
||||
|
||||
@Override
|
||||
TraceLocalVariableSymbol[] getLocalVariables();
|
||||
|
||||
@Override
|
||||
TraceLocalVariableSymbol[] getLocalVariables(VariableFilter filter);
|
||||
|
||||
@Override
|
||||
Variable[] getAllVariables();
|
||||
|
||||
@Override
|
||||
Variable[] getVariables(VariableFilter filter);
|
||||
|
||||
@Override
|
||||
TraceLocalVariableSymbol addLocalVariable(Variable var, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException;
|
||||
|
||||
@Override
|
||||
TraceFunctionSymbol getThunkedFunction(boolean recursive);
|
||||
}
|
|
@ -1,66 +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.trace.model.symbol;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.lang.PrototypeModel;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.trace.model.Lifespan;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
public interface TraceFunctionSymbolView extends TraceSymbolWithLocationView<TraceFunctionSymbol> {
|
||||
|
||||
TraceFunctionSymbol add(Lifespan lifespan, Address entryPoint, AddressSetView body,
|
||||
String name, TraceFunctionSymbol thunked, TraceNamespaceSymbol parent,
|
||||
SourceType source) throws InvalidInputException, OverlappingFunctionException;
|
||||
|
||||
default TraceFunctionSymbol create(long snap, Address entryPoint, AddressSetView body,
|
||||
String name, TraceFunctionSymbol thunked, TraceNamespaceSymbol parent,
|
||||
SourceType source) throws InvalidInputException, OverlappingFunctionException {
|
||||
return add(Lifespan.nowOn(snap), entryPoint, body, name, thunked, parent, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ordered unmodifiable set of defined calling convention names. The reserved names
|
||||
* "unknown" and "default" are not included. The returned collection may not include all names
|
||||
* referenced by various functions and function-definitions. This set is limited to
|
||||
* those defined by the associated compiler specification.
|
||||
*
|
||||
* @return the set of defined calling convention names.
|
||||
*/
|
||||
Collection<String> getCallingConventionNames();
|
||||
|
||||
/**
|
||||
* Get the default calling convention's prototype model.
|
||||
*
|
||||
* @return the default calling convention prototype model.
|
||||
*/
|
||||
PrototypeModel getDefaultCallingConvention();
|
||||
|
||||
/**
|
||||
* Get the prototype model of the calling convention with the specified name from the
|
||||
* associated compiler specification. If {@link Function#DEFAULT_CALLING_CONVENTION_STRING}
|
||||
* is specified {@link #getDefaultCallingConvention()} will be returned.
|
||||
*
|
||||
* @param name the calling convention name
|
||||
* @return the named function calling convention prototype model or null if not defined.
|
||||
*/
|
||||
PrototypeModel getCallingConvention(String name);
|
||||
}
|
|
@ -1,21 +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.trace.model.symbol;
|
||||
|
||||
public interface TraceGlobalVariableSymbol extends TraceVariableSymbol /*, GlobalVariable, no? */
|
||||
{
|
||||
|
||||
}
|
|
@ -1,21 +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.trace.model.symbol;
|
||||
|
||||
public interface TraceGlobalVariableSymbolView
|
||||
extends TraceSymbolWithAddressNoDuplicatesView<TraceGlobalVariableSymbol> {
|
||||
|
||||
}
|
|
@ -15,14 +15,16 @@
|
|||
*/
|
||||
package ghidra.trace.model.symbol;
|
||||
|
||||
import ghidra.program.database.symbol.CodeSymbol;
|
||||
import ghidra.trace.model.listing.TraceCodeUnit;
|
||||
|
||||
/**
|
||||
* TODO: Document me
|
||||
*
|
||||
* See {@link CodeSymbol}
|
||||
* A trace label symbol.
|
||||
*/
|
||||
public interface TraceLabelSymbol extends TraceSymbolWithLifespan {
|
||||
/**
|
||||
* Get the code unit at this label
|
||||
*
|
||||
* @return the code unit
|
||||
*/
|
||||
TraceCodeUnit getCodeUnit();
|
||||
}
|
||||
|
|
|
@ -21,11 +21,39 @@ import ghidra.trace.model.Lifespan;
|
|||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* The label symbol view.
|
||||
*/
|
||||
public interface TraceLabelSymbolView extends TraceSymbolWithLocationView<TraceLabelSymbol> {
|
||||
|
||||
/**
|
||||
* Add a new label symbol.
|
||||
*
|
||||
* @param lifespan the lifespan of the symbol
|
||||
* @param thread the thread, if in register space
|
||||
* @param address the address of the label
|
||||
* @param name the name of the label
|
||||
* @param parent the parent namespace
|
||||
* @param source the source
|
||||
* @return the new label symbol
|
||||
* @throws InvalidInputException if the name is not valid
|
||||
*/
|
||||
TraceLabelSymbol add(Lifespan lifespan, TraceThread thread, Address address, String name,
|
||||
TraceNamespaceSymbol parent, SourceType source) throws InvalidInputException;
|
||||
|
||||
/**
|
||||
* A shorthand for
|
||||
* {@link #add(Lifespan, TraceThread, Address, String, TraceNamespaceSymbol, SourceType)} where
|
||||
* lifespan is from the given snap on.
|
||||
*
|
||||
* @param snap the starting snapshot key of the symbol
|
||||
* @param thread the thread, if in register space
|
||||
* @param address the address of the label
|
||||
* @param name the name of the label
|
||||
* @param parent the parent namespace
|
||||
* @param source the source
|
||||
* @return the new label symbol
|
||||
* @throws InvalidInputException if the name is not valid
|
||||
*/
|
||||
default TraceLabelSymbol create(long snap, TraceThread thread, Address address, String name,
|
||||
TraceNamespaceSymbol parent, SourceType source) throws InvalidInputException {
|
||||
return add(Lifespan.nowOn(snap), thread, address, name, parent, source);
|
||||
|
|
|
@ -1,22 +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.trace.model.symbol;
|
||||
|
||||
import ghidra.program.model.listing.LocalVariable;
|
||||
|
||||
public interface TraceLocalVariableSymbol extends TraceVariableSymbol, LocalVariable {
|
||||
|
||||
}
|
|
@ -1,21 +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.trace.model.symbol;
|
||||
|
||||
public interface TraceLocalVariableSymbolView
|
||||
extends TraceSymbolWithAddressNoDuplicatesView<TraceLocalVariableSymbol> {
|
||||
|
||||
}
|
|
@ -20,6 +20,9 @@ import java.util.Collection;
|
|||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
||||
/**
|
||||
* A trace namespace symbol.
|
||||
*/
|
||||
public interface TraceNamespaceSymbol extends TraceSymbol, Namespace {
|
||||
@Override
|
||||
Trace getTrace();
|
||||
|
@ -37,6 +40,11 @@ public interface TraceNamespaceSymbol extends TraceSymbol, Namespace {
|
|||
@Override
|
||||
TraceNamespaceSymbol getParentNamespace();
|
||||
|
||||
/**
|
||||
* Get the children of this namespace
|
||||
*
|
||||
* @return the children
|
||||
*/
|
||||
Collection<? extends TraceSymbol> getChildren();
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,9 +19,21 @@ import ghidra.program.model.symbol.SourceType;
|
|||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* The namespace symbol view.
|
||||
*/
|
||||
public interface TraceNamespaceSymbolView
|
||||
extends TraceSymbolNoDuplicatesView<TraceNamespaceSymbol> {
|
||||
|
||||
/**
|
||||
* Add a new namespace symbol.
|
||||
*
|
||||
* @param name the name of the namespace
|
||||
* @param parent the parent namespace
|
||||
* @param source the source
|
||||
* @return the new namespace symbol
|
||||
* @throws DuplicateNameException if the name is duplicated in the parent namespace
|
||||
* @throws InvalidInputException if the name is not valid
|
||||
*/
|
||||
TraceNamespaceSymbol add(String name, TraceNamespaceSymbol parent, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException;
|
||||
}
|
||||
|
|
|
@ -1,22 +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.trace.model.symbol;
|
||||
|
||||
import ghidra.program.model.listing.Parameter;
|
||||
|
||||
public interface TraceParameterSymbol extends TraceSymbol, Parameter {
|
||||
|
||||
}
|
|
@ -1,21 +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.trace.model.symbol;
|
||||
|
||||
public interface TraceParameterSymbolView
|
||||
extends TraceSymbolWithAddressNoDuplicatesView<TraceParameterSymbol> {
|
||||
|
||||
}
|
|
@ -17,14 +17,37 @@ package ghidra.trace.model.symbol;
|
|||
|
||||
import java.util.Collection;
|
||||
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* A trace symbol.
|
||||
*
|
||||
* <p>
|
||||
* This is essentially the equivalent concept of {@link Symbol} from a {@link Program}. One
|
||||
* important distinction is that in the trace implementation, the symbol and the object it describes
|
||||
* are the same. For example, in a {@link Program}, a {@link Namespace} and its symbol are two
|
||||
* different things. To get the namespace, you would invoke {@link Symbol#getObject()}. That is
|
||||
* unnecessary, though permissible, with a trace, because {@link TraceNamespaceSymbol} extends from
|
||||
* both {@link Namespace} and {@link Symbol}.
|
||||
*/
|
||||
public interface TraceSymbol extends Symbol {
|
||||
/**
|
||||
* Get the trace to which this symbol belongs.
|
||||
*
|
||||
* @return the trace
|
||||
*/
|
||||
Trace getTrace();
|
||||
|
||||
/**
|
||||
* If in register space, get the thread associated with this symbol.
|
||||
*
|
||||
* @return the thread
|
||||
*/
|
||||
TraceThread getThread();
|
||||
|
||||
@Override
|
||||
|
@ -42,6 +65,11 @@ public interface TraceSymbol extends Symbol {
|
|||
@Override
|
||||
TraceReference[] getReferences(TaskMonitor monitor);
|
||||
|
||||
/**
|
||||
* Get all memory references to the address of this symbol.
|
||||
*
|
||||
* @return the references
|
||||
*/
|
||||
Collection<? extends TraceReference> getReferenceCollection();
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,19 +18,32 @@ package ghidra.trace.model.symbol;
|
|||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
||||
/**
|
||||
* The symbol table for traces.
|
||||
*
|
||||
* <p>
|
||||
* Currently, functions are not supported, so effectively, the only symbol types possible in a trace
|
||||
* are: labels, namespaces, and classes. Global variables are partially implemented, but as they are
|
||||
* not finished, even in {@link Program}, they are not available in traces, either.
|
||||
*
|
||||
* <p>
|
||||
* This manager supports a "fluid" API syntax. The methods on this manager narrow the scope in terms
|
||||
* of the symbol type. Each returns a view, the methods of which operate on that type specifically.
|
||||
* For example, to get the label at a specific address:
|
||||
*
|
||||
* <pre>
|
||||
* trace.getSymbolManager().labels().getAt(0, null, addr, false);
|
||||
* </pre>
|
||||
*/
|
||||
public interface TraceSymbolManager {
|
||||
|
||||
/**
|
||||
* A comparator that sorts primary symbols first.
|
||||
*/
|
||||
static Comparator<TraceSymbol> PRIMALITY_COMPARATOR = (a, b) -> {
|
||||
boolean aFunc = a instanceof TraceFunctionSymbol;
|
||||
boolean bFunc = b instanceof TraceFunctionSymbol;
|
||||
if (aFunc && !bFunc) {
|
||||
return -1;
|
||||
}
|
||||
if (!aFunc && bFunc) {
|
||||
return 1;
|
||||
}
|
||||
boolean aPrim = a.isPrimary();
|
||||
boolean bPrim = b.isPrimary();
|
||||
if (aPrim && !bPrim) {
|
||||
|
@ -42,47 +55,94 @@ public interface TraceSymbolManager {
|
|||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the trace for this manager.
|
||||
*
|
||||
* @return the trace
|
||||
*/
|
||||
Trace getTrace();
|
||||
|
||||
/**
|
||||
* Get a symbol by its unique identifier.
|
||||
*
|
||||
* <p>
|
||||
* The identifier is only unique within this trace.
|
||||
*
|
||||
* @param symbolID the id
|
||||
* @return the symbol, or null
|
||||
*/
|
||||
TraceSymbol getSymbolByID(long symbolID);
|
||||
|
||||
/**
|
||||
* Get the trace's global namespace.
|
||||
*
|
||||
* @return the global namespace
|
||||
*/
|
||||
TraceNamespaceSymbol getGlobalNamespace();
|
||||
|
||||
/**
|
||||
* Get a view of the labels in the trace.
|
||||
*
|
||||
* @return the labels view
|
||||
*/
|
||||
TraceLabelSymbolView labels();
|
||||
|
||||
/**
|
||||
* Get a view of the namespaces in the trace.
|
||||
*
|
||||
* @return the namespaces view
|
||||
*/
|
||||
TraceNamespaceSymbolView namespaces();
|
||||
|
||||
/**
|
||||
* Get a view of the classes in the trace.
|
||||
*
|
||||
* @return the classes view
|
||||
*/
|
||||
TraceClassSymbolView classes();
|
||||
|
||||
TraceFunctionSymbolView functions();
|
||||
|
||||
TraceParameterSymbolView parameters();
|
||||
|
||||
TraceLocalVariableSymbolView localVariables();
|
||||
|
||||
TraceGlobalVariableSymbolView globalVariables();
|
||||
|
||||
/**
|
||||
* TODO: Document me
|
||||
* Get a view of all the namespaces (including classes) in the trace.
|
||||
*
|
||||
* Note because functions are namespaces, and duplicate function names are allowed, this
|
||||
* composed view may have duplicate names.
|
||||
*
|
||||
* @return
|
||||
* @return the all-namespaces view
|
||||
*/
|
||||
TraceSymbolView<? extends TraceNamespaceSymbol> allNamespaces();
|
||||
|
||||
TraceSymbolWithAddressNoDuplicatesView<? extends TraceVariableSymbol> allLocals();
|
||||
|
||||
TraceSymbolWithAddressNoDuplicatesView<? extends TraceSymbol> allVariables();
|
||||
|
||||
TraceSymbolWithLocationView<? extends TraceSymbol> labelsAndFunctions();
|
||||
|
||||
TraceSymbolNoDuplicatesView<? extends TraceSymbol> notLabelsNorFunctions();
|
||||
/**
|
||||
* Get a view of all the symbols except labels in the trace.
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE:</b> This method is somewhat vestigial. At one point, functions were partially
|
||||
* implemented, so this would have contained functions, variables, etc. As the manager now only
|
||||
* supports labels, namespaces, and classes, this is essentially the same as
|
||||
* {@link #allNamespaces()}.
|
||||
*
|
||||
* @return the not-labels view
|
||||
*/
|
||||
TraceSymbolNoDuplicatesView<? extends TraceSymbol> notLabels();
|
||||
|
||||
/**
|
||||
* Get a view of all symbols in the trace.
|
||||
*
|
||||
* @return the all-symbols view
|
||||
*/
|
||||
TraceSymbolView<? extends TraceSymbol> allSymbols();
|
||||
|
||||
/**
|
||||
* Get the set of unique symbol IDs that are added going from one snapshot to another.
|
||||
*
|
||||
* @param from the first snapshot key
|
||||
* @param to the second snapshot key
|
||||
* @return the set of IDs absent in the first but present in the second
|
||||
*/
|
||||
Collection<Long> getIDsAdded(long from, long to);
|
||||
|
||||
/**
|
||||
* Get the set of unique symbol IDs that are removed going from one snapshot to another.
|
||||
*
|
||||
* @param from the first snapshot key
|
||||
* @param to the second snapshot key
|
||||
* @return the set of IDs present in the first but absent in the second
|
||||
*/
|
||||
Collection<Long> getIDsRemoved(long from, long to);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,20 @@ package ghidra.trace.model.symbol;
|
|||
|
||||
import ghidra.util.LockHold;
|
||||
|
||||
/**
|
||||
* A symbol view where names cannot be duplicated within the same parent namespace
|
||||
*
|
||||
* @param <T> the type of symbols in the view
|
||||
*/
|
||||
public interface TraceSymbolNoDuplicatesView<T extends TraceSymbol> extends TraceSymbolView<T> {
|
||||
|
||||
/**
|
||||
* Get the child of the given parent having the given name.
|
||||
*
|
||||
* @param name the name of the symbol
|
||||
* @param parent the parent namespace
|
||||
* @return the symbol, or null
|
||||
*/
|
||||
default T getChildNamed(String name, TraceNamespaceSymbol parent) {
|
||||
try (LockHold hold = getManager().getTrace().lockRead()) {
|
||||
for (T symbol : getChildrenNamed(name, parent)) {
|
||||
|
@ -28,6 +40,13 @@ public interface TraceSymbolNoDuplicatesView<T extends TraceSymbol> extends Trac
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A shorthand for {@link #getChildNamed(String, TraceNamespaceSymbol)} where parent is the
|
||||
* global namespace.
|
||||
*
|
||||
* @param name the name of the symbol
|
||||
* @return the symbol, or null
|
||||
*/
|
||||
default T getGlobalNamed(String name) {
|
||||
return getChildNamed(name, getManager().getGlobalNamespace());
|
||||
}
|
||||
|
|
|
@ -18,44 +18,102 @@ package ghidra.trace.model.symbol;
|
|||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* A type-specific view in the trace symbol table
|
||||
*
|
||||
* <p>
|
||||
* The sub-interfaces of this handle the nuances for symbol types with more capabilities and/or
|
||||
* restrictions.
|
||||
*
|
||||
* @param <T> the type of symbols in the view
|
||||
*/
|
||||
public interface TraceSymbolView<T extends TraceSymbol> {
|
||||
|
||||
/**
|
||||
* Get the symbol manager for the trace.
|
||||
*
|
||||
* @return the symbol manager
|
||||
*/
|
||||
TraceSymbolManager getManager();
|
||||
|
||||
/**
|
||||
* Get the number of symbols in this view.
|
||||
*
|
||||
* @param includeDynamicSymbols true to include dynamically-generated symbols
|
||||
* @return the number of symbols
|
||||
*/
|
||||
default int size(boolean includeDynamicSymbols) {
|
||||
return getAll(includeDynamicSymbols).size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the symbols in this view.
|
||||
*
|
||||
* @param includeDynamicSymbols true to include dynamically-generated symbols
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
Collection<? extends T> getAll(boolean includeDynamicSymbols);
|
||||
|
||||
/**
|
||||
* Get all children of the given parent namespace having the given name in this view.
|
||||
*
|
||||
* @param name the name of the symbols
|
||||
* @param parent the parent namespace
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
Collection<? extends T> getChildrenNamed(String name, TraceNamespaceSymbol parent);
|
||||
|
||||
/**
|
||||
* Get all children of the given parent namespace in this view.
|
||||
*
|
||||
* @param parent the parent namespace
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
Collection<? extends T> getChildren(TraceNamespaceSymbol parent);
|
||||
|
||||
/**
|
||||
* A shorthand for {@link #getChildrenNamed(String, TraceNamespaceSymbol)} where parent is the
|
||||
* global namespace.
|
||||
*
|
||||
* @param name the name of the symbols
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
default Collection<? extends T> getGlobalsNamed(String name) {
|
||||
return getChildrenNamed(name, getManager().getGlobalNamespace());
|
||||
}
|
||||
|
||||
/**
|
||||
* A shorthand for {@link #getChildren(TraceNamespaceSymbol)} where parent is the global
|
||||
* namespace.
|
||||
*
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
default Collection<? extends T> getGlobals() {
|
||||
return getChildren(getManager().getGlobalNamespace());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get symbols with the given name, regardless of parent namespace
|
||||
* Get symbols in this view with the given name, regardless of parent namespace
|
||||
*
|
||||
* @param name the name
|
||||
* @return the collection of symbols with the given name
|
||||
* @param name the name of the symbols
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
Collection<? extends T> getNamed(String name);
|
||||
|
||||
/**
|
||||
* Get symbols whose names match the given glob, regardless of parent namespace
|
||||
* Get symbols in this view whose names match the given glob, regardless of parent namespace
|
||||
*
|
||||
* @param glob the glob (* matches zero-or-more, ? matches one character)
|
||||
* @param caseSensitive true to match case
|
||||
* @return the collection of matching symbols
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
Collection<? extends T> getWithMatchingName(String glob, boolean caseSensitive);
|
||||
|
||||
/**
|
||||
* Scan symbols in this view lexicographically by name starting at the given lower bound
|
||||
*
|
||||
* @param startName the starting lower bound
|
||||
* @return an iterator over symbols in this view satisfying the query
|
||||
*/
|
||||
Iterator<? extends T> scanByName(String startName);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
*/
|
||||
package ghidra.trace.model.symbol;
|
||||
|
||||
/**
|
||||
* A symbol view where names cannot be duplicated and things have an address
|
||||
*
|
||||
* @param <T> the type of symbols in the view
|
||||
*/
|
||||
public interface TraceSymbolWithAddressNoDuplicatesView<T extends TraceSymbol>
|
||||
extends TraceSymbolWithAddressView<T>, TraceSymbolNoDuplicatesView<T> {
|
||||
// Just combine the interfaces
|
||||
|
|
|
@ -21,22 +21,70 @@ import ghidra.program.model.address.Address;
|
|||
import ghidra.program.model.address.AddressRange;
|
||||
|
||||
/**
|
||||
* A view for symbols located in stack or register space not associated with a particular thread.
|
||||
* A symbol view for things with an address in stack or register space, but not associated with a
|
||||
* trace thread.
|
||||
*
|
||||
* @param <T> the type of symbol in the view
|
||||
* <p>
|
||||
* <b>NOTE:</b> This class is somewhat vestigial. It would be used to index parameters, locals, and
|
||||
* global variables by their storage addresses. However, functions (and thus parameters and locals)
|
||||
* are no longer supported. Furthermore, global variables are not fully implemented, yet.
|
||||
*
|
||||
* @implNote If this is later used for global variables, we might need to consider that the variable
|
||||
* is no longer implicitly bound in time by a parent function. We might remove this and
|
||||
* use {@link TraceSymbolWithLocationView} instead. Even if we brought back function
|
||||
* support, being able to query by those implicit bounds would probably be useful.
|
||||
*
|
||||
* @param <T> the type of symbols in the view
|
||||
*/
|
||||
public interface TraceSymbolWithAddressView<T extends TraceSymbol> extends TraceSymbolView<T> {
|
||||
|
||||
/**
|
||||
* Get the child of the given parent having the given name at the given address.
|
||||
*
|
||||
* @param name the name of the symbol
|
||||
* @param address the address of the symbol
|
||||
* @param parent the parent namespace
|
||||
* @return the symbol, or null
|
||||
*/
|
||||
T getChildWithNameAt(String name, Address address, TraceNamespaceSymbol parent);
|
||||
|
||||
/**
|
||||
* A shorthand for {@link #getChildWithNameAt(String, Address, TraceNamespaceSymbol)} where
|
||||
* parent is the global namespace.
|
||||
*
|
||||
* @param name the name of the symbol
|
||||
* @param address the address of the symbol
|
||||
* @return the symbol, or null
|
||||
*/
|
||||
default T getGlobalWithNameAt(String name, Address address) {
|
||||
return getChildWithNameAt(name, address, getManager().getGlobalNamespace());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get symbols in this view intersecting the given address range.
|
||||
*
|
||||
* @param range the range
|
||||
* @param includeDynamicSymbols true to include dynamically-generated symbols
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
Collection<? extends T> getIntersecting(AddressRange range, boolean includeDynamicSymbols);
|
||||
|
||||
/**
|
||||
* Get symbols in this view containing the given address.
|
||||
*
|
||||
* @param address the address of the symbol
|
||||
* @param includeDynamicSymbols true to include dynamically-generated symbols
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
Collection<? extends T> getAt(Address address, boolean includeDynamicSymbols);
|
||||
|
||||
/**
|
||||
* Check if this view contains any symbols at the given address.
|
||||
*
|
||||
* @param address the address of the symbol
|
||||
* @param includeDynamicSymbols true to include dynamically-generated symbols
|
||||
* @return true if any symbols in this view satisfy the query
|
||||
*/
|
||||
default boolean hasAt(Address address, boolean includeDynamicSymbols) {
|
||||
return !getAt(address, includeDynamicSymbols).isEmpty();
|
||||
}
|
||||
|
|
|
@ -17,12 +17,35 @@ package ghidra.trace.model.symbol;
|
|||
|
||||
import ghidra.trace.model.Lifespan;
|
||||
|
||||
/**
|
||||
* A trace symbol having a lifespan.
|
||||
*/
|
||||
public interface TraceSymbolWithLifespan extends TraceSymbol {
|
||||
/**
|
||||
* Get the lifespan of the symbol
|
||||
*
|
||||
* @return the lifespan
|
||||
*/
|
||||
Lifespan getLifespan();
|
||||
|
||||
/**
|
||||
* Get the minimum snapshot key in the lifespan
|
||||
*
|
||||
* @return the minimum snapshot key
|
||||
*/
|
||||
long getStartSnap();
|
||||
|
||||
/**
|
||||
* Set the maximum snapshot key in the lifespan
|
||||
*
|
||||
* @param snap the new maximum snapshot key
|
||||
*/
|
||||
void setEndSnap(long snap);
|
||||
|
||||
/**
|
||||
* Get the maximum snapshot key in the lifespan
|
||||
*
|
||||
* @return the maximum snapshot key
|
||||
*/
|
||||
long getEndSnap();
|
||||
}
|
||||
|
|
|
@ -22,28 +22,70 @@ import ghidra.trace.model.Lifespan;
|
|||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.LockHold;
|
||||
|
||||
/**
|
||||
* A symbol view for things bound by an address range and lifespan.
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE:</b> We may eventually drop the {@code thread} parameter from these methods, as we
|
||||
* transition to using register-space overlays.
|
||||
*
|
||||
* @param <T> the type of symbols in the view
|
||||
*/
|
||||
public interface TraceSymbolWithLocationView<T extends TraceSymbol> extends TraceSymbolView<T> {
|
||||
|
||||
/**
|
||||
* Get the child of the given parent having the given name at the given point.
|
||||
*
|
||||
* @param name the name of the symbol
|
||||
* @param snap the snapshot key
|
||||
* @param thread the thread, if in register space
|
||||
* @param address the address of the symbol
|
||||
* @param parent the parent namespace
|
||||
* @return the symbol, or null
|
||||
*/
|
||||
T getChildWithNameAt(String name, long snap, TraceThread thread, Address address,
|
||||
TraceNamespaceSymbol parent);
|
||||
|
||||
/**
|
||||
* A shorthand for
|
||||
* {@link #getChildWithNameAt(String, long, TraceThread, Address, TraceNamespaceSymbol)} where
|
||||
* parent is the global namespace.
|
||||
*
|
||||
* @param name the name of the symbol
|
||||
* @param snap the snapshot key
|
||||
* @param thread the thread, if in register space
|
||||
* @param address the address of the symbol
|
||||
* @return the symbol, or null
|
||||
*/
|
||||
default T getGlobalWithNameAt(String name, long snap, TraceThread thread, Address address) {
|
||||
return getChildWithNameAt(name, snap, thread, address, getManager().getGlobalNamespace());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get symbols in this view intersecting the given box.
|
||||
*
|
||||
* @param span the time bound of the box
|
||||
* @param thread the thread, if in register space
|
||||
* @param range the address bound of the box
|
||||
* @param includeDynamicSymbols true to include dynamically-generated symbols
|
||||
* @param forward true if the collection should be ordered forward by address, false for
|
||||
* backward by address.
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
Collection<? extends T> getIntersecting(Lifespan span, TraceThread thread,
|
||||
AddressRange range, boolean includeDynamicSymbols, boolean forward);
|
||||
|
||||
/**
|
||||
* Get the symbols at the given snap and address, starting with the primary
|
||||
* Get symbols in this view at the given point.
|
||||
*
|
||||
* TODO: Document me
|
||||
* <p>
|
||||
* The result will be ordered with the primary symbol first.
|
||||
*
|
||||
* @param snap
|
||||
* @param thread
|
||||
* @param address
|
||||
* @param includeDynamicSymbols
|
||||
* @return
|
||||
* @param snap the snapshot key
|
||||
* @param thread the thread, if in register space
|
||||
* @param address the address of the symbols
|
||||
* @param includeDynamicSymbols true to include dynamically-generated symbols
|
||||
* @return the symbols in this view satisfying the query
|
||||
*/
|
||||
default Collection<? extends T> getAt(long snap, TraceThread thread, Address address,
|
||||
boolean includeDynamicSymbols) {
|
||||
|
@ -56,6 +98,15 @@ public interface TraceSymbolWithLocationView<T extends TraceSymbol> extends Trac
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this view contains any symbols at the given point.
|
||||
*
|
||||
* @param snap the snapshot key
|
||||
* @param thread the thread, if in register space
|
||||
* @param address the address of the symbols
|
||||
* @param includeDynamicSymbols true to include dynamically-generated symbols
|
||||
* @return true if any symbols in this view satisfy the query
|
||||
*/
|
||||
default boolean hasAt(long snap, TraceThread thread, Address address,
|
||||
boolean includeDynamicSymbols) {
|
||||
try (LockHold hold = getManager().getTrace().lockRead()) {
|
||||
|
|
|
@ -1,23 +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.trace.model.symbol;
|
||||
|
||||
import ghidra.program.model.listing.Variable;
|
||||
|
||||
public interface TraceVariableSymbol extends TraceSymbol, Variable {
|
||||
@Override
|
||||
TraceFunctionSymbol getFunction();
|
||||
}
|
|
@ -1,435 +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.trace.database.program;
|
||||
|
||||
import static ghidra.lifecycle.Unfinished.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import db.Transaction;
|
||||
import ghidra.app.cmd.function.AddStackVarCmd;
|
||||
import ghidra.app.cmd.refs.AddStackRefCmd;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.lang.PrototypeModel;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
public class DBTraceProgramViewFunctionManagerTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
ToyDBTraceBuilder b;
|
||||
FunctionManager functionManager;
|
||||
Program program;
|
||||
Transaction tx;
|
||||
|
||||
@Before
|
||||
public void setUpFunctionManagerTest() throws IOException {
|
||||
b = new ToyDBTraceBuilder("Testing", ProgramBuilder._TOY);
|
||||
program = b.trace.getFixedProgramView(0);
|
||||
functionManager = program.getFunctionManager();
|
||||
tx = b.startTransaction();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDownFunctionManagerTest() {
|
||||
tx.close();
|
||||
b.close();
|
||||
}
|
||||
|
||||
protected Function createFunction(String name, Address entry, AddressSetView body)
|
||||
throws InvalidInputException, OverlappingFunctionException {
|
||||
Function created =
|
||||
functionManager.createFunction(name, entry, body, SourceType.USER_DEFINED);
|
||||
Function found = functionManager.getFunctionAt(entry);
|
||||
assertSame(created, found);
|
||||
assertEquals(entry, created.getEntryPoint());
|
||||
assertEquals(body, created.getBody());
|
||||
return created;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFunction() throws Exception {
|
||||
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
|
||||
// Overlapping functions - not allowed
|
||||
try {
|
||||
functionManager.createFunction("foo1", b.addr(50), b.set(b.range(50, 100)),
|
||||
SourceType.USER_DEFINED);
|
||||
Assert.fail();
|
||||
}
|
||||
catch (OverlappingFunctionException e) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
functionManager.createFunction("foo2", b.addr(200), b.set(b.range(200, 250)),
|
||||
SourceType.USER_DEFINED);
|
||||
Assert.fail();
|
||||
}
|
||||
catch (OverlappingFunctionException e) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
functionManager.createFunction("foo3", b.addr(150), b.set(b.range(150, 250)),
|
||||
SourceType.USER_DEFINED);
|
||||
Assert.fail();
|
||||
}
|
||||
catch (OverlappingFunctionException e) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Invalid entry address
|
||||
try {
|
||||
createFunction("foo4", b.addr(250), b.set(b.range(300, 350)));
|
||||
Assert.fail();
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
createFunction("foo4", b.addr(50), b.set(b.range(50, 99)));
|
||||
createFunction("foo5", b.addr(201), b.set(b.range(201, 250)));
|
||||
|
||||
// try duplicate name
|
||||
createFunction("foo5", b.addr(500), b.set(b.range(500, 600)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateVarArgFunction() throws Exception {
|
||||
|
||||
Function f = createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
f.setVarArgs(true);
|
||||
assertEquals(true, f.hasVarArgs());
|
||||
f.setVarArgs(false);
|
||||
assertEquals(false, f.hasVarArgs());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInlineFunction() throws Exception {
|
||||
|
||||
Function f = createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
assertEquals(false, f.isInline());
|
||||
f.setInline(true);
|
||||
assertEquals(true, f.isInline());
|
||||
f.setInline(false);
|
||||
assertEquals(false, f.isInline());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNoReturnFunction() throws Exception {
|
||||
|
||||
Function f = createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
assertEquals(false, f.hasNoReturn());
|
||||
f.setNoReturn(true);
|
||||
assertEquals(true, f.hasNoReturn());
|
||||
f.setNoReturn(false);
|
||||
assertEquals(false, f.hasNoReturn());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("TODO, low priority")
|
||||
public void testRemoveFunction() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(250), b.set(b.range(250, 350)));
|
||||
Function foo2 = createFunction("foo2", b.addr(201), b.set(b.range(201, 249)));
|
||||
|
||||
// add stack references and make sure they get removed when the
|
||||
// function is deleted
|
||||
int transactionIDForTest = program.startTransaction("test");
|
||||
AddStackVarCmd cmd = new AddStackVarCmd(foo2.getEntryPoint(), -4, "local_var", null,
|
||||
SourceType.USER_DEFINED);
|
||||
assertTrue(cmd.applyTo(program));
|
||||
cmd = new AddStackVarCmd(foo2.getEntryPoint(), 4, "param_1", null, SourceType.USER_DEFINED);
|
||||
assertTrue(cmd.applyTo(program));
|
||||
|
||||
AddStackRefCmd c = new AddStackRefCmd(b.addr(210), 0, -4, SourceType.USER_DEFINED);
|
||||
assertTrue(c.applyTo(program));
|
||||
c = new AddStackRefCmd(b.addr(222), 1, 4, SourceType.USER_DEFINED);
|
||||
assertTrue(c.applyTo(program));
|
||||
|
||||
program.endTransaction(transactionIDForTest, true);
|
||||
|
||||
Variable[] vars = foo2.getLocalVariables();
|
||||
assertEquals(1, vars.length);
|
||||
|
||||
ReferenceManager refMgr = program.getReferenceManager();
|
||||
TODO(); // TODO: Need to support variable references
|
||||
Reference[] vrefs = refMgr.getReferencesTo(vars[0]);
|
||||
assertEquals(1, vrefs.length);
|
||||
assertEquals(b.addr(210), vrefs[0].getFromAddress());
|
||||
|
||||
Parameter[] params = foo2.getParameters();
|
||||
assertEquals(1, params.length);
|
||||
vrefs = refMgr.getReferencesTo(params[0]);
|
||||
assertEquals(1, vrefs.length);
|
||||
assertEquals(b.addr(222), vrefs[0].getFromAddress());
|
||||
|
||||
functionManager.removeFunction(b.addr(201));
|
||||
|
||||
vrefs = refMgr.getReferencesTo(vars[0]);
|
||||
assertEquals(0, vrefs.length);
|
||||
|
||||
vrefs = refMgr.getReferencesTo(params[0]);
|
||||
assertEquals(0, vrefs.length);
|
||||
|
||||
Function f = functionManager.getFunctionAt(b.addr(100));
|
||||
assertEquals(b.set(b.range(100, 200)), f.getBody());
|
||||
assertNull(functionManager.getFunctionAt(b.addr(201)));
|
||||
f = functionManager.getFunctionAt(b.addr(250));
|
||||
assertEquals(b.set(b.range(250, 350)), f.getBody());
|
||||
|
||||
assertTrue(program.getSymbolTable()
|
||||
.getPrimarySymbol(
|
||||
b.addr(201))
|
||||
.getSymbolType() != SymbolType.FUNCTION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFirstFunctionContaining() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(250), b.set(b.range(250, 350)));
|
||||
createFunction("foo2", b.addr(201), b.set(b.range(201, 249)));
|
||||
|
||||
Function f = functionManager.getFunctionContaining(b.addr(120));
|
||||
assertEquals(b.set(b.range(100, 200)), f.getBody());
|
||||
|
||||
f = functionManager.getFunctionContaining(b.addr(240));
|
||||
assertTrue(b.set(b.range(201, 249)).equals(f.getBody()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsInFunction() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(250), b.set(b.range(250, 350)));
|
||||
createFunction("foo2", b.addr(201), b.set(b.range(201, 249)));
|
||||
assertTrue(!functionManager.isInFunction(b.addr(95)));
|
||||
assertTrue(functionManager.isInFunction(b.addr(100)));
|
||||
assertTrue(functionManager.isInFunction(b.addr(250)));
|
||||
assertTrue(functionManager.isInFunction(b.addr(240)));
|
||||
assertTrue(!functionManager.isInFunction(b.addr(500)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFunctionsContaining() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(250), b.set(b.range(250, 350)));
|
||||
createFunction("foo2", b.addr(201), b.set(b.range(201, 249)));
|
||||
|
||||
Function function = functionManager.getFunctionContaining(b.addr(160));
|
||||
assertNotNull(function);
|
||||
assertEquals(b.addr(100), function.getEntryPoint());
|
||||
function = functionManager.getFunctionContaining(b.addr(50));
|
||||
assertNull(function);
|
||||
function = functionManager.getFunctionContaining(b.addr(100));
|
||||
assertNotNull(function);
|
||||
assertEquals(b.addr(100), function.getEntryPoint());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFunctionsOverlapping() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(250), b.set(b.range(250, 350)));
|
||||
createFunction("foo2", b.addr(201), b.set(b.range(201, 249)));
|
||||
|
||||
AddressSet set = new AddressSet();
|
||||
set.addRange(b.addr(50), b.addr(100));
|
||||
set.addRange(b.addr(350), b.addr(500));
|
||||
Iterator<Function> iter = functionManager.getFunctionsOverlapping(set);
|
||||
assertEquals(b.addr(100), iter.next().getEntryPoint());
|
||||
assertEquals(b.addr(250), iter.next().getEntryPoint());
|
||||
assertTrue(!iter.hasNext());
|
||||
|
||||
iter = functionManager.getFunctionsOverlapping(b.set(b.range(99, 199)));
|
||||
assertEquals(b.addr(100), iter.next().getEntryPoint());
|
||||
assertTrue(!iter.hasNext());
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for FunctionIterator getFunctions()
|
||||
*/
|
||||
@Test
|
||||
public void testGetFunctions() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(250), b.set(b.range(250, 350)));
|
||||
createFunction("foo2", b.addr(201), b.set(b.range(201, 249)));
|
||||
|
||||
FunctionIterator iter = functionManager.getFunctions(true);
|
||||
int cnt = 0;
|
||||
while (iter.hasNext()) {
|
||||
++cnt;
|
||||
assertNotNull(iter.next());
|
||||
}
|
||||
assertEquals(3, cnt);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetReferencedFunction() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(250), b.set(b.range(250, 350)));
|
||||
Function foo2 = createFunction("foo2", b.addr(201), b.set(b.range(201, 249)));
|
||||
|
||||
program.getMemory().setInt(b.addr(50), 201);
|
||||
program.getListing().createData(b.addr(50), PointerDataType.dataType);
|
||||
// TODO: It seems this is failing because of a missing inferred reference.
|
||||
Reference cheating = program.getReferenceManager()
|
||||
.addMemoryReference(b.addr(50),
|
||||
b.addr(201), RefType.DATA, SourceType.ANALYSIS, 0);
|
||||
// TODO: Remove the explicit reference above and ensure this test still passes
|
||||
program.getReferenceManager().setPrimary(cheating, true);
|
||||
// TODO: Also remove explit set primary
|
||||
assertEquals(foo2, program.getFunctionManager().getReferencedFunction(b.addr(50)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for FunctionIterator getFunctions(Address)
|
||||
*/
|
||||
@Test
|
||||
public void testGetFunctionsAddress() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(250), b.set(b.range(250, 350)));
|
||||
createFunction("foo2", b.addr(201), b.set(b.range(201, 249)));
|
||||
|
||||
FunctionIterator iter = functionManager.getFunctions(b.addr(125), true);
|
||||
int cnt = 0;
|
||||
while (iter.hasNext()) {
|
||||
++cnt;
|
||||
assertNotNull(iter.next());
|
||||
}
|
||||
assertEquals(2, cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for FunctionIterator getFunctions(AddressSetView)
|
||||
*/
|
||||
@Test
|
||||
public void testGetFunctionsAddressSetView() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(250), b.set(b.range(250, 350)));
|
||||
createFunction("foo2", b.addr(201), b.set(b.range(201, 249)));
|
||||
|
||||
AddressSet asv = new AddressSet();
|
||||
asv.addRange(b.addr(50), b.addr(60));
|
||||
asv.addRange(b.addr(70), b.addr(90));
|
||||
asv.addRange(b.addr(110), b.addr(160));
|
||||
asv.addRange(b.addr(200), b.addr(249));
|
||||
|
||||
FunctionIterator iter = functionManager.getFunctions(asv, true);
|
||||
int cnt = 0;
|
||||
while (iter.hasNext()) {
|
||||
++cnt;
|
||||
Function f = iter.next();
|
||||
assertEquals(b.set(b.range(201, 249)), f.getBody());
|
||||
}
|
||||
assertEquals(1, cnt);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionIteratorBackwards() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(201), b.set(b.range(201, 249)));
|
||||
createFunction("foo2", b.addr(250), b.set(b.range(250, 350)));
|
||||
|
||||
FunctionIterator iter = functionManager.getFunctions(false);
|
||||
assertTrue(iter.hasNext());
|
||||
Function f = iter.next();
|
||||
assertEquals("foo2", f.getName());
|
||||
|
||||
assertTrue(iter.hasNext());
|
||||
f = iter.next();
|
||||
assertEquals("foo1", f.getName());
|
||||
|
||||
assertTrue(iter.hasNext());
|
||||
f = iter.next();
|
||||
assertEquals("foo", f.getName());
|
||||
|
||||
assertTrue(!iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionIteratorBackwards2() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(201), b.set(b.range(201, 210)));
|
||||
createFunction("foo2", b.addr(250), b.set(b.range(250, 350)));
|
||||
|
||||
FunctionIterator iter = functionManager.getFunctions(b.addr(250), false);
|
||||
assertTrue(iter.hasNext());
|
||||
Function f = iter.next();
|
||||
assertEquals("foo2", f.getName());
|
||||
|
||||
assertTrue(iter.hasNext());
|
||||
f = iter.next();
|
||||
assertEquals("foo1", f.getName());
|
||||
|
||||
assertTrue(iter.hasNext());
|
||||
f = iter.next();
|
||||
assertEquals("foo", f.getName());
|
||||
|
||||
assertTrue(!iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionIteratorBackwards3() throws Exception {
|
||||
createFunction("foo", b.addr(100), b.set(b.range(100, 200)));
|
||||
createFunction("foo1", b.addr(201), b.set(b.range(201, 210)));
|
||||
createFunction("foo2", b.addr(250), b.set(b.range(250, 350)));
|
||||
|
||||
FunctionIterator iter = functionManager.getFunctions(b.addr(300), false);
|
||||
assertTrue(iter.hasNext());
|
||||
Function f = iter.next();
|
||||
assertEquals("foo2", f.getName());
|
||||
|
||||
assertTrue(iter.hasNext());
|
||||
f = iter.next();
|
||||
assertEquals("foo1", f.getName());
|
||||
|
||||
assertTrue(iter.hasNext());
|
||||
f = iter.next();
|
||||
assertEquals("foo", f.getName());
|
||||
|
||||
assertTrue(!iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDefaultCallingConvention() throws Exception {
|
||||
PrototypeModel protoModel = functionManager.getDefaultCallingConvention();
|
||||
assertEquals("__stdcall", protoModel.getName());
|
||||
|
||||
PrototypeModel defaultModel = functionManager.getCallingConvention("default");
|
||||
assertEquals(defaultModel, protoModel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCallingConventionNames() throws Exception {
|
||||
Collection<String> names = functionManager.getCallingConventionNames();
|
||||
assertTrue(names.size() >= 1);
|
||||
for (String name : names) {
|
||||
assertNotNull(functionManager.getCallingConvention(name));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -262,11 +262,10 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
|
||||
assertEquals(Set.of(nsA, clsA), new HashSet<>(manager.allNamespaces().getAll(false)));
|
||||
assertEquals(2, manager.allNamespaces().size(false));
|
||||
assertEquals(Set.of(lab1, lab2), new HashSet<>(manager.labelsAndFunctions().getAll(false)));
|
||||
assertEquals(2, manager.labelsAndFunctions().size(false));
|
||||
assertEquals(Set.of(nsA, clsA),
|
||||
new HashSet<>(manager.notLabelsNorFunctions().getAll(false)));
|
||||
assertEquals(2, manager.notLabelsNorFunctions().size(false));
|
||||
assertEquals(Set.of(lab1, lab2), new HashSet<>(manager.labels().getAll(false)));
|
||||
assertEquals(2, manager.labels().size(false));
|
||||
assertEquals(Set.of(nsA, clsA), new HashSet<>(manager.notLabels().getAll(false)));
|
||||
assertEquals(2, manager.notLabels().size(false));
|
||||
// TODO: Remaining composites
|
||||
assertEquals(Set.of(nsA, clsA, lab1, lab2),
|
||||
new HashSet<>(manager.allSymbols().getAll(false)));
|
||||
|
@ -297,8 +296,7 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
assertEquals(Set.of(clsA), new HashSet<>(manager.classes().getChildrenNamed("A", nsA)));
|
||||
assertEquals(clsA, manager.classes().getChildNamed("A", nsA));
|
||||
assertEquals(Set.of(lab1), new HashSet<>(manager.labels().getChildrenNamed("LAB1", nsA)));
|
||||
assertEquals(Set.of(lab2),
|
||||
new HashSet<>(manager.labelsAndFunctions().getChildrenNamed("LAB2", clsA)));
|
||||
assertEquals(Set.of(lab2), new HashSet<>(manager.labels().getChildrenNamed("LAB2", clsA)));
|
||||
assertEquals(Set.of(), new HashSet<>(manager.labels().getChildrenNamed("LAB2", nsA)));
|
||||
}
|
||||
|
||||
|
@ -405,9 +403,9 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
SourceType.USER_DEFINED);
|
||||
}
|
||||
assertEquals(Set.of(lab1),
|
||||
new HashSet<>(manager.labelsAndFunctions().getWithMatchingName("LAB?", true)));
|
||||
new HashSet<>(manager.labels().getWithMatchingName("LAB?", true)));
|
||||
assertEquals(Set.of(lab1, lab2),
|
||||
new HashSet<>(manager.labelsAndFunctions().getWithMatchingName("LAB?", false)));
|
||||
new HashSet<>(manager.labels().getWithMatchingName("LAB?", false)));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -440,21 +438,19 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
}
|
||||
assertEquals(lab1,
|
||||
manager.labels().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), nsA));
|
||||
assertNull(manager.functions().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), nsA));
|
||||
assertNull(manager.labels().getChildWithNameAt("LAB2", 4, null, b.addr(0x4000), nsA));
|
||||
assertNull(manager.labels().getChildWithNameAt("LAB1", 0, null, b.addr(0x4000), nsA));
|
||||
assertNull(manager.labels()
|
||||
.getChildWithNameAt("LAB1", 4, thread,
|
||||
b.language.getRegister("r4").getAddress(), nsA));
|
||||
assertNull(manager.labels().getChildWithNameAt("LAB1", 4, null, b.addr(0x4001), nsA));
|
||||
assertNull(
|
||||
manager.labelsAndFunctions().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), clsA));
|
||||
assertNull(manager.labels().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), clsA));
|
||||
|
||||
assertEquals(lab2,
|
||||
manager.labelsAndFunctions().getChildWithNameAt("lab2", 4, null, b.addr(0x4001), clsA));
|
||||
manager.labels().getChildWithNameAt("lab2", 4, null, b.addr(0x4001), clsA));
|
||||
assertEquals(lab3,
|
||||
manager.labelsAndFunctions().getChildWithNameAt("lab3", 4, null, b.addr(0x4001), clsA));
|
||||
assertEquals(lab4, manager.labelsAndFunctions()
|
||||
manager.labels().getChildWithNameAt("lab3", 4, null, b.addr(0x4001), clsA));
|
||||
assertEquals(lab4, manager.labels()
|
||||
.getChildWithNameAt("lab4", 0, thread,
|
||||
b.language.getRegister("r4").getAddress(), nsA));
|
||||
}
|
||||
|
@ -468,8 +464,6 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
.create(4, null, b.addr(0x4000), "LAB1", global,
|
||||
SourceType.USER_DEFINED);
|
||||
}
|
||||
assertEquals(lab1,
|
||||
manager.labelsAndFunctions().getGlobalWithNameAt("LAB1", 4, null, b.addr(0x4000)));
|
||||
assertEquals(lab1, manager.labels().getGlobalWithNameAt("LAB1", 4, null, b.addr(0x4000)));
|
||||
}
|
||||
|
||||
|
@ -504,9 +498,9 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
// TODO: Test that functions are properly excluded from labels()
|
||||
// once I have a means of adding them.
|
||||
assertEquals(Set.of(),
|
||||
new HashSet<>(manager.labelsAndFunctions()
|
||||
.getIntersecting(Lifespan.span(0, 0), null,
|
||||
b.range(0x0000, 0x4000), false, true)));
|
||||
new HashSet<>(manager.labels()
|
||||
.getIntersecting(Lifespan.span(0, 0), null, b.range(0x0000, 0x4000), false,
|
||||
true)));
|
||||
assertEquals(Set.of(lab1, lab2, lab3),
|
||||
new HashSet<>(manager.labels()
|
||||
.getIntersecting(Lifespan.nowOn(0), null,
|
||||
|
@ -549,7 +543,7 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
|||
assertEquals(Set.of(lab1),
|
||||
new HashSet<>(manager.labels().getAt(4, null, b.addr(0x4000), false)));
|
||||
assertEquals(Set.of(lab2, lab3),
|
||||
new HashSet<>(manager.labelsAndFunctions().getAt(4, null, b.addr(0x4001), false)));
|
||||
new HashSet<>(manager.labels().getAt(4, null, b.addr(0x4001), false)));
|
||||
// TODO: Test ordering by setPrimary
|
||||
|
||||
assertFalse(manager.labels().hasAt(0, null, b.addr(0x4000), false));
|
||||
|
|
|
@ -177,13 +177,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
|||
return !isConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this listing is backed by a dynamic data source (e.g., debugger)
|
||||
*/
|
||||
public boolean isDynamicListing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Remove or rename this to something that accommodates redirecting writes, e.g., to a
|
||||
* debug target process, particularly for assembly, which may involve code unit modification
|
||||
|
|
|
@ -432,7 +432,10 @@ public class FunctionPlugin extends Plugin implements DataService {
|
|||
|
||||
public boolean isCreateFunctionAllowed(ListingActionContext context, boolean allowExisting,
|
||||
boolean createThunk) {
|
||||
|
||||
// Debugger traces do not support functions
|
||||
if (context.getNavigatable().isDynamic()) {
|
||||
return false;
|
||||
}
|
||||
// A program and location is needed for any create function action.
|
||||
Program program = context.getProgram();
|
||||
if (program == null) {
|
||||
|
|
|
@ -22,7 +22,6 @@ import ghidra.program.util.ProgramLocation;
|
|||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
/**
|
||||
* Interface for a symbol, which associates a string value with
|
||||
|
@ -110,7 +109,7 @@ public interface Symbol {
|
|||
|
||||
/**
|
||||
* Returns all memory references to the address of this symbol. If you do not have a
|
||||
* {@link TaskMonitor} instance, then you can pass {@link TaskMonitorAdapter#DUMMY_MONITOR} or
|
||||
* {@link TaskMonitor} instance, then you can pass {@link TaskMonitor#DUMMY} or
|
||||
* <code>null</code>.
|
||||
*
|
||||
* @return all memory references to the address of this symbol.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue