mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 12:00:04 +02:00
Merge remote-tracking branch 'origin/GP-1082_ghidravore_improving_symbol_table_performance'
This commit is contained in:
commit
156ce7ef80
32 changed files with 1938 additions and 821 deletions
|
@ -98,7 +98,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
|
||||
@Override
|
||||
public String getOriginalImportedName() {
|
||||
return getExternalData3(symbol).getOriginalImportedName();
|
||||
return getExternalData(symbol).getOriginalImportedName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +111,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
*/
|
||||
@Override
|
||||
public Address getAddress() {
|
||||
return getExternalData3(symbol).getAddress(extMgr.getAddressMap().getAddressFactory());
|
||||
return getExternalData(symbol).getAddress(extMgr.getAddressMap().getAddressFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,7 +141,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
*/
|
||||
@Override
|
||||
public DataType getDataType() {
|
||||
long dataTypeID = symbol.getSymbolData1();
|
||||
long dataTypeID = symbol.getDataTypeId();
|
||||
if (dataTypeID < 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
@Override
|
||||
public void setDataType(DataType dt) {
|
||||
long dataTypeID = extMgr.getProgram().getDataTypeManager().getResolvedID(dt);
|
||||
symbol.setSymbolData1(dataTypeID);
|
||||
symbol.setDataTypeId(dataTypeID);
|
||||
|
||||
// TODO: change notification may be required
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
if (addressString == null && getSource() == SourceType.DEFAULT) {
|
||||
throw new InvalidInputException("Either an external label or address is required");
|
||||
}
|
||||
updateSymbolData3(symbol, getExternalData3(symbol).getOriginalImportedName(),
|
||||
updateSymbolData(symbol, getExternalData(symbol).getOriginalImportedName(),
|
||||
addressString);
|
||||
}
|
||||
|
||||
|
@ -365,18 +365,18 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
|
||||
}
|
||||
|
||||
static ExternalData3 getExternalData3(SymbolDB extSymbol) {
|
||||
return new ExternalData3(extSymbol.getSymbolData3());
|
||||
static ExternalData getExternalData(SymbolDB extSymbol) {
|
||||
return new ExternalData(extSymbol.getSymbolStringData());
|
||||
}
|
||||
|
||||
static void setOriginalImportedName(SymbolDB extSymbol, String name) {
|
||||
updateSymbolData3(extSymbol, name, getExternalData3(extSymbol).getAddressString());
|
||||
updateSymbolData(extSymbol, name, getExternalData(extSymbol).getAddressString());
|
||||
}
|
||||
|
||||
static void updateSymbolData3(SymbolDB extSymbol, String originalImportedName,
|
||||
static void updateSymbolData(SymbolDB extSymbol, String originalImportedName,
|
||||
String addressString) {
|
||||
if (addressString == null && originalImportedName == null) {
|
||||
extSymbol.setSymbolData3(null);
|
||||
extSymbol.setSymbolStringData(null);
|
||||
}
|
||||
StringBuilder buf = new StringBuilder();
|
||||
if (addressString != null) {
|
||||
|
@ -386,18 +386,18 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
buf.append(ORIGINAL_IMPORTED_DELIMITER);
|
||||
buf.append(originalImportedName);
|
||||
}
|
||||
extSymbol.setSymbolData3(buf.toString());
|
||||
extSymbol.setSymbolStringData(buf.toString());
|
||||
}
|
||||
|
||||
static class ExternalData3 {
|
||||
static class ExternalData {
|
||||
private String originalImportedName;
|
||||
private String addressString;
|
||||
|
||||
ExternalData3(String data3) {
|
||||
if (data3 != null) {
|
||||
int indexOf = data3.indexOf(ORIGINAL_IMPORTED_DELIMITER);
|
||||
originalImportedName = indexOf >= 0 ? data3.substring(indexOf + 1) : null;
|
||||
addressString = indexOf >= 0 ? data3.substring(0, indexOf) : data3;
|
||||
ExternalData(String stringData) {
|
||||
if (stringData != null) {
|
||||
int indexOf = stringData.indexOf(ORIGINAL_IMPORTED_DELIMITER);
|
||||
originalImportedName = indexOf >= 0 ? stringData.substring(indexOf + 1) : null;
|
||||
addressString = indexOf >= 0 ? stringData.substring(0, indexOf) : stringData;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import db.*;
|
|||
import ghidra.framework.store.FileSystem;
|
||||
import ghidra.program.database.ManagerDB;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.external.ExternalLocationDB.ExternalData3;
|
||||
import ghidra.program.database.external.ExternalLocationDB.ExternalData;
|
||||
import ghidra.program.database.function.FunctionManagerDB;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.database.symbol.*;
|
||||
|
@ -556,15 +556,15 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
if ((type != SymbolType.LABEL && type != SymbolType.FUNCTION) || !sym.isExternal()) {
|
||||
throw new AssertException();
|
||||
}
|
||||
ExternalData3 externalData3 = ExternalLocationDB.getExternalData3(sym);
|
||||
Address addr = externalData3.getAddress(sym.getProgram().getAddressFactory());
|
||||
ExternalData externalData = ExternalLocationDB.getExternalData(sym);
|
||||
Address addr = externalData.getAddress(sym.getProgram().getAddressFactory());
|
||||
if (addr == null) {
|
||||
throw new AssertException("External should not be default without memory address");
|
||||
}
|
||||
if (type == SymbolType.FUNCTION) {
|
||||
return SymbolUtilities.getDefaultExternalFunctionName(addr);
|
||||
}
|
||||
long dataTypeID = sym.getSymbolData1();
|
||||
long dataTypeID = sym.getDataTypeId();
|
||||
DataType dt =
|
||||
(dataTypeID < 0) ? null : sym.getProgram().getDataTypeManager().getDataType(dataTypeID);
|
||||
return SymbolUtilities.getDefaultExternalName(addr, dt);
|
||||
|
@ -695,7 +695,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
private Library addExternalName(String name, String pathname, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
SymbolDB s = symbolMgr.createSpecialSymbol(Address.NO_ADDRESS, name,
|
||||
scopeMgr.getGlobalNamespace(), SymbolType.LIBRARY, -1, 0, pathname, source); // 0 set first id for external names
|
||||
scopeMgr.getGlobalNamespace(), SymbolType.LIBRARY, null, null, pathname, source);
|
||||
return (Library) s.getObject();
|
||||
}
|
||||
|
||||
|
@ -742,7 +742,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
public String getExternalLibraryPath(String externalName) {
|
||||
SymbolDB s = (SymbolDB) symbolMgr.getLibrarySymbol(externalName);
|
||||
if (s instanceof LibrarySymbol) {
|
||||
return s.getSymbolData3();
|
||||
return s.getSymbolStringData();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -771,7 +771,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
}
|
||||
}
|
||||
else if (s instanceof LibrarySymbol) {
|
||||
s.setSymbolData3(externalPath);
|
||||
s.setSymbolStringData(externalPath);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -802,7 +802,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
return null;
|
||||
}
|
||||
//long dtId = symbol.getSymbolData1();
|
||||
String extData3 = symbol.getSymbolData3();
|
||||
String extData = symbol.getSymbolStringData();
|
||||
String name = symbol.getName();
|
||||
Namespace namespace = symbol.getParentNamespace();
|
||||
Address extAddr = symbol.getAddress();
|
||||
|
@ -810,7 +810,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
|
||||
((CodeSymbol) symbol).delete(true);
|
||||
|
||||
return functionMgr.createExternalFunction(extAddr, name, namespace, extData3, source);
|
||||
return functionMgr.createExternalFunction(extAddr, name, namespace, extData, source);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -927,8 +927,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
while (externalSymbols.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
SymbolDB s = (SymbolDB) externalSymbols.next();
|
||||
ExternalData3 externalData3 = ExternalLocationDB.getExternalData3(s);
|
||||
String addrStr = externalData3.getAddressString();
|
||||
ExternalData externalData = ExternalLocationDB.getExternalData(s);
|
||||
String addrStr = externalData.getAddressString();
|
||||
if (addrStr == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -947,7 +947,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
addr = newAddressSpace.getAddress(addr.getOffset());
|
||||
String newAddrStr = addr.toString();
|
||||
if (!newAddrStr.equals(addrStr)) {
|
||||
ExternalLocationDB.updateSymbolData3(s, externalData3.getOriginalImportedName(),
|
||||
ExternalLocationDB.updateSymbolData(s, externalData.getOriginalImportedName(),
|
||||
newAddrStr); // store translated external location address
|
||||
}
|
||||
}
|
||||
|
|
|
@ -990,7 +990,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
|||
symbolMap.put(v.symbol, v);
|
||||
}
|
||||
if (var.getComment() != null) {
|
||||
v.symbol.setSymbolData3(var.getComment());
|
||||
v.symbol.setSymbolStringData(var.getComment());
|
||||
}
|
||||
manager.functionChanged(this, 0);
|
||||
return v;
|
||||
|
@ -1678,7 +1678,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
|||
manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_PARAMETERS);
|
||||
}
|
||||
if (var.getComment() != null) {
|
||||
p.symbol.setSymbolData3(var.getComment());
|
||||
p.symbol.setSymbolStringData(var.getComment());
|
||||
}
|
||||
updateSignatureSourceAfterVariableChange(source, p.getDataType());
|
||||
return p;
|
||||
|
|
|
@ -273,22 +273,22 @@ public class FunctionManagerDB implements FunctionManager {
|
|||
* Transform an existing external symbol into an external function.
|
||||
* This method should only be invoked by an ExternalSymbol
|
||||
* @param extSpaceAddr the external space address to use when creating this external.
|
||||
* @param name
|
||||
* @param nameSpace
|
||||
* @param extData3 internal symbol-data-3 string (see {@link ExternalLocationDB})
|
||||
* @param name the external function name
|
||||
* @param nameSpace the external function namespace
|
||||
* @param extData the external data string to store additional info (see {@link ExternalLocationDB})
|
||||
* @param source the source of this external.
|
||||
* @return external function
|
||||
* @throws InvalidInputException
|
||||
* @throws DuplicateNameException
|
||||
* @throws InvalidInputException if the name is invalid
|
||||
* @throws DuplicateNameException if the name is an invalid duplicate
|
||||
*/
|
||||
public Function createExternalFunction(Address extSpaceAddr, String name, Namespace nameSpace,
|
||||
String extData3, SourceType source)
|
||||
String extData, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
lock.acquire();
|
||||
try {
|
||||
|
||||
Symbol symbol = symbolMgr.createSpecialSymbol(extSpaceAddr, name, nameSpace,
|
||||
SymbolType.FUNCTION, -1, -1, extData3, source);
|
||||
SymbolType.FUNCTION, null, null, extData, source);
|
||||
|
||||
long returnDataTypeId = program.getDataTypeManager().getResolvedID(DataType.DEFAULT);
|
||||
|
||||
|
|
|
@ -167,12 +167,12 @@ public abstract class VariableDB implements Variable {
|
|||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return symbol.getSymbolData3();
|
||||
return symbol.getSymbolStringData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComment(String comment) {
|
||||
symbol.setSymbolData3(comment);
|
||||
symbol.setSymbolStringData(comment);
|
||||
functionMgr.functionChanged(function, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,26 +20,21 @@ import java.util.Iterator;
|
|||
|
||||
import db.DBRecord;
|
||||
import db.RecordIterator;
|
||||
import ghidra.program.database.util.Query;
|
||||
import ghidra.program.database.util.QueryRecordIterator;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.database.util.*;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolIterator;
|
||||
|
||||
/**
|
||||
*
|
||||
* Iterator (in address order) over primary symbols in an address set.
|
||||
* Iterator (in address order) over all symbols that match the given query in an address set.
|
||||
*
|
||||
*
|
||||
*/
|
||||
class AddressSetFilteredSymbolIterator implements SymbolIterator {
|
||||
private SymbolManager symbolMgr;
|
||||
private AddressRangeIterator rangeIter;
|
||||
private QueryRecordIterator recIter;
|
||||
private Symbol currentSymbol;
|
||||
private SymbolDatabaseAdapter adapter;
|
||||
private boolean forward;
|
||||
private Query query;
|
||||
|
||||
/**
|
||||
* Construct a new AddressSetFilteredSymbolIterator.
|
||||
|
@ -51,53 +46,40 @@ class AddressSetFilteredSymbolIterator implements SymbolIterator {
|
|||
AddressSetFilteredSymbolIterator(SymbolManager symbolMgr, AddressSetView set, Query query,
|
||||
boolean forward) {
|
||||
this.symbolMgr = symbolMgr;
|
||||
rangeIter = set.getAddressRanges(forward);
|
||||
adapter = symbolMgr.getDatabaseAdapter();
|
||||
this.forward = forward;
|
||||
this.query = query;
|
||||
try {
|
||||
RecordIterator it = adapter.getSymbols(set, forward);
|
||||
recIter = new QueryRecordIterator(it, query, forward);
|
||||
}
|
||||
catch (IOException e) {
|
||||
symbolMgr.dbError(e);
|
||||
recIter = new QueryRecordIterator(new EmptyRecordIterator(), query, forward);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (currentSymbol == null) {
|
||||
try {
|
||||
findNext();
|
||||
}
|
||||
catch (IOException e) {
|
||||
symbolMgr.dbError(e);
|
||||
}
|
||||
try {
|
||||
return recIter.hasNext();
|
||||
}
|
||||
return currentSymbol != null;
|
||||
catch (IOException e) {
|
||||
symbolMgr.dbError(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol next() {
|
||||
if (hasNext()) {
|
||||
Symbol s = currentSymbol;
|
||||
currentSymbol = null;
|
||||
return s;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void findNext() throws IOException {
|
||||
if (recIter != null && recIter.hasNext()) {
|
||||
DBRecord rec = recIter.next();
|
||||
currentSymbol = symbolMgr.getSymbol(rec);
|
||||
}
|
||||
else {
|
||||
while (rangeIter.hasNext()) {
|
||||
AddressRange range = rangeIter.next();
|
||||
RecordIterator it =
|
||||
adapter.getSymbols(range.getMinAddress(), range.getMaxAddress(), forward);
|
||||
recIter = new QueryRecordIterator(it, query, forward);
|
||||
if (recIter.hasNext()) {
|
||||
DBRecord rec = recIter.next();
|
||||
currentSymbol = symbolMgr.getSymbol(rec);
|
||||
break;
|
||||
}
|
||||
try {
|
||||
DBRecord rec = recIter.next();
|
||||
return symbolMgr.getSymbol(rec);
|
||||
}
|
||||
catch (IOException e) {
|
||||
symbolMgr.dbError(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,10 +30,7 @@ import ghidra.program.util.ProgramLocation;
|
|||
*
|
||||
* Symbol data usage:
|
||||
* EXTERNAL:
|
||||
* long data1 - external data type
|
||||
* String data3 - external memory address
|
||||
* NON-EXTERNAL:
|
||||
* int data2 - primary flag
|
||||
* String stringData - external memory address/label
|
||||
*/
|
||||
|
||||
public class CodeSymbol extends SymbolDB {
|
||||
|
@ -162,7 +159,7 @@ public class CodeSymbol extends SymbolDB {
|
|||
if (getSource() == SourceType.DEFAULT || isExternal()) {
|
||||
return true;
|
||||
}
|
||||
return getSymbolData2() == 1;
|
||||
return doCheckIsPrimary();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,7 +198,7 @@ public class CodeSymbol extends SymbolDB {
|
|||
}
|
||||
|
||||
void setPrimary(boolean primary) {
|
||||
setSymbolData2(primary ? 1 : 0);
|
||||
doSetPrimary(primary);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,10 +39,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
*
|
||||
* Symbol Data Usage:
|
||||
* EXTERNAL:
|
||||
* long data1 - external data type
|
||||
* String data3 - external memory address
|
||||
* NON-EXTERNAL:
|
||||
* - not used -
|
||||
* String stringData - external memory address/label
|
||||
*/
|
||||
public class FunctionSymbol extends SymbolDB {
|
||||
|
||||
|
@ -103,9 +100,9 @@ public class FunctionSymbol extends SymbolDB {
|
|||
try {
|
||||
boolean restoreLabel = isExternal() || (getSource() != SourceType.DEFAULT);
|
||||
String symName = getName();
|
||||
String extData3 = null;
|
||||
String extData = null;
|
||||
if (isExternal()) {
|
||||
extData3 = getSymbolData3(); // preserve external data
|
||||
extData = getSymbolStringData(); // preserve external data
|
||||
}
|
||||
Namespace namespace = getParentNamespace();
|
||||
SourceType source = getSource();
|
||||
|
@ -120,7 +117,7 @@ public class FunctionSymbol extends SymbolDB {
|
|||
|
||||
if (super.delete()) {
|
||||
if (restoreLabel) {
|
||||
boolean restored = createLabelForDeletedFunctionName(address, symName, extData3,
|
||||
boolean restored = createLabelForDeletedFunctionName(address, symName, extData,
|
||||
namespace, source, pinned);
|
||||
if (!restored && isExternal()) {
|
||||
removeAllReferencesTo();
|
||||
|
@ -140,7 +137,7 @@ public class FunctionSymbol extends SymbolDB {
|
|||
* does not mean that we want to lose the function name (that is our policy).
|
||||
*/
|
||||
private boolean createLabelForDeletedFunctionName(Address entryPoint, String symName,
|
||||
String data3, Namespace namespace, SourceType source, boolean pinned) {
|
||||
String stringData, Namespace namespace, SourceType source, boolean pinned) {
|
||||
if (isExternal()) {
|
||||
SymbolDB parent = (SymbolDB) namespace.getSymbol();
|
||||
if (parent.isDeleting()) {
|
||||
|
@ -151,7 +148,7 @@ public class FunctionSymbol extends SymbolDB {
|
|||
SymbolDB newSym;
|
||||
try {
|
||||
newSym = symbolMgr.createSpecialSymbol(entryPoint, symName, namespace,
|
||||
SymbolType.LABEL, -1, -1, data3, source);
|
||||
SymbolType.LABEL, null, null, stringData, source);
|
||||
if (pinned) {
|
||||
newSym.setPinned(true);
|
||||
}
|
||||
|
@ -161,7 +158,7 @@ public class FunctionSymbol extends SymbolDB {
|
|||
newSym = (SymbolDB) symbolMgr.createLabel(entryPoint, symName,
|
||||
program.getGlobalNamespace(), source);
|
||||
}
|
||||
newSym.setSymbolData3(data3); // reserved for external location use
|
||||
newSym.setSymbolStringData(stringData);
|
||||
newSym.setPrimary();
|
||||
return true;
|
||||
}
|
||||
|
@ -275,56 +272,11 @@ public class FunctionSymbol extends SymbolDB {
|
|||
return super.doGetParentNamespace();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source)
|
||||
// throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||
//
|
||||
// if (!isExternal()) {
|
||||
//
|
||||
// // Check thunk function name - if name matches thunked function
|
||||
// // name switch to using DEFAULT name
|
||||
//
|
||||
// // NOTE: Removed this since this prevents having a second symbol
|
||||
//
|
||||
// Symbol thunkedSymbol = getThunkedSymbol();
|
||||
// if (thunkedSymbol != null) {
|
||||
// String thunkedName = thunkedSymbol.getName();
|
||||
// if (thunkedName.equals(newName)) {
|
||||
// newName = "";
|
||||
// source = SourceType.DEFAULT;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// super.setNameAndNamespace(newName, newNamespace, source);
|
||||
// }
|
||||
|
||||
private Symbol getThunkedSymbol() {
|
||||
long thunkedFunctionId = functionMgr.getThunkedFunctionId(key);
|
||||
return (thunkedFunctionId >= 0) ? symbolMgr.getSymbol(thunkedFunctionId) : null;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source)
|
||||
// throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||
//
|
||||
// long thunkedFunctionId = functionMgr.getThunkedFunctionId(key);
|
||||
// if (thunkedFunctionId >= 0) {
|
||||
// if (!newName.startsWith(Function.THUNK_PREFIX)) {
|
||||
// // ignore
|
||||
// return;
|
||||
// }
|
||||
// // rename thunked function based on thunk name specified
|
||||
// Symbol s = symbolMgr.getSymbol(thunkedFunctionId);
|
||||
// if (s != null) {
|
||||
// s.setName(newName.substring(Function.THUNK_PREFIX.length()), source);
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// super.setNameAndNamespace(newName, newNamespace, source);
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected SourceType validateNameSource(String newName, SourceType source) {
|
||||
// if (isThunk()) {
|
||||
|
|
|
@ -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.
|
||||
|
@ -109,7 +108,7 @@ class LibraryDB implements Library {
|
|||
|
||||
@Override
|
||||
public String getAssociatedProgramPath() {
|
||||
return symbol.getSymbolData3();
|
||||
return symbol.getSymbolStringData();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,8 +31,7 @@ import ghidra.util.exception.InvalidInputException;
|
|||
* Class for library symbols.
|
||||
*
|
||||
* Symbol data usage:
|
||||
* int data2 - set to 0 (not used)
|
||||
* String data3 - associated program project file path
|
||||
* String stringData - associated program project file path
|
||||
*/
|
||||
|
||||
public class LibrarySymbol extends SymbolDB {
|
||||
|
@ -64,8 +63,9 @@ public class LibrarySymbol extends SymbolDB {
|
|||
super.setName(newName, source);
|
||||
|
||||
if (!oldName.equals(getName())) {
|
||||
symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED,
|
||||
(Address) null, null, oldName, newName);
|
||||
symbolMgr.getProgram()
|
||||
.setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED,
|
||||
(Address) null, null, oldName, newName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,19 +77,21 @@ public class LibrarySymbol extends SymbolDB {
|
|||
super.setNameAndNamespace(newName, newNamespace, source);
|
||||
|
||||
if (!oldName.equals(getName())) {
|
||||
symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED,
|
||||
(Address) null, null, oldName, newName);
|
||||
symbolMgr.getProgram()
|
||||
.setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED,
|
||||
(Address) null, null, oldName, newName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSymbolData3(String newPath) {
|
||||
String oldPath = getSymbolData3();
|
||||
public void setSymbolStringData(String newPath) {
|
||||
String oldPath = getSymbolStringData();
|
||||
|
||||
super.setSymbolData3(newPath);
|
||||
super.setSymbolStringData(newPath);
|
||||
|
||||
symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_PATH_CHANGED, getName(),
|
||||
oldPath, newPath);
|
||||
symbolMgr.getProgram()
|
||||
.setObjChanged(ChangeManager.DOCR_EXTERNAL_PATH_CHANGED, getName(),
|
||||
oldPath, newPath);
|
||||
}
|
||||
|
||||
public SymbolType getSymbolType() {
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
package ghidra.program.database.symbol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import db.DBRecord;
|
||||
import db.Field;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.database.external.ExternalLocationDB;
|
||||
import ghidra.program.database.external.ExternalManagerDB;
|
||||
|
@ -141,21 +141,25 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
* @param newAddress the new address for the symbol
|
||||
* @param newName the new name for the symbol (or null if the name should stay the same)
|
||||
* @param newNamespace the new namespace for the symbol (or null if it should stay the same)
|
||||
* @param newSource
|
||||
* @param newSource the new SourceType for the symbol (or null if it should stay the same)
|
||||
* @param pinned the new pinned state
|
||||
*/
|
||||
protected void moveLowLevel(Address newAddress, String newName, Namespace newNamespace,
|
||||
SourceType newSource, boolean pinned) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
Address oldAddress = address;
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL,
|
||||
symbolMgr.getAddressMap().getKey(newAddress, true));
|
||||
|
||||
// update the address to the new location
|
||||
long newAddressKey = symbolMgr.getAddressMap().getKey(newAddress, true);
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, newAddressKey);
|
||||
|
||||
// if the primary field is set, be sure to update it to the new address as well
|
||||
if (record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL) != null) {
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, newAddressKey);
|
||||
}
|
||||
if (newName != null) {
|
||||
record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName);
|
||||
if (newName.length() == 0) {
|
||||
setSourceFlagBit(SourceType.DEFAULT);
|
||||
}
|
||||
}
|
||||
if (newNamespace != null) {
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, newNamespace.getID());
|
||||
|
@ -793,32 +797,42 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
public String getSymbolData3() {
|
||||
/**
|
||||
* Returns the symbol's string data which has different meanings depending on the symbol type
|
||||
* and whether or not it is external
|
||||
* @return the symbol's string data
|
||||
*/
|
||||
public String getSymbolStringData() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
return record.getString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL);
|
||||
return record.getString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
public void setSymbolData3(String data3) {
|
||||
/**
|
||||
* Sets the symbol's string data field. This field's data has different uses depending on the
|
||||
* symbol type and whether or not it is external.
|
||||
* @param stringData the string to store in the string data field
|
||||
*/
|
||||
public void setSymbolStringData(String stringData) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (record == null) {
|
||||
return;
|
||||
}
|
||||
String oldData = record.getString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL);
|
||||
if (SystemUtilities.isEqual(data3, oldData)) {
|
||||
String oldData = record.getString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL);
|
||||
if (Objects.equals(stringData, oldData)) {
|
||||
return;
|
||||
}
|
||||
record.setString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL, data3);
|
||||
record.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL, stringData);
|
||||
updateRecord();
|
||||
symbolMgr.symbolDataChanged(this);
|
||||
}
|
||||
|
@ -836,14 +850,18 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
public long getSymbolData1() {
|
||||
public long getDataTypeId() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (record != null) {
|
||||
return record.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL);
|
||||
Field value = record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||
if (value.isNull()) {
|
||||
return -1;
|
||||
}
|
||||
return value.getLongValue();
|
||||
}
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -854,12 +872,12 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
* Sets the generic symbol data 1.
|
||||
* @param value the value to set as symbol data 1.
|
||||
*/
|
||||
public void setSymbolData1(long value) {
|
||||
public void setDataTypeId(long value) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (record != null) {
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, value);
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, value);
|
||||
updateRecord();
|
||||
symbolMgr.symbolDataChanged(this);
|
||||
}
|
||||
|
@ -873,12 +891,12 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
* gets the generic symbol data 2 data.
|
||||
* @return the symbol data
|
||||
*/
|
||||
public int getSymbolData2() {
|
||||
protected int getVariableOffset() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (record != null) {
|
||||
return record.getIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL);
|
||||
return record.getIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -888,15 +906,16 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the generic symbol data 2 data
|
||||
* @param value the value to set as the symbols data 2 value.
|
||||
* Sets the symbol's variable offset. For parameters, this is the ordinal, for locals, it is
|
||||
* the first use offset
|
||||
* @param offset the value to set as the symbols variable offset.
|
||||
*/
|
||||
public void setSymbolData2(int value) {
|
||||
public void setVariableOffset(int offset) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (record != null) {
|
||||
record.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, value);
|
||||
record.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, offset);
|
||||
updateRecord();
|
||||
symbolMgr.symbolDataChanged(this);
|
||||
}
|
||||
|
@ -906,6 +925,42 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
protected void doSetPrimary(boolean primary) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (record != null) {
|
||||
if (primary) {
|
||||
long addrKey = record.getLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL);
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addrKey);
|
||||
}
|
||||
else {
|
||||
record.setField(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, null);
|
||||
}
|
||||
updateRecord();
|
||||
symbolMgr.symbolDataChanged(this);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean doCheckIsPrimary() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (record != null) {
|
||||
return !record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL).isNull();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
lock.acquire();
|
||||
|
|
|
@ -16,14 +16,16 @@
|
|||
package ghidra.program.database.symbol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.program.database.util.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -32,24 +34,23 @@ import ghidra.util.task.TaskMonitor;
|
|||
* Adapter to access records in the symbol table.
|
||||
*/
|
||||
abstract class SymbolDatabaseAdapter {
|
||||
|
||||
static final String SYMBOL_TABLE_NAME = "Symbols";
|
||||
|
||||
static final Schema SYMBOL_SCHEMA = new Schema(2, "Key",
|
||||
new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||
ByteField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE, StringField.INSTANCE,
|
||||
ByteField.INSTANCE },
|
||||
new String[] { "Name", "Address", "Parent", "Symbol Type", "SymbolData1", "SymbolData2",
|
||||
"SymbolData3", "Flags" });
|
||||
|
||||
static final int SYMBOL_NAME_COL = 0;
|
||||
static final int SYMBOL_ADDR_COL = 1;
|
||||
static final int SYMBOL_PARENT_COL = 2;
|
||||
static final int SYMBOL_TYPE_COL = 3;
|
||||
static final int SYMBOL_DATA1_COL = 4;
|
||||
static final int SYMBOL_DATA2_COL = 5;
|
||||
static final int SYMBOL_DATA3_COL = 6;
|
||||
static final int SYMBOL_FLAGS_COL = 7;
|
||||
static final int SYMBOL_STRING_DATA_COL = 4;
|
||||
static final int SYMBOL_FLAGS_COL = 5;
|
||||
|
||||
// sparse fields - the following fields are not always applicable so they are optional and
|
||||
// don't consume space in the database if they aren't used.
|
||||
static final int SYMBOL_HASH_COL = 6;
|
||||
static final int SYMBOL_PRIMARY_COL = 7;
|
||||
static final int SYMBOL_DATATYPE_COL = 8;
|
||||
static final int SYMBOL_VAROFFSET_COL = 9;
|
||||
|
||||
static final Schema SYMBOL_SCHEMA = SymbolDatabaseAdapterV3.V3_SYMBOL_SCHEMA;
|
||||
|
||||
// Bits 0 & 1 are used for the source of the symbol.
|
||||
static final byte SYMBOL_SOURCE_BITS = (byte) 0x3;
|
||||
|
@ -59,26 +60,24 @@ abstract class SymbolDatabaseAdapter {
|
|||
|
||||
/**
|
||||
* Gets a new SymbolDatabaseAdapter
|
||||
* @param dbHandle the database handle.
|
||||
* @param openMode the openmode
|
||||
* @param dbHandle the database handle
|
||||
* @param openMode the open mode. See {@link DBConstants}
|
||||
* @param addrMap the address map
|
||||
* @param monitor the progress monitor.
|
||||
* @throws VersionException if the database table does not match the adapter.
|
||||
* @throws CancelledException if the user cancels an upgrade.
|
||||
* @throws IOException if a database io error occurs.
|
||||
* @param monitor the progress monitor
|
||||
* @return a new SymbolDatabaseAdapter
|
||||
* @throws VersionException if the database table does not match the adapter
|
||||
* @throws CancelledException if the user cancels an upgrade
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
static SymbolDatabaseAdapter getAdapter(DBHandle dbHandle, int openMode, AddressMap addrMap,
|
||||
TaskMonitor monitor) throws VersionException, CancelledException, IOException {
|
||||
|
||||
if (openMode == DBConstants.CREATE) {
|
||||
return new SymbolDatabaseAdapterV2(dbHandle, addrMap, true);
|
||||
return new SymbolDatabaseAdapterV3(dbHandle, addrMap, true);
|
||||
}
|
||||
|
||||
try {
|
||||
SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV2(dbHandle, addrMap, false);
|
||||
if (addrMap.isUpgraded()) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV3(dbHandle, addrMap, false);
|
||||
return adapter;
|
||||
}
|
||||
catch (VersionException e) {
|
||||
|
@ -87,7 +86,7 @@ abstract class SymbolDatabaseAdapter {
|
|||
}
|
||||
SymbolDatabaseAdapter adapter = findReadOnlyAdapter(dbHandle, addrMap);
|
||||
if (openMode == DBConstants.UPGRADE) {
|
||||
adapter = SymbolDatabaseAdapterV2.upgrade(dbHandle, addrMap, adapter, monitor);
|
||||
adapter = upgrade(dbHandle, addrMap, adapter, monitor);
|
||||
}
|
||||
else if (adapter instanceof SymbolDatabaseAdapterV0) {
|
||||
// Upgrade required - read-only use not supported
|
||||
|
@ -101,39 +100,125 @@ abstract class SymbolDatabaseAdapter {
|
|||
throws VersionException, IOException {
|
||||
|
||||
try {
|
||||
return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap(), false);
|
||||
return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap());
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
// failed try older version
|
||||
}
|
||||
|
||||
try {
|
||||
return new SymbolDatabaseAdapterV1(handle, addrMap.getOldAddressMap());
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
// failed try older version
|
||||
}
|
||||
|
||||
return new SymbolDatabaseAdapterV0(handle, addrMap);
|
||||
try {
|
||||
return new SymbolDatabaseAdapterV0(handle, addrMap.getOldAddressMap());
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
// failed - can't handle whatever version this is trying to open
|
||||
}
|
||||
|
||||
throw new VersionException(false);
|
||||
}
|
||||
|
||||
static SymbolDatabaseAdapter upgrade(DBHandle dbHandle, AddressMap addrMap,
|
||||
SymbolDatabaseAdapter oldAdapter, TaskMonitor monitor)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
|
||||
monitor.setMessage("Upgrading Symbol Table...");
|
||||
monitor.initialize(oldAdapter.getSymbolCount() * 2);
|
||||
|
||||
DBHandle tmpHandle = dbHandle.getScratchPad();
|
||||
|
||||
try {
|
||||
SymbolDatabaseAdapter tmpAdapter =
|
||||
copyToTempAndFixupRecords(addrMap, oldAdapter, tmpHandle, monitor);
|
||||
|
||||
dbHandle.deleteTable(SYMBOL_TABLE_NAME);
|
||||
|
||||
SymbolDatabaseAdapter newAdapter =
|
||||
new SymbolDatabaseAdapterV3(dbHandle, addrMap, true);
|
||||
|
||||
copyTempToNewAdapter(tmpAdapter, newAdapter, monitor);
|
||||
return newAdapter;
|
||||
}
|
||||
finally {
|
||||
tmpHandle.deleteTable(SYMBOL_TABLE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
private static SymbolDatabaseAdapter copyToTempAndFixupRecords(AddressMap addrMap,
|
||||
SymbolDatabaseAdapter oldAdapter, DBHandle tmpHandle, TaskMonitor monitor)
|
||||
throws IOException, CancelledException, VersionException {
|
||||
|
||||
AddressMap oldAddrMap = addrMap.getOldAddressMap();
|
||||
|
||||
long nextKey = 1; // only used for V0 upgrade if a record with key 0 is encountered
|
||||
if (oldAdapter instanceof SymbolDatabaseAdapterV0) {
|
||||
// V0 is so old that there is not enough info in the current record to create new
|
||||
// records. So store the current info in a temp database table and complete the upgrade
|
||||
// when SymbolManager.programReady() is called. The missing info can be retrieved from
|
||||
// other managers in the program at that point.
|
||||
nextKey =
|
||||
((SymbolDatabaseAdapterV0) oldAdapter).extractLocalSymbols(tmpHandle, monitor);
|
||||
}
|
||||
|
||||
SymbolDatabaseAdapterV3 tmpAdapter = new SymbolDatabaseAdapterV3(tmpHandle, addrMap, true);
|
||||
RecordIterator iter = oldAdapter.getSymbols();
|
||||
while (iter.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
DBRecord rec = iter.next();
|
||||
Address addr = oldAddrMap.decodeAddress(rec.getLongValue(SYMBOL_ADDR_COL));
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, addrMap.getKey(addr, true));
|
||||
|
||||
// We don't allow 0 keys starting with V1, set its key to next available
|
||||
// which we got from the call to extractLocalSymbols() above
|
||||
if (rec.getKey() == 0) {
|
||||
rec.setKey(Math.max(1, nextKey));
|
||||
}
|
||||
|
||||
tmpAdapter.updateSymbolRecord(rec);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
return tmpAdapter;
|
||||
}
|
||||
|
||||
private static void copyTempToNewAdapter(SymbolDatabaseAdapter tmpAdapter,
|
||||
SymbolDatabaseAdapter newAdapter, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
RecordIterator iter = tmpAdapter.getSymbols();
|
||||
while (iter.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
newAdapter.updateSymbolRecord(iter.next());
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new symbol
|
||||
* @param name name of the symbol
|
||||
* @param addr address of the symbol
|
||||
* @param parentSymbolID the id of the containing namespace symbol
|
||||
* @param address the address for the symbol
|
||||
* @param namespaceID the id of the containing namespace symbol
|
||||
* @param symbolType the type of this symbol
|
||||
* @param data1 place to store a long value that depends on the symbol type
|
||||
* @param data2 place to store an int value that depends on the symbol type
|
||||
* @param data3 place to store a String value that depends on the symbol type
|
||||
* @param source the source of this symbol
|
||||
* <br>Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT.
|
||||
* @param stringData place to store a String value that depends on the symbol type
|
||||
* @param source the source type of this symbol
|
||||
* Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT
|
||||
* @param dataTypeId the id of an associated datatype or null if there is no associated datatype
|
||||
* @param varOffset the variable offset will be the ordinal for a parameter or first use offset
|
||||
* for a local variable
|
||||
* @param isPrimary true if the symbol is primary. Only applicable for labels and functions
|
||||
* @return the new record
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
* @throws IllegalArgumentException if you try to set the source to DEFAULT for a symbol type
|
||||
* that doesn't allow it.
|
||||
* that doesn't allow it
|
||||
*/
|
||||
abstract DBRecord createSymbol(String name, Address address, long parentSymbolID,
|
||||
SymbolType symbolType, long data1, int data2, String data3, SourceType source)
|
||||
throws IOException;
|
||||
abstract DBRecord createSymbol(String name, Address address, long namespaceID,
|
||||
SymbolType symbolType, String stringData, Long dataTypeId, Integer varOffset,
|
||||
SourceType source, boolean isPrimary) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the record with the given symbol ID
|
||||
|
@ -160,58 +245,96 @@ abstract class SymbolDatabaseAdapter {
|
|||
abstract boolean hasSymbol(Address addr) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the symbolIDs at the given address.
|
||||
* Get the symbolIDs at the given address
|
||||
* @param addr address to filter on
|
||||
* @return array of database LongField keys contained within a Field array.
|
||||
* @return array of database LongField keys contained within a Field array
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
*/
|
||||
abstract Field[] getSymbolIDs(Address addr) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the number of symbols.
|
||||
* Get the number of symbols
|
||||
* @return the number of symbols
|
||||
*/
|
||||
abstract int getSymbolCount();
|
||||
|
||||
/**
|
||||
* Get an iterator over all the symbols in ascending address order.
|
||||
* @return
|
||||
* Get an iterator over all the symbols in ascending address order
|
||||
* @param forward the direction to iterator
|
||||
* @return a record iterator over all symbols
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
*/
|
||||
abstract RecordIterator getSymbolsByAddress(boolean forward) throws IOException;
|
||||
|
||||
/**
|
||||
* Get an iterator over all the symbols starting at startAddr.
|
||||
* Get an iterator over all the symbols starting at startAddr
|
||||
* @param startAddr start address of where to get symbols
|
||||
* @param forward true to iterate from low to high addresses
|
||||
* @return a record iterator over all symbols starting at the given start address
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
*/
|
||||
abstract RecordIterator getSymbolsByAddress(Address startAddr, boolean forward)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Update the table with the given record.
|
||||
* @param record
|
||||
* Update the table with the given record
|
||||
* @param record the record to update in the database
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
*/
|
||||
abstract void updateSymbolRecord(DBRecord record) throws IOException;
|
||||
|
||||
/**
|
||||
* Get all of the symbols.
|
||||
* @return a record iterator over all symbols
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
*/
|
||||
abstract RecordIterator getSymbols() throws IOException;
|
||||
|
||||
/**
|
||||
* Get symbols in the given range.
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
* Get symbols in the given range
|
||||
* @param start the start address of the range
|
||||
* @param end the last address of the range
|
||||
* @param forward true if iterating from start to end, otherwise iterate from end to start
|
||||
* @return a record iterator for all symbols in the range
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getSymbols(Address start, Address end, boolean forward)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Get symbols in the given range
|
||||
* @param set the set of addresses to iterate over
|
||||
* @param forward true if iterating from start to end, otherwise iterate from end to start
|
||||
* @return a record iterator for all symbols in the range
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getSymbols(AddressSetView set, boolean forward)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns an iterator over the primary symbols in the given range
|
||||
* @param set the address set to iterator over when getting primary symbol records
|
||||
* @param forward true if iterating from start to end, otherwise iterate from end to start
|
||||
* @return a record iterator for all symbols in the range
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the symbol record for the primary symbol at the given address
|
||||
* @param address the address to get its primary symbol record
|
||||
* @return the primary symbol record at the given address or null if no label or function
|
||||
* exists at that address
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract DBRecord getPrimarySymbol(Address address) throws IOException;
|
||||
|
||||
/**
|
||||
* Update the address in all records to reflect the movement of a symbol address.
|
||||
* @param oldAddr the original symbol address
|
||||
* @param newAddr the new symbol address
|
||||
* @throws IOException
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract void moveAddress(Address oldAddr, Address newAddr) throws IOException;
|
||||
|
||||
|
@ -221,38 +344,125 @@ abstract class SymbolDatabaseAdapter {
|
|||
* @param endAddr maximum address in range
|
||||
* @param monitor progress monitor
|
||||
* @return returns the set of addresses where symbols where not deleted because they were anchored
|
||||
* @throws CancelledException
|
||||
* @throws IOException
|
||||
* @throws CancelledException if the user cancels the operation
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract Set<Address> deleteAddressRange(Address startAddr, Address endAddr,
|
||||
TaskMonitor monitor) throws CancelledException, IOException;
|
||||
|
||||
/**
|
||||
* Get all symbols contained within the specified namespace
|
||||
* @param id the namespace id.
|
||||
* @return an iterator over all symbols in the given namespace.
|
||||
* @throws IOException
|
||||
* @param id the namespace id
|
||||
* @return an iterator over all symbols in the given namespace
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getSymbolsByNamespace(long id) throws IOException;
|
||||
|
||||
/**
|
||||
* Get symbols starting with the specified name in name order
|
||||
* @param name name to start with.
|
||||
* @return a record iterator over the symbols.
|
||||
* @throws IOException if a database io error occurs.
|
||||
* Get symbols that have the specified name
|
||||
* @param name name to search
|
||||
* @return a record iterator over the symbols with the given name
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getSymbolsByName(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the maximum symbol address within the specified address space.
|
||||
* Intended for update use only.
|
||||
* Get all symbols contained in the given {@link Namespace} that have the given name
|
||||
* @param name the symbol name
|
||||
* @param id the id of the parent namespace
|
||||
* @return a record iterator all the symbols in the given namespace with the given name
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the symbol Record with the given address, name, and namespace id or null if there is
|
||||
* no match
|
||||
* @param address the symbol address
|
||||
* @param name the symbol name
|
||||
* @param namespaceId the id of the parent namespace of the symbol
|
||||
* @return a record that matches the address, name, and namespaceId or null if there is no match
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract DBRecord getSymbolRecord(Address address, String name, long namespaceId)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the maximum symbol address within the specified address space
|
||||
* Intended for update use only
|
||||
* @param space address space
|
||||
* @return maximum symbol address within space or null if none are found.
|
||||
* @return maximum symbol address within space or null if none are found
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract Address getMaxSymbolAddress(AddressSpace space) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the underlying symbol table (for upgrade use only).
|
||||
* Returns the underlying symbol table (for upgrade use only)
|
||||
* @return the database table for this adapter
|
||||
*/
|
||||
abstract Table getTable();
|
||||
|
||||
/**
|
||||
* Computes a hash value for a symbol that facilitates fast lookups of symbols given
|
||||
* a name, namespace, and address. The hash is formed so that it can also be used for fast
|
||||
* lookups of all symbols that have the same name and namespace regardless of address.
|
||||
* @param name the symbol name
|
||||
* @param namespaceID the namespace id
|
||||
* @param addressKey the encoded address
|
||||
* @return a database Long field containing the computed hash
|
||||
*/
|
||||
protected static LongField computeLocatorHash(String name, long namespaceID,
|
||||
long addressKey) {
|
||||
// Default functions have no name, no point in storing a hash for those.
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// store the name/namespace hash in upper 32 bits of the resulting hash and the
|
||||
// addressKey's lower 32 bits in the lower 32 bits of the resulting hash
|
||||
long nameNamespaceHash = Objects.hash(name, namespaceID);
|
||||
long combinedHash = (nameNamespaceHash << 32) | (addressKey & 0xFFFFFFFFL);
|
||||
return new LongField(combinedHash);
|
||||
}
|
||||
|
||||
// This wraps a record iterator to make sure it only returns records for symbols that match
|
||||
// the given name and name space.
|
||||
protected static RecordIterator getNameAndNamespaceFilterIterator(String name,
|
||||
long namespaceId, RecordIterator it) {
|
||||
Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name));
|
||||
Query namespaceQuery = new FieldMatchQuery(SYMBOL_PARENT_COL, new LongField(namespaceId));
|
||||
Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery);
|
||||
return new QueryRecordIterator(it, nameAndNamespaceQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a record iterator to make sure it only returns records for symbols that match
|
||||
* the given name and name space and address
|
||||
* @param name the name of the symbol
|
||||
* @param namespaceId the name space id of the symbol
|
||||
* @param addressKey the address key of the symbol
|
||||
* @param it the record iterator to wrap with the query
|
||||
* @return a filtered RecordIterator that only returns records that match the name, name space,
|
||||
* and address
|
||||
*/
|
||||
protected static RecordIterator getNameNamespaceAddressFilterIterator(String name,
|
||||
long namespaceId, long addressKey, RecordIterator it) {
|
||||
Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name));
|
||||
Query namespaceQuery = new FieldMatchQuery(SYMBOL_PARENT_COL, new LongField(namespaceId));
|
||||
Query addressQuery = new FieldMatchQuery(SYMBOL_ADDR_COL, new LongField(addressKey));
|
||||
Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery);
|
||||
Query fullQuery = new AndQuery(nameAndNamespaceQuery, addressQuery);
|
||||
return new QueryRecordIterator(it, fullQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a record iterator to filter out any symbols that are not primary
|
||||
* @param it the record iterator to wrap
|
||||
* @return a record iterator that only returns primary symbols
|
||||
*/
|
||||
protected static RecordIterator getPrimaryFilterRecordIterator(RecordIterator it) {
|
||||
Query query = record -> !record.getFieldValue(SYMBOL_PRIMARY_COL).isNull();
|
||||
return new QueryRecordIterator(it, query);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,8 +21,7 @@ import java.util.Set;
|
|||
import db.*;
|
||||
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -58,13 +57,10 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
private AddressMap addrMap;
|
||||
|
||||
/**
|
||||
* Construct a Version-0 Symbol Table adadpter.
|
||||
* Construct a Version-0 Symbol Table adapter.
|
||||
* @param handle the database handle.
|
||||
* @param addrMap the address map
|
||||
* @param namespaceMgr namespace manager which already contains function namespaces
|
||||
* @throws VersionException if the database version doesn't match this adapter.
|
||||
* @throws IOException if a database io error occurs.
|
||||
* @throws CancelledException if the user cancels the upgrade.
|
||||
*/
|
||||
SymbolDatabaseAdapterV0(DBHandle handle, AddressMap addrMap) throws VersionException {
|
||||
this.addrMap = addrMap.getOldAddressMap();
|
||||
|
@ -77,10 +73,22 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores local symbols information in a temporary database table because this version
|
||||
* is so old, we don't have enough information in the record to upgrade during the normal
|
||||
* upgrade time. So we store off the information and will complete this upgrade when
|
||||
* {@link SymbolManager#programReady(int, int, TaskMonitor)} is called
|
||||
*
|
||||
* @param handle handle to temporary database
|
||||
* @param monitor the {@link TaskMonitor}
|
||||
* @return the next available database key after all the records are store
|
||||
* @throws IOException if a database I/O error occurs
|
||||
* @throws CancelledException if the user cancels the upgrade
|
||||
*/
|
||||
long extractLocalSymbols(DBHandle handle, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
monitor.setMessage("Extracting Local and Dynamic Symbols...");
|
||||
monitor.setMessage("Extracting Local Symbols...");
|
||||
monitor.initialize(symbolTable.getRecordCount());
|
||||
int cnt = 0;
|
||||
RecordIterator iter = symbolTable.iterator();
|
||||
|
@ -106,22 +114,36 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
throw new AssertException("Unexpected Symbol");
|
||||
}
|
||||
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey());
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, record.getString(V0_SYMBOL_NAME_COL));
|
||||
|
||||
String symbolName = record.getString(V0_SYMBOL_NAME_COL);
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
|
||||
long addressKey = record.getLongValue(V0_SYMBOL_ADDR_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL,
|
||||
record.getLongValue(V0_SYMBOL_ADDR_COL));
|
||||
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL,
|
||||
record.getBooleanValue(V0_SYMBOL_PRIMARY_COL) ? 1 : 0);
|
||||
addressKey);
|
||||
|
||||
boolean isPrimary = record.getBooleanValue(V0_SYMBOL_PRIMARY_COL);
|
||||
if (isPrimary) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey);
|
||||
}
|
||||
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, SymbolType.LABEL.getID());
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, -1); // not applicable
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, Namespace.GLOBAL_NAMESPACE_ID);
|
||||
|
||||
long namespaceId = Namespace.GLOBAL_NAMESPACE_ID;
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId);
|
||||
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL,
|
||||
(byte) SourceType.USER_DEFINED.ordinal());
|
||||
|
||||
Field hash = computeLocatorHash(symbolName, namespaceId, addressKey);
|
||||
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
long data1, int data2, String data3, SourceType source) {
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -175,16 +197,37 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException {
|
||||
|
||||
if (!forward)
|
||||
throw new UnsupportedOperationException();
|
||||
//TODO: Is there any reason we need to support reverse symbol iteration ???
|
||||
// Yes, to search text backwards!
|
||||
return new V0ConvertedRecordIterator(
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
V0_SYMBOL_ADDR_COL, addrMap, start, end, forward)));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
return new V0ConvertedRecordIterator(
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
V0_SYMBOL_ADDR_COL, addrMap, set, forward)));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
|
||||
return getPrimaryFilterRecordIterator(new V0ConvertedRecordIterator(it));
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getPrimarySymbol(Address address) throws IOException {
|
||||
RecordIterator it = getPrimarySymbols(new AddressSet(address, address), true);
|
||||
if (it.hasNext()) {
|
||||
return it.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void moveAddress(Address oldAddr, Address newAddr) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -219,8 +262,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
|
||||
/**
|
||||
* Construct a symbol filtered record iterator
|
||||
* @param iter
|
||||
* @param locals if true
|
||||
* @param symIter the {@link RecordIterator} to wrap so that records are adapter to new schema
|
||||
*/
|
||||
V0ConvertedRecordIterator(RecordIterator symIter) {
|
||||
this.symIter = symIter;
|
||||
|
@ -277,4 +319,23 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
||||
RecordIterator symbolsByName = getSymbolsByName(name);
|
||||
return getNameAndNamespaceFilterIterator(name, id, symbolsByName);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
||||
StringField value = new StringField(name);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true);
|
||||
long addressKey = addrMap.getKey(address, false);
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,8 +21,7 @@ import java.util.Set;
|
|||
import db.*;
|
||||
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
@ -72,7 +71,8 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
long data1, int data2, String data3, SourceType source) {
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -116,20 +116,21 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey());
|
||||
String symbolName = record.getString(V1_SYMBOL_NAME_COL);
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
|
||||
|
||||
long symbolAddrKey = record.getLongValue(V1_SYMBOL_ADDR_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL,
|
||||
record.getLongValue(V1_SYMBOL_PARENT_COL));
|
||||
byte symbolType = record.getByteValue(V1_SYMBOL_TYPE_COL);
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolType);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL,
|
||||
record.getLongValue(V1_SYMBOL_DATA1_COL));
|
||||
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL,
|
||||
record.getIntValue(V1_SYMBOL_DATA2_COL));
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL,
|
||||
|
||||
long namespaceId = record.getLongValue(V1_SYMBOL_PARENT_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId);
|
||||
|
||||
byte symbolTypeId = record.getByteValue(V1_SYMBOL_TYPE_COL);
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId);
|
||||
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL,
|
||||
record.getString(V1_SYMBOL_COMMENT_COL));
|
||||
|
||||
SourceType source = SourceType.USER_DEFINED;
|
||||
if (symbolType == SymbolType.FUNCTION.getID()) {
|
||||
if (symbolTypeId == SymbolType.FUNCTION.getID()) {
|
||||
Address symbolAddress = addrMap.decodeAddress(symbolAddrKey);
|
||||
String defaultName = SymbolUtilities.getDefaultFunctionName(symbolAddress);
|
||||
if (symbolName.equals(defaultName)) {
|
||||
|
@ -137,6 +138,33 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
}
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal());
|
||||
|
||||
long dataTypeId = record.getLongValue(V1_SYMBOL_DATA1_COL);
|
||||
if (dataTypeId != -1) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
||||
}
|
||||
|
||||
SymbolType type = SymbolType.getSymbolType(symbolTypeId);
|
||||
int data2 = record.getIntValue(V1_SYMBOL_DATA2_COL);
|
||||
// The data1 field was used in two ways for label symbols, it stored a 1 for primary and 0
|
||||
// for non-primary. If the type was a parameter or variable, it stored the ordinal or
|
||||
// first use offset respectively.
|
||||
if (SymbolType.LABEL.equals(type)) {
|
||||
if (data2 == 1) { // if it was primary, put the address in the indexed primary col
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
||||
}
|
||||
}
|
||||
else if (SymbolType.PARAMETER.equals(type) || SymbolType.LOCAL_VAR.equals(type)) {
|
||||
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, data2);
|
||||
}
|
||||
|
||||
// also need to store primary for functions
|
||||
if (SymbolType.FUNCTION.equals(type)) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
||||
}
|
||||
Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey);
|
||||
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
|
@ -175,8 +203,30 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
V1_SYMBOL_ADDR_COL, addrMap, start, end, forward)));
|
||||
}
|
||||
|
||||
RecordIterator getSymbolsByName() throws IOException {
|
||||
return new V1ConvertedRecordIterator(symbolTable.indexIterator(V1_SYMBOL_NAME_COL));
|
||||
@Override
|
||||
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
return new V1ConvertedRecordIterator(
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
V1_SYMBOL_ADDR_COL, addrMap, set, forward)));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
|
||||
return getPrimaryFilterRecordIterator(new V1ConvertedRecordIterator(it));
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getPrimarySymbol(Address address) throws IOException {
|
||||
RecordIterator it = getPrimarySymbols(new AddressSet(address, address), true);
|
||||
if (it.hasNext()) {
|
||||
return it.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -225,4 +275,23 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
Address getMaxSymbolAddress(AddressSpace space) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
||||
RecordIterator symbolsByName = getSymbolsByName(name);
|
||||
return getNameAndNamespaceFilterIterator(name, id, symbolsByName);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
||||
RecordIterator it = getSymbolsByName(name);
|
||||
long addressKey = addrMap.getKey(address, false);
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,10 +22,11 @@ import java.util.Set;
|
|||
import db.*;
|
||||
import ghidra.program.database.map.*;
|
||||
import ghidra.program.database.util.RecordFilter;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -33,185 +34,54 @@ import ghidra.util.task.TaskMonitor;
|
|||
*/
|
||||
class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||
|
||||
/* Do not remove the following commented out schema! It shows the version 2 symbol table schema. */
|
||||
// static final Schema SYMBOL_SCHEMA = new Schema(2, "Key",
|
||||
// new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||
// ByteField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE, StringField.INSTANCE,
|
||||
// ByteField.INSTANCE },
|
||||
// new String[] { "Name", "Address", "Parent", "Symbol Type", "SymbolData1", "SymbolData2",
|
||||
// "SymbolData3", "Flags" });
|
||||
|
||||
private static final int SYMBOL_VERSION = 2;
|
||||
private Table symbolTable;
|
||||
private AddressMap addrMap;
|
||||
|
||||
SymbolDatabaseAdapterV2(DBHandle handle, AddressMap addrMap, boolean create)
|
||||
throws VersionException, IOException {
|
||||
static final int V2_SYMBOL_NAME_COL = 0;
|
||||
static final int V2_SYMBOL_ADDR_COL = 1;
|
||||
static final int V2_SYMBOL_PARENT_COL = 2;
|
||||
static final int V2_SYMBOL_TYPE_COL = 3;
|
||||
static final int V2_SYMBOL_DATA1_COL = 4;
|
||||
static final int V2_SYMBOL_DATA2_COL = 5;
|
||||
static final int V2_SYMBOL_DATA3_COL = 6;
|
||||
static final int V2_SYMBOL_FLAGS_COL = 7;
|
||||
|
||||
SymbolDatabaseAdapterV2(DBHandle handle, AddressMap addrMap)
|
||||
throws VersionException {
|
||||
|
||||
this.addrMap = addrMap;
|
||||
if (create) {
|
||||
|
||||
symbolTable = handle.createTable(SYMBOL_TABLE_NAME, SYMBOL_SCHEMA,
|
||||
new int[] { SYMBOL_ADDR_COL, SYMBOL_NAME_COL, SYMBOL_PARENT_COL });
|
||||
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
||||
if (symbolTable == null) {
|
||||
throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME);
|
||||
}
|
||||
else {
|
||||
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
||||
if (symbolTable == null) {
|
||||
throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME);
|
||||
}
|
||||
if (symbolTable.getSchema().getVersion() != SYMBOL_VERSION) {
|
||||
int version = symbolTable.getSchema().getVersion();
|
||||
if (version < SYMBOL_VERSION) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
throw new VersionException(VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SymbolDatabaseAdapter upgrade(DBHandle dbHandle, AddressMap addrMap,
|
||||
SymbolDatabaseAdapter oldAdapter, TaskMonitor monitor)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
|
||||
AddressMap oldAddrMap = addrMap.getOldAddressMap();
|
||||
|
||||
DBHandle tmpHandle = dbHandle.getScratchPad();
|
||||
long nextKey = 1;
|
||||
try {
|
||||
if (oldAdapter instanceof SymbolDatabaseAdapterV0) {
|
||||
// Defer upgrade of local symbols and remove dynamic symbols
|
||||
nextKey =
|
||||
((SymbolDatabaseAdapterV0) oldAdapter).extractLocalSymbols(tmpHandle, monitor);
|
||||
}
|
||||
|
||||
monitor.setMessage("Upgrading Symbol Table...");
|
||||
monitor.initialize((oldAdapter.getSymbolCount()) * 2);
|
||||
int count = 0;
|
||||
|
||||
SymbolDatabaseAdapterV2 tmpAdapter =
|
||||
new SymbolDatabaseAdapterV2(tmpHandle, addrMap, true);
|
||||
RecordIterator iter = oldAdapter.getSymbols();
|
||||
DBRecord zeroRecord = null;
|
||||
while (iter.hasNext()) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
DBRecord rec = iter.next();
|
||||
Address addr = oldAddrMap.decodeAddress(rec.getLongValue(SYMBOL_ADDR_COL));
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, addrMap.getKey(addr, true));
|
||||
if (rec.getKey() == 0) {
|
||||
zeroRecord = rec;
|
||||
}
|
||||
else {
|
||||
tmpAdapter.symbolTable.putRecord(rec);
|
||||
}
|
||||
monitor.setProgress(++count);
|
||||
}
|
||||
if (zeroRecord != null) {
|
||||
tmpAdapter.createSymbol(Math.max(1, nextKey), zeroRecord);
|
||||
}
|
||||
// TODO keep this until I fix up SymbolManager
|
||||
// AddressKeyIterator entryPts = oldAdapter.getExternalEntryInterator();
|
||||
// while (entryPts.hasNext()) {
|
||||
// if (monitor.isCancelled()) {
|
||||
// throw new CancelledException();
|
||||
// }
|
||||
// Address addr = oldAddrMap.decodeAddress(entryPts.next());
|
||||
// tmpAdapter.setExternalEntry(addr);
|
||||
// monitor.setProgress(++count);
|
||||
// }
|
||||
|
||||
dbHandle.deleteTable(SYMBOL_TABLE_NAME);
|
||||
SymbolDatabaseAdapterV2 newAdapter =
|
||||
new SymbolDatabaseAdapterV2(dbHandle, addrMap, true);
|
||||
|
||||
iter = tmpAdapter.getSymbols();
|
||||
while (iter.hasNext()) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
DBRecord rec = iter.next();
|
||||
|
||||
// Make sure user symbols do not start with reserved prefix
|
||||
String name = rec.getString(SYMBOL_NAME_COL);
|
||||
if (SymbolUtilities.startsWithDefaultDynamicPrefix(name)) {
|
||||
rec.setString(SYMBOL_NAME_COL,
|
||||
fixSymbolName(tmpAdapter, name, rec.getLongValue(SYMBOL_PARENT_COL)));
|
||||
}
|
||||
|
||||
// TODO May want to check for default name to set flags when upgrading.
|
||||
// long addr = rec.getLongValue(SYMBOL_ADDR_COL);
|
||||
// Address address = addrMap.decodeAddress(addr);
|
||||
// String defaultName = ???;
|
||||
// byte flags = name.equals(defaultName) ? SYMBOL_DEFAULT_FLAG : SYMBOL_USER_DEFINED_FLAG;
|
||||
// rec.setByteValue(SYMBOL_FLAGS_COL, SYMBOL_USER_DEFINED_FLAG);
|
||||
|
||||
newAdapter.symbolTable.putRecord(rec);
|
||||
monitor.setProgress(++count);
|
||||
}
|
||||
return newAdapter;
|
||||
}
|
||||
finally {
|
||||
tmpHandle.deleteTable(SYMBOL_TABLE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param zeroRecord
|
||||
* @throws IOException
|
||||
*/
|
||||
private void createSymbol(long nextKey, DBRecord zeroRecord) throws IOException {
|
||||
zeroRecord.setKey(nextKey);
|
||||
symbolTable.putRecord(zeroRecord);
|
||||
}
|
||||
|
||||
private static String fixSymbolName(SymbolDatabaseAdapter tmpAdapter, String name,
|
||||
long namespaceId) throws IOException {
|
||||
String baseName = "_" + name; // dynamic prefix is reserved
|
||||
String newName = baseName;
|
||||
int cnt = 0;
|
||||
while (true) {
|
||||
try {
|
||||
RecordIterator iter = tmpAdapter.getSymbolsByName(newName);
|
||||
while (iter.hasNext()) {
|
||||
DBRecord otherRec = iter.next();
|
||||
if (namespaceId == otherRec.getLongValue(SYMBOL_PARENT_COL)) {
|
||||
throw new DuplicateNameException();
|
||||
}
|
||||
}
|
||||
return newName;
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
newName = baseName + "_" + (++cnt);
|
||||
if (symbolTable.getSchema().getVersion() != SYMBOL_VERSION) {
|
||||
int version = symbolTable.getSchema().getVersion();
|
||||
if (version < SYMBOL_VERSION) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
throw new VersionException(VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
long data1, int data2, String data3, SourceType source) throws IOException {
|
||||
long nextID = symbolTable.getKey();
|
||||
|
||||
// avoiding key 0, because we use the negative of the address offset as keys for dynamic symbols
|
||||
if (nextID == 0) {
|
||||
nextID++;
|
||||
}
|
||||
return createSymbol(nextID, name, address, namespaceID, symbolType, data1, data2, data3,
|
||||
(byte) source.ordinal());
|
||||
}
|
||||
|
||||
private DBRecord createSymbol(long id, String name, Address address, long namespaceID,
|
||||
SymbolType symbolType, long data1, int data2, String data3, byte flags)
|
||||
throws IOException {
|
||||
|
||||
DBRecord rec = symbolTable.getSchema().createRecord(id);
|
||||
rec.setString(SYMBOL_NAME_COL, name);
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, addrMap.getKey(address, true));
|
||||
rec.setLongValue(SYMBOL_PARENT_COL, namespaceID);
|
||||
rec.setByteValue(SYMBOL_TYPE_COL, symbolType.getID());
|
||||
rec.setLongValue(SYMBOL_DATA1_COL, data1);
|
||||
rec.setIntValue(SYMBOL_DATA2_COL, data2);
|
||||
rec.setString(SYMBOL_DATA3_COL, data3);
|
||||
rec.setByteValue(SYMBOL_FLAGS_COL, flags);
|
||||
symbolTable.putRecord(rec);
|
||||
return rec;
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
void removeSymbol(long symbolID) throws IOException {
|
||||
symbolTable.deleteRecord(symbolID);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -234,7 +104,7 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(long symbolID) throws IOException {
|
||||
return symbolTable.getRecord(symbolID);
|
||||
return convertV2Record(symbolTable.getRecord(symbolID));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -244,30 +114,62 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
RecordIterator getSymbolsByAddress(boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable,
|
||||
KeyToRecordIterator it = new KeyToRecordIterator(symbolTable,
|
||||
new AddressIndexPrimaryKeyIterator(symbolTable, SYMBOL_ADDR_COL, addrMap, forward));
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, startAddr, forward));
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, startAddr, forward));
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateSymbolRecord(DBRecord record) throws IOException {
|
||||
symbolTable.putRecord(record);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols() throws IOException {
|
||||
return symbolTable.iterator();
|
||||
return new V2ConvertedRecordIterator(symbolTable.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, start, end, forward));
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, start, end, forward));
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
|
||||
return getPrimaryFilterRecordIterator(new V2ConvertedRecordIterator(it));
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getPrimarySymbol(Address address) throws IOException {
|
||||
RecordIterator it = getPrimarySymbols(new AddressSet(address, address), true);
|
||||
if (it.hasNext()) {
|
||||
return it.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -316,13 +218,15 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
@Override
|
||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||
LongField field = new LongField(id);
|
||||
return symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true);
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByName(String name) throws IOException {
|
||||
StringField field = new StringField(name);
|
||||
return symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true);
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -353,4 +257,97 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
Table getTable() {
|
||||
return symbolTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
||||
StringField value = new StringField(name);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true);
|
||||
RecordIterator filtered = getNameAndNamespaceFilterIterator(name, id, it);
|
||||
return new V2ConvertedRecordIterator(filtered);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
||||
StringField value = new StringField(name);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true);
|
||||
long addressKey = addrMap.getKey(address, false);
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a record matching the current database schema from the version 2 record.
|
||||
* @param record the record matching the version 2 schema.
|
||||
* @return a current symbol record.
|
||||
*/
|
||||
private DBRecord convertV2Record(DBRecord record) {
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey());
|
||||
|
||||
String symbolName = record.getString(V2_SYMBOL_NAME_COL);
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
|
||||
|
||||
long symbolAddrKey = record.getLongValue(V2_SYMBOL_ADDR_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
||||
|
||||
long namespaceId = record.getLongValue(V2_SYMBOL_PARENT_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId);
|
||||
|
||||
byte symbolTypeId = record.getByteValue(V2_SYMBOL_TYPE_COL);
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId);
|
||||
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL,
|
||||
record.getString(V2_SYMBOL_DATA3_COL));
|
||||
|
||||
Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey);
|
||||
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL,
|
||||
record.getByteValue(V2_SYMBOL_FLAGS_COL));
|
||||
|
||||
long dataTypeId = record.getLongValue(V2_SYMBOL_DATA1_COL);
|
||||
if (dataTypeId != -1) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
||||
}
|
||||
|
||||
SymbolType type = SymbolType.getSymbolType(symbolTypeId);
|
||||
int data2 = record.getIntValue(V2_SYMBOL_DATA2_COL);
|
||||
// The data1 field was used in two ways for label symbols, it stored a 1 for primary and 0
|
||||
// for non-primary. If the type was a parameter or variable, it stored the ordinal or
|
||||
// first use offset respectively
|
||||
if (SymbolType.LABEL.equals(type)) {
|
||||
if (data2 == 1) { // if it was primary, put the address in the indexed primary col
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
||||
}
|
||||
}
|
||||
else if (SymbolType.PARAMETER.equals(type) || SymbolType.LOCAL_VAR.equals(type)) {
|
||||
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, data2);
|
||||
}
|
||||
|
||||
// also need to store primary for functions
|
||||
if (SymbolType.FUNCTION.equals(type)) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
||||
}
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
private class V2ConvertedRecordIterator extends ConvertedRecordIterator {
|
||||
|
||||
V2ConvertedRecordIterator(RecordIterator originalIterator) {
|
||||
super(originalIterator, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DBRecord convertRecord(DBRecord record) {
|
||||
return convertV2Record(record);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
/* ###
|
||||
* 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 java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.database.map.*;
|
||||
import ghidra.program.database.util.EmptyRecordIterator;
|
||||
import ghidra.program.database.util.RecordFilter;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* SymbolDatabaseAdapter for version 3
|
||||
*
|
||||
* This version provides for fast symbol lookup by namespace and name.
|
||||
* It was created in June 2021 with ProgramDB version 24.
|
||||
* It will be included in Ghidra starting at version 10.1
|
||||
*/
|
||||
class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||
|
||||
static final int SYMBOL_VERSION = 3;
|
||||
|
||||
// Used to create a range when searching symbols by name/namespace but don't care about address
|
||||
private static final long MIN_ADDRESS_OFFSET = 0;
|
||||
private static final long MAX_ADDRESS_OFFSET = -1;
|
||||
|
||||
// NOTE: the primary field duplicates the symbol's address when the symbol is primary. This
|
||||
// allows us to index this field and quickly find the primary symbols. The field is sparse
|
||||
// so that non-primary symbols don't consume any space for this field.
|
||||
|
||||
static final Schema V3_SYMBOL_SCHEMA = new Schema(SYMBOL_VERSION, "Key",
|
||||
new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||
ByteField.INSTANCE, StringField.INSTANCE, ByteField.INSTANCE,
|
||||
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE },
|
||||
new String[] { "Name", "Address", "Namespace", "Symbol Type", "String Data", "Flags",
|
||||
"Locator Hash", "Primary", "Datatype", "Variable Offset" },
|
||||
new int[] { SYMBOL_HASH_COL, SYMBOL_PRIMARY_COL, SYMBOL_DATATYPE_COL,
|
||||
SYMBOL_VAROFFSET_COL });
|
||||
|
||||
private Table symbolTable;
|
||||
private AddressMap addrMap;
|
||||
|
||||
SymbolDatabaseAdapterV3(DBHandle handle, AddressMap addrMap, boolean create)
|
||||
throws VersionException, IOException {
|
||||
|
||||
this.addrMap = addrMap;
|
||||
if (create) {
|
||||
symbolTable = handle.createTable(SYMBOL_TABLE_NAME, SYMBOL_SCHEMA,
|
||||
new int[] { SYMBOL_ADDR_COL, SYMBOL_NAME_COL, SYMBOL_PARENT_COL, SYMBOL_HASH_COL,
|
||||
SYMBOL_PRIMARY_COL });
|
||||
}
|
||||
else {
|
||||
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
||||
if (symbolTable == null) {
|
||||
throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME);
|
||||
}
|
||||
if (symbolTable.getSchema().getVersion() != SYMBOL_VERSION) {
|
||||
int version = symbolTable.getSchema().getVersion();
|
||||
if (version < SYMBOL_VERSION) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
throw new VersionException(VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
long nextID = symbolTable.getKey();
|
||||
|
||||
// avoiding key 0, as it is reserved for the global namespace
|
||||
if (nextID == 0) {
|
||||
nextID++;
|
||||
}
|
||||
return createSymbol(nextID, name, address, namespaceID, symbolType, stringData,
|
||||
(byte) source.ordinal(), dataTypeId, varOffset, isPrimary);
|
||||
}
|
||||
|
||||
private DBRecord createSymbol(long id, String name, Address address, long namespaceID,
|
||||
SymbolType symbolType, String stringData, byte flags,
|
||||
Long dataTypeId, Integer varOffset, boolean isPrimary) throws IOException {
|
||||
|
||||
long addressKey = addrMap.getKey(address, true);
|
||||
|
||||
DBRecord rec = symbolTable.getSchema().createRecord(id);
|
||||
rec.setString(SYMBOL_NAME_COL, name);
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, addressKey);
|
||||
rec.setLongValue(SYMBOL_PARENT_COL, namespaceID);
|
||||
rec.setByteValue(SYMBOL_TYPE_COL, symbolType.getID());
|
||||
rec.setString(SYMBOL_STRING_DATA_COL, stringData);
|
||||
rec.setByteValue(SYMBOL_FLAGS_COL, flags);
|
||||
|
||||
// sparse columns - these columns don't apply to all symbols.
|
||||
// they default to null unless specifically set. Null values don't consume space.
|
||||
|
||||
rec.setField(SYMBOL_HASH_COL,
|
||||
computeLocatorHash(name, namespaceID, addressKey));
|
||||
|
||||
if (isPrimary) {
|
||||
rec.setLongValue(SYMBOL_PRIMARY_COL, addressKey);
|
||||
}
|
||||
|
||||
if (dataTypeId != null) {
|
||||
rec.setLongValue(SYMBOL_DATATYPE_COL, dataTypeId);
|
||||
}
|
||||
|
||||
if (varOffset != null) {
|
||||
rec.setIntValue(SYMBOL_VAROFFSET_COL, varOffset);
|
||||
}
|
||||
|
||||
symbolTable.putRecord(rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
@Override
|
||||
void removeSymbol(long symbolID) throws IOException {
|
||||
symbolTable.deleteRecord(symbolID);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasSymbol(Address addr) throws IOException {
|
||||
long key = addrMap.getKey(addr, false);
|
||||
if (key == AddressMap.INVALID_ADDRESS_KEY && !addr.equals(Address.NO_ADDRESS)) {
|
||||
return false;
|
||||
}
|
||||
return symbolTable.hasRecord(new LongField(key), SYMBOL_ADDR_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
Field[] getSymbolIDs(Address addr) throws IOException {
|
||||
long key = addrMap.getKey(addr, false);
|
||||
if (key == AddressMap.INVALID_ADDRESS_KEY && !addr.equals(Address.NO_ADDRESS)) {
|
||||
return Field.EMPTY_ARRAY;
|
||||
}
|
||||
return symbolTable.findRecords(new LongField(key), SYMBOL_ADDR_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(long symbolID) throws IOException {
|
||||
return symbolTable.getRecord(symbolID);
|
||||
}
|
||||
|
||||
@Override
|
||||
int getSymbolCount() {
|
||||
return symbolTable.getRecordCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByAddress(boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable,
|
||||
new AddressIndexPrimaryKeyIterator(symbolTable, SYMBOL_ADDR_COL, addrMap, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, startAddr, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateSymbolRecord(DBRecord record) throws IOException {
|
||||
// make sure hash is updated to current name and name space
|
||||
String name = record.getString(SYMBOL_NAME_COL);
|
||||
long namespaceId = record.getLongValue(SYMBOL_PARENT_COL);
|
||||
long addressKey = record.getLongValue(SYMBOL_ADDR_COL);
|
||||
record.setField(SYMBOL_HASH_COL,
|
||||
computeLocatorHash(name, namespaceId, addressKey));
|
||||
symbolTable.putRecord(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols() throws IOException {
|
||||
return symbolTable.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, start, end, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_PRIMARY_COL, addrMap, set, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DBRecord getPrimarySymbol(Address address) throws IOException {
|
||||
AddressIndexPrimaryKeyIterator it = new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_PRIMARY_COL, addrMap, address, address, true);
|
||||
if (it.hasNext()) {
|
||||
return symbolTable.getRecord(it.next());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void deleteExternalEntries(Address start, Address end) throws IOException {
|
||||
AddressRecordDeleter.deleteRecords(symbolTable, SYMBOL_ADDR_COL, addrMap, start, end, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
void moveAddress(Address oldAddr, Address newAddr) throws IOException {
|
||||
LongField oldKey = new LongField(addrMap.getKey(oldAddr, false));
|
||||
long newKey = addrMap.getKey(newAddr, true);
|
||||
Field[] keys = symbolTable.findRecords(oldKey, SYMBOL_ADDR_COL);
|
||||
for (Field key : keys) {
|
||||
DBRecord rec = symbolTable.getRecord(key);
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, newKey);
|
||||
symbolTable.putRecord(rec);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Address> deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
|
||||
AnchoredSymbolRecordFilter filter = new AnchoredSymbolRecordFilter();
|
||||
AddressRecordDeleter.deleteRecords(symbolTable, SYMBOL_ADDR_COL, addrMap, startAddr,
|
||||
endAddr, filter);
|
||||
|
||||
return filter.getAddressesForSkippedRecords();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||
LongField field = new LongField(id);
|
||||
return symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByName(String name) throws IOException {
|
||||
StringField field = new StringField(name);
|
||||
return symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
||||
// create a range of hash fields for all symbols with this name and namespace id over all
|
||||
// possible addresses
|
||||
Field start = computeLocatorHash(name, id, MIN_ADDRESS_OFFSET);
|
||||
if (start == null) {
|
||||
return EmptyRecordIterator.INSTANCE;
|
||||
}
|
||||
|
||||
Field end = computeLocatorHash(name, id, MAX_ADDRESS_OFFSET);
|
||||
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_HASH_COL, start, end, true);
|
||||
return getNameAndNamespaceFilterIterator(name, id, it);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(Address address, String name, long namespaceId) throws IOException {
|
||||
long addressKey = addrMap.getKey(address, false);
|
||||
Field search = computeLocatorHash(name, namespaceId, addressKey);
|
||||
if (search == null) {
|
||||
return null;
|
||||
}
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_HASH_COL, search, search, true);
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, namespaceId, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
Address getMaxSymbolAddress(AddressSpace space) throws IOException {
|
||||
if (space.isMemorySpace()) {
|
||||
AddressIndexKeyIterator addressKeyIterator = new AddressIndexKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, space.getMinAddress(), space.getMaxAddress(), false);
|
||||
if (addressKeyIterator.hasNext()) {
|
||||
return addrMap.decodeAddress(addressKeyIterator.next());
|
||||
}
|
||||
}
|
||||
else {
|
||||
LongField max = new LongField(addrMap.getKey(space.getMaxAddress(), false));
|
||||
DBFieldIterator iterator =
|
||||
symbolTable.indexFieldIterator(null, max, false, SYMBOL_ADDR_COL);
|
||||
if (iterator.hasPrevious()) {
|
||||
LongField val = (LongField) iterator.previous();
|
||||
Address addr = addrMap.decodeAddress(val.getLongValue());
|
||||
if (space.equals(addr.getAddressSpace())) {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
Table getTable() {
|
||||
return symbolTable;
|
||||
}
|
||||
|
||||
private class AnchoredSymbolRecordFilter implements RecordFilter {
|
||||
private Set<Address> set = new HashSet<Address>();
|
||||
|
||||
@Override
|
||||
public boolean matches(DBRecord record) {
|
||||
// only move symbols whose anchor flag is not on
|
||||
Address addr = addrMap.decodeAddress(record.getLongValue(SYMBOL_ADDR_COL));
|
||||
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
||||
boolean pinned = (flags & SymbolDatabaseAdapter.SYMBOL_PINNED_FLAG) != 0;
|
||||
if (!pinned) {
|
||||
return true;
|
||||
}
|
||||
set.add(addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Address> getAddressesForSkippedRecords() {
|
||||
return set;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -73,7 +73,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
|
||||
private Lock lock;
|
||||
final static Symbol[] NO_SYMBOLS = new SymbolDB[0];
|
||||
private static final int MAX_DUPLICATE_COUNT = 10;
|
||||
|
||||
/**
|
||||
* Creates a new Symbol manager.
|
||||
|
@ -211,7 +210,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
refMgr.moveReferencesTo(oldAddr, nextExtAddr, monitor);
|
||||
nextExtAddr = nextExtAddr.next();
|
||||
}
|
||||
libSym.setSymbolData2(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -275,7 +273,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
|
||||
try {
|
||||
Address variableAddr = getUpgradedVariableAddress(storageAddr,
|
||||
rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL));
|
||||
rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL));
|
||||
|
||||
// fix symbol address
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL,
|
||||
|
@ -321,12 +319,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
throw new RuntimeException("Unexpected");
|
||||
}
|
||||
|
||||
long dataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL);
|
||||
long dataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||
|
||||
if (curVarAddr == null || !addr.equals(curVarAddr) || dataTypeId != curDataTypeId) {
|
||||
|
||||
curVarAddr = addr;
|
||||
curDataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL);
|
||||
curDataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||
|
||||
Address storageAddr = oldVariableStorageMgr.getStorageAddress(addr);
|
||||
|
||||
|
@ -450,7 +448,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* @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,
|
||||
static void saveLocalSymbol(DBHandle tmpHandle, long symbolID, long oldAddr, String name,
|
||||
boolean isPrimary) throws IOException {
|
||||
Table table = tmpHandle.getTable(OLD_LOCAL_SYMBOLS_TABLE);
|
||||
if (table == null) {
|
||||
|
@ -506,8 +504,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID,
|
||||
null);
|
||||
DBRecord record =
|
||||
adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, 0,
|
||||
1, null, source);
|
||||
adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, null,
|
||||
null, null, source, true);
|
||||
symbol.setRecord(record);// symbol object was morphed
|
||||
symbolAdded(symbol);
|
||||
}
|
||||
|
@ -548,12 +546,15 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
|
||||
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(symbolID);
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, name);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, addrMap.getKey(addr, true));
|
||||
long addressKey = addrMap.getKey(addr, true);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, addressKey);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespace.getID());
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, type.getID());
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, -1);
|
||||
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, isPrimary ? 1 : 0);
|
||||
if (isPrimary) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey);
|
||||
}
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal());
|
||||
|
||||
adapter.updateSymbolRecord(rec);
|
||||
}
|
||||
|
||||
|
@ -868,38 +869,51 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Symbol getSymbol(String name, Address addr, Namespace namespace) {
|
||||
public Symbol getSymbol(String name, Address address, Namespace namespace) {
|
||||
if (namespace == null) {
|
||||
namespace = program.getGlobalNamespace();
|
||||
}
|
||||
|
||||
if (addr instanceof SpecialAddress) {
|
||||
List<Symbol> symbols = getSymbols(name, namespace);
|
||||
for (Symbol symbol : symbols) {
|
||||
if (symbol.getAddress().equals(addr)) {
|
||||
return symbol;
|
||||
}
|
||||
long namespaceId = namespace.getID();
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
DBRecord record = adapter.getSymbolRecord(address, name, namespaceId);
|
||||
if (record != null) {
|
||||
return getSymbol(record);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
return getSymbol(name, addr, namespace.getID());
|
||||
// check for default external symbol
|
||||
if (namespace.isExternal() && SymbolUtilities.isPossibleDefaultExternalName(name)) {
|
||||
return searchNamespaceForSymbol(namespace, name, address);
|
||||
}
|
||||
|
||||
// also check for possible default parameter or local variable symbol
|
||||
if (namespace instanceof Function &&
|
||||
SymbolUtilities.isPossibleDefaultLocalOrParamName(name)) {
|
||||
return searchNamespaceForSymbol(namespace, name, address);
|
||||
}
|
||||
|
||||
// check if name is a default name
|
||||
Symbol symbol = getSymbolForDynamicName(name);
|
||||
if (symbol != null && address.equals(symbol.getAddress()) &&
|
||||
namespace.equals(symbol.getParentNamespace())) {
|
||||
return symbol;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the symbol with the given info.
|
||||
* @param name the name of the symbol
|
||||
* @param addr the address of the symbol
|
||||
* @param parentID the id of the namespace symbol that the symbol belongs to.
|
||||
*/
|
||||
private Symbol getSymbol(String name, Address addr, long parentID) {
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
for (Symbol sym : symbols) {
|
||||
if (parentID != ((SymbolDB) sym).getParentID()) {
|
||||
continue;
|
||||
}
|
||||
if (!isDefaultThunk(sym) && sym.getName().equals(name)) {
|
||||
return sym;
|
||||
private Symbol searchNamespaceForSymbol(Namespace namespace, String name, Address address) {
|
||||
for (Symbol symbol : getSymbols(namespace)) {
|
||||
if (address.equals(symbol.getAddress()) && name.equals(symbol.getName())) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -916,13 +930,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
return symbols.isEmpty() ? null : symbols.get(0);
|
||||
}
|
||||
|
||||
private boolean hasDefaultVariablePrefix(String name) {
|
||||
return name.startsWith(Function.DEFAULT_LOCAL_PREFIX) ||
|
||||
name.startsWith(Function.DEFAULT_LOCAL_RESERVED_PREFIX) ||
|
||||
name.startsWith(Function.DEFAULT_LOCAL_TEMP_PREFIX) ||
|
||||
name.startsWith(Function.DEFAULT_PARAM_PREFIX) || name.equals("this");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol getGlobalSymbol(String name, Address addr) {
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
|
@ -981,38 +988,60 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
namespace = namespaceMgr.getGlobalNamespace();
|
||||
}
|
||||
|
||||
// if name is possible default parameter or local variable name, must do brute force search
|
||||
if (namespace instanceof Function &&
|
||||
SymbolUtilities.isPossibleDefaultLocalOrParamName(name)) {
|
||||
return searchNamespaceForSymbols(name, namespace);
|
||||
}
|
||||
|
||||
// if the name is a possible default external name, do brute force search
|
||||
if (namespace.isExternal() && SymbolUtilities.isPossibleDefaultExternalName(name)) {
|
||||
return searchNamespaceForSymbols(name, namespace);
|
||||
}
|
||||
|
||||
List<Symbol> list = new ArrayList<>();
|
||||
lock.acquire();
|
||||
try {
|
||||
if (namespace.isExternal() &&
|
||||
SymbolUtilities.isReservedExternalDefaultName(name, program.getAddressFactory())) {
|
||||
return searchSymbolsByNamespaceFirst(name, namespace);
|
||||
RecordIterator it = adapter.getSymbolsByNameAndNamespace(name, namespace.getID());
|
||||
while (it.hasNext()) {
|
||||
list.add(getSymbol(it.next()));
|
||||
}
|
||||
|
||||
if (namespace instanceof Function && hasDefaultVariablePrefix(name)) {
|
||||
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.
|
||||
int count = 0;
|
||||
List<Symbol> list = new ArrayList<>();
|
||||
SymbolIterator symbols = getSymbols(name); // will not include default thunks
|
||||
for (Symbol s : symbols) {
|
||||
if (++count == MAX_DUPLICATE_COUNT && !namespace.isGlobal()) {
|
||||
return searchSymbolsByNamespaceFirst(name, namespace);
|
||||
}
|
||||
if (s.getParentNamespace().equals(namespace)) {
|
||||
list.add(s);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
// also check if the given name could be a default symbol
|
||||
Symbol symbol = getSymbolForDynamicName(name);
|
||||
if (symbol != null && symbol.getParentNamespace().equals(namespace)) {
|
||||
list.add(symbol);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<Symbol> searchNamespaceForSymbols(String name, Namespace namespace) {
|
||||
List<Symbol> list = new ArrayList<>();
|
||||
for (Symbol symbol : getSymbols(namespace)) {
|
||||
if (name.equals(symbol.getName())) {
|
||||
list.add(symbol);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private Symbol getSymbolForDynamicName(String name) {
|
||||
Address address = SymbolUtilities.parseDynamicName(addrMap.getAddressFactory(), name);
|
||||
if (address != null) {
|
||||
Symbol primarySymbol = getPrimarySymbol(address);
|
||||
if (primarySymbol != null && primarySymbol.getSource() == SourceType.DEFAULT) {
|
||||
return primarySymbol;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// note: this could be public; adding it may be confusing due to the potential for having
|
||||
|
@ -1021,57 +1050,31 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
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);
|
||||
lock.acquire();
|
||||
try {
|
||||
RecordIterator it = adapter.getSymbolsByNameAndNamespace(name, namespace.getID());
|
||||
while (it.hasNext()) {
|
||||
SymbolDB symbol = getSymbol(it.next());
|
||||
if (test.test(symbol)) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
if (s.getParentNamespace().equals(namespace) &&
|
||||
test.test(s)) {
|
||||
return s;
|
||||
// didn't find one in the database, see if it is a default dynamic name
|
||||
Symbol symbol = getSymbolForDynamicName(name);
|
||||
if (symbol != null && symbol.getParentNamespace().equals(namespace) &&
|
||||
test.test(symbol)) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of symbols with the given name and namespace.
|
||||
*
|
||||
* <P>This method works by examining all symbols in the given namespace for those with
|
||||
* the specified name.
|
||||
*
|
||||
* @param name the name of the symbols in include.
|
||||
* @param namespace the namespace of the symbols to include.
|
||||
* @return the list of symbols with the given name and namespace.
|
||||
*/
|
||||
private List<Symbol> searchSymbolsByNamespaceFirst(String name, Namespace namespace) {
|
||||
List<Symbol> list = new ArrayList<>();
|
||||
SymbolIterator symbols = getSymbols(namespace);
|
||||
for (Symbol symbol : symbols) {
|
||||
if (symbol.getName().equals(name)) {
|
||||
list.add(symbol);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Namespace getNamespace(String name, Namespace namespace) {
|
||||
List<Symbol> symbols = getSymbols(name, namespace);
|
||||
|
@ -1107,16 +1110,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
try {
|
||||
SymbolIterator symIter = new SymbolNameRecordIterator(name);
|
||||
if (!symIter.hasNext()) {
|
||||
Address addr = SymbolUtilities.parseDynamicName(addrMap.getAddressFactory(), name);
|
||||
if (addr != null) {
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
for (Symbol symbol : symbols) {
|
||||
if (name.equals(symbol.getName())) {
|
||||
return new SingleSymbolIterator(symbol);
|
||||
}
|
||||
}
|
||||
return new SingleSymbolIterator(null);
|
||||
}
|
||||
Symbol symbol = getSymbolForDynamicName(name);
|
||||
return new SingleSymbolIterator(symbol); // this handles a null symbol
|
||||
}
|
||||
return symIter;
|
||||
}
|
||||
|
@ -1134,19 +1129,28 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
if (!addr.isMemoryAddress() && !addr.isExternalAddress()) {
|
||||
return null;
|
||||
}
|
||||
if (addr.isExternalAddress()) {
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
return symbols.length > 0 ? symbols[0] : null;
|
||||
}
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
for (Symbol element : symbols) {
|
||||
if (element.isPrimary()) {
|
||||
return element;
|
||||
}
|
||||
DBRecord record = adapter.getPrimarySymbol(addr);
|
||||
if (record != null) {
|
||||
return getSymbol(record);
|
||||
}
|
||||
return null;
|
||||
if (addr.isMemoryAddress() && refManager.hasReferencesTo(addr)) {
|
||||
return getDynamicSymbol(addr);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1207,14 +1211,14 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
if (set.isEmpty()) {
|
||||
return SymbolIterator.EMPTY_ITERATOR;
|
||||
}
|
||||
Query query1 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, new IntField(1));
|
||||
Query query2 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_TYPE_COL,
|
||||
new ByteField(SymbolType.LABEL.getID()));
|
||||
Query query3 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_TYPE_COL,
|
||||
new ByteField(SymbolType.FUNCTION.getID()));
|
||||
Query query4 = new AndQuery(query1, query2);
|
||||
Query query5 = new OrQuery(query3, query4);
|
||||
return new AddressSetFilteredSymbolIterator(this, set, query5, forward);
|
||||
try {
|
||||
RecordIterator recordIterator = adapter.getPrimarySymbols(set, forward);
|
||||
return new SymbolRecordIterator(recordIterator, true, forward);
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
return new SymbolRecordIterator(new EmptyRecordIterator(), true, forward);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2130,9 +2134,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
long id = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL);
|
||||
long id = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||
if (id == oldDataTypeID) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, newDataTypeID);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, newDataTypeID);
|
||||
adapter.updateSymbolRecord(rec);
|
||||
symbolDataChanged(getSymbol(rec));
|
||||
}
|
||||
|
@ -2157,14 +2161,14 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
lock.acquire();
|
||||
try {
|
||||
invalidateCache(true);
|
||||
Address lastAddress = fromAddr.add(length-1);
|
||||
Address lastAddress = fromAddr.add(length - 1);
|
||||
AddressRange range = new AddressRangeImpl(fromAddr, lastAddress);
|
||||
|
||||
// in order to handle overlapping ranges, need to iterate in the correct direction
|
||||
SymbolIterator symbolIterator = (fromAddr.compareTo(toAddr) > 0) ?
|
||||
getSymbolIterator(fromAddr, true) :
|
||||
getSymbolIterator(lastAddress, false);
|
||||
|
||||
SymbolIterator symbolIterator =
|
||||
(fromAddr.compareTo(toAddr) > 0) ? getSymbolIterator(fromAddr, true)
|
||||
: getSymbolIterator(lastAddress, false);
|
||||
|
||||
for (Symbol symbol : symbolIterator) {
|
||||
if (!range.contains(symbol.getAddress())) {
|
||||
break;
|
||||
|
@ -2174,7 +2178,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
// any address that has symbols added or removed may have a corrupted primary (too many or non-existent)
|
||||
primaryFixups.add(symbol.getAddress());
|
||||
primaryFixups.add(newAddress);
|
||||
|
||||
|
||||
moveSymbolForMemoryBlockMove((SymbolDB) symbol, newAddress);
|
||||
}
|
||||
// go back and make sure there is a valid primary symbol at touched addressess
|
||||
|
@ -2386,7 +2390,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
try {
|
||||
Symbol newLabel =
|
||||
createLabel(newAddress, symbol.getName(), symbol.getParentNamespace(),
|
||||
symbol.getSource());
|
||||
symbol.getSource());
|
||||
newLabel.setPinned(true);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
|
@ -2479,8 +2483,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
try {
|
||||
source = adjustSourceTypeIfNecessary(name, type, source, storage);
|
||||
Address varAddr = variableStorageMgr.getVariableStorageAddress(storage, true);
|
||||
return (VariableSymbolDB) createSpecialSymbol(varAddr, name, namespace, type, -1,
|
||||
firstUseOffsetOrOrdinal, null, source);
|
||||
return (VariableSymbolDB) createSpecialSymbol(varAddr, name, namespace, type,
|
||||
null, Integer.valueOf(firstUseOffsetOrOrdinal), null, source);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
|
@ -2506,8 +2510,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
@Override
|
||||
public GhidraClass createClass(Namespace parent, String name, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.CLASS, -1, -1,
|
||||
null, source);
|
||||
SymbolDB s =
|
||||
createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.CLASS, null, null,
|
||||
null, source);
|
||||
return new GhidraClassDB(s, namespaceMgr);
|
||||
}
|
||||
|
||||
|
@ -2515,8 +2520,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
public Library createExternalLibrary(String name, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, null, SymbolType.LIBRARY, -1, -1,
|
||||
null, source);
|
||||
SymbolDB s =
|
||||
createSpecialSymbol(Address.NO_ADDRESS, name, null, SymbolType.LIBRARY, null, null,
|
||||
null, source);
|
||||
return new LibraryDB(s, namespaceMgr);
|
||||
}
|
||||
|
||||
|
@ -2524,8 +2530,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
public Namespace createNameSpace(Namespace parent, String name, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, -1,
|
||||
-1, null, source);
|
||||
SymbolDB s =
|
||||
createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, null,
|
||||
null, null, source);
|
||||
return new NamespaceDB(s, namespaceMgr);
|
||||
}
|
||||
|
||||
|
@ -2549,7 +2556,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
String tempName = "_temp_" + System.nanoTime();
|
||||
SymbolDB classSymbol =
|
||||
doCreateSpecialSymbol(Address.NO_ADDRESS, tempName, namespace.getParentNamespace(),
|
||||
SymbolType.CLASS, -1, -1, null, originalSource, false /*check for duplicate */);
|
||||
SymbolType.CLASS, null, null, null, originalSource,
|
||||
false /*check for duplicate */);
|
||||
GhidraClassDB classNamespace = new GhidraClassDB(classSymbol, namespaceMgr);
|
||||
|
||||
// move everything from old namespace into new class namespace
|
||||
|
@ -2624,8 +2632,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
// 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*/);
|
||||
doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, null,
|
||||
null, null, source, true /*check for duplicates*/);
|
||||
return new NamespaceDB(s, namespaceMgr);
|
||||
|
||||
}
|
||||
|
@ -2643,9 +2651,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* @param name the name of the symbol
|
||||
* @param parent the namespace for the symbol
|
||||
* @param symbolType the type of the symbol
|
||||
* @param data1 long value whose meaning depends on the symbol type.
|
||||
* @param data2 int value whose meaning depends on the symbol type.
|
||||
* @param data3 string value whose meaning depends on the symbol type.
|
||||
* @param dataTypeId the id for an associated datatype or null
|
||||
* @param variableOffset this is the ordinal for params and firstUseOffset for locals
|
||||
* @param stringData value whose meaning depends on the symbol type.
|
||||
* @param source the SourceType for the new symbol
|
||||
* @return the newly created symbol
|
||||
* @throws DuplicateNameException if the symbol type must be unique and another already has that name
|
||||
|
@ -2653,15 +2661,17 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* @throws InvalidInputException if the name contains any illegal characters (i.e. space)
|
||||
*/
|
||||
public SymbolDB createSpecialSymbol(Address addr, String name, Namespace parent,
|
||||
SymbolType symbolType, long data1, int data2, String data3, SourceType source)
|
||||
SymbolType symbolType, Long dataTypeId, Integer variableOffset, String stringData,
|
||||
SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
return doCreateSpecialSymbol(addr, name, parent, symbolType, data1, data2, data3, source,
|
||||
true);
|
||||
return doCreateSpecialSymbol(addr, name, parent, symbolType, stringData, dataTypeId,
|
||||
variableOffset, source, true);
|
||||
}
|
||||
|
||||
private SymbolDB doCreateSpecialSymbol(Address addr, String name, Namespace parent,
|
||||
SymbolType symbolType, long data1, int data2, String data3, SourceType source,
|
||||
SymbolType symbolType, String stringData, Long dataTypeId, Integer variableOffset,
|
||||
SourceType source,
|
||||
boolean checkForDuplicates)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
|
@ -2675,7 +2685,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
checkDuplicateSymbolName(addr, name, parent, symbolType);
|
||||
}
|
||||
|
||||
return doCreateSymbol(name, addr, parent, symbolType, data1, data2, data3, source);
|
||||
return doCreateSymbol(name, addr, parent, symbolType, stringData, dataTypeId,
|
||||
variableOffset, source, false);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -2713,12 +2724,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* @param name the name of the new symbol
|
||||
* @param namespace the namespace for the new symbol
|
||||
* @param source the SourceType of the new symbol
|
||||
* @param data3 special use depending on the symbol type and whether or not it is external
|
||||
* @param stringData special use depending on the symbol type and whether or not it is external
|
||||
* @return the new symbol
|
||||
* @throws InvalidInputException if the name contains illegal characters (i.e. space)
|
||||
*/
|
||||
public Symbol createCodeSymbol(Address addr, String name, Namespace namespace,
|
||||
SourceType source, String data3) throws InvalidInputException {
|
||||
SourceType source, String stringData) throws InvalidInputException {
|
||||
lock.acquire();
|
||||
try {
|
||||
namespace = validateNamespace(namespace, addr, SymbolType.LABEL);
|
||||
|
@ -2744,8 +2755,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
boolean makePrimary = primary == null;
|
||||
|
||||
return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, -1, makePrimary ? 1 : 0,
|
||||
data3, source);
|
||||
return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, stringData, null, null,
|
||||
source, makePrimary);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -2759,34 +2770,32 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* @param name the name of the new symbol
|
||||
* @param namespace the namespace for the new symbol
|
||||
* @param source the SourceType of the new symbol
|
||||
* @param data3 special use depending on the symbol type and whether or not it is external.
|
||||
* @param stringData special use depending on the symbol type and whether or not it is external.
|
||||
* @return the new symbol
|
||||
* @throws InvalidInputException if the name contains illegal characters (i.e. space)
|
||||
*/
|
||||
public Symbol createFunctionSymbol(Address addr, String name, Namespace namespace,
|
||||
SourceType source, String data3) throws InvalidInputException {
|
||||
SourceType source, String stringData) throws InvalidInputException {
|
||||
|
||||
namespace = validateNamespace(namespace, addr, SymbolType.FUNCTION);
|
||||
source = validateSource(source, name, addr, SymbolType.FUNCTION);
|
||||
name = validateName(name, source);
|
||||
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
|
||||
// if there is already a FUNCTION symbol with that name and namespace here, just return it.
|
||||
Symbol matching =
|
||||
findMatchingSymbol(symbols, new SymbolMatcher(name, namespace, SymbolType.FUNCTION));
|
||||
if (matching != null) {
|
||||
Symbol matching = getSymbol(name, addr, namespace);
|
||||
if (matching != null && matching.getSymbolType() == SymbolType.FUNCTION) {
|
||||
return matching;
|
||||
}
|
||||
|
||||
// if there is another function at the same address, throw InvalidInputException
|
||||
if (findMatchingSymbol(symbols, s -> s.getSymbolType() == SymbolType.FUNCTION) != null) {
|
||||
Symbol primary = getPrimarySymbol(addr);
|
||||
if (primary != null && primary.getSymbolType() == SymbolType.FUNCTION) {
|
||||
throw new InvalidInputException("Function already exists at: " + addr);
|
||||
}
|
||||
|
||||
// See if there is a symbol we want to change into the function symbol
|
||||
Symbol symbolToPromote = findSymbolToPromote(symbols, name, namespace, source);
|
||||
if (symbolToPromote != null) {
|
||||
Symbol symbolToPromote = findSymbolToPromote(matching, primary, source);
|
||||
if (symbolToPromote != null && !symbolToPromote.isDynamic()) {
|
||||
name = symbolToPromote.getName();
|
||||
namespace = symbolToPromote.getParentNamespace();
|
||||
source = symbolToPromote.getSource();
|
||||
|
@ -2795,11 +2804,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
// If promoting a pinned symbol, we need to pin the new function symbol.
|
||||
boolean needsPinning = symbolToPromote == null ? false : symbolToPromote.isPinned();
|
||||
|
||||
// delete any promoted symbol, dynamic symbol, and make sure any others are not primary
|
||||
cleanUpSymbols(symbols, symbolToPromote);
|
||||
// delete any promoted symbol, dynamic symbol, and make sure all others are not primary
|
||||
cleanUpSymbols(addr, symbolToPromote, primary);
|
||||
|
||||
Symbol symbol =
|
||||
doCreateSymbol(name, addr, namespace, SymbolType.FUNCTION, -1, -1, data3, source);
|
||||
doCreateSymbol(name, addr, namespace, SymbolType.FUNCTION, stringData, null, null,
|
||||
source, true);
|
||||
|
||||
if (needsPinning) {
|
||||
symbol.setPinned(true);
|
||||
|
@ -2809,48 +2819,45 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
|
||||
/**
|
||||
* If the new symbol is Default, returns the primary symbol if it is dynamic. Otherwise
|
||||
* returns any Code symbol with the same name and namespace.
|
||||
* Finds the appropriate symbol to promote when function is created. And by promote, we really
|
||||
* mean find the symbol that needs to be deleted before creating the function symbol. If the
|
||||
* found symbol is not dynamic, the function symbol will assume its name and namespace.
|
||||
*/
|
||||
private Symbol findSymbolToPromote(Symbol[] symbols, String name, Namespace namespace,
|
||||
SourceType source) {
|
||||
private Symbol findSymbolToPromote(Symbol matching, Symbol primary, SourceType source) {
|
||||
// if the function is default, then the primary will be promoted
|
||||
if (source == SourceType.DEFAULT) {
|
||||
Symbol primary = findMatchingSymbol(symbols, s -> s.isPrimary());
|
||||
if (primary != null && !primary.isDynamic()) {
|
||||
return primary;
|
||||
}
|
||||
return null;
|
||||
return primary;
|
||||
}
|
||||
// Even though this doesn't change the name or namespace, return this so it will be deleted later.
|
||||
return findMatchingSymbol(symbols, new SymbolMatcher(name, namespace, SymbolType.LABEL));
|
||||
// if the primary is a default, it needs to be deleted, so return it as the "promoted" symbol
|
||||
if (primary != null && primary.isDynamic()) {
|
||||
return primary;
|
||||
}
|
||||
// otherwise return a symbol that has the same name and namespce as the function (if it exists)
|
||||
return matching;
|
||||
}
|
||||
|
||||
private void cleanUpSymbols(Symbol[] symbols, Symbol symbolToPromote) {
|
||||
private void cleanUpSymbols(Address address, Symbol symbolToPromote, Symbol primary) {
|
||||
if (symbolToPromote != null) {
|
||||
if (symbolToPromote.isDynamic()) {
|
||||
deleteDynamicSymbol(symbolToPromote);
|
||||
primary = null;
|
||||
}
|
||||
else {
|
||||
symbolToPromote.delete();
|
||||
primary = getPrimarySymbol(address);
|
||||
if (primary != null && primary.isDynamic()) {
|
||||
deleteDynamicSymbol(primary);
|
||||
primary = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// clean up any symbol that may have been made primary when we deleted the symbolToPromote
|
||||
for (Symbol symbol : symbols) {
|
||||
if (symbol != symbolToPromote && symbol.isPrimary()) {
|
||||
((CodeSymbol) symbol).setPrimary(false);
|
||||
}
|
||||
// clear the primary symbol during cleanup because a new symbol is about to be created
|
||||
// that will be the primary symbol
|
||||
if (primary != null && !primary.isDynamic()) {
|
||||
((CodeSymbol) primary).setPrimary(false);
|
||||
}
|
||||
}
|
||||
|
||||
private Symbol findMatchingSymbol(Symbol[] symbols, Predicate<Symbol> matcher) {
|
||||
for (Symbol symbol : symbols) {
|
||||
if (matcher.test(symbol)) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Namespace validateNamespace(Namespace namespace, Address addr, SymbolType type)
|
||||
throws InvalidInputException {
|
||||
|
||||
|
@ -2862,12 +2869,13 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
|
||||
private SymbolDB doCreateSymbol(String name, Address addr, Namespace namespace, SymbolType type,
|
||||
long data1, int data2, String data3, SourceType source) {
|
||||
String stringData, Long dataTypeId, Integer variableOffset, SourceType source,
|
||||
boolean isPrimary) {
|
||||
|
||||
try {
|
||||
DBRecord record =
|
||||
adapter.createSymbol(name, addr, namespace.getID(), type, data1, data2,
|
||||
data3, source);
|
||||
adapter.createSymbol(name, addr, namespace.getID(), type, stringData, dataTypeId,
|
||||
variableOffset, source, isPrimary);
|
||||
|
||||
SymbolDB newSymbol = makeSymbol(addr, record, type);
|
||||
symbolAdded(newSymbol);
|
||||
|
@ -3019,21 +3027,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
private Symbol getSpecificSymbol(String name, Namespace namespace, SymbolType type) {
|
||||
return getFirstSymbol(name, namespace, s -> s.getSymbolType() == type);
|
||||
}
|
||||
|
||||
private Symbol findFirstSymbol(String name, Namespace namespace, Predicate<Symbol> test) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
class SymbolMatcher implements Predicate<Symbol> {
|
||||
|
|
|
@ -36,9 +36,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
* Symbol class for function variables.
|
||||
*
|
||||
* Symbol Data Usage:
|
||||
* long data1 - data type ID
|
||||
* int data2 - first-use-offset / ordinal
|
||||
* String data3 - variable comment
|
||||
* String stringData - variable comment
|
||||
*/
|
||||
public class VariableSymbolDB extends SymbolDB {
|
||||
|
||||
|
@ -174,8 +172,9 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
}
|
||||
|
||||
public FunctionDB getFunction() {
|
||||
return (FunctionDB) symbolMgr.getFunctionManager().getFunction(
|
||||
getParentNamespace().getID());
|
||||
return (FunctionDB) symbolMgr.getFunctionManager()
|
||||
.getFunction(
|
||||
getParentNamespace().getID());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -252,7 +251,7 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
}
|
||||
|
||||
public DataType getDataType() {
|
||||
DataType dt = symbolMgr.getDataType(getSymbolData1());
|
||||
DataType dt = symbolMgr.getDataType(getDataTypeId());
|
||||
if (dt == null) {
|
||||
VariableStorage storage = getVariableStorage();
|
||||
if (storage == null) {
|
||||
|
@ -286,8 +285,8 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
Address newAddr = variableMgr.getVariableStorageAddress(newStorage, true);
|
||||
setAddress(newAddr); // this may be the only symbol which changes its address
|
||||
|
||||
if (dataTypeID != getSymbolData1()) {
|
||||
setSymbolData1(dataTypeID);
|
||||
if (dataTypeID != getDataTypeId()) {
|
||||
setDataTypeId(dataTypeID);
|
||||
}
|
||||
else {
|
||||
symbolMgr.symbolDataChanged(this);
|
||||
|
@ -302,22 +301,22 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
}
|
||||
|
||||
public int getFirstUseOffset() {
|
||||
return type == SymbolType.PARAMETER ? 0 : getSymbolData2();
|
||||
return type == SymbolType.PARAMETER ? 0 : getVariableOffset();
|
||||
}
|
||||
|
||||
public void setFirstUseOffset(int firstUseOffset) {
|
||||
if (type == SymbolType.LOCAL_VAR) {
|
||||
setSymbolData2(firstUseOffset);
|
||||
setVariableOffset(firstUseOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return type == SymbolType.PARAMETER ? getSymbolData2() : Integer.MIN_VALUE;
|
||||
return type == SymbolType.PARAMETER ? getVariableOffset() : Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
public void setOrdinal(int ordinal) {
|
||||
if (type == SymbolType.PARAMETER) {
|
||||
setSymbolData2(ordinal);
|
||||
setVariableOffset(ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,9 @@ import db.RecordIterator;
|
|||
/**
|
||||
* Implementation of a RecordIterator that is always empty.
|
||||
*/
|
||||
|
||||
public class EmptyRecordIterator implements RecordIterator {
|
||||
public static final RecordIterator INSTANCE = new EmptyRecordIterator();
|
||||
|
||||
/**
|
||||
* @see db.RecordIterator#hasNext()
|
||||
|
|
|
@ -760,6 +760,29 @@ public class SymbolUtilities {
|
|||
return addr.getAddressSpace().getName() + Long.toHexString(addr.getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given name is a possible default parameter name or local variable name
|
||||
*
|
||||
* @param name the name to check to see if it is a possible default local or parameter name
|
||||
* @return true if the given name is a possible default parameter name or local variable name
|
||||
*/
|
||||
public static boolean isPossibleDefaultLocalOrParamName(String name) {
|
||||
if (isDefaultParameterName(name)) {
|
||||
return true;
|
||||
}
|
||||
return name.startsWith(Function.DEFAULT_LOCAL_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given name could be a default external location name
|
||||
*
|
||||
* @param name the name to check
|
||||
* @return true if the given name is a possible default external location name
|
||||
*/
|
||||
public static boolean isPossibleDefaultExternalName(String name) {
|
||||
return name.startsWith(DEFAULT_EXTERNAL_ENTRY_PREFIX);
|
||||
}
|
||||
|
||||
public static boolean isDefaultLocalStackName(String name) {
|
||||
if (name == null || name.length() == 0) {
|
||||
return true;
|
||||
|
@ -1042,4 +1065,5 @@ public class SymbolUtilities {
|
|||
public static Comparator<Symbol> getSymbolNameComparator() {
|
||||
return CASE_INSENSITIVE_SYMBOL_NAME_COMPARATOR;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -193,8 +193,8 @@ public interface ChangeManager {
|
|||
public static final int DOCR_SYMBOL_ASSOCIATION_REMOVED = 51;
|
||||
|
||||
/**
|
||||
* Symbol data changed. This corresponds to unspecified data
|
||||
* changes within the symbol (e.g., Data1, Data2, Data3, or VariableStorage).
|
||||
* Symbol data changed. This corresponds to various
|
||||
* changes within the symbol (e.g., primary status, datatype, external path or VariableStorage).
|
||||
*/
|
||||
public static final int DOCR_SYMBOL_DATA_CHANGED = 52;
|
||||
|
||||
|
@ -592,7 +592,6 @@ public interface ChangeManager {
|
|||
*/
|
||||
public final static int DOCR_TAG_REMOVED_FROM_FUNCTION = 157;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DOCR_FUNCTION_CHANGED - Sub Event Types
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue