Function Tags - updated DB to have a tag count cache; added service

interface
This commit is contained in:
dragonmacher 2020-11-04 16:35:31 -05:00
parent 8ec3f786ff
commit 0fcdb7c6c3
30 changed files with 682 additions and 595 deletions

View file

@ -283,8 +283,9 @@ public class FunctionDB extends DatabaseObject implements Function {
manager.lock.acquire();
try {
checkIsValid();
return manager.getCodeManager().getComment(CodeUnit.REPEATABLE_COMMENT,
getEntryPoint());
return manager.getCodeManager()
.getComment(CodeUnit.REPEATABLE_COMMENT,
getEntryPoint());
}
finally {
manager.lock.release();
@ -301,8 +302,9 @@ public class FunctionDB extends DatabaseObject implements Function {
manager.lock.acquire();
try {
checkDeleted();
manager.getCodeManager().setComment(getEntryPoint(), CodeUnit.REPEATABLE_COMMENT,
comment);
manager.getCodeManager()
.setComment(getEntryPoint(), CodeUnit.REPEATABLE_COMMENT,
comment);
}
finally {
manager.lock.release();
@ -885,8 +887,9 @@ public class FunctionDB extends DatabaseObject implements Function {
}
}
}
program.getBookmarkManager().setBookmark(getEntryPoint(), BookmarkType.ERROR,
"Bad Variables Removed", "Removed " + badSymbols.size() + " bad variables");
program.getBookmarkManager()
.setBookmark(getEntryPoint(), BookmarkType.ERROR,
"Bad Variables Removed", "Removed " + badSymbols.size() + " bad variables");
for (Symbol s : badSymbols) {
s.delete();
}
@ -2703,8 +2706,10 @@ public class FunctionDB extends DatabaseObject implements Function {
callFixupMap.remove(entryPoint);
}
else {
if (program.getCompilerSpec().getPcodeInjectLibrary().getPayload(
InjectPayload.CALLFIXUP_TYPE, name, null, null) == null) {
if (program.getCompilerSpec()
.getPcodeInjectLibrary()
.getPayload(
InjectPayload.CALLFIXUP_TYPE, name, null, null) == null) {
Msg.warn(this, "Undefined CallFixup set at " + entryPoint + ": " + name);
}
callFixupMap.add(entryPoint, name);
@ -2815,13 +2820,12 @@ public class FunctionDB extends DatabaseObject implements Function {
tag = tagManager.createFunctionTag(name, "");
}
FunctionTagMappingAdapter mappingAdapter = tagManager.getFunctionTagMappingAdapter();
if (mappingAdapter.getRecord(getID(), tag.getId()) == null) {
mappingAdapter.createFunctionTagRecord(getID(), tag.getId());
if (!tagManager.isTagApplied(getID(), tag.getId())) {
tagManager.applyFunctionTag(getID(), tag.getId());
Address addr = getEntryPoint();
program.setChanged(ChangeManager.DOCR_TAG_ADDED_TO_FUNCTION, addr, addr, null,
null);
program.setChanged(ChangeManager.DOCR_TAG_ADDED_TO_FUNCTION, addr, addr, tag,
tag);
}
// Add to local cache
@ -2829,9 +2833,6 @@ public class FunctionDB extends DatabaseObject implements Function {
tags.add(tag);
}
}
catch (IOException e) {
manager.dbError(e);
}
finally {
endUpdate();
manager.lock.release();
@ -2853,13 +2854,12 @@ public class FunctionDB extends DatabaseObject implements Function {
FunctionTagManagerDB tagManager =
(FunctionTagManagerDB) manager.getFunctionTagManager();
FunctionTagMappingAdapter mappingAdapter = tagManager.getFunctionTagMappingAdapter();
boolean removed = mappingAdapter.removeFunctionTagRecord(getID(), tag.getId());
boolean removed = tagManager.removeFunctionTag(getID(), tag.getId());
if (removed) {
Address addr = getEntryPoint();
program.setChanged(ChangeManager.DOCR_TAG_REMOVED_FROM_FUNCTION, addr, addr, null,
null);
program.setChanged(ChangeManager.DOCR_TAG_REMOVED_FROM_FUNCTION, addr, addr, tag,
tag);
// Remove from the local cache.
if (tags != null) {
@ -2867,9 +2867,6 @@ public class FunctionDB extends DatabaseObject implements Function {
}
}
}
catch (IOException e) {
manager.dbError(e);
}
finally {
endUpdate();
manager.lock.release();

View file

@ -21,7 +21,8 @@ import java.util.function.Predicate;
import db.*;
import generic.FilteredIterator;
import ghidra.program.database.*;
import ghidra.program.database.DBObjectCache;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.code.CodeManager;
import ghidra.program.database.external.ExternalLocationDB;
import ghidra.program.database.map.AddressMap;
@ -48,7 +49,7 @@ import ghidra.util.task.TaskMonitor;
* all function related calls are routed to this class.
*
*/
public class FunctionManagerDB implements ManagerDB, FunctionManager {
public class FunctionManagerDB implements FunctionManager {
private final String CALLFIXUP_MAP = "CallFixup"; // string map used to store call-fixup name
@ -64,7 +65,7 @@ public class FunctionManagerDB implements ManagerDB, FunctionManager {
private NamespaceManager namespaceMgr;
private SymbolManager symbolMgr;
private CodeManager codeMgr;
private FunctionTagManager functionTagManager;
private FunctionTagManagerDB functionTagManager;
private Namespace globalNamespace;
private Predicate<Function> functionFilter = f -> {
@ -352,7 +353,7 @@ public class FunctionManagerDB implements ManagerDB, FunctionManager {
throw new IllegalArgumentException(
"Function entryPoint may not be created on defined data");
}
if (namespaceMgr.overlapsNamespace(body) != null) {
throw new OverlappingFunctionException(entryPoint);
}
@ -552,7 +553,7 @@ public class FunctionManagerDB implements ManagerDB, FunctionManager {
// Remove all tag mappings associated with this function
for (FunctionTag tag : function.getTags()) {
tag.delete();
function.removeTag(tag.getName());
}
long functionID = function.getID();
@ -930,6 +931,7 @@ public class FunctionManagerDB implements ManagerDB, FunctionManager {
public void invalidateCache(boolean all) {
lock.acquire();
try {
functionTagManager.invalidateCache();
callFixupMap = null;
lastFuncID = -1;
cache.invalidate();
@ -996,14 +998,16 @@ public class FunctionManagerDB implements ManagerDB, FunctionManager {
*/
FunctionIteratorDB(boolean external, boolean forward) {
if (external) {
it = program.getSymbolTable().getSymbols(
new AddressSet(AddressSpace.EXTERNAL_SPACE.getMinAddress(),
AddressSpace.EXTERNAL_SPACE.getMaxAddress()),
SymbolType.FUNCTION, forward);
it = program.getSymbolTable()
.getSymbols(
new AddressSet(AddressSpace.EXTERNAL_SPACE.getMinAddress(),
AddressSpace.EXTERNAL_SPACE.getMaxAddress()),
SymbolType.FUNCTION, forward);
}
else {
it = program.getSymbolTable().getSymbols(program.getMemory(), SymbolType.FUNCTION,
forward);
it = program.getSymbolTable()
.getSymbols(program.getMemory(), SymbolType.FUNCTION,
forward);
}
}
@ -1144,8 +1148,7 @@ public class FunctionManagerDB implements ManagerDB, FunctionManager {
list.add(symbol);
}
}
for (int i = 0; i < list.size(); i++) {
Symbol symbol = list.get(i);
for (Symbol symbol : list) {
symbol.delete();
}
}
@ -1477,6 +1480,7 @@ public class FunctionManagerDB implements ManagerDB, FunctionManager {
}
}
@Override
public FunctionTagManager getFunctionTagManager() {
return functionTagManager;
}

View file

@ -53,9 +53,10 @@ public class FunctionTagDB extends DatabaseObject implements FunctionTag {
comment = "";
}
if (!comment.equals(record.getString(FunctionTagAdapter.COMMENT_COL))) {
String oldValue = record.getString(FunctionTagAdapter.COMMENT_COL);
if (!comment.equals(oldValue)) {
record.setString(FunctionTagAdapter.COMMENT_COL, comment);
mgr.updateFunctionTag(this);
mgr.updateFunctionTag(this, oldValue, comment);
}
}
@ -77,9 +78,10 @@ public class FunctionTagDB extends DatabaseObject implements FunctionTag {
name = "";
}
if (!name.equals(record.getString(FunctionTagAdapter.NAME_COL))) {
String oldValue = record.getString(FunctionTagAdapter.NAME_COL);
if (!name.equals(oldValue)) {
record.setString(FunctionTagAdapter.NAME_COL, name);
mgr.updateFunctionTag(this);
mgr.updateFunctionTag(this, oldValue, name);
}
}
catch (IOException e) {
@ -137,7 +139,7 @@ public class FunctionTagDB extends DatabaseObject implements FunctionTag {
// is null, use whatever is in the database.
if (rec == null) {
try {
rec = mgr.getFunctionTagAdapter().getRecord(key);
rec = mgr.getTagRecord(key);
}
catch (IOException e) {
mgr.dbError(e);

View file

@ -18,6 +18,8 @@ package ghidra.program.database.function;
import java.io.IOException;
import java.util.*;
import org.apache.commons.collections4.map.LazyMap;
import db.*;
import db.util.ErrorHandler;
import ghidra.program.database.DBObjectCache;
@ -25,6 +27,7 @@ import ghidra.program.database.ProgramDB;
import ghidra.program.model.listing.*;
import ghidra.program.util.ChangeManager;
import ghidra.util.Lock;
import ghidra.util.datastruct.Counter;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@ -41,6 +44,8 @@ public class FunctionTagManagerDB implements FunctionTagManager, ErrorHandler {
private DBObjectCache<FunctionTagDB> cache;
private Map<FunctionTag, Counter> tagCountCache;
protected final Lock lock;
/**
@ -53,7 +58,7 @@ public class FunctionTagManagerDB implements FunctionTagManager, ErrorHandler {
* @throws VersionException if the database is incompatible with the current
* schema
* @throws IOException if there is a problem accessing the database.
* @throws CancelledException
* @throws CancelledException if the program loading is cancelled
*/
FunctionTagManagerDB(DBHandle handle, int openMode, Lock lock, TaskMonitor monitor)
throws VersionException, IOException, CancelledException {
@ -62,10 +67,9 @@ public class FunctionTagManagerDB implements FunctionTagManager, ErrorHandler {
functionTagAdapter = FunctionTagAdapter.getAdapter(handle, openMode, monitor);
functionTagMappingAdapter = FunctionTagMappingAdapter.getAdapter(handle, openMode, monitor);
cache = new DBObjectCache<FunctionTagDB>(100);
cache = new DBObjectCache<>(100);
}
@Override
public void setProgram(Program program) {
this.program = (ProgramDB) program;
}
@ -172,21 +176,89 @@ public class FunctionTagManagerDB implements FunctionTagManager, ErrorHandler {
return null;
}
void updateFunctionTag(FunctionTagDB tag) throws IOException {
boolean isTagApplied(long functionId, long tagId) {
lock.acquire();
try {
return functionTagMappingAdapter.getRecord(functionId, tagId) != null;
}
catch (IOException e) {
dbError(e);
}
finally {
lock.release();
}
return false;
}
void applyFunctionTag(long functionId, long tagId) {
lock.acquire();
try {
FunctionTag tag = getFunctionTag(tagId);
if (tag == null) {
return; // shouldn't happen
}
functionTagMappingAdapter.createFunctionTagRecord(functionId, tagId);
incrementCountCache(tag);
}
catch (IOException e) {
dbError(e);
}
finally {
lock.release();
}
}
private void incrementCountCache(FunctionTag tag) {
if (tagCountCache != null) {
tagCountCache.get(tag).count++;
}
}
private void decrementCountCache(FunctionTag tag) {
if (tagCountCache != null) {
tagCountCache.get(tag).count--;
}
}
boolean removeFunctionTag(long functionId, long tagId) {
lock.acquire();
try {
FunctionTag tag = getFunctionTag(tagId);
if (tag == null) {
return false; // shouldn't happen
}
if (functionTagMappingAdapter.removeFunctionTagRecord(functionId, tagId)) {
decrementCountCache(tag);
return true;
}
}
catch (IOException e) {
dbError(e);
}
finally {
lock.release();
}
return false;
}
void updateFunctionTag(FunctionTagDB tag, String oldValue, String newValue) throws IOException {
// Update the tag attributes.
functionTagAdapter.updateRecord(tag.getRecord());
// Notify subscribers of the change.
fireTagChangedNotification(ChangeManager.DOCR_FUNCTION_TAG_CHANGED, tag);
fireTagChangedNotification(ChangeManager.DOCR_FUNCTION_TAG_CHANGED, tag, oldValue,
newValue);
invalidateFunctions();
}
/* (non-Javadoc)
* TODO: Be a bit smarter about this - if the cache contains all the tags in
* the db we can just return the cache itself. If not, then go to the
* db to get the remainder.
*/
@Override
public List<? extends FunctionTag> getAllFunctionTags() {
@ -211,27 +283,25 @@ public class FunctionTagManagerDB implements FunctionTagManager, ErrorHandler {
return Collections.emptyList();
}
public FunctionTagAdapter getFunctionTagAdapter() {
return functionTagAdapter;
public Record getTagRecord(long id) throws IOException {
return functionTagAdapter.getRecord(id);
}
public FunctionTagMappingAdapter getFunctionTagMappingAdapter() {
return functionTagMappingAdapter;
}
/*****************************************************************************
* PRIVATE METHODS
*****************************************************************************/
//==================================================================================================
// Private Methods
//==================================================================================================
/**
* Sends a notification when a tag has been changed (edited or deleted).
*
* @param type {@link ChangeManager} change type
* @param tag the tag that was changed
* @throws IOException
* @param oldValue the old value
* @param newValue the new value
*/
private void fireTagChangedNotification(int type, FunctionTag tag) throws IOException {
program.tagChanged(tag, type, null, null);
private void fireTagChangedNotification(int type, FunctionTag tag, String oldValue,
String newValue) {
program.tagChanged(tag, type, oldValue, newValue);
}
/**
@ -239,9 +309,8 @@ public class FunctionTagManagerDB implements FunctionTagManager, ErrorHandler {
*
* @param type {@link ChangeManager} change type
* @param tag the tag that was created
* @throws IOException
*/
private void fireTagCreatedNotification(int type, FunctionTag tag) throws IOException {
private void fireTagCreatedNotification(int type, FunctionTag tag) {
program.tagCreated(tag, type);
}
@ -250,10 +319,9 @@ public class FunctionTagManagerDB implements FunctionTagManager, ErrorHandler {
*
* @param type the type of change
* @param tag the tag that was deleted
* @throws IOException
*/
private void fireTagDeletedNotification(int type, FunctionTag tag) throws IOException {
program.tagChanged(tag, type, null, null);
private void fireTagDeletedNotification(int type, FunctionTag tag) {
program.tagChanged(tag, type, tag, null);
}
/**
@ -275,6 +343,7 @@ public class FunctionTagManagerDB implements FunctionTagManager, ErrorHandler {
* Deletes the given function tag.
*
* @param tag the tag to delete
* @throws IOException if there is an issue reading from the db
*/
void doDeleteTag(FunctionTag tag) throws IOException {
@ -304,20 +373,56 @@ public class FunctionTagManagerDB implements FunctionTagManager, ErrorHandler {
* Returns all function tags associated with the given function id.
*
* @param functionId the function id
* @return
* @throws IOException
* @return the tags
* @throws IOException if there is an issue reading from the db
*/
Set<FunctionTag> getFunctionTagsByFunctionID(long functionId) throws IOException {
Set<FunctionTag> tags = new HashSet<>();
RecordIterator functionTagMappingRecords =
RecordIterator functionRecords =
functionTagMappingAdapter.getRecordsByFunctionID(functionId);
while (functionTagMappingRecords.hasNext()) {
Record mappingRecord = functionTagMappingRecords.next();
while (functionRecords.hasNext()) {
Record mappingRecord = functionRecords.next();
Record tagRecord = functionTagAdapter.getRecord(
mappingRecord.getLongValue(FunctionTagMappingAdapter.TAG_ID_COL));
tags.add(getFunctionTagFromCache(tagRecord));
}
return tags;
}
void invalidateCache() {
cache.invalidate();
tagCountCache = null;
}
@Override
public int getUseCount(FunctionTag tag) {
lock.acquire();
try {
if (tagCountCache == null) {
buildTagCountCache();
}
Counter counter = tagCountCache.get(tag);
return counter.count;
}
catch (IOException e) {
dbError(e);
return 0;
}
finally {
lock.release();
}
}
private void buildTagCountCache() throws IOException {
Map<FunctionTag, Counter> map = LazyMap.lazyMap(new HashMap<>(), () -> new Counter());
RecordIterator records = functionTagMappingAdapter.getRecords();
while (records.hasNext()) {
Record mappingRecord = records.next();
long tagId = mappingRecord.getLongValue(FunctionTagMappingAdapter.TAG_ID_COL);
FunctionTag tag = getFunctionTag(tagId);
map.get(tag).count++;
}
tagCountCache = map;
}
}

View file

@ -32,7 +32,7 @@ abstract class FunctionTagMappingAdapter {
static final String TABLE_NAME = "Function Tag Map";
static final int CURRENT_VERSION = 0;
static final int FUNCTION_ID_COL = 0;
static final int TAG_ID_COL = 1;
@ -74,7 +74,7 @@ abstract class FunctionTagMappingAdapter {
*
* @param functionID index into the {@link SymbolTable} table
* @return iterator of database records
* @throws IOException
* @throws IOException if database error occurs
*/
abstract RecordIterator getRecordsByFunctionID(long functionID) throws IOException;
@ -84,17 +84,17 @@ abstract class FunctionTagMappingAdapter {
* @param functionID index into the {@link SymbolTable} table
* @param tagID index into the {@link FunctionTagAdapter} table
* @return null if not found
* @throws IOException
* @throws IOException if database error occurs
*/
abstract Record getRecord(long functionID, long tagID) throws IOException;
/**
* Creates a new record with the given function and tag ID's.
*
* @param functionID
* @param tagID
* @param functionID the function's database id
* @param tagID the FunctionTags database id
* @return newly-created database record
* @throws IOException
* @throws IOException if database error occurs
*/
abstract Record createFunctionTagRecord(long functionID, long tagID)
throws IOException;
@ -106,7 +106,7 @@ abstract class FunctionTagMappingAdapter {
* @param functionID index into the {@link SymbolTable} table
* @param tagID index into the {@link FunctionTagAdapter} table
* @return true if the remove was performed
* @throws IOException
* @throws IOException if database error occurs
*/
abstract boolean removeFunctionTagRecord(long functionID, long tagID)
throws IOException;
@ -116,16 +116,22 @@ abstract class FunctionTagMappingAdapter {
* whenever a tag is being deleted from the system.
*
* @param tagID index into the {@link FunctionTagAdapter} table
* @throws IOException
* @throws IOException if database error occurs
*/
abstract void removeFunctionTagRecord(long tagID) throws IOException;
/**
* Determine if the specified tag ID has been applied to a function
* @param tagId tag ID
* @param id tag ID
* @return true if tag applied to one or more functions
* @throws IOException
* @throws IOException if database error occurs
*/
abstract boolean isTagAssigned(long id) throws IOException;
/**
* Returns a RecordIterator over all the records in this table
* @return a RecordIterator over all the records in this table
* @throws IOException if database error occurs
*/
protected abstract RecordIterator getRecords() throws IOException;
}

View file

@ -65,4 +65,9 @@ class FunctionTagMappingAdapterNoTable extends FunctionTagMappingAdapter {
boolean isTagAssigned(long id) throws IOException {
return false;
}
@Override
protected RecordIterator getRecords() throws IOException {
return new EmptyRecordIterator();
}
}

View file

@ -147,6 +147,14 @@ class FunctionTagMappingAdapterV0 extends FunctionTagMappingAdapter implements D
return table.indexIterator(V0_FUNCTION_ID_COL, value, value, true);
}
@Override
protected RecordIterator getRecords() throws IOException {
if (table == null) {
return new EmptyRecordIterator();
}
return table.iterator();
}
@Override
boolean isTagAssigned(long tagID) throws IOException {
if (table == null) {

View file

@ -29,10 +29,7 @@ import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
/**
* Interface to define methods available on a function. Functions
* have a single entry point.
*
*
* Interface to define methods available on a function. Functions have a single entry point.
*/
public interface Function extends Namespace {
@ -110,8 +107,8 @@ public interface Function extends Namespace {
public void setCallFixup(String name);
/**
* Returns the current call-fixup name set on this instruction or null
* if one has not been set.
* Returns the current call-fixup name set on this instruction or null if one has not been set
* @return the name
*/
public String getCallFixup();
@ -131,6 +128,7 @@ public interface Function extends Namespace {
/**
* Returns the function (same as plate) comment as an array of strings where
* each item in the array is a line of text in the comment.
* @return the comments
*/
public String[] getCommentAsArray();
@ -194,11 +192,15 @@ public interface Function extends Namespace {
/**
* Set the return data-type and storage.
* <p>NOTE: The storage and source are ignored if the function does not have custom storage enabled.
* @param type
* @param storage
*
* <p>NOTE: The storage and source are ignored if the function does not have custom storage
* enabled.
*
* @param type the data type
* @param storage the storage
* @param source source to be combined with the overall signature source.
* @throws InvalidInputException if data type is not a fixed length or storage is improperly sized
* @throws InvalidInputException if data type is not a fixed length or storage is improperly
* sized
*/
public void setReturn(DataType type, VariableStorage storage, SourceType source)
throws InvalidInputException;
@ -216,21 +218,22 @@ public interface Function extends Namespace {
/**
* Get the function's signature.
* <br><br>WARNING! It is important to note that the calling convention may not be properly retained
* by the returned signature object if a non-generic calling convention is used by this function as
* defined by the program's compiler specification.
* <br><br>WARNING! It is important to note that the calling convention may not be properly
* retained by the returned signature object if a non-generic calling convention is used by
* this function as defined by the program's compiler specification.
*
* @param formalSignature if true only original raw types will be retained and
* auto-params discarded (e.g., this, __return_storage_ptr__, etc.) within the returned
* signature. If false, the effective signature will be returned where forced indirect
* and auto-params are reflected in the signature. This option has no affect if the specified
* function has custom storage enabled.
*
* @return the function's signature
*/
public FunctionSignature getSignature(boolean formalSignature);
/**
* Return a string representation of the function signature
*
* @param formalSignature if true only original raw return/parameter types will be retained and
* auto-params discarded (e.g., this, __return_storage_ptr__, etc.) within the returned
* signature. If false, the effective signature will be returned where forced indirect
@ -238,6 +241,7 @@ public interface Function extends Namespace {
* function has custom storage enabled.
* @param includeCallingConvention if true prototype will include call convention
* declaration if known.
* @return the prototype
*/
public String getPrototypeString(boolean formalSignature, boolean includeCallingConvention);
@ -464,6 +468,7 @@ public interface Function extends Namespace {
* @param fromOrdinal from ordinal position using the current numbering
* @param toOrdinal the final position of the specified parameter
* @return parameter which was moved
* @throws InvalidInputException if either ordinal is invalid
* @deprecated The use of this method is discouraged. The function signature should generally be
* adjusted with a single call to {@link #updateFunction(String, Variable, List, FunctionUpdateType, boolean, SourceType)}
*/
@ -520,7 +525,7 @@ public interface Function extends Namespace {
/**
* Returns an array of all local and parameter variables
* @return
* @return the variables
*/
public Variable[] getAllVariables();
@ -533,6 +538,7 @@ public interface Function extends Namespace {
* @return the Variable added to the program.
* @throws DuplicateNameException if another local variable or parameter already
* has that name.
* @throws InvalidInputException if there is an error or conflict when resolving the variable
*/
public Variable addLocalVariable(Variable var, SourceType source)
throws DuplicateNameException, InvalidInputException;
@ -553,14 +559,16 @@ public interface Function extends Namespace {
public void setBody(AddressSetView newBody) throws OverlappingFunctionException;
/**
* Returns true if this function has a variable argument list (VarArgs).
* Returns true if this function has a variable argument list (VarArgs)
* @return true if this function has a variable argument list (VarArgs)
*/
public boolean hasVarArgs();
/**
* Set whether parameters can be passed as a VarArg (variable argument list).
* Set whether parameters can be passed as a VarArg (variable argument list)
*
* @param hasVarArgs true if this function has a variable argument list (ie printf(fmt, ...)).
* @param hasVarArgs true if this function has a variable argument list
* (e.g., printf(fmt, ...)).
*/
public void setVarArgs(boolean hasVarArgs);
@ -595,7 +603,7 @@ public interface Function extends Namespace {
/**
* Set whether or not this function uses custom variable storage
* @param hasCustomVariableStorage
* @param hasCustomVariableStorage true if this function uses custom storage
*/
public void setCustomVariableStorage(boolean hasCustomVariableStorage);

View file

@ -15,22 +15,29 @@
*/
package ghidra.program.model.listing;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.ManagerDB;
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.Namespace;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
public interface FunctionManager {
/**
* The manager for functions
*/
public interface FunctionManager extends ManagerDB {
/**
* Returns this manager's program
* @return the program
*/
public Program getProgram();
/**
@ -50,8 +57,8 @@ public interface FunctionManager {
public PrototypeModel getDefaultCallingConvention();
/**
* Gets the prototype model of the calling convention with the specified name in this program.
*
* Gets the prototype model of the calling convention with the specified name in this program
* @param name the calling convention name
* @return the named function calling convention prototype model or null.
*/
public PrototypeModel getCallingConvention(String name);
@ -113,25 +120,28 @@ public interface FunctionManager {
throws OverlappingFunctionException;
/**
* Returns the total number of functions in the program including external functions.
* Returns the total number of functions in the program including external functions
* @return the count
*/
public int getFunctionCount();
/**
* Remove a function defined at entryPoint.
* Remove a function defined at entryPoint
* @param entryPoint the entry point
* @return true if the function was removed
*/
public boolean removeFunction(Address entryPoint);
/**
* Get the function at entryPoint.
*
* @return null if there is no function at entryPoint.
* Get the function at entryPoint
* @param entryPoint the entry point
* @return null if there is no function at entryPoint
*/
public Function getFunctionAt(Address entryPoint);
/**
* Get the function which resides at the specified address or is referenced from the specified
* address.
* Get the function which resides at the specified address or is referenced from the specified
* address
*
* @param address function address or address of pointer to a function.
* @return referenced function or null
@ -147,19 +157,18 @@ public interface FunctionManager {
public Function getFunctionContaining(Address addr);
/**
* Returns an iterator over all non-external functions in address (entry point) order.
*
* Returns an iterator over all non-external functions in address (entry point) order
* @param forward true means to iterate in ascending address order
* @return the iterator
*/
public FunctionIterator getFunctions(boolean forward);
/**
* Get an iterator over non-external functions starting at an address and ordered by entry
* address.
* address
*
* @param start starting address
* @param forward true means to iterate in ascending address order
*
* @return an iterator over functions.
*/
public FunctionIterator getFunctions(Address start, boolean forward);
@ -176,9 +185,10 @@ public interface FunctionManager {
/**
* Returns an iterator over all REAL functions in address (entry point) order (real functions
* have instructions, and aren't stubs).
* have instructions, and aren't stubs)
*
* @param forward true means to iterate in ascending address order
* @return the iterator
*/
public FunctionIterator getFunctionsNoStubs(boolean forward);
@ -220,39 +230,6 @@ public interface FunctionManager {
*/
public boolean isInFunction(Address addr);
/**
* @see ghidra.program.database.ManagerDB#moveAddressRange(ghidra.program.model.address.Address,
* ghidra.program.model.address.Address, long, ghidra.util.task.TaskMonitor)
*/
public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
throws CancelledException;
/**
* @see ghidra.program.database.ManagerDB#deleteAddressRange(ghidra.program.model.address.Address,
* ghidra.program.model.address.Address, ghidra.util.task.TaskMonitor)
*/
public void deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
throws CancelledException;
/**
* @see ghidra.program.database.ManagerDB#setProgram(ghidra.program.database.ProgramDB)
*/
public void setProgram(ProgramDB program);
/**
* @param currentRevision TODO
* @see ghidra.program.database.ManagerDB#programReady(int, int, ghidra.util.task.TaskMonitor)
*/
public void programReady(int openMode, int currentRevision, TaskMonitor monitor)
throws IOException, CancelledException;
/*
* (non-Javadoc)
*
* @see ghidra.program.database.ManagerDB#invalidateCache(boolean)
*/
public void invalidateCache(boolean all);
/**
* Return an iterator over functions that overlap the given address set.
*
@ -268,10 +245,10 @@ public interface FunctionManager {
* function. While this does not account for the actual instruction flow, it is hopefully
* accurate enough for most situations.
*
* @param instrAddr
* @param storageAddr
* @param instrAddr the instruction address
* @param storageAddr the storage address
* @param size varnode size in bytes (1 is assumed if value &lt;= 0)
* @param isRead
* @param isRead true if the reference is a read reference
* @return referenced variable or null if one not found
*/
public Variable getReferencedVariable(Address instrAddr, Address storageAddr, int size,
@ -284,4 +261,30 @@ public interface FunctionManager {
*/
public Function getFunction(long key);
/**
* Returns the function tag manager
* @return the function tag manager
*/
public FunctionTagManager getFunctionTagManager();
/**
* Clears all data caches
* @param all if false, some managers may not need to update their cache if they can
* tell that its not necessary. If this flag is true, then all managers should clear
* their cache no matter what.
*/
@Override
public void invalidateCache(boolean all); // note: redeclared to not throw an exception
/**
* Move all objects within an address range to a new location
* @param fromAddr the first address of the range to be moved
* @param toAddr the address where to the range is to be moved
* @param length the number of addresses to move
* @param monitor the task monitor to use in any upgrade operations
* @throws CancelledException if the user cancelled the operation via the task monitor
*/
@Override
void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
throws CancelledException; // note: redeclared to not throw an AddressOverflowException
}

View file

@ -18,39 +18,39 @@ package ghidra.program.model.listing;
import java.util.List;
/**
* Interface for managing function tags. Tags are simple objects consisting of
* a name and an optional comment, which can be applied to functions in Ghidra.
* Interface for managing function tags. Tags are simple objects consisting of a name and an
* optional comment, which can be applied to functions.
*
* @see ghidra.program.database.function.FunctionTagAdapter FunctionTagAdapter
* @see ghidra.program.database.function.FunctionTagMappingAdapter FunctionTagMappingAdapter
* See ghidra.program.database.function.FunctionTagAdapter
* See ghidra.program.database.function.FunctionTagMappingAdapter
*/
public interface FunctionTagManager {
/**
* Returns the function tag with the given name.
* Returns the function tag with the given name
*
* @param name the tag name
* @return the function tag, or null if not found
*/
FunctionTag getFunctionTag(String name);
public FunctionTag getFunctionTag(String name);
/**
* Returns the function tag with the given database id.
* Returns the function tag with the given database id
*
* @param id the tags database id
* @return the function tag, or null if not found
*/
FunctionTag getFunctionTag(long id);
public FunctionTag getFunctionTag(long id);
/**
* Returns all function tags in the database.
* Returns all function tags in the database
*
* @return list of function tags
*/
List<? extends FunctionTag> getAllFunctionTags();
public List<? extends FunctionTag> getAllFunctionTags();
/**
* Returns true if the given tag is assigned to a function.
* Returns true if the given tag is assigned to a function
*
* @param name the tag name
* @return true if assigned to a function
@ -65,13 +65,12 @@ public interface FunctionTagManager {
* @param comment the comment associated with the tag (optional)
* @return the new function tag
*/
FunctionTag createFunctionTag(String name, String comment);
public FunctionTag createFunctionTag(String name, String comment);
/**
* Sets the program on this manager to allow the manager to persist changes
* and notify subscribers.
*
* @param program the program
* Returns the number of times the given tag has been applied to a function
* @param tag the tag
* @return the count
*/
void setProgram(Program program);
public int getUseCount(FunctionTag tag);
}

View file

@ -187,4 +187,8 @@ public class FunctionManagerTestDouble implements FunctionManager {
throw new UnsupportedOperationException();
}
@Override
public FunctionTagManager getFunctionTagManager() {
throw new UnsupportedOperationException();
}
}