GP-1069 improved namespace checking for symbols

This commit is contained in:
ghidra1 2021-12-13 14:22:27 -05:00
parent b5927ce849
commit d618f84b7c
14 changed files with 103 additions and 198 deletions

View file

@ -95,18 +95,7 @@ public class ClassSymbol extends SymbolDB {
*/
@Override
public boolean isValidParent(Namespace parent) {
return SymbolType.CLASS.isValidParent(symbolMgr.getProgram(), parent, address,
isExternal());
// if (parent == symbolMgr.getProgram().getGlobalNamespace()) {
// return true;
// }
// if (isExternal() != parent.isExternal()) {
// return false;
// }
// Symbol newParentSym = parent.getSymbol();
// if (symbolMgr.getProgram() != newParentSym.getProgram()) {
// return false;
// }
// return (symbolMgr.getFunctionSymbol(parent) == null);
return super.isValidParent(parent) &&
SymbolType.CLASS.isValidParent(symbolMgr.getProgram(), parent, address, isExternal());
}
}

View file

@ -218,29 +218,8 @@ public class CodeSymbol extends SymbolDB {
*/
@Override
public boolean isValidParent(Namespace parent) {
return SymbolType.LABEL.isValidParent(symbolMgr.getProgram(), parent, address,
isExternal());
// if (isExternal() != parent.isExternal()) {
// return false;
// }
// Symbol newParentSym = parent.getSymbol();
// if (symbolMgr.getProgram() != newParentSym.getProgram()) {
// return false;
// }
// SymbolDB functionSymbol = symbolMgr.getFunctionSymbol(parent);
// if (functionSymbol != null) {
// if (isExternal()) {
// return false;
// }
// CodeUnit cu = (CodeUnit) getObject();
// if (cu != null) {
// Function function = (Function) functionSymbol.getObject();
// return function.getBody().contains(cu.getMinAddress());
// }
// return false;
// }
// return true;
return super.isValidParent(parent) &&
SymbolType.LABEL.isValidParent(symbolMgr.getProgram(), parent, address, isExternal());
}
@Override

View file

@ -202,8 +202,8 @@ public class FunctionSymbol extends SymbolDB {
@Override
public boolean isValidParent(Namespace parent) {
return SymbolType.FUNCTION.isValidParent(symbolMgr.getProgram(), parent, address,
isExternal());
return super.isValidParent(parent) && SymbolType.FUNCTION
.isValidParent(symbolMgr.getProgram(), parent, address, isExternal());
}
@Override

View file

@ -1,87 +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.program.database.symbol;
import db.DBRecord;
import ghidra.program.database.DBObjectCache;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.Register;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SymbolType;
import ghidra.program.util.ProgramLocation;
/**
* Symbols for global registers.
*/
public class GlobalRegisterSymbol extends SymbolDB {
/**
* Construct a new GlobalRegisterSymbol.
* @param mgr the symbol manager
* @param cache symbol object cache
* @param addr the address for this symbol.
* @param record the record for this symbol.
*/
public GlobalRegisterSymbol(SymbolManager mgr, DBObjectCache<SymbolDB> cache, Address addr,
DBRecord record) {
super(mgr, cache, addr, record);
}
/**
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
*/
public SymbolType getSymbolType() {
return SymbolType.GLOBAL_VAR;
}
@Override
public boolean isExternal() {
return false;
}
/**
* @see ghidra.program.model.symbol.Symbol#getObject()
*/
public Object getObject() {
Register reg = symbolMgr.getProgram().getRegister(getAddress());
return reg;
}
/**
* @see ghidra.program.model.symbol.Symbol#isPrimary()
*/
@Override
public boolean isPrimary() {
return true;
}
/**
* @see ghidra.program.model.symbol.Symbol#getProgramLocation()
*/
public ProgramLocation getProgramLocation() {
return null;
}
/**
* @see ghidra.program.model.symbol.Symbol#isValidParent(ghidra.program.model.symbol.Namespace)
*/
@Override
public boolean isValidParent(Namespace parent) {
return SymbolType.GLOBAL_VAR.isValidParent(symbolMgr.getProgram(), parent, address,
isExternal());
}
}

View file

@ -18,22 +18,31 @@ package ghidra.program.database.symbol;
import db.DBRecord;
import ghidra.program.database.DBObjectCache;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.symbol.SymbolType;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.AssertException;
public class GlobalVariableSymbolDB extends VariableSymbolDB {
// NOTE: global variable symbols are not yet supported (API does not yet facilitate creation)
/**
* Constructs a new GlobalVariableSymbolDB
* Constructs a new GlobalVariableSymbolDB which are restricted to the global namespace
* @param symbolMgr the symbol manager
* @param cache symbol object cache
* @param variableMgr variable storage manager
* @param address the address of the symbol (stack address)
* @param record the record for the symbol
*/
public GlobalVariableSymbolDB(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache,
VariableStorageManagerDB variableMgr, Address address, DBRecord record) {
super(symbolMgr, cache, SymbolType.GLOBAL_VAR, variableMgr, address, record);
if (record.getLongValue(
SymbolDatabaseAdapter.SYMBOL_PARENT_COL) != Namespace.GLOBAL_NAMESPACE_ID) {
throw new AssertException();
}
}
@Override
@ -41,6 +50,12 @@ public class GlobalVariableSymbolDB extends VariableSymbolDB {
return SymbolType.GLOBAL_VAR;
}
@Override
public boolean isValidParent(Namespace parent) {
// symbol is locked to program's global namespace
return symbolMgr.getProgram().getGlobalNamespace() == parent;
}
@Override
public Object getObject() {
if (!checkIsValid()) {
@ -50,20 +65,44 @@ public class GlobalVariableSymbolDB extends VariableSymbolDB {
if (storage == null) {
return null;
}
return storage.getRegister();
return storage;
}
@Override
protected String doGetName() {
if (!checkIsValid()) {
// TODO: SCR
return "[Invalid VariableSymbol - Deleted!]";
// TODO: SCR
return "[Invalid Global Variable Symbol - Deleted!]";
}
VariableStorage storage = getVariableStorage();
if (storage == null) {
if (storage == null || storage.isBadStorage()) {
return Function.DEFAULT_LOCAL_PREFIX + "_!BAD!";
}
if (getSource() == SourceType.DEFAULT) {
return getDefaultLocalName(getProgram(), storage);
}
return super.doGetName();
}
// TODO: move method to SymbolUtilities when support for global variables has been added
private static String getDefaultLocalName(Program program, VariableStorage storage) {
StringBuilder buffy = new StringBuilder("global");
for (Varnode v : storage.getVarnodes()) {
buffy.append('_');
Register reg = program.getRegister(v);
if (reg != null) {
buffy.append(reg.getName());
}
else {
Address addr = v.getAddress();
buffy.append(addr.getAddressSpace().getName() + Long.toHexString(addr.getOffset()));
}
}
return buffy.toString();
}
}

View file

@ -126,7 +126,7 @@ public class LibrarySymbol extends SymbolDB {
@Override
public boolean isValidParent(Namespace parent) {
return SymbolType.LIBRARY.isValidParent(symbolMgr.getProgram(), parent, address,
isExternal());
return super.isValidParent(parent) &&
SymbolType.LIBRARY.isValidParent(symbolMgr.getProgram(), parent, address, isExternal());
}
}

View file

@ -91,23 +91,7 @@ public class NamespaceSymbol extends SymbolDB {
@Override
public boolean isValidParent(Namespace parent) {
// TODO: Not sure what other constraints should be placed on namespace movement
return SymbolType.NAMESPACE.isValidParent(symbolMgr.getProgram(), parent, address,
isExternal());
// if (parent == symbolMgr.getProgram().getGlobalNamespace()) {
// return true;
// }
// if (isExternal() != parent.isExternal()) {
// return false;
// }
// Symbol newParentSym = parent.getSymbol();
// if (symbolMgr.getProgram() != newParentSym.getProgram()) {
// return false;
// }
// if (isExternal() && symbolMgr.getFunctionSymbol(parent) != null) {
// // External function can not have a child namespace
// return false;
// }
// return true;
return super.isValidParent(parent) && SymbolType.NAMESPACE
.isValidParent(symbolMgr.getProgram(), parent, address, isExternal());
}
}

View file

@ -570,6 +570,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
checkDeleted();
checkEditOK();
symbolMgr.checkValidNamespaceArgument(newNamespace);
source = validateNameSource(newName, source);
symbolMgr.validateSource(newName, getAddress(), getSymbolType(), source);
@ -1004,7 +1006,9 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
}
@Override
public abstract boolean isValidParent(Namespace parent);
public boolean isValidParent(Namespace parent) {
return symbolMgr.isMyNamespace(parent);
}
/**
* Change the record and key associated with this symbol

View file

@ -27,6 +27,7 @@ import db.*;
import ghidra.program.database.*;
import ghidra.program.database.code.CodeManager;
import ghidra.program.database.external.ExternalManagerDB;
import ghidra.program.database.function.FunctionDB;
import ghidra.program.database.function.FunctionManagerDB;
import ghidra.program.database.map.AddressMap;
import ghidra.program.database.references.ReferenceDBManager;
@ -582,8 +583,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
return new VariableSymbolDB(this, cache, type, variableStorageMgr, addr, record);
}
else if (type == SymbolType.GLOBAL_VAR) {
// TODO: Should this be a variable symbol which can return a variable ??
return new GlobalRegisterSymbol(this, cache, addr, record);
return new GlobalVariableSymbolDB(this, cache, variableStorageMgr, addr, record);
}
throw new IllegalArgumentException("No symbol type for " + type);
}
@ -884,6 +884,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
namespace = program.getGlobalNamespace();
}
checkValidNamespaceArgument(namespace);
long namespaceId = namespace.getID();
lock.acquire();
@ -966,6 +968,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
namespace = namespaceMgr.getGlobalNamespace();
}
checkValidNamespaceArgument(namespace);
// if name is possible default parameter or local variable name, must do brute force search
if (namespace instanceof Function &&
SymbolUtilities.isPossibleDefaultLocalOrParamName(name)) {
@ -1040,6 +1044,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
namespace = namespaceMgr.getGlobalNamespace();
}
checkValidNamespaceArgument(namespace);
// if name is possible default parameter or local variable name, must do brute force search
if (namespace instanceof Function &&
SymbolUtilities.isPossibleDefaultLocalOrParamName(name)) {
@ -1090,6 +1096,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
@Override
public SymbolIterator getSymbols(Namespace namespace) {
checkValidNamespaceArgument(namespace);
return getSymbols(namespace.getID());
}
@ -2472,7 +2479,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* Creates variable symbols. Note this is not a method defined in the Symbol Table interface.
* It is intended to be used by Ghidra program internals.
* @param name the name of the variable
* @param namespace the function that contains the variable.
* @param function the function that contains the variable.
* @param type the type of the variable (can only be PARAMETER or LOCAL_VAR)
* @param firstUseOffsetOrOrdinal the offset in the function where the variable is first used.
* @param storage the VariableStorage (stack, registers, etc.)
@ -2481,7 +2488,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* @throws DuplicateNameException if there is another variable in this function with that name.
* @throws InvalidInputException if the name contains illegal characters (space for example)
*/
public VariableSymbolDB createVariableSymbol(String name, Namespace namespace, SymbolType type,
public VariableSymbolDB createVariableSymbol(String name, FunctionDB function, SymbolType type,
int firstUseOffsetOrOrdinal, VariableStorage storage, SourceType source)
throws DuplicateNameException, InvalidInputException {
@ -2489,16 +2496,13 @@ public class SymbolManager implements SymbolTable, ManagerDB {
throw new IllegalArgumentException("Invalid symbol type for variable: " + type);
}
if (!(namespace instanceof Function)) {
throw new IllegalArgumentException(
"Function must be namespace for local variable or parameter");
}
checkValidNamespaceArgument(function);
lock.acquire();
try {
source = adjustSourceTypeIfNecessary(name, type, source, storage);
Address varAddr = variableStorageMgr.getVariableStorageAddress(storage, true);
return (VariableSymbolDB) doCreateSpecialSymbol(varAddr, name, namespace, type, null,
return (VariableSymbolDB) doCreateSpecialSymbol(varAddr, name, function, type, null,
Integer.valueOf(firstUseOffsetOrOrdinal), null, source, true);
}
catch (IOException e) {
@ -2553,7 +2557,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
lock.acquire();
try {
checkIsValidNamespaceForMyProgram(namespace);
checkValidNamespaceArgument(namespace);
Symbol namespaceSymbol = namespace.getSymbol();
String name = namespaceSymbol.getName();
@ -2589,33 +2593,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
}
private void checkIsValidNamespaceForMyProgram(Namespace namespace) {
if (namespace == null) {
return;
}
if (namespace == program.getGlobalNamespace()) {
return;
}
Symbol symbol = namespace.getSymbol();
if (!(symbol instanceof SymbolDB)) {
// unexpected namespace type; all supported types will be db objects
throw new IllegalArgumentException(
"Namespace is not a valid parent for symbols: " + namespace.getClass());
}
SymbolDB dbSymbol = (SymbolDB) symbol;
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 {
@ -2623,7 +2600,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
lock.acquire();
try {
checkIsValidNamespaceForMyProgram(parent);
checkValidNamespaceArgument(parent);
Symbol namespaceSymbol = getFirstSymbol(name, parent, s -> {
return s.getSymbolType() == SymbolType.NAMESPACE ||
@ -2718,7 +2695,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
@Override
public Symbol createLabel(Address addr, String name, SourceType source)
throws InvalidInputException {
return createLabel(addr, name, null, source);
}
@ -2909,6 +2885,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
namespace = namespace == null ? namespaceMgr.getGlobalNamespace() : namespace;
checkValidNamespaceArgument(namespace);
checkAddressAndNameSpaceValidForSymbolType(addr, namespace, type);
return namespace;
@ -3073,4 +3051,18 @@ public class SymbolManager implements SymbolTable, ManagerDB {
private Symbol getSpecificSymbol(String name, Namespace namespace, SymbolType type) {
return getFirstSymbol(name, namespace, s -> s.getSymbolType() == type);
}
void checkValidNamespaceArgument(Namespace namespace) throws IllegalArgumentException {
if (!isMyNamespace(namespace)) {
String kind = (namespace instanceof Function) ? "function" : "namespace";
throw new IllegalArgumentException(
kind + " is from different program instance: " + namespace);
}
}
boolean isMyNamespace(Namespace namespace) {
Symbol newNamespaceSymbol = namespace.getSymbol();
return newNamespaceSymbol != null && !newNamespaceSymbol.isDeleted() &&
(newNamespaceSymbol.getProgram() == getProgram());
}
}

View file

@ -49,6 +49,7 @@ public class VariableSymbolDB extends SymbolDB {
* @param symbolMgr the symbol manager
* @param cache symbol object cache
* @param type the symbol type.
* @param variableMgr variable storage manager
* @param address the address of the symbol (stack address)
* @param record the record for the symbol
*/
@ -194,6 +195,7 @@ public class VariableSymbolDB extends SymbolDB {
*/
@Override
public boolean isValidParent(Namespace parent) {
// symbol is locked to single function and can't be moved
return getFunction() == parent;
}

View file

@ -33,8 +33,8 @@ public class GlobalNamespace implements Namespace {
*/
public static final String GLOBAL_NAMESPACE_NAME = "Global";
private Memory memory;
private Symbol globalSymbol;
final Memory memory;
final Symbol globalSymbol;
/**
* Constructs a new GlobalNamespace

View file

@ -68,7 +68,7 @@ public class GlobalSymbol implements Symbol {
@Override
public Program getProgram() {
return null;
return globalNamespace.memory.getProgram();
}
@Override

View file

@ -164,6 +164,9 @@ public class HighFunction extends PcodeSyntaxTree {
* a) switch flow
*/
private void grabOverrides() {
if (!(func instanceof FunctionDB)) {
return; // undefined function
}
SymbolTable symtab = func.getProgram().getSymbolTable();
Namespace space = findOverrideSpace(func);
if (space == null) {

View file

@ -39,8 +39,8 @@ public interface Namespace {
public static final String NAMESPACE_DELIMITER = "::";
/**
* Get the symbol for this namespace; Note: The global namespace will return null
* @return the symbol for this namespace; Note: The global namespace will return null
* Get the symbol for this namespace.
* @return the symbol for this namespace.
*/
public Symbol getSymbol();