GP-706 - Speed up namespace lookup and creation

This commit is contained in:
dragonmacher 2021-03-18 12:13:28 -04:00
parent 79fce9b032
commit ae69ba87d1
35 changed files with 862 additions and 633 deletions

View file

@ -534,53 +534,7 @@ public class NamespaceUtils {
throws InvalidInputException {
Symbol namespaceSymbol = namespace.getSymbol();
String name = namespaceSymbol.getName();
SourceType originalSource = namespaceSymbol.getSource();
SymbolTable symbolTable = namespaceSymbol.getProgram().getSymbolTable();
// Temporarily rename old namespace (it will be removed at the end)
int count = 1;
while (true) {
String n = name + "_" + count++;
try {
namespaceSymbol.setName(n, SourceType.ANALYSIS);
break;
}
catch (DuplicateNameException e) {
// continue
}
catch (InvalidInputException e) {
throw new AssertException(e);
}
}
// create new class namespace
GhidraClass classNamespace = null;
try {
classNamespace =
symbolTable.createClass(namespace.getParentNamespace(), name, originalSource);
}
catch (DuplicateNameException e) {
throw new AssertException(e);
}
catch (InvalidInputException e) {
// The only cause of this exception can be assumed but we need to
// avoid showing the user a temporary name
throw new InvalidInputException(
"Namespace contained within Function may not be converted to a class: " + name);
}
// move everything from old namespace into new class namespace
try {
for (Symbol s : symbolTable.getSymbols(namespace)) {
s.setNamespace(classNamespace);
}
namespaceSymbol.delete();
}
catch (DuplicateNameException | InvalidInputException | CircularDependencyException e) {
throw new AssertException(e);
}
return classNamespace;
return symbolTable.convertNamespaceToClass(namespace);
}
}

View file

@ -1695,34 +1695,41 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
@Override
public void disassociate(DataType dataType) {
UniversalID oldDtID = dataType.getUniversalID();
SourceArchive sourceArchive = dataType.getSourceArchive();
sourceArchive = resolveSourceArchive(sourceArchive);
UniversalID id = sourceArchive == null ? DataTypeManager.LOCAL_ARCHIVE_UNIVERSAL_ID
: sourceArchive.getSourceArchiveID();
if (id.equals(getUniversalID())) {
id = DataTypeManager.LOCAL_ARCHIVE_UNIVERSAL_ID;
}
if (id == DataTypeManager.LOCAL_ARCHIVE_UNIVERSAL_ID) {
// Already local data type so no source archive associated.
return;
}
// Set the source archive to null indicating no associated archive.
dataType.setSourceArchive(null);
lock.acquire();
try {
UniversalID oldDtID = dataType.getUniversalID();
SourceArchive sourceArchive = dataType.getSourceArchive();
sourceArchive = resolveSourceArchive(sourceArchive);
UniversalID id = sourceArchive == null ? DataTypeManager.LOCAL_ARCHIVE_UNIVERSAL_ID
: sourceArchive.getSourceArchiveID();
if (id.equals(getUniversalID())) {
id = DataTypeManager.LOCAL_ARCHIVE_UNIVERSAL_ID;
}
if (id == DataTypeManager.LOCAL_ARCHIVE_UNIVERSAL_ID) {
// Already local data type so no source archive associated.
return;
}
// Set the datatype's universal ID to a newly generated universal ID,
// since we no longer want the source archive data type's universal ID.
if (dataType instanceof DataTypeDB) {
DataTypeDB dt = (DataTypeDB) dataType;
dt.setUniversalID(UniversalIdGenerator.nextID());
// Set the source archive to null indicating no associated archive.
dataType.setSourceArchive(null);
// Set the datatype's universal ID to a newly generated universal ID,
// since we no longer want the source archive data type's universal ID.
if (dataType instanceof DataTypeDB) {
DataTypeDB dt = (DataTypeDB) dataType;
dt.setUniversalID(UniversalIdGenerator.nextID());
}
if (oldDtID != null) {
idsToDataTypeMap.removeDataType(sourceArchive, oldDtID);
}
dataTypeChanged(dataType);
}
if (oldDtID != null) {
idsToDataTypeMap.removeDataType(sourceArchive, oldDtID);
finally {
lock.release();
}
dataTypeChanged(dataType);
}
private Collection<DataType> filterOutNonSourceSettableDataTypes(
@ -2694,9 +2701,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
try {
creatingDataType++;
DBRecord record = functionDefAdapter.createRecord(name, funDef.getComment(), cat.getID(),
DEFAULT_DATATYPE_ID, funDef.hasVarArgs(), funDef.getGenericCallingConvention(),
sourceArchiveIdValue, universalIdValue, funDef.getLastChangeTime());
DBRecord record =
functionDefAdapter.createRecord(name, funDef.getComment(), cat.getID(),
DEFAULT_DATATYPE_ID, funDef.hasVarArgs(), funDef.getGenericCallingConvention(),
sourceArchiveIdValue, universalIdValue, funDef.getLastChangeTime());
FunctionDefinitionDB funDefDb =
new FunctionDefinitionDB(this, dtCache, functionDefAdapter, paramAdapter, record);
@ -3696,7 +3704,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
@Override
public DataType getDataType(SourceArchive sourceArchive, UniversalID datatypeID) {
UniversalID sourceID = sourceArchive == null ? null : sourceArchive.getSourceArchiveID();
return idsToDataTypeMap.getDataType(sourceID, datatypeID);
lock.acquire();
try {
return idsToDataTypeMap.getDataType(sourceID, datatypeID);
}
finally {
lock.release();
}
}
@Override
@ -3829,7 +3843,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
monitor.setProgress(0);
monitor.setMaximum(orderedComposites.size());
monitor.setMessage("Updating Datatype Sizes...");
int count = 0;
for (CompositeDB c : orderedComposites) {
monitor.checkCanceled();
@ -4162,7 +4176,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
Map<UniversalID, DataType> idMap =
map.computeIfAbsent(sourceID, k -> new ConcurrentHashMap<>());
final UniversalID sourceArchiveID = sourceID;
UniversalID sourceArchiveID = sourceID;
// note: this call is atomic and has a lock on the 'idMap'. It may call to a method
// that requires a db lock. As such, the call to computeIfAbsent() must be
// made while holding the db lock.
return idMap.computeIfAbsent(dataTypeID,
k -> findDataTypeForIDs(sourceArchiveID, dataTypeID));
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,8 +18,7 @@ package ghidra.program.database.symbol;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.CircularDependencyException;
import ghidra.program.model.listing.GhidraClass;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
@ -63,6 +61,19 @@ class GhidraClassDB implements GhidraClass {
return symbol.getName();
}
public void setName(String name, SourceType source, boolean checkForDuplicates)
throws DuplicateNameException, InvalidInputException {
try {
symbol.doSetNameAndNamespace(name, symbol.getParentNamespace(), source,
checkForDuplicates);
}
catch (CircularDependencyException e) {
// can't happen since we are not changing the namespace
}
}
/**
* @see ghidra.program.model.symbol.Namespace#getID()
*/

View file

@ -104,8 +104,9 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
return false;
}
record = rec;
address = symbolMgr.getAddressMap().decodeAddress(
rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL));
address = symbolMgr.getAddressMap()
.decodeAddress(
rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL));
return true;
}
return false;
@ -522,8 +523,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
return source;
}
@Override
public void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source)
public void doSetNameAndNamespace(String newName, Namespace newNamespace, SourceType source,
boolean checkForDuplicates)
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
lock.acquire();
@ -563,7 +564,11 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
if (!namespaceChange && !nameChange) {
return;
}
symbolMgr.checkDuplicateSymbolName(address, newName, newNamespace, getSymbolType());
if (checkForDuplicates) {
symbolMgr.checkDuplicateSymbolName(address, newName, newNamespace,
getSymbolType());
}
}
if (record != null) {
@ -617,6 +622,13 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
}
}
@Override
public void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source)
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
doSetNameAndNamespace(newName, newNamespace, source, true);
}
protected List<SymbolDB> getSymbolsDynamicallyRenamedByMyRename() {
return null;
}

View file

@ -40,7 +40,6 @@ import ghidra.program.util.LanguageTranslator;
import ghidra.util.*;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
public class SymbolManager implements SymbolTable, ManagerDB {
@ -128,7 +127,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* Find previously defined variable storage address
* @param storage variable storage
* @return previously defined variable storage address or null if not found
* @throws IOException
* @throws IOException if there is database exception
*/
public Address findVariableStorageAddress(VariableStorage storage) throws IOException {
return variableStorageMgr.getVariableStorageAddress(storage, false);
@ -183,7 +182,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* where all the moved external addresses will be placed.
* The triggering of this upgrade relies on the addition of the VariableManager which
* trigger an upgrade.
* @param monitor
* @param monitor the task monitor
*/
private boolean upgradeOldNamespaceAddresses(TaskMonitor monitor)
throws IOException, CancelledException {
@ -239,9 +238,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Upgrade old stack and register variable symbol address to variable addresses.
* Also force associated references to be updated to new variable addresses.
* @param monitor
* @throws IOException
* @throws CancelledException
* @param monitor the task monitor
* @throws IOException if there is database exception
* @throws CancelledException if the operation is cancelled
*/
private void processOldVariableAddresses(TaskMonitor monitor)
throws IOException, CancelledException {
@ -296,8 +295,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* No more sharing the same variable address for multiple variable symbols.
* Must split these up. Only reference to variable addresses should be the
* symbol address - reference refer to physical/stack addresses, and symbolIDs.
* @param monitor
* @throws CancelledException
* @param monitor the task monitor
* @throws CancelledException if the operation is cancelled
*/
public void migrateFromOldVariableStorageManager(TaskMonitor monitor)
throws CancelledException {
@ -396,9 +395,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Add old local symbols
* @param table
* @throws IOException
* @throws CancelledException
* @throws IOException if there is database exception
* @throws CancelledException if the operation is cancelled
*/
private void processOldLocalSymbols(TaskMonitor monitor)
throws IOException, CancelledException {
@ -450,6 +448,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* @param oldAddr old address value from symbol table
* @param name symbol name
* @param isPrimary true if symbol is primary at oldAddr
* @throws IOException if there is database exception
*/
public static void saveLocalSymbol(DBHandle tmpHandle, long symbolID, long oldAddr, String name,
boolean isPrimary) throws IOException {
@ -480,18 +479,15 @@ public class SymbolManager implements SymbolTable, ManagerDB {
return;
}
List<Symbol> symbolList = getSymbols(name, namespace);
for (Symbol symbol : symbolList) {
if (!symbol.getSymbolType().allowsDuplicates()) {
throw new DuplicateNameException(
"A " + symbol.getSymbolType() + " symbol with name " + name +
" already exists in namespace " + symbol.getParentNamespace().getName());
}
Symbol symbol = getFirstSymbol(name, namespace, s -> !s.getSymbolType().allowsDuplicates());
if (symbol != null) {
throw new DuplicateNameException(
"A " + symbol.getSymbolType() + " symbol with name " + name +
" already exists in namespace " + symbol.getParentNamespace().getName());
}
}
/**
/*
* Convert the specified dynamic symbol to a named symbol. Both symbol removed and symbol added
* notifications are performed, although the symbol instance is changed and continues to be
* valid.
@ -509,8 +505,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
Address address = symbol.getAddress();
symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID,
null);
DBRecord record = adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, 0,
1, null, source);
DBRecord record =
adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, 0,
1, null, source);
symbol.setRecord(record);// symbol object was morphed
symbolAdded(symbol);
}
@ -987,10 +984,11 @@ public class SymbolManager implements SymbolTable, ManagerDB {
return searchSymbolsByNamespaceFirst(name, namespace);
}
// Try to find the symbols by searching through all the symbols with the given name and including
// only those in the specified namespace. If there are too many symbols with the same name and
// we are not in the global space, abandon this approach and instead search through all
// the symbols in the namespace and only include those with the specified name.
// Try to find the symbols by searching through all the symbols with the given name
// and including only those in the specified namespace. If there are too many symbols
// with the same name and we are not in the global space, abandon this approach and
// instead search through all the symbols in the namespace and only include those with
// the specified name.
int count = 0;
List<Symbol> list = new ArrayList<>();
SymbolIterator symbols = getSymbols(name);
@ -1009,6 +1007,42 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
}
// note: this could be public; adding it may be confusing due to the potential for having
// multiple symbols and not knowing when to call which method.
private Symbol getFirstSymbol(String name, Namespace namespace, Predicate<Symbol> test) {
if (namespace == null) {
namespace = namespaceMgr.getGlobalNamespace();
}
if (namespace.isExternal() &&
SymbolUtilities.isReservedExternalDefaultName(name, program.getAddressFactory())) {
return findFirstSymbol(name, namespace, test);
}
else if (namespace instanceof Function && hasDefaultVariablePrefix(name)) {
return findFirstSymbol(name, namespace, test);
}
// Try to find the symbols by searching through all the symbols with the given name
// and including only those in the specified namespace. If there are too many symbols
// with the same name and we are not in the global space, abandon this approach and
// instead search through all the symbols in the namespace and only include those with
// the specified name.
int count = 0;
SymbolIterator symbols = getSymbols(name);
for (Symbol s : symbols) {
if (++count == MAX_DUPLICATE_COUNT && !namespace.isGlobal()) {
return findFirstSymbol(name, namespace, test);
}
if (s.getParentNamespace().equals(namespace) &&
test.test(s)) {
return s;
}
}
return null;
}
/**
* Returns the list of symbols with the given name and namespace.
*
@ -1143,7 +1177,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Returns the next available external symbol address
* @return
* @return the address
*/
public Address getNextExternalSymbolAddress() {
int extID = 1;
@ -1414,6 +1448,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
if (!symbol.isDynamic()) {
createLabelHistoryRecord(addr, oldName, newName, LabelHistory.RENAME);
}
program.symbolChanged(symbol, ChangeManager.DOCR_SYMBOL_RENAMED, addr, symbol, oldName,
newName);
}
@ -1493,7 +1528,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
// fire event
program.symbolChanged(symbol, ChangeManager.DOCR_SYMBOL_REMOVED, addr, symbol, name,
new Long(symbolID));
symbolID);
}
void externalEntryPointRemoved(Address addr) {
@ -1543,11 +1578,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
Symbol sym;
/**
* Construct iterator which returns a single symbol
*
* @param addr
*/
SingleSymbolIterator(Symbol sym) {
this.sym = sym;
}
@ -2175,8 +2205,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
void moveLabelHistory(Address oldAddress, Address address) {
try {
historyAdapter.moveAddressRange(oldAddress, address, 1, addrMap,
TaskMonitorAdapter.DUMMY_MONITOR);
historyAdapter.moveAddressRange(oldAddress, address, 1, addrMap, TaskMonitor.DUMMY);
}
catch (CancelledException e) {
// can't happen, used dummy monitor
@ -2266,6 +2295,109 @@ public class SymbolManager implements SymbolTable, ManagerDB {
return new NamespaceDB(s, namespaceMgr);
}
@Override
public GhidraClass convertNamespaceToClass(Namespace namespace) {
if (namespace instanceof GhidraClass) {
return (GhidraClass) namespace;
}
lock.acquire();
try {
checkIsValidNamespaceForMyProgram(namespace);
Symbol namespaceSymbol = namespace.getSymbol();
String name = namespaceSymbol.getName();
SourceType originalSource = namespaceSymbol.getSource();
// no duplicate check, since this class name will be set to that of the existing namespace
String tempName = name + System.nanoTime();
SymbolDB classSymbol =
doCreateSpecialSymbol(Address.NO_ADDRESS, tempName, namespace.getParentNamespace(),
SymbolType.CLASS, -1, -1, null, originalSource, false /*check for duplicate */);
GhidraClassDB classNamespace = new GhidraClassDB(classSymbol, namespaceMgr);
// move everything from old namespace into new class namespace
for (Symbol s : getSymbols(namespace)) {
// no duplicate check, since these symbols all lived under the existing namespace
((SymbolDB) s).doSetNameAndNamespace(s.getName(), classNamespace, s.getSource(),
false /*check for duplicate */);
}
namespaceSymbol.delete();
// fix name now that the old namespace is deleted
classNamespace.setName(name, SourceType.ANALYSIS, false /*check for duplicate */);
return classNamespace;
}
catch (DuplicateNameException | InvalidInputException | CircularDependencyException e) {
throw new AssertException("Unexpected exception creating class from namespace", e);
}
finally {
lock.release();
}
}
private void checkIsValidNamespaceForMyProgram(Namespace namespace) {
if (namespace == null) {
return;
}
if (namespace == program.getGlobalNamespace()) {
return;
}
if (!(namespace instanceof NamespaceDB)) {
throw new IllegalArgumentException(
"Namespace is not a valid parent for symbols: " +
namespace.getClass());
}
SymbolDB dbSymbol = (SymbolDB) namespace.getSymbol();
if (program != dbSymbol.getProgram()) {
throw new IllegalArgumentException(
"Namespace symbol is from a different program");
}
// may throw a ConcurrentModificationException
dbSymbol.checkDeleted();
}
@Override
public Namespace getOrCreateNameSpace(Namespace parent, String name, SourceType source)
throws DuplicateNameException, InvalidInputException {
lock.acquire();
try {
checkIsValidNamespaceForMyProgram(parent);
Symbol namespaceSymbol = getFirstSymbol(name, parent, s -> {
return s.getSymbolType() == SymbolType.NAMESPACE ||
s.getSymbolType() == SymbolType.CLASS;
});
if (namespaceSymbol != null) {
return (Namespace) namespaceSymbol.getObject();
}
// Note: We know there are no namespaces with the name; do we still have to check for
// duplicates? Assuming yes, as another symbol type may exist with this name.
SymbolDB s =
doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, -1,
-1, null, source, true /*check for duplicates*/);
return new NamespaceDB(s, namespaceMgr);
}
finally {
lock.release();
}
}
@Override
public Symbol createSymbolPlaceholder(Address address, long id) {
return SymbolDB.createSymbolPlaceholder(this, address, id);
@ -2293,12 +2425,24 @@ public class SymbolManager implements SymbolTable, ManagerDB {
SymbolType symbolType, long data1, int data2, String data3, SourceType source)
throws DuplicateNameException, InvalidInputException {
return doCreateSpecialSymbol(addr, name, parent, symbolType, data1, data2, data3, source,
true);
}
private SymbolDB doCreateSpecialSymbol(Address addr, String name, Namespace parent,
SymbolType symbolType, long data1, int data2, String data3, SourceType source,
boolean checkForDuplicates)
throws DuplicateNameException, InvalidInputException {
lock.acquire();
try {
parent = validateNamespace(parent, addr, symbolType);
source = validateSource(source, name, addr, symbolType);
name = validateName(name, source);
checkDuplicateSymbolName(addr, name, parent, symbolType);
if (checkForDuplicates) {
checkDuplicateSymbolName(addr, name, parent, symbolType);
}
return doCreateSymbol(name, addr, parent, symbolType, data1, data2, data3, source);
}
@ -2378,7 +2522,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
/**
* Internal method for creating funcions symbols.
* Internal method for creating function symbols
*
* @param addr the address for the new symbol
* @param name the name of the new symbol
* @param namespace the namespace for the new symbol
@ -2489,8 +2634,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
long data1, int data2, String data3, SourceType source) {
try {
DBRecord record = adapter.createSymbol(name, addr, namespace.getID(), type, data1, data2,
data3, source);
DBRecord record =
adapter.createSymbol(name, addr, namespace.getID(), type, data1, data2,
data3, source);
SymbolDB newSymbol = makeSymbol(addr, record, type);
symbolAdded(newSymbol);
@ -2633,19 +2779,29 @@ public class SymbolManager implements SymbolTable, ManagerDB {
@Override
public Symbol getVariableSymbol(String name, Function function) {
return findFirstSymbol(name, function, s -> {
return getFirstSymbol(name, function, s -> {
SymbolType t = s.getSymbolType();
return t == SymbolType.PARAMETER || t == SymbolType.LOCAL_VAR;
});
}
private Symbol getSpecificSymbol(String name, Namespace namespace, SymbolType type) {
return findFirstSymbol(name, namespace, s -> s.getSymbolType() == type);
return getFirstSymbol(name, namespace, s -> s.getSymbolType() == type);
}
private Symbol findFirstSymbol(String name, Namespace namespace, Predicate<Symbol> test) {
List<Symbol> symbols = getSymbols(name, namespace);
return symbols.stream().filter(test).findFirst().orElse(null);
if (namespace == null) {
namespace = namespaceMgr.getGlobalNamespace();
}
SymbolIterator it = getSymbols(namespace);
while (it.hasNext()) {
Symbol s = it.next();
if (s.getName().equals(name) && test.test(s)) {
return s;
}
}
return null;
}
}

View file

@ -15,8 +15,7 @@
*/
package ghidra.program.model.symbol;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
@ -504,7 +503,7 @@ public interface SymbolTable {
* @param name name of the namespace
* @param source the source of this class namespace's symbol
* @return new class namespace
* @throws DuplicateNameException thrown if another non function or lable symbol exists with the given name
* @throws DuplicateNameException thrown if another non function or label symbol exists with the given name
* @throws InvalidInputException throw if the name has invalid characters or is null
* @throws IllegalArgumentException if you try to set the source to 'Symbol.DEFAULT'.
*/
@ -523,7 +522,7 @@ public interface SymbolTable {
* @param source the source of this external library's symbol
* @return the new Library namespace.
* @throws IllegalArgumentException if you try to set the source to 'Symbol.DEFAULT'.
* @throws DuplicateNameException thrown if another non function or lable symbol exists with the given name
* @throws DuplicateNameException thrown if another non function or label symbol exists with the given name
*/
public Library createExternalLibrary(String name, SourceType source)
throws DuplicateNameException, InvalidInputException;
@ -534,7 +533,7 @@ public interface SymbolTable {
* @param name the name of the new namespace
* @param source the source of this namespace's symbol
* @return the new Namespace object.
* @throws DuplicateNameException thrown if another non function or lable symbol exists with the given name
* @throws DuplicateNameException thrown if another non function or label symbol exists with the given name
* @throws InvalidInputException if the name is invalid.
* @throws IllegalArgumentException if you try to set the source to 'Symbol.DEFAULT'.
*/
@ -552,4 +551,32 @@ public interface SymbolTable {
*/
public Symbol createSymbolPlaceholder(Address address, long id);
/**
* Converts the given namespace to a class namespace
*
* @param namespace the namespace to convert
* @return the new class
* @throws IllegalArgumentException if the given parent namespace is from a different program
* than that of this symbol table
* @throws ConcurrentModificationException if the given parent namespace has been deleted
*/
public GhidraClass convertNamespaceToClass(Namespace namespace);
/**
* Gets an existing namespace with the given name in the given parent. If no namespace exists,
* then one will be created.
*
* @param parent the parent namespace
* @param name the namespace name
* @param source the source type for the namespace if one is created
* @return the namespace
* @throws DuplicateNameException thrown if another non function or label symbol exists with
* the given name
* @throws InvalidInputException if the name is invalid
* @throws IllegalArgumentException if the given parent namespace is from a different program
* than that of this symbol table
* @throws ConcurrentModificationException if the given parent namespace has been deleted
*/
public Namespace getOrCreateNameSpace(Namespace parent, String name, SourceType source)
throws DuplicateNameException, InvalidInputException;
}