mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +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);
|
return !mode.canEdit(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDynamicListing() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWindowGroup() {
|
public String getWindowGroup() {
|
||||||
//TODO: Overriding this to align disconnected providers
|
//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
|
* 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
|
* 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
|
* libraries than an expression might like to use. The better approach would be to
|
||||||
* to incorporate a better error message into the Sleigh compiler, but it won't
|
* incorporate a better error message into the Sleigh compiler, but it won't always
|
||||||
* always know the use case for a clear message.
|
* know the use case for a clear message.
|
||||||
*/
|
*/
|
||||||
throw new SleighException("Unknown register or label: '" + nm + "'");
|
throw new SleighException("Unknown register or label: '" + nm + "'");
|
||||||
}
|
}
|
||||||
|
@ -114,9 +114,7 @@ public enum DebuggerPcodeUtils {
|
||||||
protected SleighSymbol findUserSymbol(String nm) {
|
protected SleighSymbol findUserSymbol(String nm) {
|
||||||
Trace trace = coordinates.getTrace();
|
Trace trace = coordinates.getTrace();
|
||||||
long snap = coordinates.getSnap();
|
long snap = coordinates.getSnap();
|
||||||
for (TraceSymbol symbol : trace.getSymbolManager()
|
for (TraceSymbol symbol : trace.getSymbolManager().labels().getNamed(nm)) {
|
||||||
.labelsAndFunctions()
|
|
||||||
.getNamed(nm)) {
|
|
||||||
if (symbol instanceof TraceSymbolWithLifespan lifeSym &&
|
if (symbol instanceof TraceSymbolWithLifespan lifeSym &&
|
||||||
!lifeSym.getLifespan().contains(snap)) {
|
!lifeSym.getLifespan().contains(snap)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -224,11 +224,9 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferMixin {
|
||||||
@Override
|
@Override
|
||||||
default Symbol[] getSymbols() {
|
default Symbol[] getSymbols() {
|
||||||
try (LockHold hold = getTrace().lockRead()) {
|
try (LockHold hold = getTrace().lockRead()) {
|
||||||
Collection<? extends TraceSymbol> at =
|
Collection<? extends TraceSymbol> at = getTrace().getSymbolManager()
|
||||||
getTrace().getSymbolManager()
|
.labels()
|
||||||
.labelsAndFunctions()
|
.getAt(getStartSnap(), getThread(), getAddress(), true);
|
||||||
.getAt(getStartSnap(), getThread(),
|
|
||||||
getAddress(), true);
|
|
||||||
return at.toArray(new TraceSymbol[at.size()]);
|
return at.toArray(new TraceSymbol[at.size()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,11 +234,9 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferMixin {
|
||||||
@Override
|
@Override
|
||||||
default Symbol getPrimarySymbol() {
|
default Symbol getPrimarySymbol() {
|
||||||
try (LockHold hold = getTrace().lockRead()) {
|
try (LockHold hold = getTrace().lockRead()) {
|
||||||
Collection<? extends TraceSymbol> at =
|
Collection<? extends TraceSymbol> at = getTrace().getSymbolManager()
|
||||||
getTrace().getSymbolManager()
|
.labels()
|
||||||
.labelsAndFunctions()
|
.getAt(getStartSnap(), getThread(), getAddress(), true);
|
||||||
.getAt(getStartSnap(), getThread(),
|
|
||||||
getAddress(), true);
|
|
||||||
if (at.isEmpty()) {
|
if (at.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.guest.InternalTracePlatform;
|
import ghidra.trace.database.guest.InternalTracePlatform;
|
||||||
import ghidra.trace.database.listing.UndefinedDBTraceData;
|
import ghidra.trace.database.listing.UndefinedDBTraceData;
|
||||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||||
import ghidra.trace.database.symbol.DBTraceFunctionSymbol;
|
|
||||||
import ghidra.trace.database.thread.DBTraceThread;
|
import ghidra.trace.database.thread.DBTraceThread;
|
||||||
import ghidra.trace.model.*;
|
import ghidra.trace.model.*;
|
||||||
import ghidra.trace.model.listing.*;
|
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.TraceProgramView;
|
||||||
import ghidra.trace.model.program.TraceProgramViewListing;
|
import ghidra.trace.model.program.TraceProgramViewListing;
|
||||||
import ghidra.trace.model.property.TracePropertyMapOperations;
|
import ghidra.trace.model.property.TracePropertyMapOperations;
|
||||||
import ghidra.trace.model.symbol.TraceFunctionSymbol;
|
|
||||||
import ghidra.trace.util.*;
|
import ghidra.trace.util.*;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.AddressIteratorAdapter;
|
import ghidra.util.AddressIteratorAdapter;
|
||||||
|
@ -867,13 +865,13 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceFunctionSymbol createFunction(String name, Address entryPoint, AddressSetView body,
|
public Function createFunction(String name, Address entryPoint, AddressSetView body,
|
||||||
SourceType source) throws InvalidInputException, OverlappingFunctionException {
|
SourceType source) throws InvalidInputException, OverlappingFunctionException {
|
||||||
return program.functionManager.createFunction(name, entryPoint, body, source);
|
return program.functionManager.createFunction(name, entryPoint, body, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceFunctionSymbol createFunction(String name, Namespace nameSpace, Address entryPoint,
|
public Function createFunction(String name, Namespace nameSpace, Address entryPoint,
|
||||||
AddressSetView body, SourceType source)
|
AddressSetView body, SourceType source)
|
||||||
throws InvalidInputException, OverlappingFunctionException {
|
throws InvalidInputException, OverlappingFunctionException {
|
||||||
return program.functionManager.createFunction(name, nameSpace, entryPoint, body, source);
|
return program.functionManager.createFunction(name, nameSpace, entryPoint, body, source);
|
||||||
|
@ -891,22 +889,12 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Function> getGlobalFunctions(String name) {
|
public List<Function> getGlobalFunctions(String name) {
|
||||||
return new ArrayList<>(program.trace.getSymbolManager().functions().getGlobalsNamed(name));
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Function> getFunctions(String namespace, String name) {
|
public List<Function> getFunctions(String namespace, String name) {
|
||||||
// NOTE: This implementation allows namespaces to contain the separator symbol
|
return List.of();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -916,7 +904,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionIterator getExternalFunctions() {
|
public FunctionIterator getExternalFunctions() {
|
||||||
return program.functionManager.getExternalFunctions();
|
return EmptyFunctionIterator.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -47,10 +47,10 @@ import ghidra.trace.database.*;
|
||||||
import ghidra.trace.database.listing.DBTraceCodeSpace;
|
import ghidra.trace.database.listing.DBTraceCodeSpace;
|
||||||
import ghidra.trace.database.listing.DBTraceDefinedUnitsView;
|
import ghidra.trace.database.listing.DBTraceDefinedUnitsView;
|
||||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||||
import ghidra.trace.database.symbol.DBTraceFunctionSymbolView;
|
|
||||||
import ghidra.trace.model.*;
|
import ghidra.trace.model.*;
|
||||||
import ghidra.trace.model.Trace.*;
|
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.TraceBookmark;
|
||||||
import ghidra.trace.model.bookmark.TraceBookmarkType;
|
import ghidra.trace.model.bookmark.TraceBookmarkType;
|
||||||
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||||
|
@ -129,22 +129,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
listenFor(TraceDataTypeChangeType.RENAMED, this::dataTypeRenamed);
|
listenFor(TraceDataTypeChangeType.RENAMED, this::dataTypeRenamed);
|
||||||
listenFor(TraceDataTypeChangeType.DELETED, this::dataTypeDeleted);
|
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,
|
listenFor(TraceInstructionChangeType.FLOW_OVERRIDE_CHANGED,
|
||||||
this::instructionFlowOverrideChanged);
|
this::instructionFlowOverrideChanged);
|
||||||
listenFor(TraceInstructionChangeType.FALL_THROUGH_OVERRIDE_CHANGED,
|
listenFor(TraceInstructionChangeType.FALL_THROUGH_OVERRIDE_CHANGED,
|
||||||
|
@ -465,107 +449,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
null, null, oldPath, newIsNull));
|
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,
|
private void instructionFlowOverrideChanged(TraceAddressSpace space,
|
||||||
TraceInstruction instruction, FlowOverride oldOverride, FlowOverride newOverride) {
|
TraceInstruction instruction, FlowOverride oldOverride, FlowOverride newOverride) {
|
||||||
DomainObjectEventQueues queues = isCodeVisible(space, instruction);
|
DomainObjectEventQueues queues = isCodeVisible(space, instruction);
|
||||||
|
@ -667,39 +550,12 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
null, null, id, null, null));
|
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) {
|
private void symbolAdded(TraceAddressSpace space, TraceSymbol symbol) {
|
||||||
DomainObjectEventQueues queues = isSymbolVisible(space, symbol);
|
DomainObjectEventQueues queues = isSymbolVisible(space, symbol);
|
||||||
if (queues == null) {
|
if (queues == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fireSymbolAdded(queues, symbol);
|
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) {
|
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,
|
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_SOURCE_CHANGED,
|
||||||
symbol.getAddress(), symbol.getAddress(), symbol, null, null));
|
symbol.getAddress(), symbol.getAddress(), symbol, null, null));
|
||||||
checkVariableFunctionChanged(space, symbol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void symbolSetAsPrimary(TraceAddressSpace space, TraceSymbol symbol,
|
private void symbolSetAsPrimary(TraceAddressSpace space, TraceSymbol symbol,
|
||||||
|
@ -731,7 +586,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
assert oldQueues == newQueues || oldQueues == null;
|
assert oldQueues == newQueues || oldQueues == null;
|
||||||
newQueues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_SET_AS_PRIMARY,
|
newQueues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_SET_AS_PRIMARY,
|
||||||
symbol.getAddress(), symbol.getAddress(), null, oldPrimary, newPrimary));
|
symbol.getAddress(), symbol.getAddress(), null, oldPrimary, newPrimary));
|
||||||
checkVariableFunctionChanged(space, symbol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void symbolRenamed(TraceAddressSpace space, TraceSymbol symbol, String oldName,
|
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,
|
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_RENAMED,
|
||||||
symbol.getAddress(), symbol.getAddress(), symbol, oldName, newName));
|
symbol.getAddress(), symbol.getAddress(), symbol, oldName, newName));
|
||||||
checkVariableFunctionChanged(space, symbol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void symbolParentChanged(TraceAddressSpace space, TraceSymbol 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,
|
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_SCOPE_CHANGED,
|
||||||
symbol.getAddress(), symbol.getAddress(), symbol, oldParent, newParent));
|
symbol.getAddress(), symbol.getAddress(), symbol, oldParent, newParent));
|
||||||
checkVariableFunctionChanged(space, symbol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void symbolAssociationAdded(TraceAddressSpace space, TraceSymbol 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,
|
queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_ADDRESS_CHANGED,
|
||||||
oldAddress, oldAddress, symbol, oldAddress, newAddress));
|
oldAddress, oldAddress, symbol, oldAddress, newAddress));
|
||||||
checkVariableFunctionChanged(space, symbol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void symbolLifespanChanged(TraceAddressSpace space, TraceSymbolWithLifespan symbol,
|
private void symbolLifespanChanged(TraceAddressSpace space, TraceSymbolWithLifespan symbol,
|
||||||
|
@ -799,20 +650,9 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
boolean inNew = isSymbolWithLifespanVisible(symbol, newSpan);
|
boolean inNew = isSymbolWithLifespanVisible(symbol, newSpan);
|
||||||
if (inOld && !inNew) {
|
if (inOld && !inNew) {
|
||||||
fireSymbolRemoved(queues, symbol);
|
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) {
|
if (!inOld && inNew) {
|
||||||
fireSymbolAdded(queues, symbol);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
fireSymbolRemoved(queues, symbol);
|
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) {
|
protected void fireSymbolRemoved(DomainObjectEventQueues queues, TraceSymbol symbol) {
|
||||||
|
@ -1775,51 +1608,8 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
return getEventQueues(space);
|
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,
|
protected boolean isSymbolWithLifespanVisible(TraceSymbolWithLifespan symbol,
|
||||||
Lifespan lifespan) {
|
Lifespan lifespan) {
|
||||||
if (symbol instanceof TraceFunctionSymbol) {
|
|
||||||
TraceFunctionSymbol func = (TraceFunctionSymbol) symbol;
|
|
||||||
return isFunctionVisible(func, lifespan);
|
|
||||||
}
|
|
||||||
if (!viewport.containsAnyUpper(lifespan)) {
|
if (!viewport.containsAnyUpper(lifespan)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1832,14 +1622,6 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
if (queues == null) {
|
if (queues == null) {
|
||||||
return 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)) {
|
if (!(symbol instanceof TraceSymbolWithLifespan)) {
|
||||||
return queues;
|
return queues;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,28 +15,20 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.database.program;
|
package ghidra.trace.database.program;
|
||||||
|
|
||||||
import static ghidra.lifecycle.Unfinished.*;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import generic.NestedIterator;
|
|
||||||
import ghidra.program.database.ProgramDB;
|
import ghidra.program.database.ProgramDB;
|
||||||
import ghidra.program.database.function.OverlappingFunctionException;
|
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.lang.PrototypeModel;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.symbol.Namespace;
|
import ghidra.program.model.symbol.Namespace;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.trace.database.DBTraceUtils;
|
import ghidra.trace.database.symbol.DBTraceNamespaceSymbol;
|
||||||
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.util.EmptyFunctionIterator;
|
import ghidra.trace.util.EmptyFunctionIterator;
|
||||||
import ghidra.trace.util.WrappingFunctionIterator;
|
|
||||||
import ghidra.util.LockHold;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
@ -44,12 +36,10 @@ import ghidra.util.task.TaskMonitor;
|
||||||
public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
||||||
|
|
||||||
protected final DBTraceProgramView program;
|
protected final DBTraceProgramView program;
|
||||||
protected final DBTraceFunctionSymbolView functions;
|
|
||||||
protected final DBTraceNamespaceSymbol global;
|
protected final DBTraceNamespaceSymbol global;
|
||||||
|
|
||||||
public DBTraceProgramViewFunctionManager(DBTraceProgramView program) {
|
public DBTraceProgramViewFunctionManager(DBTraceProgramView program) {
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.functions = program.trace.getSymbolManager().functions();
|
|
||||||
this.global = program.trace.getSymbolManager().getGlobalNamespace();
|
this.global = program.trace.getSymbolManager().getGlobalNamespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,135 +50,69 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionTagManager getFunctionTagManager() {
|
public FunctionTagManager getFunctionTagManager() {
|
||||||
return TODO();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<String> getCallingConventionNames() {
|
public Collection<String> getCallingConventionNames() {
|
||||||
return functions.getCallingConventionNames();
|
return Stream.of(program.trace.getBaseCompilerSpec().getCallingConventions())
|
||||||
|
.map(PrototypeModel::getName)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrototypeModel getDefaultCallingConvention() {
|
public PrototypeModel getDefaultCallingConvention() {
|
||||||
return functions.getDefaultCallingConvention();
|
return program.trace.getBaseCompilerSpec().getDefaultCallingConvention();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrototypeModel getCallingConvention(String name) {
|
public PrototypeModel getCallingConvention(String name) {
|
||||||
return functions.getCallingConvention(name);
|
return program.trace.getBaseCompilerSpec().getCallingConvention(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceFunctionSymbol createFunction(String name, Address entryPoint, AddressSetView body,
|
public Function createFunction(String name, Address entryPoint, AddressSetView body,
|
||||||
SourceType source) throws InvalidInputException, OverlappingFunctionException {
|
SourceType source) throws InvalidInputException, OverlappingFunctionException {
|
||||||
return functions.create(program.snap, entryPoint, body, name, null, global, source);
|
throw new UnsupportedOperationException();
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceFunctionSymbol createFunction(String name, Namespace nameSpace, Address entryPoint,
|
public Function createFunction(String name, Namespace nameSpace, Address entryPoint,
|
||||||
AddressSetView body, SourceType source)
|
AddressSetView body, SourceType source)
|
||||||
throws InvalidInputException, OverlappingFunctionException {
|
throws InvalidInputException, OverlappingFunctionException {
|
||||||
return functions.create(program.snap, entryPoint, body, name, null,
|
throw new UnsupportedOperationException();
|
||||||
validateParent(nameSpace), source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceFunctionSymbol createThunkFunction(String name, Namespace nameSpace,
|
public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint,
|
||||||
Address entryPoint, AddressSetView body, Function thunkedFunction, SourceType source)
|
AddressSetView body, Function thunkedFunction, SourceType source)
|
||||||
throws OverlappingFunctionException {
|
throws OverlappingFunctionException {
|
||||||
try {
|
throw new UnsupportedOperationException();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getFunctionCount() {
|
public int getFunctionCount() {
|
||||||
return functions.size(false); // NOTE: May include those not at this snap
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeFunction(Address entryPoint) {
|
public boolean removeFunction(Address entryPoint) {
|
||||||
try (LockHold hold = program.trace.lockWrite()) {
|
return false;
|
||||||
TraceFunctionSymbol at = getFunctionAt(entryPoint);
|
|
||||||
if (at == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
at.delete();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceFunctionSymbol getFunctionAt(Address entryPoint) {
|
public Function 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceFunctionSymbol getReferencedFunction(Address address) {
|
public Function 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;
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Iterator<? extends DBTraceFunctionSymbol> getFunctionsInRange(AddressRange range,
|
@Override
|
||||||
boolean forward) {
|
public Function getFunctionContaining(Address addr) {
|
||||||
return functions.getIntersecting(Lifespan.at(program.snap), null, range, false,
|
return null;
|
||||||
forward).iterator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -198,52 +122,27 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionIterator getFunctions(Address start, boolean forward) {
|
public FunctionIterator getFunctions(Address start, boolean forward) {
|
||||||
return getFunctions(DBTraceUtils.getAddressSet(program.getAddressFactory(), start, forward),
|
return EmptyFunctionIterator.INSTANCE;
|
||||||
forward);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionIterator getFunctions(AddressSetView asv, boolean forward) {
|
public FunctionIterator getFunctions(AddressSetView asv, boolean forward) {
|
||||||
return new WrappingFunctionIterator(
|
return EmptyFunctionIterator.INSTANCE;
|
||||||
NestedIterator.start(asv.iterator(forward), rng -> getFunctionsInRange(rng, forward)),
|
|
||||||
f -> {
|
|
||||||
if (!asv.contains(f.getEntryPoint())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionIterator getFunctionsNoStubs(boolean forward) {
|
public FunctionIterator getFunctionsNoStubs(boolean forward) {
|
||||||
return getFunctionsNoStubs(program.getAddressFactory().getAddressSet(), forward);
|
return EmptyFunctionIterator.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionIterator getFunctionsNoStubs(Address start, boolean forward) {
|
public FunctionIterator getFunctionsNoStubs(Address start, boolean forward) {
|
||||||
return getFunctionsNoStubs(
|
return EmptyFunctionIterator.INSTANCE;
|
||||||
DBTraceUtils.getAddressSet(program.getAddressFactory(), start, forward), forward);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionIterator getFunctionsNoStubs(AddressSetView asv, boolean forward) {
|
public FunctionIterator getFunctionsNoStubs(AddressSetView asv, boolean forward) {
|
||||||
return new WrappingFunctionIterator(
|
return EmptyFunctionIterator.INSTANCE;
|
||||||
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;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -253,8 +152,7 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInFunction(Address addr) {
|
public boolean isInFunction(Address addr) {
|
||||||
// TODO: Could use idMap directly to avoid loading the function
|
return false;
|
||||||
return getFunctionContaining(addr) != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -266,12 +164,7 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
||||||
@Override
|
@Override
|
||||||
public void deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
public void deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
Iterator<? extends DBTraceFunctionSymbol> it =
|
// Do nothing
|
||||||
getFunctionsInRange(new AddressRangeImpl(startAddr, endAddr), true);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
|
||||||
it.next().delete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -287,28 +180,22 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invalidateCache(boolean all) {
|
public void invalidateCache(boolean all) {
|
||||||
throw new UnsupportedOperationException();
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Function> getFunctionsOverlapping(AddressSetView set) {
|
public Iterator<Function> getFunctionsOverlapping(AddressSetView set) {
|
||||||
return new WrappingFunctionIterator(
|
return Collections.emptyIterator();
|
||||||
NestedIterator.start(set.iterator(true), rng -> getFunctionsInRange(rng, true)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Variable getReferencedVariable(Address instrAddr, Address storageAddr, int size,
|
public Variable getReferencedVariable(Address instrAddr, Address storageAddr, int size,
|
||||||
boolean isRead) {
|
boolean isRead) {
|
||||||
TraceFunctionSymbol function = getFunctionContaining(instrAddr);
|
return null;
|
||||||
if (function == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return DBTraceFunctionSymbolView.getReferencedVariable(function, instrAddr, storageAddr,
|
|
||||||
size, isRead, program.language);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceFunctionSymbol getFunction(long key) {
|
public Function getFunction(long key) {
|
||||||
return functions.getByKey(key);
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,14 +144,9 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T extends TraceSymbol> T requireVisible(T sym) {
|
protected <T extends TraceSymbol> T requireVisible(T sym) {
|
||||||
if (!(sym instanceof TraceSymbolWithLifespan)) {
|
if (!(sym instanceof TraceSymbolWithLifespan wl)) {
|
||||||
return sym;
|
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())) {
|
if (program.viewport.containsAnyUpper(wl.getLifespan())) {
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
@ -210,9 +205,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
TraceNamespaceSymbol parent = assertTraceNamespace(namespace);
|
TraceNamespaceSymbol parent = assertTraceNamespace(namespace);
|
||||||
try (LockHold hold = program.trace.lockRead()) {
|
try (LockHold hold = program.trace.lockRead()) {
|
||||||
List<Symbol> result = new ArrayList<>();
|
List<Symbol> result = new ArrayList<>();
|
||||||
for (TraceSymbol sym : symbolManager.labelsAndFunctions()
|
for (TraceSymbol sym : symbolManager.labels().getChildrenNamed(name, parent)) {
|
||||||
.getChildrenNamed(name,
|
|
||||||
parent)) {
|
|
||||||
if (requireVisible(sym) != null) {
|
if (requireVisible(sym) != null) {
|
||||||
result.add(sym);
|
result.add(sym);
|
||||||
}
|
}
|
||||||
|
@ -239,17 +232,17 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol getParameterSymbol(String name, Namespace namespace) {
|
public Symbol getParameterSymbol(String name, Namespace namespace) {
|
||||||
return symbolManager.parameters().getChildNamed(name, assertTraceNamespace(namespace));
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol getLocalVariableSymbol(String name, Namespace namespace) {
|
public Symbol getLocalVariableSymbol(String name, Namespace namespace) {
|
||||||
return symbolManager.localVariables().getChildNamed(name, assertTraceNamespace(namespace));
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol getVariableSymbol(String name, Function function) {
|
public Symbol getVariableSymbol(String name, Function function) {
|
||||||
return symbolManager.allVariables().getChildNamed(name, assertTraceNamespace(function));
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -279,7 +272,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
public Symbol getPrimarySymbol(Address addr) {
|
public Symbol getPrimarySymbol(Address addr) {
|
||||||
try (LockHold hold = program.trace.lockRead()) {
|
try (LockHold hold = program.trace.lockRead()) {
|
||||||
Collection<? extends TraceSymbol> at =
|
Collection<? extends TraceSymbol> at =
|
||||||
symbolManager.labelsAndFunctions().getAt(program.snap, null, addr, true);
|
symbolManager.labels().getAt(program.snap, null, addr, true);
|
||||||
if (at.isEmpty()) {
|
if (at.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -291,7 +284,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
public Symbol[] getSymbols(Address addr) {
|
public Symbol[] getSymbols(Address addr) {
|
||||||
try (LockHold hold = program.trace.lockRead()) {
|
try (LockHold hold = program.trace.lockRead()) {
|
||||||
Collection<? extends TraceSymbol> at =
|
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()]);
|
return at.toArray(new Symbol[at.size()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +300,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
public Symbol[] getUserSymbols(Address addr) {
|
public Symbol[] getUserSymbols(Address addr) {
|
||||||
try (LockHold hold = program.trace.lockRead()) {
|
try (LockHold hold = program.trace.lockRead()) {
|
||||||
Collection<? extends TraceSymbol> at =
|
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()]);
|
return at.toArray(new Symbol[at.size()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,10 +324,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSymbol(Address addr) {
|
public boolean hasSymbol(Address addr) {
|
||||||
if (addr.isMemoryAddress()) {
|
if (addr.isMemoryAddress()) {
|
||||||
return symbolManager.labelsAndFunctions().hasAt(program.snap, null, addr, true);
|
return symbolManager.labels().hasAt(program.snap, null, addr, true);
|
||||||
}
|
|
||||||
if (addr.getAddressSpace().isRegisterSpace() || addr.isStackAddress()) {
|
|
||||||
return symbolManager.allVariables().hasAt(addr, true);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -360,23 +350,6 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
.getIntersecting(Lifespan.at(program.snap), null, range, true, forward)
|
.getIntersecting(Lifespan.at(program.snap), null, range, true, forward)
|
||||||
.iterator();
|
.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();
|
return Collections.emptyIterator();
|
||||||
}));
|
}));
|
||||||
|
@ -437,8 +410,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolIterator getSymbolIterator(Address startAddr, boolean forward) {
|
public SymbolIterator getSymbolIterator(Address startAddr, boolean forward) {
|
||||||
return new SymbolIteratorAdapter(getSymbolIteratorAtMySnap(
|
return new SymbolIteratorAdapter(getSymbolIteratorAtMySnap(symbolManager.labels(),
|
||||||
symbolManager.labelsAndFunctions(),
|
|
||||||
DBTraceUtils.getAddressSet(program.language.getAddressFactory(), startAddr, forward),
|
DBTraceUtils.getAddressSet(program.language.getAddressFactory(), startAddr, forward),
|
||||||
true, forward));
|
true, forward));
|
||||||
}
|
}
|
||||||
|
@ -456,7 +428,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
@Override
|
@Override
|
||||||
public SymbolIterator getPrimarySymbolIterator(AddressSetView asv, boolean forward) {
|
public SymbolIterator getPrimarySymbolIterator(AddressSetView asv, boolean forward) {
|
||||||
return new PrimarySymbolIterator(NestedIterator.start(asv.iterator(forward),
|
return new PrimarySymbolIterator(NestedIterator.start(asv.iterator(forward),
|
||||||
range -> symbolManager.labelsAndFunctions()
|
range -> symbolManager.labels()
|
||||||
.getIntersecting(Lifespan.at(program.snap), null, range, true, forward)
|
.getIntersecting(Lifespan.at(program.snap), null, range, true, forward)
|
||||||
.iterator()));
|
.iterator()));
|
||||||
}
|
}
|
||||||
|
@ -501,20 +473,13 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
||||||
// NOTE: Currently, traces do not allow namespaces to have arbitrary bodies.
|
// NOTE: Currently, traces do not allow namespaces to have arbitrary bodies.
|
||||||
// Instead, their bodies are the union of addresses of their descendants.
|
// Instead, their bodies are the union of addresses of their descendants.
|
||||||
if (addr.isMemoryAddress()) {
|
if (addr.isMemoryAddress()) {
|
||||||
for (TraceSymbol sym : symbolManager.labelsAndFunctions()
|
for (TraceSymbol sym : symbolManager.labels().getAt(program.snap, null, addr, true)) {
|
||||||
.getAt(program.snap, null,
|
|
||||||
addr, true)) {
|
|
||||||
if (sym instanceof TraceNamespaceSymbol /* Function */) {
|
if (sym instanceof TraceNamespaceSymbol /* Function */) {
|
||||||
return (TraceNamespaceSymbol) sym;
|
return (TraceNamespaceSymbol) sym;
|
||||||
}
|
}
|
||||||
return sym.getParentNamespace();
|
return sym.getParentNamespace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (addr.getAddressSpace().isRegisterSpace() || addr.isStackAddress()) {
|
|
||||||
for (TraceSymbol sym : symbolManager.allVariables().getAt(addr, true)) {
|
|
||||||
return sym.getParentNamespace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return symbolManager.getGlobalNamespace();
|
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() {
|
public boolean setPrimary() {
|
||||||
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
try (LockHold hold = LockHold.lock(manager.lock.writeLock())) {
|
||||||
AddressRangeImpl range = new AddressRangeImpl(address, address);
|
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);
|
boolean result = doSetPrimary(true);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
Address toAddress = getToAddress();
|
Address toAddress = getToAddress();
|
||||||
if (dbSym instanceof AbstractDBTraceVariableSymbol) {
|
if (!Objects.equals(symbol.getAddress(), toAddress)) {
|
||||||
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)) {
|
|
||||||
throw new IllegalArgumentException(String.format(
|
throw new IllegalArgumentException(String.format(
|
||||||
"Symbol address (%s) of '%s' must match Reference's to address (%s)",
|
"Symbol address (%s) of '%s' must match Reference's to address (%s)",
|
||||||
symbol.getAddress(), symbol.getName(), toAddress));
|
symbol.getAddress(), symbol.getName(), toAddress));
|
||||||
|
|
|
@ -21,10 +21,12 @@ import java.util.*;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
|
||||||
import db.*;
|
import db.*;
|
||||||
|
import ghidra.lifecycle.Internal;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.Language;
|
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.program.model.symbol.*;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.DBTraceManager;
|
import ghidra.trace.database.DBTraceManager;
|
||||||
|
@ -37,7 +39,6 @@ import ghidra.trace.database.space.DBTraceSpaceKey;
|
||||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||||
import ghidra.trace.model.Lifespan;
|
import ghidra.trace.model.Lifespan;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.Trace.TraceFunctionTagChangeType;
|
|
||||||
import ghidra.trace.model.Trace.TraceSymbolChangeType;
|
import ghidra.trace.model.Trace.TraceSymbolChangeType;
|
||||||
import ghidra.trace.model.symbol.*;
|
import ghidra.trace.model.symbol.*;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
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
|
public static class VariableStorageDBFieldCodec extends
|
||||||
AbstractDBFieldCodec<VariableStorage, DBTraceVariableStorageEntry, StringField> {
|
AbstractDBFieldCodec<VariableStorage, DBTraceVariableStorageEntry, StringField> {
|
||||||
|
|
||||||
|
@ -351,25 +194,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
CLASS {
|
CLASS {
|
||||||
@Override
|
@Override
|
||||||
boolean isValidParent(DBTraceNamespaceSymbol parent) {
|
boolean isValidParent(DBTraceNamespaceSymbol parent) {
|
||||||
return isNoFunctionAncestor(parent);
|
return true;
|
||||||
}
|
|
||||||
},
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GLOBAL_VAR {
|
GLOBAL_VAR {
|
||||||
|
@ -382,15 +207,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
public static final List<MySymbolTypes> VALUES = List.of(values());
|
public static final List<MySymbolTypes> VALUES = List.of(values());
|
||||||
|
|
||||||
abstract boolean isValidParent(DBTraceNamespaceSymbol parent);
|
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;
|
protected final DBTrace trace;
|
||||||
|
@ -401,41 +217,23 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
|
|
||||||
protected final DBTraceAddressSnapRangePropertyMap<Long, DBTraceSymbolIDEntry> idMap;
|
protected final DBTraceAddressSnapRangePropertyMap<Long, DBTraceSymbolIDEntry> idMap;
|
||||||
|
|
||||||
protected final DBCachedObjectStore<DBTraceFunctionTag> tagStore;
|
// NB. This is unused since the purging of trace function symbols
|
||||||
protected final DBCachedObjectIndex<String, DBTraceFunctionTag> tagsByName;
|
// In theory, may get used by global variables.
|
||||||
|
|
||||||
protected final DBCachedObjectStore<DBTraceFunctionTagMapping> tagMappingStore;
|
|
||||||
protected final DBCachedObjectIndex<Long, DBTraceFunctionTagMapping> tagMappingsByFunc;
|
|
||||||
protected final DBCachedObjectIndex<Long, DBTraceFunctionTagMapping> tagMappingsByTag;
|
|
||||||
|
|
||||||
protected final DBCachedObjectStore<DBTraceVariableStorageEntry> storageStore;
|
protected final DBCachedObjectStore<DBTraceVariableStorageEntry> storageStore;
|
||||||
protected final DBCachedObjectIndex<VariableStorage, DBTraceVariableStorageEntry> storageByStorage;
|
protected final DBCachedObjectIndex<VariableStorage, DBTraceVariableStorageEntry> storageByStorage;
|
||||||
|
|
||||||
protected final DBCachedObjectStore<DBTraceLabelSymbol> labelStore;
|
protected final DBCachedObjectStore<DBTraceLabelSymbol> labelStore;
|
||||||
protected final DBCachedObjectStore<DBTraceNamespaceSymbol> namespaceStore;
|
protected final DBCachedObjectStore<DBTraceNamespaceSymbol> namespaceStore;
|
||||||
protected final DBCachedObjectStore<DBTraceClassSymbol> classStore;
|
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 DBTraceNamespaceSymbol globalNamespace;
|
||||||
|
|
||||||
protected final DBTraceLabelSymbolView labels;
|
protected final DBTraceLabelSymbolView labels;
|
||||||
protected final DBTraceNamespaceSymbolView namespaces;
|
protected final DBTraceNamespaceSymbolView namespaces;
|
||||||
protected final DBTraceClassSymbolView classes;
|
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 DBTraceSymbolMultipleTypesView<? extends DBTraceNamespaceSymbol> allNamespaces;
|
||||||
protected final DBTraceSymbolMultipleTypesNoDuplicatesView<? extends DBTraceNamespaceSymbol> uniqueNamespaces;
|
protected final DBTraceSymbolMultipleTypesNoDuplicatesView<? extends DBTraceNamespaceSymbol> uniqueNamespaces;
|
||||||
protected final DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView<? extends AbstractDBTraceVariableSymbol> allLocals;
|
protected final DBTraceSymbolMultipleTypesNoDuplicatesView<?> notLabels;
|
||||||
protected final DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView<?> allVariables;
|
|
||||||
protected final DBTraceSymbolMultipleTypesWithLocationView<?> labelsAndFunctions;
|
|
||||||
protected final DBTraceSymbolMultipleTypesNoDuplicatesView<?> notLabelsNorFunctions;
|
|
||||||
protected final DBTraceSymbolMultipleTypesView<?> allSymbols;
|
protected final DBTraceSymbolMultipleTypesView<?> allSymbols;
|
||||||
|
|
||||||
protected final Map<Byte, AbstractDBTraceSymbolSingleTypeView<?>> symbolViews = new HashMap<>();
|
protected final Map<Byte, AbstractDBTraceSymbolSingleTypeView<?>> symbolViews = new HashMap<>();
|
||||||
|
@ -457,17 +255,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
baseLanguage, trace, threadManager, DBTraceSymbolIDEntry.class,
|
baseLanguage, trace, threadManager, DBTraceSymbolIDEntry.class,
|
||||||
DBTraceSymbolIDEntry::new);
|
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,
|
storageStore = factory.getOrCreateCachedStore(DBTraceVariableStorageEntry.TABLE_NAME,
|
||||||
DBTraceVariableStorageEntry.class,
|
DBTraceVariableStorageEntry.class,
|
||||||
(s, r) -> new DBTraceVariableStorageEntry(this, s, r), true);
|
(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);
|
DBTraceNamespaceSymbol.class, (s, r) -> new DBTraceNamespaceSymbol(this, s, r), true);
|
||||||
classStore = factory.getOrCreateCachedStore(DBTraceClassSymbol.TABLE_NAME,
|
classStore = factory.getOrCreateCachedStore(DBTraceClassSymbol.TABLE_NAME,
|
||||||
DBTraceClassSymbol.class, (s, r) -> new DBTraceClassSymbol(this, s, r), true);
|
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();
|
globalNamespace = getOrCreateGlobalNamespace();
|
||||||
|
|
||||||
|
@ -499,25 +274,13 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
labels = putInMap(new DBTraceLabelSymbolView(this));
|
labels = putInMap(new DBTraceLabelSymbolView(this));
|
||||||
namespaces = putInMap(new DBTraceNamespaceSymbolView(this));
|
namespaces = putInMap(new DBTraceNamespaceSymbolView(this));
|
||||||
classes = putInMap(new DBTraceClassSymbolView(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 =
|
uniqueNamespaces =
|
||||||
new DBTraceSymbolMultipleTypesNoDuplicatesView<>(this, namespaces, classes);
|
new DBTraceSymbolMultipleTypesNoDuplicatesView<>(this, namespaces, classes);
|
||||||
allLocals = new DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView<>(this, parameters,
|
notLabels =
|
||||||
localVars);
|
new DBTraceSymbolMultipleTypesNoDuplicatesView<>(this, namespaces, classes);
|
||||||
allVariables = new DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView<>(this, parameters,
|
allSymbols = new DBTraceSymbolMultipleTypesView<>(this, labels, namespaces, classes);
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DataType checkIndirection(VariableStorage s, DataType formal) {
|
protected DataType checkIndirection(VariableStorage s, DataType formal) {
|
||||||
|
@ -595,8 +358,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
public void replaceDataTypes(long oldID, long newID) {
|
public void replaceDataTypes(long oldID, long newID) {
|
||||||
// TODO Auto-generated method stub
|
// Would apply to functions and variables, but those are not supported.
|
||||||
// DataTypes of Function returns, params, locals, globalRegs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertValidThreadAddress(TraceThread thread, Address address) {
|
protected void assertValidThreadAddress(TraceThread thread, Address address) {
|
||||||
|
@ -644,26 +406,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
return classes;
|
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
|
@Override
|
||||||
public TraceSymbolView<? extends DBTraceNamespaceSymbol> allNamespaces() {
|
public TraceSymbolView<? extends DBTraceNamespaceSymbol> allNamespaces() {
|
||||||
return allNamespaces;
|
return allNamespaces;
|
||||||
|
@ -674,23 +416,8 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceSymbolWithAddressNoDuplicatesView<? extends AbstractDBTraceVariableSymbol> allLocals() {
|
public TraceSymbolNoDuplicatesView<? extends AbstractDBTraceSymbol> notLabels() {
|
||||||
return allLocals;
|
return notLabels;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TraceSymbolWithAddressNoDuplicatesView<? extends AbstractDBTraceSymbol> allVariables() {
|
|
||||||
return allVariables;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TraceSymbolWithLocationView<? extends AbstractDBTraceSymbol> labelsAndFunctions() {
|
|
||||||
return labelsAndFunctions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TraceSymbolNoDuplicatesView<? extends AbstractDBTraceSymbol> notLabelsNorFunctions() {
|
|
||||||
return notLabelsNorFunctions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -700,10 +427,9 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
public DBTraceNamespaceSymbol checkIsMine(Namespace ns) {
|
public DBTraceNamespaceSymbol checkIsMine(Namespace ns) {
|
||||||
if (!(ns instanceof DBTraceNamespaceSymbol)) {
|
if (!(ns instanceof DBTraceNamespaceSymbol dbns)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
DBTraceNamespaceSymbol dbns = (DBTraceNamespaceSymbol) ns;
|
|
||||||
if (dbns.manager != this) {
|
if (dbns.manager != this) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -713,13 +439,8 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
if (namespaceStore.contains(dbns)) {
|
if (namespaceStore.contains(dbns)) {
|
||||||
return dbns;
|
return dbns;
|
||||||
}
|
}
|
||||||
if (dbns instanceof DBTraceClassSymbol) {
|
if (dbns instanceof DBTraceClassSymbol dbcs) {
|
||||||
if (classStore.contains((DBTraceClassSymbol) dbns)) {
|
if (classStore.contains(dbcs)) {
|
||||||
return dbns;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dbns instanceof DBTraceFunctionSymbol) {
|
|
||||||
if (functionStore.contains((DBTraceFunctionSymbol) dbns)) {
|
|
||||||
return dbns;
|
return dbns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -728,10 +449,9 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
public AbstractDBTraceSymbol checkIsMine(Symbol symbol) {
|
public AbstractDBTraceSymbol checkIsMine(Symbol symbol) {
|
||||||
if (!(symbol instanceof AbstractDBTraceSymbol)) {
|
if (!(symbol instanceof AbstractDBTraceSymbol dbSym)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
AbstractDBTraceSymbol dbSym = (AbstractDBTraceSymbol) symbol;
|
|
||||||
if (dbSym.manager != this) {
|
if (dbSym.manager != this) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -750,25 +470,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
return dbSym;
|
return dbSym;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal
|
@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
|
|
||||||
public DBTraceNamespaceSymbol assertIsMine(Namespace ns) {
|
public DBTraceNamespaceSymbol assertIsMine(Namespace ns) {
|
||||||
DBTraceNamespaceSymbol dbns = checkIsMine(ns);
|
DBTraceNamespaceSymbol dbns = checkIsMine(ns);
|
||||||
if (dbns == null) {
|
if (dbns == null) {
|
||||||
|
@ -777,7 +479,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
return dbns;
|
return dbns;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal
|
@Internal
|
||||||
public AbstractDBTraceSymbol assertIsMine(Symbol symbol) {
|
public AbstractDBTraceSymbol assertIsMine(Symbol symbol) {
|
||||||
AbstractDBTraceSymbol dbSym = checkIsMine(symbol);
|
AbstractDBTraceSymbol dbSym = checkIsMine(symbol);
|
||||||
if (dbSym == null) {
|
if (dbSym == null) {
|
||||||
|
@ -786,15 +488,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
return dbSym;
|
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 {
|
protected static void assertValidName(String name) throws InvalidInputException {
|
||||||
if (name == null || name.length() == 0 || !name.matches("\\p{Graph}+")) {
|
if (name == null || name.length() == 0 || !name.matches("\\p{Graph}+")) {
|
||||||
throw new InvalidInputException(name);
|
throw new InvalidInputException(name);
|
||||||
|
@ -802,8 +495,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for duplicate names, allowing {@link SymbolType#LABEL} and
|
* Checks for duplicate names, allowing {@link SymbolType#LABEL}
|
||||||
* {@link SymbolType#FUNCTION}.
|
|
||||||
*
|
*
|
||||||
* @param name the proposed name
|
* @param name the proposed name
|
||||||
* @param parent the parent namespace
|
* @param parent the parent namespace
|
||||||
|
@ -811,7 +503,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
*/
|
*/
|
||||||
protected void assertUniqueName(String name, DBTraceNamespaceSymbol parent)
|
protected void assertUniqueName(String name, DBTraceNamespaceSymbol parent)
|
||||||
throws DuplicateNameException {
|
throws DuplicateNameException {
|
||||||
for (AbstractDBTraceSymbol symbol : notLabelsNorFunctions.getChildren(parent)) {
|
for (AbstractDBTraceSymbol symbol : notLabels.getChildren(parent)) {
|
||||||
if (name.equals(symbol.name)) {
|
if (name.equals(symbol.name)) {
|
||||||
throw new DuplicateNameException(name);
|
throw new DuplicateNameException(name);
|
||||||
}
|
}
|
||||||
|
@ -866,8 +558,8 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
TraceThread thread, Address address, String name, DBTraceNamespaceSymbol parent)
|
TraceThread thread, Address address, String name, DBTraceNamespaceSymbol parent)
|
||||||
throws DuplicateNameException {
|
throws DuplicateNameException {
|
||||||
if (address.isMemoryAddress()) {
|
if (address.isMemoryAddress()) {
|
||||||
for (AbstractDBTraceSymbol duplicate : labelsAndFunctions.getIntersecting(lifespan,
|
for (AbstractDBTraceSymbol duplicate : labels.getIntersecting(lifespan, thread,
|
||||||
thread, new AddressRangeImpl(address, address), false, true)) {
|
new AddressRangeImpl(address, address), false, true)) {
|
||||||
if (duplicate == exclude) {
|
if (duplicate == exclude) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -885,8 +577,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager
|
||||||
|
|
||||||
protected void assertNotDuplicate(AbstractDBTraceSymbol exclude, String name,
|
protected void assertNotDuplicate(AbstractDBTraceSymbol exclude, String name,
|
||||||
DBTraceNamespaceSymbol parent) throws DuplicateNameException {
|
DBTraceNamespaceSymbol parent) throws DuplicateNameException {
|
||||||
for (AbstractDBTraceSymbol duplicate : notLabelsNorFunctions.getChildrenNamed(name,
|
for (AbstractDBTraceSymbol duplicate : notLabels.getChildrenNamed(name, parent)) {
|
||||||
parent)) {
|
|
||||||
if (duplicate == exclude) {
|
if (duplicate == exclude) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,44 +229,6 @@ public interface Trace extends DataTypeManagerDomainObject {
|
||||||
new TraceDataTypeChangeType<>();
|
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>
|
public static final class TraceInstructionChangeType<U>
|
||||||
extends DefaultTraceChangeType<TraceInstruction, U> {
|
extends DefaultTraceChangeType<TraceInstruction, U> {
|
||||||
public static final TraceInstructionChangeType<FlowOverride> FLOW_OVERRIDE_CHANGED =
|
public static final TraceInstructionChangeType<FlowOverride> FLOW_OVERRIDE_CHANGED =
|
||||||
|
|
|
@ -17,6 +17,9 @@ package ghidra.trace.model.symbol;
|
||||||
|
|
||||||
import ghidra.program.model.listing.GhidraClass;
|
import ghidra.program.model.listing.GhidraClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trace class symbol
|
||||||
|
*/
|
||||||
public interface TraceClassSymbol extends TraceNamespaceSymbol, GhidraClass {
|
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.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class symbol view.
|
||||||
|
*/
|
||||||
public interface TraceClassSymbolView extends TraceSymbolNoDuplicatesView<TraceClassSymbol> {
|
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)
|
TraceClassSymbol add(String name, TraceNamespaceSymbol parent, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException, IllegalArgumentException;
|
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;
|
package ghidra.trace.model.symbol;
|
||||||
|
|
||||||
import ghidra.program.database.symbol.CodeSymbol;
|
|
||||||
import ghidra.trace.model.listing.TraceCodeUnit;
|
import ghidra.trace.model.listing.TraceCodeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Document me
|
* A trace label symbol.
|
||||||
*
|
|
||||||
* See {@link CodeSymbol}
|
|
||||||
*/
|
*/
|
||||||
public interface TraceLabelSymbol extends TraceSymbolWithLifespan {
|
public interface TraceLabelSymbol extends TraceSymbolWithLifespan {
|
||||||
|
/**
|
||||||
|
* Get the code unit at this label
|
||||||
|
*
|
||||||
|
* @return the code unit
|
||||||
|
*/
|
||||||
TraceCodeUnit getCodeUnit();
|
TraceCodeUnit getCodeUnit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,39 @@ import ghidra.trace.model.Lifespan;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The label symbol view.
|
||||||
|
*/
|
||||||
public interface TraceLabelSymbolView extends TraceSymbolWithLocationView<TraceLabelSymbol> {
|
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,
|
TraceLabelSymbol add(Lifespan lifespan, TraceThread thread, Address address, String name,
|
||||||
TraceNamespaceSymbol parent, SourceType source) throws InvalidInputException;
|
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,
|
default TraceLabelSymbol create(long snap, TraceThread thread, Address address, String name,
|
||||||
TraceNamespaceSymbol parent, SourceType source) throws InvalidInputException {
|
TraceNamespaceSymbol parent, SourceType source) throws InvalidInputException {
|
||||||
return add(Lifespan.nowOn(snap), thread, address, name, parent, source);
|
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.program.model.symbol.Namespace;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trace namespace symbol.
|
||||||
|
*/
|
||||||
public interface TraceNamespaceSymbol extends TraceSymbol, Namespace {
|
public interface TraceNamespaceSymbol extends TraceSymbol, Namespace {
|
||||||
@Override
|
@Override
|
||||||
Trace getTrace();
|
Trace getTrace();
|
||||||
|
@ -37,6 +40,11 @@ public interface TraceNamespaceSymbol extends TraceSymbol, Namespace {
|
||||||
@Override
|
@Override
|
||||||
TraceNamespaceSymbol getParentNamespace();
|
TraceNamespaceSymbol getParentNamespace();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the children of this namespace
|
||||||
|
*
|
||||||
|
* @return the children
|
||||||
|
*/
|
||||||
Collection<? extends TraceSymbol> getChildren();
|
Collection<? extends TraceSymbol> getChildren();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,9 +19,21 @@ import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The namespace symbol view.
|
||||||
|
*/
|
||||||
public interface TraceNamespaceSymbolView
|
public interface TraceNamespaceSymbolView
|
||||||
extends TraceSymbolNoDuplicatesView<TraceNamespaceSymbol> {
|
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)
|
TraceNamespaceSymbol add(String name, TraceNamespaceSymbol parent, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException;
|
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 java.util.Collection;
|
||||||
|
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.Namespace;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.util.task.TaskMonitor;
|
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 {
|
public interface TraceSymbol extends Symbol {
|
||||||
|
/**
|
||||||
|
* Get the trace to which this symbol belongs.
|
||||||
|
*
|
||||||
|
* @return the trace
|
||||||
|
*/
|
||||||
Trace getTrace();
|
Trace getTrace();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If in register space, get the thread associated with this symbol.
|
||||||
|
*
|
||||||
|
* @return the thread
|
||||||
|
*/
|
||||||
TraceThread getThread();
|
TraceThread getThread();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,6 +65,11 @@ public interface TraceSymbol extends Symbol {
|
||||||
@Override
|
@Override
|
||||||
TraceReference[] getReferences(TaskMonitor monitor);
|
TraceReference[] getReferences(TaskMonitor monitor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all memory references to the address of this symbol.
|
||||||
|
*
|
||||||
|
* @return the references
|
||||||
|
*/
|
||||||
Collection<? extends TraceReference> getReferenceCollection();
|
Collection<? extends TraceReference> getReferenceCollection();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,19 +18,32 @@ package ghidra.trace.model.symbol;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.trace.model.Trace;
|
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 {
|
public interface TraceSymbolManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A comparator that sorts primary symbols first.
|
||||||
|
*/
|
||||||
static Comparator<TraceSymbol> PRIMALITY_COMPARATOR = (a, b) -> {
|
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 aPrim = a.isPrimary();
|
||||||
boolean bPrim = b.isPrimary();
|
boolean bPrim = b.isPrimary();
|
||||||
if (aPrim && !bPrim) {
|
if (aPrim && !bPrim) {
|
||||||
|
@ -42,47 +55,94 @@ public interface TraceSymbolManager {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the trace for this manager.
|
||||||
|
*
|
||||||
|
* @return the trace
|
||||||
|
*/
|
||||||
Trace getTrace();
|
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);
|
TraceSymbol getSymbolByID(long symbolID);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the trace's global namespace.
|
||||||
|
*
|
||||||
|
* @return the global namespace
|
||||||
|
*/
|
||||||
TraceNamespaceSymbol getGlobalNamespace();
|
TraceNamespaceSymbol getGlobalNamespace();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a view of the labels in the trace.
|
||||||
|
*
|
||||||
|
* @return the labels view
|
||||||
|
*/
|
||||||
TraceLabelSymbolView labels();
|
TraceLabelSymbolView labels();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a view of the namespaces in the trace.
|
||||||
|
*
|
||||||
|
* @return the namespaces view
|
||||||
|
*/
|
||||||
TraceNamespaceSymbolView namespaces();
|
TraceNamespaceSymbolView namespaces();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a view of the classes in the trace.
|
||||||
|
*
|
||||||
|
* @return the classes view
|
||||||
|
*/
|
||||||
TraceClassSymbolView classes();
|
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
|
* @return the all-namespaces view
|
||||||
* composed view may have duplicate names.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
TraceSymbolView<? extends TraceNamespaceSymbol> allNamespaces();
|
TraceSymbolView<? extends TraceNamespaceSymbol> allNamespaces();
|
||||||
|
|
||||||
TraceSymbolWithAddressNoDuplicatesView<? extends TraceVariableSymbol> allLocals();
|
/**
|
||||||
|
* Get a view of all the symbols except labels in the trace.
|
||||||
TraceSymbolWithAddressNoDuplicatesView<? extends TraceSymbol> allVariables();
|
*
|
||||||
|
* <p>
|
||||||
TraceSymbolWithLocationView<? extends TraceSymbol> labelsAndFunctions();
|
* <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
|
||||||
TraceSymbolNoDuplicatesView<? extends TraceSymbol> notLabelsNorFunctions();
|
* 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();
|
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);
|
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);
|
Collection<Long> getIDsRemoved(long from, long to);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,20 @@ package ghidra.trace.model.symbol;
|
||||||
|
|
||||||
import ghidra.util.LockHold;
|
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> {
|
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) {
|
default T getChildNamed(String name, TraceNamespaceSymbol parent) {
|
||||||
try (LockHold hold = getManager().getTrace().lockRead()) {
|
try (LockHold hold = getManager().getTrace().lockRead()) {
|
||||||
for (T symbol : getChildrenNamed(name, parent)) {
|
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) {
|
default T getGlobalNamed(String name) {
|
||||||
return getChildNamed(name, getManager().getGlobalNamespace());
|
return getChildNamed(name, getManager().getGlobalNamespace());
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,44 +18,102 @@ package ghidra.trace.model.symbol;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
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> {
|
public interface TraceSymbolView<T extends TraceSymbol> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the symbol manager for the trace.
|
||||||
|
*
|
||||||
|
* @return the symbol manager
|
||||||
|
*/
|
||||||
TraceSymbolManager getManager();
|
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) {
|
default int size(boolean includeDynamicSymbols) {
|
||||||
return getAll(includeDynamicSymbols).size();
|
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);
|
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);
|
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);
|
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) {
|
default Collection<? extends T> getGlobalsNamed(String name) {
|
||||||
return getChildrenNamed(name, getManager().getGlobalNamespace());
|
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() {
|
default Collection<? extends T> getGlobals() {
|
||||||
return getChildren(getManager().getGlobalNamespace());
|
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
|
* @param name the name of the symbols
|
||||||
* @return the collection of symbols with the given name
|
* @return the symbols in this view satisfying the query
|
||||||
*/
|
*/
|
||||||
Collection<? extends T> getNamed(String name);
|
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 glob the glob (* matches zero-or-more, ? matches one character)
|
||||||
* @param caseSensitive true to match case
|
* @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);
|
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);
|
Iterator<? extends T> scanByName(String startName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.model.symbol;
|
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>
|
public interface TraceSymbolWithAddressNoDuplicatesView<T extends TraceSymbol>
|
||||||
extends TraceSymbolWithAddressView<T>, TraceSymbolNoDuplicatesView<T> {
|
extends TraceSymbolWithAddressView<T>, TraceSymbolNoDuplicatesView<T> {
|
||||||
// Just combine the interfaces
|
// Just combine the interfaces
|
||||||
|
|
|
@ -21,22 +21,70 @@ import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressRange;
|
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> {
|
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);
|
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) {
|
default T getGlobalWithNameAt(String name, Address address) {
|
||||||
return getChildWithNameAt(name, address, getManager().getGlobalNamespace());
|
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);
|
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);
|
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) {
|
default boolean hasAt(Address address, boolean includeDynamicSymbols) {
|
||||||
return !getAt(address, includeDynamicSymbols).isEmpty();
|
return !getAt(address, includeDynamicSymbols).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,35 @@ package ghidra.trace.model.symbol;
|
||||||
|
|
||||||
import ghidra.trace.model.Lifespan;
|
import ghidra.trace.model.Lifespan;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trace symbol having a lifespan.
|
||||||
|
*/
|
||||||
public interface TraceSymbolWithLifespan extends TraceSymbol {
|
public interface TraceSymbolWithLifespan extends TraceSymbol {
|
||||||
|
/**
|
||||||
|
* Get the lifespan of the symbol
|
||||||
|
*
|
||||||
|
* @return the lifespan
|
||||||
|
*/
|
||||||
Lifespan getLifespan();
|
Lifespan getLifespan();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the minimum snapshot key in the lifespan
|
||||||
|
*
|
||||||
|
* @return the minimum snapshot key
|
||||||
|
*/
|
||||||
long getStartSnap();
|
long getStartSnap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum snapshot key in the lifespan
|
||||||
|
*
|
||||||
|
* @param snap the new maximum snapshot key
|
||||||
|
*/
|
||||||
void setEndSnap(long snap);
|
void setEndSnap(long snap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the maximum snapshot key in the lifespan
|
||||||
|
*
|
||||||
|
* @return the maximum snapshot key
|
||||||
|
*/
|
||||||
long getEndSnap();
|
long getEndSnap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,28 +22,70 @@ import ghidra.trace.model.Lifespan;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.util.LockHold;
|
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> {
|
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,
|
T getChildWithNameAt(String name, long snap, TraceThread thread, Address address,
|
||||||
TraceNamespaceSymbol parent);
|
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) {
|
default T getGlobalWithNameAt(String name, long snap, TraceThread thread, Address address) {
|
||||||
return getChildWithNameAt(name, snap, thread, address, getManager().getGlobalNamespace());
|
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,
|
Collection<? extends T> getIntersecting(Lifespan span, TraceThread thread,
|
||||||
AddressRange range, boolean includeDynamicSymbols, boolean forward);
|
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 snap the snapshot key
|
||||||
* @param thread
|
* @param thread the thread, if in register space
|
||||||
* @param address
|
* @param address the address of the symbols
|
||||||
* @param includeDynamicSymbols
|
* @param includeDynamicSymbols true to include dynamically-generated symbols
|
||||||
* @return
|
* @return the symbols in this view satisfying the query
|
||||||
*/
|
*/
|
||||||
default Collection<? extends T> getAt(long snap, TraceThread thread, Address address,
|
default Collection<? extends T> getAt(long snap, TraceThread thread, Address address,
|
||||||
boolean includeDynamicSymbols) {
|
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,
|
default boolean hasAt(long snap, TraceThread thread, Address address,
|
||||||
boolean includeDynamicSymbols) {
|
boolean includeDynamicSymbols) {
|
||||||
try (LockHold hold = getManager().getTrace().lockRead()) {
|
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(Set.of(nsA, clsA), new HashSet<>(manager.allNamespaces().getAll(false)));
|
||||||
assertEquals(2, manager.allNamespaces().size(false));
|
assertEquals(2, manager.allNamespaces().size(false));
|
||||||
assertEquals(Set.of(lab1, lab2), new HashSet<>(manager.labelsAndFunctions().getAll(false)));
|
assertEquals(Set.of(lab1, lab2), new HashSet<>(manager.labels().getAll(false)));
|
||||||
assertEquals(2, manager.labelsAndFunctions().size(false));
|
assertEquals(2, manager.labels().size(false));
|
||||||
assertEquals(Set.of(nsA, clsA),
|
assertEquals(Set.of(nsA, clsA), new HashSet<>(manager.notLabels().getAll(false)));
|
||||||
new HashSet<>(manager.notLabelsNorFunctions().getAll(false)));
|
assertEquals(2, manager.notLabels().size(false));
|
||||||
assertEquals(2, manager.notLabelsNorFunctions().size(false));
|
|
||||||
// TODO: Remaining composites
|
// TODO: Remaining composites
|
||||||
assertEquals(Set.of(nsA, clsA, lab1, lab2),
|
assertEquals(Set.of(nsA, clsA, lab1, lab2),
|
||||||
new HashSet<>(manager.allSymbols().getAll(false)));
|
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(Set.of(clsA), new HashSet<>(manager.classes().getChildrenNamed("A", nsA)));
|
||||||
assertEquals(clsA, manager.classes().getChildNamed("A", nsA));
|
assertEquals(clsA, manager.classes().getChildNamed("A", nsA));
|
||||||
assertEquals(Set.of(lab1), new HashSet<>(manager.labels().getChildrenNamed("LAB1", nsA)));
|
assertEquals(Set.of(lab1), new HashSet<>(manager.labels().getChildrenNamed("LAB1", nsA)));
|
||||||
assertEquals(Set.of(lab2),
|
assertEquals(Set.of(lab2), new HashSet<>(manager.labels().getChildrenNamed("LAB2", clsA)));
|
||||||
new HashSet<>(manager.labelsAndFunctions().getChildrenNamed("LAB2", clsA)));
|
|
||||||
assertEquals(Set.of(), new HashSet<>(manager.labels().getChildrenNamed("LAB2", nsA)));
|
assertEquals(Set.of(), new HashSet<>(manager.labels().getChildrenNamed("LAB2", nsA)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,9 +403,9 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
||||||
SourceType.USER_DEFINED);
|
SourceType.USER_DEFINED);
|
||||||
}
|
}
|
||||||
assertEquals(Set.of(lab1),
|
assertEquals(Set.of(lab1),
|
||||||
new HashSet<>(manager.labelsAndFunctions().getWithMatchingName("LAB?", true)));
|
new HashSet<>(manager.labels().getWithMatchingName("LAB?", true)));
|
||||||
assertEquals(Set.of(lab1, lab2),
|
assertEquals(Set.of(lab1, lab2),
|
||||||
new HashSet<>(manager.labelsAndFunctions().getWithMatchingName("LAB?", false)));
|
new HashSet<>(manager.labels().getWithMatchingName("LAB?", false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -440,21 +438,19 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
||||||
}
|
}
|
||||||
assertEquals(lab1,
|
assertEquals(lab1,
|
||||||
manager.labels().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), nsA));
|
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("LAB2", 4, null, b.addr(0x4000), nsA));
|
||||||
assertNull(manager.labels().getChildWithNameAt("LAB1", 0, null, b.addr(0x4000), nsA));
|
assertNull(manager.labels().getChildWithNameAt("LAB1", 0, null, b.addr(0x4000), nsA));
|
||||||
assertNull(manager.labels()
|
assertNull(manager.labels()
|
||||||
.getChildWithNameAt("LAB1", 4, thread,
|
.getChildWithNameAt("LAB1", 4, thread,
|
||||||
b.language.getRegister("r4").getAddress(), nsA));
|
b.language.getRegister("r4").getAddress(), nsA));
|
||||||
assertNull(manager.labels().getChildWithNameAt("LAB1", 4, null, b.addr(0x4001), nsA));
|
assertNull(manager.labels().getChildWithNameAt("LAB1", 4, null, b.addr(0x4001), nsA));
|
||||||
assertNull(
|
assertNull(manager.labels().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), clsA));
|
||||||
manager.labelsAndFunctions().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), clsA));
|
|
||||||
|
|
||||||
assertEquals(lab2,
|
assertEquals(lab2,
|
||||||
manager.labelsAndFunctions().getChildWithNameAt("lab2", 4, null, b.addr(0x4001), clsA));
|
manager.labels().getChildWithNameAt("lab2", 4, null, b.addr(0x4001), clsA));
|
||||||
assertEquals(lab3,
|
assertEquals(lab3,
|
||||||
manager.labelsAndFunctions().getChildWithNameAt("lab3", 4, null, b.addr(0x4001), clsA));
|
manager.labels().getChildWithNameAt("lab3", 4, null, b.addr(0x4001), clsA));
|
||||||
assertEquals(lab4, manager.labelsAndFunctions()
|
assertEquals(lab4, manager.labels()
|
||||||
.getChildWithNameAt("lab4", 0, thread,
|
.getChildWithNameAt("lab4", 0, thread,
|
||||||
b.language.getRegister("r4").getAddress(), nsA));
|
b.language.getRegister("r4").getAddress(), nsA));
|
||||||
}
|
}
|
||||||
|
@ -468,8 +464,6 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
||||||
.create(4, null, b.addr(0x4000), "LAB1", global,
|
.create(4, null, b.addr(0x4000), "LAB1", global,
|
||||||
SourceType.USER_DEFINED);
|
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)));
|
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()
|
// TODO: Test that functions are properly excluded from labels()
|
||||||
// once I have a means of adding them.
|
// once I have a means of adding them.
|
||||||
assertEquals(Set.of(),
|
assertEquals(Set.of(),
|
||||||
new HashSet<>(manager.labelsAndFunctions()
|
new HashSet<>(manager.labels()
|
||||||
.getIntersecting(Lifespan.span(0, 0), null,
|
.getIntersecting(Lifespan.span(0, 0), null, b.range(0x0000, 0x4000), false,
|
||||||
b.range(0x0000, 0x4000), false, true)));
|
true)));
|
||||||
assertEquals(Set.of(lab1, lab2, lab3),
|
assertEquals(Set.of(lab1, lab2, lab3),
|
||||||
new HashSet<>(manager.labels()
|
new HashSet<>(manager.labels()
|
||||||
.getIntersecting(Lifespan.nowOn(0), null,
|
.getIntersecting(Lifespan.nowOn(0), null,
|
||||||
|
@ -549,7 +543,7 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT
|
||||||
assertEquals(Set.of(lab1),
|
assertEquals(Set.of(lab1),
|
||||||
new HashSet<>(manager.labels().getAt(4, null, b.addr(0x4000), false)));
|
new HashSet<>(manager.labels().getAt(4, null, b.addr(0x4000), false)));
|
||||||
assertEquals(Set.of(lab2, lab3),
|
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
|
// TODO: Test ordering by setPrimary
|
||||||
|
|
||||||
assertFalse(manager.labels().hasAt(0, null, b.addr(0x4000), false));
|
assertFalse(manager.labels().hasAt(0, null, b.addr(0x4000), false));
|
||||||
|
|
|
@ -177,13 +177,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||||
return !isConnected();
|
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
|
* 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
|
* 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,
|
public boolean isCreateFunctionAllowed(ListingActionContext context, boolean allowExisting,
|
||||||
boolean createThunk) {
|
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.
|
// A program and location is needed for any create function action.
|
||||||
Program program = context.getProgram();
|
Program program = context.getProgram();
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
|
|
|
@ -22,7 +22,6 @@ import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for a symbol, which associates a string value with
|
* 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
|
* 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>.
|
* <code>null</code>.
|
||||||
*
|
*
|
||||||
* @return all memory references to the address of this symbol.
|
* @return all memory references to the address of this symbol.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue