mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge remote-tracking branch 'origin/GP-5498_ghidra1_ExternalSymbolDB--SQUASHED'
This commit is contained in:
commit
5b71018f82
54 changed files with 2538 additions and 1662 deletions
|
@ -286,12 +286,6 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
|
||||||
return getReferenceCollection().size();
|
return getReferenceCollection().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasMultipleReferences() {
|
|
||||||
// TODO: Could be slightly more efficient by just iterating twice?
|
|
||||||
return getReferenceCount() > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasReferences() {
|
public boolean hasReferences() {
|
||||||
return !getReferenceCollection().isEmpty();
|
return !getReferenceCollection().isEmpty();
|
||||||
|
@ -564,8 +558,4 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isExternalEntryPoint() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
* @deprecated function signatures should be modified in their entirety using
|
* @deprecated function signatures should be modified in their entirety using
|
||||||
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "11.1")
|
@Deprecated(forRemoval = true, since = "11.1")
|
||||||
public class AddMemoryParameterCommand extends AddParameterCommand {
|
public class AddMemoryParameterCommand extends AddParameterCommand {
|
||||||
|
|
||||||
private final Address memAddr;
|
private final Address memAddr;
|
||||||
|
|
|
@ -34,7 +34,7 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
* @deprecated function signatures should be modified in their entirety using
|
* @deprecated function signatures should be modified in their entirety using
|
||||||
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "11.1")
|
@Deprecated(forRemoval = true, since = "11.1")
|
||||||
public class AddParameterCommand implements Command<Program> {
|
public class AddParameterCommand implements Command<Program> {
|
||||||
|
|
||||||
protected final Function function;
|
protected final Function function;
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
* @deprecated function signatures should be modified in their entirety using
|
* @deprecated function signatures should be modified in their entirety using
|
||||||
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "11.1")
|
@Deprecated(forRemoval = true, since = "11.1")
|
||||||
public class AddRegisterParameterCommand extends AddParameterCommand {
|
public class AddRegisterParameterCommand extends AddParameterCommand {
|
||||||
|
|
||||||
private final Register register;
|
private final Register register;
|
||||||
|
|
|
@ -26,7 +26,7 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
* @deprecated function signatures should be modified in their entirety using
|
* @deprecated function signatures should be modified in their entirety using
|
||||||
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "11.1")
|
@Deprecated(forRemoval = true, since = "11.1")
|
||||||
public class AddStackParameterCommand extends AddParameterCommand {
|
public class AddStackParameterCommand extends AddParameterCommand {
|
||||||
|
|
||||||
private final int stackOffset;
|
private final int stackOffset;
|
||||||
|
|
|
@ -48,8 +48,6 @@ import ghidra.framework.options.OptionsChangeListener;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.database.mem.AddressSourceInfo;
|
import ghidra.program.database.mem.AddressSourceInfo;
|
||||||
import ghidra.program.database.symbol.CodeSymbol;
|
|
||||||
import ghidra.program.database.symbol.FunctionSymbol;
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
|
@ -736,7 +734,11 @@ public class CodeBrowserClipboardProvider extends ByteCopier
|
||||||
|
|
||||||
SymbolTable symbolTable = currentProgram.getSymbolTable();
|
SymbolTable symbolTable = currentProgram.getSymbolTable();
|
||||||
Symbol symbol = symbolTable.getSymbol(reference);
|
Symbol symbol = symbolTable.getSymbol(reference);
|
||||||
if ((symbol instanceof CodeSymbol) || (symbol instanceof FunctionSymbol)) {
|
if (symbol == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SymbolType type = symbol.getSymbolType();
|
||||||
|
if ((type == SymbolType.LABEL) || (type == SymbolType.FUNCTION)) {
|
||||||
RenameLabelCmd cmd = new RenameLabelCmd(symbol, labelName, SourceType.USER_DEFINED);
|
RenameLabelCmd cmd = new RenameLabelCmd(symbol, labelName, SourceType.USER_DEFINED);
|
||||||
return tool.execute(cmd, currentProgram);
|
return tool.execute(cmd, currentProgram);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,7 @@ import ghidra.app.context.ListingActionContext;
|
||||||
import ghidra.app.context.ListingContextAction;
|
import ghidra.app.context.ListingContextAction;
|
||||||
import ghidra.program.database.symbol.CodeSymbol;
|
import ghidra.program.database.symbol.CodeSymbol;
|
||||||
import ghidra.program.database.symbol.FunctionSymbol;
|
import ghidra.program.database.symbol.FunctionSymbol;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <CODE>RemoveLabelAction</CODE> allows the user to remove a label.
|
* <CODE>RemoveLabelAction</CODE> allows the user to remove a label.
|
||||||
|
@ -63,8 +62,12 @@ class RemoveLabelAction extends ListingContextAction {
|
||||||
|
|
||||||
boolean isOnSymbol(ListingActionContext context) {
|
boolean isOnSymbol(ListingActionContext context) {
|
||||||
Symbol s = plugin.getSymbol(context);
|
Symbol s = plugin.getSymbol(context);
|
||||||
return ((s instanceof CodeSymbol) && !s.isDynamic()) ||
|
if (s == null) {
|
||||||
((s instanceof FunctionSymbol) && s.getSource() != SourceType.DEFAULT);
|
return false;
|
||||||
|
}
|
||||||
|
SymbolType type = s.getSymbolType();
|
||||||
|
return (type == SymbolType.LABEL && !s.isDynamic()) ||
|
||||||
|
(type == SymbolType.FUNCTION && s.getSource() != SourceType.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,7 +20,7 @@ import static ghidra.framework.main.DataTreeDialogType.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.border.*;
|
import javax.swing.border.*;
|
||||||
|
@ -270,8 +270,7 @@ class EditExternalLocationPanel extends JPanel {
|
||||||
* Pop up the data tree dialog so the user can choose the external program.
|
* Pop up the data tree dialog so the user can choose the external program.
|
||||||
*/
|
*/
|
||||||
private void popupProgramChooser() {
|
private void popupProgramChooser() {
|
||||||
DataTreeDialog d =
|
DataTreeDialog d = new DataTreeDialog(this.getParent(), "Choose External Program", OPEN);
|
||||||
new DataTreeDialog(this.getParent(), "Choose External Program", OPEN);
|
|
||||||
final DataTreeDialog dialog = d;
|
final DataTreeDialog dialog = d;
|
||||||
d.addOkActionListener(e -> {
|
d.addOkActionListener(e -> {
|
||||||
DomainFile df = dialog.getDomainFile();
|
DomainFile df = dialog.getDomainFile();
|
||||||
|
@ -402,10 +401,9 @@ class EditExternalLocationPanel extends JPanel {
|
||||||
String locationName = getLocationName();
|
String locationName = getLocationName();
|
||||||
if (locationName != null && locationName.length() > 0) {
|
if (locationName != null && locationName.length() > 0) {
|
||||||
ExternalManager externalManager = program.getExternalManager();
|
ExternalManager externalManager = program.getExternalManager();
|
||||||
List<ExternalLocation> externalLocations =
|
Set<ExternalLocation> externalLocations =
|
||||||
externalManager.getExternalLocations(extLibName, locationName);
|
externalManager.getExternalLocations(extLibName, locationName);
|
||||||
externalLocations.remove(externalLocation);
|
if (externalLocations.size() == 1 && !externalLocations.contains(externalLocation)) {
|
||||||
if (!externalLocations.isEmpty()) {
|
|
||||||
int result = OptionDialog.showYesNoDialog(null, "Duplicate External Name",
|
int result = OptionDialog.showYesNoDialog(null, "Duplicate External Name",
|
||||||
"Another symbol named '" + locationName + "' already exists in the '" +
|
"Another symbol named '" + locationName + "' already exists in the '" +
|
||||||
extLibName + "' library. Are you sure you want to create another?");
|
extLibName + "' library. Are you sure you want to create another?");
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,32 +15,37 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.symboltree.actions;
|
package ghidra.app.plugin.core.symboltree.actions;
|
||||||
|
|
||||||
|
import docking.action.MenuData;
|
||||||
import ghidra.app.context.ProgramSymbolActionContext;
|
import ghidra.app.context.ProgramSymbolActionContext;
|
||||||
import ghidra.app.context.ProgramSymbolContextAction;
|
import ghidra.app.context.ProgramSymbolContextAction;
|
||||||
import ghidra.program.database.symbol.CodeSymbol;
|
|
||||||
import ghidra.program.database.symbol.FunctionSymbol;
|
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
|
import ghidra.program.model.symbol.SymbolType;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import docking.action.MenuData;
|
|
||||||
|
|
||||||
public class PinSymbolAction extends ProgramSymbolContextAction {
|
public class PinSymbolAction extends ProgramSymbolContextAction {
|
||||||
|
|
||||||
public PinSymbolAction(String owner, String popupGroup) {
|
public PinSymbolAction(String owner, String popupGroup) {
|
||||||
super("Pin Symbol", owner);
|
super("Pin Symbol", owner);
|
||||||
setPopupMenuData(new MenuData(new String[] { "Set Pinned" }, popupGroup));
|
setPopupMenuData(new MenuData(new String[] { "Set Pinned" }, popupGroup));
|
||||||
setDescription("Pins the symbol(s) to the address so that it is unaffected by memory block moves or image base changes.");
|
setDescription(
|
||||||
|
"Pins the symbol(s) to the address so that it is unaffected by memory block moves or image base changes.");
|
||||||
setHelpLocation(new HelpLocation("SymbolTablePlugin", "Pinning a Symbol"));
|
setHelpLocation(new HelpLocation("SymbolTablePlugin", "Pinning a Symbol"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean canPinSymbol(Symbol symbol) {
|
||||||
|
SymbolType type = symbol.getSymbolType();
|
||||||
|
return (type == SymbolType.LABEL || type == SymbolType.FUNCTION) && !symbol.isExternal() &&
|
||||||
|
!symbol.isPinned();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void actionPerformed(ProgramSymbolActionContext context) {
|
protected void actionPerformed(ProgramSymbolActionContext context) {
|
||||||
Program program = context.getProgram();
|
Program program = context.getProgram();
|
||||||
int transactionID = program.startTransaction("Pin Symbol(s)");
|
int transactionID = program.startTransaction("Pin Symbol(s)");
|
||||||
try {
|
try {
|
||||||
for (Symbol symbol : context.getSymbols()) {
|
for (Symbol symbol : context.getSymbols()) {
|
||||||
if ((symbol instanceof CodeSymbol || symbol instanceof FunctionSymbol) &&
|
if (canPinSymbol(symbol)) {
|
||||||
!symbol.isExternal() && !symbol.isPinned()) {
|
|
||||||
symbol.setPinned(true);
|
symbol.setPinned(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,8 +58,7 @@ public class PinSymbolAction extends ProgramSymbolContextAction {
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnabledForContext(ProgramSymbolActionContext context) {
|
protected boolean isEnabledForContext(ProgramSymbolActionContext context) {
|
||||||
for (Symbol symbol : context.getSymbols()) {
|
for (Symbol symbol : context.getSymbols()) {
|
||||||
if ((symbol instanceof CodeSymbol || symbol instanceof FunctionSymbol) &&
|
if (canPinSymbol(symbol)) {
|
||||||
!symbol.isExternal() && !symbol.isPinned()) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static org.junit.Assert.*;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
|
@ -926,4 +927,33 @@ public abstract class AbstractExternalMergerTest extends AbstractListingMergeMan
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void assertHasExtAddresses(Set<ExternalLocation> externalLocations,
|
||||||
|
String... addrStrings) {
|
||||||
|
|
||||||
|
Address[] addrs = new Address[addrStrings.length];
|
||||||
|
for (int i = 0; i < addrs.length; i++) {
|
||||||
|
addrs[i] = addr(resultProgram, addrStrings[i]);
|
||||||
|
}
|
||||||
|
boolean[] foundAddrs = new boolean[addrStrings.length];
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (ExternalLocation extLoc : externalLocations) {
|
||||||
|
Address addr = extLoc.getAddress();
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
|
for (int i = 0; i < addrs.length; i++) {
|
||||||
|
if (addrs[i].equals(addr)) {
|
||||||
|
assertFalse("Duplicate ext addr: " + addr, foundAddrs[i]);
|
||||||
|
foundAddrs[i] = true;
|
||||||
|
found = true;
|
||||||
|
++count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue("Unexpected extaddr: " + addr, found);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("Did not find expected ext addrs", addrs.length, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,13 @@ package ghidra.app.merge.listing;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import ghidra.app.cmd.function.AddRegisterParameterCommand;
|
import ghidra.app.cmd.function.AddRegisterParameterCommand;
|
||||||
import ghidra.program.database.*;
|
import ghidra.program.database.*;
|
||||||
import ghidra.program.model.address.Address;
|
|
||||||
import ghidra.program.model.address.AddressSet;
|
import ghidra.program.model.address.AddressSet;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
|
@ -1604,35 +1603,18 @@ public class ExternalFunctionMergeManagerTest extends AbstractExternalMergerTest
|
||||||
waitForMergeCompletion();
|
waitForMergeCompletion();
|
||||||
|
|
||||||
ExternalManager externalManager = resultProgram.getExternalManager();
|
ExternalManager externalManager = resultProgram.getExternalManager();
|
||||||
List<ExternalLocation> externalLocations =
|
Set<ExternalLocation> externalLocations =
|
||||||
externalManager.getExternalLocations("user32.dll", "BETTY");
|
externalManager.getExternalLocations("user32.dll", "BETTY");
|
||||||
assertEquals(2, externalLocations.size());
|
assertEquals(2, externalLocations.size());
|
||||||
assertHasDifferentAddresses(externalLocations, "1002239", "10063b4");
|
assertHasExtAddresses(externalLocations, "1002239", "10063b4");
|
||||||
|
|
||||||
List<ExternalLocation> externalLocations2 =
|
Set<ExternalLocation> externalLocations2 =
|
||||||
externalManager.getExternalLocations("user32.dll", "BARNEY");
|
externalManager.getExternalLocations("user32.dll", "BARNEY");
|
||||||
assertEquals(2, externalLocations2.size());
|
assertEquals(2, externalLocations2.size());
|
||||||
assertHasDifferentAddresses(externalLocations2, "77db1020", "77db1130");
|
assertHasExtAddresses(externalLocations2, "77db1020", "77db1130");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertHasDifferentAddresses(List<ExternalLocation> externalLocations,
|
|
||||||
String addrString1, String addrString2) {
|
|
||||||
Address addr1 = addr(resultProgram, addrString1);
|
|
||||||
Address addr2 = addr(resultProgram, addrString2);
|
|
||||||
|
|
||||||
Address extAddr1 = externalLocations.get(0).getAddress();
|
|
||||||
Address extAddr2 = externalLocations.get(1).getAddress();
|
|
||||||
if (addr1.equals(extAddr1) && addr2.equals(extAddr2)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (addr1.equals(extAddr2) && addr2.equals(extAddr1)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fail("Expected addresses: " + addr1 + ", " + addr2 + " but got " + extAddr1 + ", " +
|
|
||||||
extAddr2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddExternalFunctionsWithFunctionConflicts() throws Exception {
|
public void testAddExternalFunctionsWithFunctionConflicts() throws Exception {
|
||||||
|
|
||||||
|
@ -1674,15 +1656,14 @@ public class ExternalFunctionMergeManagerTest extends AbstractExternalMergerTest
|
||||||
waitForMergeCompletion();
|
waitForMergeCompletion();
|
||||||
|
|
||||||
ExternalManager externalManager = resultProgram.getExternalManager();
|
ExternalManager externalManager = resultProgram.getExternalManager();
|
||||||
List<ExternalLocation> externalLocations =
|
Set<ExternalLocation> externalLocations =
|
||||||
externalManager.getExternalLocations("user32.dll", "BARNEY");
|
externalManager.getExternalLocations("user32.dll", "BARNEY");
|
||||||
assertEquals(2, externalLocations.size());
|
assertEquals(2, externalLocations.size());
|
||||||
assertHasDifferentAddresses(externalLocations, "1002239", "77db1020");
|
assertHasExtAddresses(externalLocations, "1002239", "77db1020");
|
||||||
|
|
||||||
externalLocations = externalManager.getExternalLocations("user32.dll", "BETTY");
|
externalLocations = externalManager.getExternalLocations("user32.dll", "BETTY");
|
||||||
assertEquals(1, externalLocations.size());
|
assertEquals(1, externalLocations.size());
|
||||||
assertEquals("01002239", externalLocations.get(0).getAddress().toString());
|
assertHasExtAddresses(externalLocations, "01002239");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.merge.listing;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -438,8 +439,11 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
|
||||||
|
|
||||||
ExternalManager externalManager = resultProgram.getExternalManager();
|
ExternalManager externalManager = resultProgram.getExternalManager();
|
||||||
assertTrue(externalManager.contains(libname));
|
assertTrue(externalManager.contains(libname));
|
||||||
List<ExternalLocation> externals = externalManager.getExternalLocations(libname, label);
|
Set<ExternalLocation> externalLocations =
|
||||||
assertEquals(2, externals.size());
|
externalManager.getExternalLocations(libname, label);
|
||||||
|
assertEquals(2, externalLocations.size());
|
||||||
|
assertHasExtAddresses(externalLocations, address1, address2);
|
||||||
|
|
||||||
ExternalLocationIterator loc1It = externalManager.getExternalLocations(addr(address1));
|
ExternalLocationIterator loc1It = externalManager.getExternalLocations(addr(address1));
|
||||||
assertTrue(loc1It.hasNext());
|
assertTrue(loc1It.hasNext());
|
||||||
assertEquals(label, loc1It.next().getLabel());
|
assertEquals(label, loc1It.next().getLabel());
|
||||||
|
@ -3403,13 +3407,16 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
|
||||||
ExternalManager externalManager = resultProgram.getExternalManager();
|
ExternalManager externalManager = resultProgram.getExternalManager();
|
||||||
assertTrue(externalManager.contains(libname));
|
assertTrue(externalManager.contains(libname));
|
||||||
|
|
||||||
List<ExternalLocation> externalLocations =
|
Set<ExternalLocation> externalLocations =
|
||||||
externalManager.getExternalLocations(libname, label);
|
externalManager.getExternalLocations(libname, label);
|
||||||
assertEquals(2, externalLocations.size());
|
assertEquals(2, externalLocations.size());
|
||||||
|
assertHasExtAddresses(externalLocations, "00000100", "00000110");
|
||||||
|
|
||||||
List<ExternalLocation> externalLocations2 =
|
Set<ExternalLocation> externalLocations2 =
|
||||||
externalManager.getExternalLocations(BLUE_PATH[0], BLUE_PATH[1]);
|
externalManager.getExternalLocations(BLUE_PATH[0], BLUE_PATH[1]);
|
||||||
assertEquals(2, externalLocations2.size());
|
assertEquals(2, externalLocations2.size());
|
||||||
|
assertHasExtAddresses(externalLocations, "00000100", "00000110");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -3484,13 +3491,15 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
|
||||||
ExternalManager externalManager = resultProgram.getExternalManager();
|
ExternalManager externalManager = resultProgram.getExternalManager();
|
||||||
assertTrue(externalManager.contains(libname));
|
assertTrue(externalManager.contains(libname));
|
||||||
|
|
||||||
List<ExternalLocation> externalLocations =
|
Set<ExternalLocation> externalLocations =
|
||||||
externalManager.getExternalLocations(libname, label);
|
externalManager.getExternalLocations(libname, label);
|
||||||
assertEquals(2, externalLocations.size());
|
assertEquals(2, externalLocations.size());
|
||||||
|
assertHasExtAddresses(externalLocations, "00000100", "00000110");
|
||||||
|
|
||||||
List<ExternalLocation> externalLocations2 =
|
Set<ExternalLocation> externalLocations2 =
|
||||||
externalManager.getExternalLocations(BLUE_PATH[0], BLUE_PATH[1]);
|
externalManager.getExternalLocations(BLUE_PATH[0], BLUE_PATH[1]);
|
||||||
assertEquals(2, externalLocations2.size());
|
assertEquals(2, externalLocations2.size());
|
||||||
|
assertHasExtAddresses(externalLocations, "00000100", "00000110");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.app.merge.listing;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -50,10 +51,10 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
||||||
@Override
|
@Override
|
||||||
public void modifyLatest(ProgramDB program) {
|
public void modifyLatest(ProgramDB program) {
|
||||||
try {
|
try {
|
||||||
program.getExternalManager().setExternalPath("COMDLG32.DLL", "//comdlg32.dll",
|
program.getExternalManager()
|
||||||
true);
|
.setExternalPath("COMDLG32.DLL", "//comdlg32.dll", true);
|
||||||
program.getExternalManager().setExternalPath("KERNEL32.DLL", "//kernel32.dll",
|
program.getExternalManager()
|
||||||
true);
|
.setExternalPath("KERNEL32.DLL", "//kernel32.dll", true);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
|
@ -65,8 +66,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
||||||
public void modifyPrivate(ProgramDB program) {
|
public void modifyPrivate(ProgramDB program) {
|
||||||
try {
|
try {
|
||||||
program.getExternalManager().setExternalPath("GDI32.DLL", "//gdi32.dll", true);
|
program.getExternalManager().setExternalPath("GDI32.DLL", "//gdi32.dll", true);
|
||||||
program.getExternalManager().setExternalPath("KERNEL32.DLL", "//kernel32.dll",
|
program.getExternalManager()
|
||||||
true);
|
.setExternalPath("KERNEL32.DLL", "//kernel32.dll", true);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
|
@ -104,8 +105,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
||||||
public void modifyLatest(ProgramDB program) {
|
public void modifyLatest(ProgramDB program) {
|
||||||
try {
|
try {
|
||||||
program.getExternalManager().setExternalPath("ADVAPI32.DLL", "//foo.dll", true);
|
program.getExternalManager().setExternalPath("ADVAPI32.DLL", "//foo.dll", true);
|
||||||
program.getExternalManager().setExternalPath("KERNEL32.DLL", "//latest.dll",
|
program.getExternalManager()
|
||||||
true);
|
.setExternalPath("KERNEL32.DLL", "//latest.dll", true);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
|
@ -191,8 +192,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
||||||
public void modifyLatest(ProgramDB program) {
|
public void modifyLatest(ProgramDB program) {
|
||||||
try {
|
try {
|
||||||
removeExternalLibrary(program, "ADVAPI32.DLL");
|
removeExternalLibrary(program, "ADVAPI32.DLL");
|
||||||
program.getExternalManager().setExternalPath("USER32.DLL", "//latest.dll",
|
program.getExternalManager()
|
||||||
true);
|
.setExternalPath("USER32.DLL", "//latest.dll", true);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
|
@ -251,8 +252,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
||||||
public void modifyLatest(ProgramDB program) {
|
public void modifyLatest(ProgramDB program) {
|
||||||
try {
|
try {
|
||||||
removeExternalLibrary(program, "ADVAPI32.DLL");
|
removeExternalLibrary(program, "ADVAPI32.DLL");
|
||||||
program.getExternalManager().setExternalPath("USER32.DLL", "//latest.dll",
|
program.getExternalManager()
|
||||||
true);
|
.setExternalPath("USER32.DLL", "//latest.dll", true);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
|
@ -311,8 +312,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
||||||
public void modifyLatest(ProgramDB program) {
|
public void modifyLatest(ProgramDB program) {
|
||||||
try {
|
try {
|
||||||
removeExternalLibrary(program, "ADVAPI32.DLL");
|
removeExternalLibrary(program, "ADVAPI32.DLL");
|
||||||
program.getExternalManager().setExternalPath("USER32.DLL", "//latest.dll",
|
program.getExternalManager()
|
||||||
true);
|
.setExternalPath("USER32.DLL", "//latest.dll", true);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
|
@ -487,7 +488,7 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
||||||
try {
|
try {
|
||||||
removeExternalLibrary(program, "ADVAPI32.DLL");
|
removeExternalLibrary(program, "ADVAPI32.DLL");
|
||||||
Reference[] refs =
|
Reference[] refs =
|
||||||
program.getReferenceManager().getReferencesFrom(addr(program, "0x10011e4")); // SetCursor
|
program.getReferenceManager().getReferencesFrom(addr(program, "0x10011e4")); // setCursor
|
||||||
SymbolTable symTab = program.getSymbolTable();
|
SymbolTable symTab = program.getSymbolTable();
|
||||||
Symbol s = symTab.getSymbol(refs[0]);
|
Symbol s = symTab.getSymbol(refs[0]);
|
||||||
s.setName("SetCursor99", SourceType.USER_DEFINED);
|
s.setName("SetCursor99", SourceType.USER_DEFINED);
|
||||||
|
@ -538,13 +539,24 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
||||||
// Check that the 2 renames happened.
|
// Check that the 2 renames happened.
|
||||||
ExternalLocation extLoc =
|
ExternalLocation extLoc =
|
||||||
resultExtMgr.getUniqueExternalLocation("ADVAPI32.DLL", "RegCreateKeyW");
|
resultExtMgr.getUniqueExternalLocation("ADVAPI32.DLL", "RegCreateKeyW");
|
||||||
assertNull(extLoc);
|
assertNotNull(extLoc);
|
||||||
|
assertEquals("RegCreateKeyW", extLoc.getOriginalImportedName());
|
||||||
|
assertEquals("RegCreateKeyW99", extLoc.getLabel());
|
||||||
|
|
||||||
extLoc = resultExtMgr.getUniqueExternalLocation("ADVAPI32.DLL", "RegCreateKeyW99");
|
extLoc = resultExtMgr.getUniqueExternalLocation("ADVAPI32.DLL", "RegCreateKeyW99");
|
||||||
assertNotNull(extLoc);
|
assertNotNull(extLoc);
|
||||||
extLoc = resultExtMgr.getUniqueExternalLocation("USER32.DLL", "SetCursor");
|
assertEquals("RegCreateKeyW", extLoc.getOriginalImportedName());
|
||||||
assertNull(extLoc);
|
assertEquals("RegCreateKeyW99", extLoc.getLabel());
|
||||||
|
|
||||||
|
extLoc = resultExtMgr.getUniqueExternalLocation("USER32.DLL", "setCursor");
|
||||||
|
assertNotNull(extLoc);
|
||||||
|
assertEquals("setCursor", extLoc.getOriginalImportedName());
|
||||||
|
assertEquals("SetCursor99", extLoc.getLabel());
|
||||||
|
|
||||||
extLoc = resultExtMgr.getUniqueExternalLocation("USER32.DLL", "SetCursor99");
|
extLoc = resultExtMgr.getUniqueExternalLocation("USER32.DLL", "SetCursor99");
|
||||||
assertNotNull(extLoc);
|
assertNotNull(extLoc);
|
||||||
|
assertEquals("setCursor", extLoc.getOriginalImportedName());
|
||||||
|
assertEquals("SetCursor99", extLoc.getLabel());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,8 +626,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
||||||
ExternalLocationIterator iter = extMgr.getExternalLocations(libName);
|
ExternalLocationIterator iter = extMgr.getExternalLocations(libName);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
ExternalLocation loc = iter.next();
|
ExternalLocation loc = iter.next();
|
||||||
if (!((ExternalManagerDB) extMgr).removeExternalLocation(
|
if (!((ExternalManagerDB) extMgr)
|
||||||
loc.getExternalSpaceAddress())) {
|
.removeExternalLocation(loc.getExternalSpaceAddress())) {
|
||||||
Assert.fail("Couldn't remove external location for library " + libName);
|
Assert.fail("Couldn't remove external location for library " + libName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ package ghidra.app.merge.listing;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
|
|
||||||
|
@ -944,27 +944,10 @@ public class FunctionMergerThunkTest extends AbstractExternalMergerTest {
|
||||||
ExternalLocation externalLocation = thunkedFunction.getExternalLocation();
|
ExternalLocation externalLocation = thunkedFunction.getExternalLocation();
|
||||||
assertEquals(addr(resultProgram, "77db1020"), externalLocation.getAddress());
|
assertEquals(addr(resultProgram, "77db1020"), externalLocation.getAddress());
|
||||||
|
|
||||||
List<ExternalLocation> externalLocations =
|
Set<ExternalLocation> externalLocations =
|
||||||
resultProgram.getExternalManager().getExternalLocations("user32.dll", "printf");
|
resultProgram.getExternalManager().getExternalLocations("user32.dll", "printf");
|
||||||
assertEquals(2, externalLocations.size());
|
assertEquals(2, externalLocations.size());
|
||||||
Address address1 = externalLocations.get(0).getAddress();
|
assertHasExtAddresses(externalLocations, "77db1020", "77db1130");
|
||||||
Address address2 = externalLocations.get(1).getAddress();
|
|
||||||
assertTrue("Expected one location to be ", areOneOfEach(address1, address2,
|
|
||||||
addr(resultProgram, "77db1020"), addr(resultProgram, "77db1130")));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> boolean areOneOfEach(T t1, T t2, T v1, T v2) {
|
|
||||||
|
|
||||||
if (t1.equals(v1) && t2.equals(v2)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t1.equals(v2) && t2.equals(v1)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -99,7 +99,7 @@ public class ExternalCodeBrowserNavigationTest extends AbstractCodeBrowserNaviga
|
||||||
private void addThunkToExternalFunction(String libraryName, String label,
|
private void addThunkToExternalFunction(String libraryName, String label,
|
||||||
Address thunkAddress) {
|
Address thunkAddress) {
|
||||||
ExternalLocation externalLocation =
|
ExternalLocation externalLocation =
|
||||||
program.getExternalManager().getExternalLocation(libraryName, label);
|
program.getExternalManager().getUniqueExternalLocation(libraryName, label);
|
||||||
Function extFunction = externalLocation.getFunction();
|
Function extFunction = externalLocation.getFunction();
|
||||||
|
|
||||||
CreateThunkFunctionCmd cmd = new CreateThunkFunctionCmd(thunkAddress,
|
CreateThunkFunctionCmd cmd = new CreateThunkFunctionCmd(thunkAddress,
|
||||||
|
|
|
@ -109,10 +109,8 @@ public class SymbolTreeLocationReferencesTest extends AbstractLocationReferences
|
||||||
private Function addExternalFunctionReference(Address refAddr, String libraryName,
|
private Function addExternalFunctionReference(Address refAddr, String libraryName,
|
||||||
String extLabel, RefType refType) throws Exception {
|
String extLabel, RefType refType) throws Exception {
|
||||||
|
|
||||||
List<ExternalLocation> locations =
|
ExternalLocation externalLocation =
|
||||||
program.getExternalManager().getExternalLocations(libraryName, extLabel);
|
program.getExternalManager().getUniqueExternalLocation(libraryName, extLabel);
|
||||||
assertEquals(1, locations.size());
|
|
||||||
ExternalLocation externalLocation = locations.get(0);
|
|
||||||
|
|
||||||
assertNotNull("External location not found: " + libraryName + "::" + extLabel,
|
assertNotNull("External location not found: " + libraryName + "::" + extLabel,
|
||||||
externalLocation);
|
externalLocation);
|
||||||
|
|
|
@ -387,6 +387,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
||||||
assertEquals(addr(0x0100688c), loc.getByteAddress());
|
assertEquals(addr(0x0100688c), loc.getByteAddress());
|
||||||
assertTrue(loc instanceof CommentFieldLocation);
|
assertTrue(loc instanceof CommentFieldLocation);
|
||||||
//
|
//
|
||||||
|
assertTrue("Search result not found: " + addr(0x01006890), searcher.hasNext());
|
||||||
loc = searcher.next().programLocation();
|
loc = searcher.next().programLocation();
|
||||||
assertNotNull(loc);
|
assertNotNull(loc);
|
||||||
assertEquals(addr(0x01006890), loc.getByteAddress());
|
assertEquals(addr(0x01006890), loc.getByteAddress());
|
||||||
|
@ -394,11 +395,13 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
||||||
MnemonicFieldLocation mloc = (MnemonicFieldLocation) loc;
|
MnemonicFieldLocation mloc = (MnemonicFieldLocation) loc;
|
||||||
assertEquals("float", mloc.getMnemonic());
|
assertEquals("float", mloc.getMnemonic());
|
||||||
//
|
//
|
||||||
|
assertTrue("Search result not found: " + addr(0x01006890), searcher.hasNext());
|
||||||
loc = searcher.next().programLocation();
|
loc = searcher.next().programLocation();
|
||||||
assertNotNull(loc);
|
assertNotNull(loc);
|
||||||
assertEquals(addr(0x01006890), loc.getByteAddress());
|
assertEquals(addr(0x01006890), loc.getByteAddress());
|
||||||
assertTrue(loc instanceof CommentFieldLocation);
|
assertTrue(loc instanceof CommentFieldLocation);
|
||||||
//
|
//
|
||||||
|
assertTrue("Search result not found: " + addr(0x0100689b), searcher.hasNext());
|
||||||
loc = searcher.next().programLocation();
|
loc = searcher.next().programLocation();
|
||||||
assertNotNull(loc);
|
assertNotNull(loc);
|
||||||
assertEquals(addr(0x0100689b), loc.getByteAddress());
|
assertEquals(addr(0x0100689b), loc.getByteAddress());
|
||||||
|
@ -406,6 +409,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
||||||
mloc = (MnemonicFieldLocation) loc;
|
mloc = (MnemonicFieldLocation) loc;
|
||||||
assertEquals("float", mloc.getMnemonic());
|
assertEquals("float", mloc.getMnemonic());
|
||||||
//
|
//
|
||||||
|
assertTrue("Search result not found: " + addr(0x0100689f), searcher.hasNext());
|
||||||
loc = searcher.next().programLocation();
|
loc = searcher.next().programLocation();
|
||||||
assertNotNull(loc);
|
assertNotNull(loc);
|
||||||
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
||||||
|
@ -413,6 +417,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
||||||
mloc = (MnemonicFieldLocation) loc;
|
mloc = (MnemonicFieldLocation) loc;
|
||||||
assertEquals("float", mloc.getMnemonic());
|
assertEquals("float", mloc.getMnemonic());
|
||||||
//
|
//
|
||||||
|
assertTrue("Search result not found: " + addr(0x0100689f), searcher.hasNext());
|
||||||
loc = searcher.next().programLocation();
|
loc = searcher.next().programLocation();
|
||||||
assertNotNull(loc);
|
assertNotNull(loc);
|
||||||
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
||||||
|
@ -478,6 +483,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
||||||
assertEquals(addr(0x0100688c), loc.getByteAddress());
|
assertEquals(addr(0x0100688c), loc.getByteAddress());
|
||||||
assertTrue(loc instanceof CommentFieldLocation);
|
assertTrue(loc instanceof CommentFieldLocation);
|
||||||
//
|
//
|
||||||
|
assertTrue("Search result not found: " + addr(0x0100689b), searcher.hasNext());
|
||||||
loc = searcher.next().programLocation();
|
loc = searcher.next().programLocation();
|
||||||
assertNotNull(loc);
|
assertNotNull(loc);
|
||||||
assertEquals(addr(0x0100689b), loc.getByteAddress());
|
assertEquals(addr(0x0100689b), loc.getByteAddress());
|
||||||
|
@ -485,6 +491,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
||||||
MnemonicFieldLocation mloc = (MnemonicFieldLocation) loc;
|
MnemonicFieldLocation mloc = (MnemonicFieldLocation) loc;
|
||||||
assertEquals("float", mloc.getMnemonic());
|
assertEquals("float", mloc.getMnemonic());
|
||||||
//
|
//
|
||||||
|
assertTrue("Search result not found: " + addr(0x0100689f), searcher.hasNext());
|
||||||
loc = searcher.next().programLocation();
|
loc = searcher.next().programLocation();
|
||||||
assertNotNull(loc);
|
assertNotNull(loc);
|
||||||
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
||||||
|
@ -492,6 +499,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
||||||
mloc = (MnemonicFieldLocation) loc;
|
mloc = (MnemonicFieldLocation) loc;
|
||||||
assertEquals("float", mloc.getMnemonic());
|
assertEquals("float", mloc.getMnemonic());
|
||||||
//
|
//
|
||||||
|
assertTrue("Search result not found: " + addr(0x0100689f), searcher.hasNext());
|
||||||
loc = searcher.next().programLocation();
|
loc = searcher.next().programLocation();
|
||||||
assertNotNull(loc);
|
assertNotNull(loc);
|
||||||
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
||||||
|
@ -819,6 +827,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
||||||
private void checkTextFound(ArrayList<Address> startList, Class<?> fieldClass) {
|
private void checkTextFound(ArrayList<Address> startList, Class<?> fieldClass) {
|
||||||
|
|
||||||
for (Address start : startList) {
|
for (Address start : startList) {
|
||||||
|
assertTrue("Search result not found: " + start, searcher.hasNext());
|
||||||
ProgramLocation loc = searcher.next().programLocation();
|
ProgramLocation loc = searcher.next().programLocation();
|
||||||
assertNotNull(loc);
|
assertNotNull(loc);
|
||||||
assertTrue(fieldClass.isAssignableFrom(loc.getClass()));
|
assertTrue(fieldClass.isAssignableFrom(loc.getClass()));
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* ###
|
||||||
|
* 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 db;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ConstrainedForwardRecordIterator} provides the ability to both filter and
|
||||||
|
* translate records returned from an underlying {@link RecordIterator}.
|
||||||
|
*/
|
||||||
|
public class ConstrainedForwardRecordIterator implements RecordIterator {
|
||||||
|
private DBRecord nextConvertedRecord;
|
||||||
|
|
||||||
|
private final RecordIterator it;
|
||||||
|
private final Function<DBRecord, DBRecord> recordPredicateAndTranslate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a constrained/filtered record iterator.
|
||||||
|
* @param it source record iterator
|
||||||
|
* @param recordPredicateAndTranslate function which enables both filtering of records
|
||||||
|
* (null returned if record should be skipped) and the ability to translate the record
|
||||||
|
* to an alternate table/record schema.
|
||||||
|
*/
|
||||||
|
public ConstrainedForwardRecordIterator(RecordIterator it,
|
||||||
|
Function<DBRecord, DBRecord> recordPredicateAndTranslate) {
|
||||||
|
this.it = it;
|
||||||
|
this.recordPredicateAndTranslate = recordPredicateAndTranslate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPrevious() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DBRecord previous() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean delete() throws IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() throws IOException {
|
||||||
|
if (nextConvertedRecord != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
while (nextConvertedRecord == null && it.hasNext()) {
|
||||||
|
nextConvertedRecord = recordPredicateAndTranslate.apply(it.next());
|
||||||
|
}
|
||||||
|
return nextConvertedRecord != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DBRecord next() throws IOException {
|
||||||
|
if (hasNext()) {
|
||||||
|
DBRecord returnedRecord = nextConvertedRecord;
|
||||||
|
nextConvertedRecord = null;
|
||||||
|
return returnedRecord;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -114,8 +114,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
||||||
* 19-Oct-2023 - version 28 Revised overlay address space table and eliminated min/max.
|
* 19-Oct-2023 - version 28 Revised overlay address space table and eliminated min/max.
|
||||||
* Multiple blocks are permitted within a single overlay space.
|
* Multiple blocks are permitted within a single overlay space.
|
||||||
* 13-Dec-2024 - version 29 Added source file manager.
|
* 13-Dec-2024 - version 29 Added source file manager.
|
||||||
|
* 3-Jun-2025 - version 30 Symbol Table schema V4 with external symbol data indexing
|
||||||
*/
|
*/
|
||||||
static final int DB_VERSION = 29;
|
static final int DB_VERSION = 30;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UPGRADE_REQUIRED_BFORE_VERSION should be changed to DB_VERSION anytime the
|
* UPGRADE_REQUIRED_BFORE_VERSION should be changed to DB_VERSION anytime the
|
||||||
|
@ -2103,7 +2104,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
||||||
|
|
||||||
monitor.setMessage("Updating symbols...");
|
monitor.setMessage("Updating symbols...");
|
||||||
getSymbolTable().setLanguage(translator, monitor);
|
getSymbolTable().setLanguage(translator, monitor);
|
||||||
getExternalManager().setLanguage(translator, monitor);
|
|
||||||
getFunctionManager().setLanguage(translator, monitor);
|
getFunctionManager().setLanguage(translator, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,8 @@ import ghidra.docking.settings.Settings;
|
||||||
import ghidra.program.database.DBObjectCache;
|
import ghidra.program.database.DBObjectCache;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.CommentType;
|
||||||
|
import ghidra.program.model.listing.Data;
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,9 +17,9 @@ package ghidra.program.database.external;
|
||||||
|
|
||||||
import ghidra.app.util.NamespaceUtils;
|
import ghidra.app.util.NamespaceUtils;
|
||||||
import ghidra.app.util.SymbolPath;
|
import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.program.database.symbol.SymbolDB;
|
import ghidra.program.database.symbol.FunctionSymbol;
|
||||||
|
import ghidra.program.database.symbol.MemorySymbol;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressFactory;
|
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
|
@ -28,19 +28,18 @@ import ghidra.util.exception.*;
|
||||||
|
|
||||||
public class ExternalLocationDB implements ExternalLocation {
|
public class ExternalLocationDB implements ExternalLocation {
|
||||||
|
|
||||||
private static final char ORIGINAL_IMPORTED_DELIMITER = ',';
|
|
||||||
private ExternalManagerDB extMgr;
|
private ExternalManagerDB extMgr;
|
||||||
private SymbolDB symbol;
|
private MemorySymbol symbol;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an externalLocationDB using a symbol
|
* Creates an externalLocationDB using a symbol
|
||||||
* at the same external space address.
|
* at the same external space address.
|
||||||
* @param extMgr the ExternalManager.
|
* @param extMgr the ExternalManager.
|
||||||
* @param symbol the symbol for this external location.
|
* @param symbol the memory (label or function) symbol for this external location.
|
||||||
* Typically, this will store the original mangled name when and if the original name
|
* Typically, this will store the original mangled name when and if the original name
|
||||||
* is demangled.
|
* is demangled, as well as the external program's memory address for the location if known.
|
||||||
*/
|
*/
|
||||||
ExternalLocationDB(ExternalManagerDB extMgr, SymbolDB symbol) {
|
ExternalLocationDB(ExternalManagerDB extMgr, MemorySymbol symbol) {
|
||||||
this.extMgr = extMgr;
|
this.extMgr = extMgr;
|
||||||
this.symbol = symbol;
|
this.symbol = symbol;
|
||||||
}
|
}
|
||||||
|
@ -50,9 +49,6 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.ExternalLocation#getLibraryName()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getLibraryName() {
|
public String getLibraryName() {
|
||||||
Library library = getLibrary();
|
Library library = getLibrary();
|
||||||
|
@ -68,17 +64,11 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.ExternalLocation#getParentNameSpace()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Namespace getParentNameSpace() {
|
public Namespace getParentNameSpace() {
|
||||||
return symbol.getParentNamespace();
|
return symbol.getParentNamespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.ExternalLocation#getParentName()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getParentName() {
|
public String getParentName() {
|
||||||
return symbol.getParentNamespace().getName();
|
return symbol.getParentNamespace().getName();
|
||||||
|
@ -88,9 +78,6 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
return symbol.getParentNamespace().getID();
|
return symbol.getParentNamespace().getID();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.ExternalLocation#getLabel()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return symbol.getName();
|
return symbol.getName();
|
||||||
|
@ -98,7 +85,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getOriginalImportedName() {
|
public String getOriginalImportedName() {
|
||||||
return getExternalData(symbol).getOriginalImportedName();
|
return symbol.getExternalOriginalImportedName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -106,17 +93,11 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
return symbol.getSource();
|
return symbol.getSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.ExternalLocation#getAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address getAddress() {
|
public Address getAddress() {
|
||||||
return getExternalData(symbol).getAddress(extMgr.getAddressMap().getAddressFactory());
|
return symbol.getExternalProgramAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.ExternalLocation#getExternalSpaceAddress()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Address getExternalSpaceAddress() {
|
public Address getExternalSpaceAddress() {
|
||||||
return symbol.getAddress();
|
return symbol.getAddress();
|
||||||
|
@ -136,9 +117,6 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
return symbol.getSymbolType() == SymbolType.FUNCTION;
|
return symbol.getSymbolType() == SymbolType.FUNCTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.ExternalLocation#getDataType()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public DataType getDataType() {
|
public DataType getDataType() {
|
||||||
long dataTypeID = symbol.getDataTypeId();
|
long dataTypeID = symbol.getDataTypeId();
|
||||||
|
@ -148,15 +126,10 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
return extMgr.getProgram().getDataTypeManager().getDataType(dataTypeID);
|
return extMgr.getProgram().getDataTypeManager().getDataType(dataTypeID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.ExternalLocation#setDataType(ghidra.program.model.data.DataType)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setDataType(DataType dt) {
|
public void setDataType(DataType dt) {
|
||||||
long dataTypeID = extMgr.getProgram().getDataTypeManager().getResolvedID(dt);
|
long dataTypeID = extMgr.getProgram().getDataTypeManager().getResolvedID(dt);
|
||||||
symbol.setDataTypeId(dataTypeID);
|
symbol.setDataTypeId(dataTypeID);
|
||||||
|
|
||||||
// TODO: change notification may be required
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -173,7 +146,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
return getFunction();
|
return getFunction();
|
||||||
}
|
}
|
||||||
Function function = extMgr.createFunction(this);
|
Function function = extMgr.createFunction(this);
|
||||||
symbol = (SymbolDB) function.getSymbol();
|
symbol = (FunctionSymbol) function.getSymbol();
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,8 +159,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
* If a namespace is not included within label, the current namespace will be preserved.
|
* If a namespace is not included within label, the current namespace will be preserved.
|
||||||
* @param source the source of this external symbol:
|
* @param source the source of this external symbol:
|
||||||
* Symbol.DEFAULT, Symbol.ANALYSIS, Symbol.IMPORTED, or Symbol.USER_DEFINED
|
* Symbol.DEFAULT, Symbol.ANALYSIS, Symbol.IMPORTED, or Symbol.USER_DEFINED
|
||||||
* @throws InvalidInputException
|
* @throws InvalidInputException if the name contains illegal characters (space for example)
|
||||||
* @see ghidra.program.model.symbol.ExternalLocation#setLabel(java.lang.String)
|
|
||||||
*/
|
*/
|
||||||
void setLabel(String label, SourceType source) throws InvalidInputException {
|
void setLabel(String label, SourceType source) throws InvalidInputException {
|
||||||
if (label == null) {
|
if (label == null) {
|
||||||
|
@ -223,12 +195,10 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAddress(Address address) throws InvalidInputException {
|
public void setAddress(Address address) throws InvalidInputException {
|
||||||
String addressString = address != null ? address.toString() : null;
|
if (address == null && getSource() == SourceType.DEFAULT) {
|
||||||
if (addressString == null && getSource() == SourceType.DEFAULT) {
|
|
||||||
throw new InvalidInputException("Either an external label or address is required");
|
throw new InvalidInputException("Either an external label or address is required");
|
||||||
}
|
}
|
||||||
updateSymbolData(symbol, getExternalData(symbol).getOriginalImportedName(),
|
symbol.setExternalProgramAddress(address, true);
|
||||||
addressString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveOriginalNameIfNeeded(Namespace oldNamespace, String oldName,
|
public void saveOriginalNameIfNeeded(Namespace oldNamespace, String oldName,
|
||||||
|
@ -239,11 +209,11 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
// if we don't have an original already set and it is an imported symbol, save it
|
// if we don't have an original already set and it is an imported symbol, save it
|
||||||
String originalImportedName = getOriginalImportedName();
|
String originalImportedName = getOriginalImportedName();
|
||||||
if (getLabel().equals(originalImportedName)) {
|
if (getLabel().equals(originalImportedName)) {
|
||||||
setOriginalImportedName(symbol, null);
|
symbol.setExternalOriginalImportedName(null, false);
|
||||||
}
|
}
|
||||||
else if (wasInLibrary && getSource() != SourceType.DEFAULT &&
|
else if (wasInLibrary && getSource() != SourceType.DEFAULT &&
|
||||||
oldSource == SourceType.IMPORTED && originalImportedName == null) {
|
oldSource == SourceType.IMPORTED && originalImportedName == null) {
|
||||||
setOriginalImportedName(symbol, oldName);
|
symbol.setExternalOriginalImportedName(oldName, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,8 +258,8 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Library library = NamespaceUtils.getLibrary(symbol.getParentNamespace());
|
Library library = NamespaceUtils.getLibrary(symbol.getParentNamespace());
|
||||||
|
symbol.setExternalOriginalImportedName(null, false); // clear orig imported name
|
||||||
symbol.setNameAndNamespace(originalName, library, SourceType.IMPORTED);
|
symbol.setNameAndNamespace(originalName, library, SourceType.IMPORTED);
|
||||||
setOriginalImportedName(symbol, null);
|
|
||||||
}
|
}
|
||||||
catch (CircularDependencyException | DuplicateNameException | InvalidInputException e) {
|
catch (CircularDependencyException | DuplicateNameException | InvalidInputException e) {
|
||||||
throw new AssertException("Can't happen here", e);
|
throw new AssertException("Can't happen here", e);
|
||||||
|
@ -365,57 +335,4 @@ public class ExternalLocationDB implements ExternalLocation {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExternalData getExternalData(SymbolDB extSymbol) {
|
|
||||||
return new ExternalData(extSymbol.getSymbolStringData());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setOriginalImportedName(SymbolDB extSymbol, String name) {
|
|
||||||
updateSymbolData(extSymbol, name, getExternalData(extSymbol).getAddressString());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updateSymbolData(SymbolDB extSymbol, String originalImportedName,
|
|
||||||
String addressString) {
|
|
||||||
if (addressString == null && originalImportedName == null) {
|
|
||||||
extSymbol.setSymbolStringData(null);
|
|
||||||
}
|
|
||||||
StringBuilder buf = new StringBuilder();
|
|
||||||
if (addressString != null) {
|
|
||||||
buf.append(addressString);
|
|
||||||
}
|
|
||||||
if (originalImportedName != null) {
|
|
||||||
buf.append(ORIGINAL_IMPORTED_DELIMITER);
|
|
||||||
buf.append(originalImportedName);
|
|
||||||
}
|
|
||||||
extSymbol.setSymbolStringData(buf.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ExternalData {
|
|
||||||
private String originalImportedName;
|
|
||||||
private String addressString;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAddressString() {
|
|
||||||
return addressString;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getOriginalImportedName() {
|
|
||||||
return originalImportedName;
|
|
||||||
}
|
|
||||||
|
|
||||||
Address getAddress(AddressFactory addrFactory) {
|
|
||||||
if (addressString == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return addrFactory.getAddress(addressString);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,16 +25,16 @@ import ghidra.framework.data.OpenMode;
|
||||||
import ghidra.framework.store.FileSystem;
|
import ghidra.framework.store.FileSystem;
|
||||||
import ghidra.program.database.ManagerDB;
|
import ghidra.program.database.ManagerDB;
|
||||||
import ghidra.program.database.ProgramDB;
|
import ghidra.program.database.ProgramDB;
|
||||||
import ghidra.program.database.external.ExternalLocationDB.ExternalData;
|
import ghidra.program.database.function.FunctionDB;
|
||||||
import ghidra.program.database.function.FunctionManagerDB;
|
import ghidra.program.database.function.FunctionManagerDB;
|
||||||
import ghidra.program.database.map.AddressMap;
|
import ghidra.program.database.map.AddressMap;
|
||||||
import ghidra.program.database.symbol.*;
|
import ghidra.program.database.symbol.*;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Library;
|
import ghidra.program.model.listing.Library;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.LanguageTranslator;
|
|
||||||
import ghidra.util.Lock;
|
import ghidra.util.Lock;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
|
@ -46,7 +46,6 @@ import ghidra.util.task.TaskMonitor;
|
||||||
public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
|
|
||||||
private AddressMap addrMap;
|
private AddressMap addrMap;
|
||||||
private NamespaceManager scopeMgr;
|
|
||||||
private SymbolManager symbolMgr;
|
private SymbolManager symbolMgr;
|
||||||
private FunctionManagerDB functionMgr;
|
private FunctionManagerDB functionMgr;
|
||||||
|
|
||||||
|
@ -95,7 +94,6 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
this.program = program;
|
this.program = program;
|
||||||
symbolMgr = program.getSymbolTable();
|
symbolMgr = program.getSymbolTable();
|
||||||
functionMgr = program.getFunctionManager();
|
functionMgr = program.getFunctionManager();
|
||||||
scopeMgr = program.getNamespaceManager();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -202,7 +200,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
SourceType locSourceType = checkExternalLabel(extLabel, extAddr, sourceType);
|
SourceType locSourceType = checkExternalLabel(extLabel, extAddr, sourceType);
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
Namespace libraryScope = getLibraryScope(extLibraryName);
|
Library libraryScope = getLibraryScope(extLibraryName);
|
||||||
if (libraryScope == null) {
|
if (libraryScope == null) {
|
||||||
libraryScope = addExternalName(extLibraryName, null, sourceType);
|
libraryScope = addExternalName(extLibraryName, null, sourceType);
|
||||||
}
|
}
|
||||||
|
@ -245,7 +243,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
SourceType locSourceType = checkExternalLabel(extLabel, extAddr, sourceType);
|
SourceType locSourceType = checkExternalLabel(extLabel, extAddr, sourceType);
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
Namespace libraryScope = getLibraryScope(extLibraryName);
|
Library libraryScope = getLibraryScope(extLibraryName);
|
||||||
if (libraryScope == null) {
|
if (libraryScope == null) {
|
||||||
libraryScope = addExternalName(extLibraryName, null,
|
libraryScope = addExternalName(extLibraryName, null,
|
||||||
sourceType != SourceType.DEFAULT ? sourceType : SourceType.ANALYSIS);
|
sourceType != SourceType.DEFAULT ? sourceType : SourceType.ANALYSIS);
|
||||||
|
@ -284,9 +282,9 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
|
|
||||||
private SourceType checkExternalLabel(String extLabel, Address extAddr, SourceType source)
|
private SourceType checkExternalLabel(String extLabel, Address extAddr, SourceType source)
|
||||||
throws InvalidInputException {
|
throws InvalidInputException {
|
||||||
if (extLabel != null && (StringUtils.isBlank(extLabel) ||
|
if (StringUtils.isBlank(extLabel) ||
|
||||||
SymbolUtilities.isReservedExternalDefaultName(extLabel, addrMap.getAddressFactory()))) {
|
SymbolUtilities.isReservedExternalDefaultName(extLabel, addrMap.getAddressFactory())) {
|
||||||
extLabel = null;
|
extLabel = null; // force use of address
|
||||||
}
|
}
|
||||||
if (extLabel == null && extAddr == null) {
|
if (extLabel == null && extAddr == null) {
|
||||||
throw new InvalidInputException("Either an external label or address is required");
|
throw new InvalidInputException("Either an external label or address is required");
|
||||||
|
@ -329,12 +327,18 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
if (sourceType == SourceType.DEFAULT) {
|
if (sourceType == SourceType.DEFAULT) {
|
||||||
extLabel = null;
|
extLabel = null;
|
||||||
}
|
}
|
||||||
ExternalLocationDB extLoc =
|
else if (StringUtils.isBlank(extLabel) || SymbolUtilities
|
||||||
(ExternalLocationDB) getExtLocation(extNamespace, extLabel, extAddr, reuseExisting);
|
.isReservedExternalDefaultName(extLabel, addrMap.getAddressFactory())) {
|
||||||
|
extLabel = null; // force use of address
|
||||||
|
}
|
||||||
|
if (extAddr != null || reuseExisting) {
|
||||||
|
|
||||||
|
ExternalLocationDB extLoc = (ExternalLocationDB) getExtLocation(extNamespace,
|
||||||
|
extLabel, extAddr, reuseExisting);
|
||||||
|
|
||||||
if (extLoc != null) {
|
if (extLoc != null) {
|
||||||
|
|
||||||
// if there is already a location with the address, then we must use it
|
// if there is already a location with the address, then we must use it
|
||||||
if (extAddr != null || reuseExisting) {
|
|
||||||
if (extLabel != null && !extLabel.equals(extLoc.getLabel())) {
|
if (extLabel != null && !extLabel.equals(extLoc.getLabel())) {
|
||||||
extLoc.setLabel(extLabel, sourceType);
|
extLoc.setLabel(extLabel, sourceType);
|
||||||
}
|
}
|
||||||
|
@ -345,21 +349,25 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
return extLoc;
|
return extLoc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ok can't or don't want to reuse an existing one, so make a new one.
|
// ok can't or don't want to reuse an existing one, so make a new one.
|
||||||
SymbolDB s;
|
MemorySymbol s;
|
||||||
Address externalSpaceAddress = symbolMgr.getNextExternalSymbolAddress();
|
Address externalSpaceAddress = symbolMgr.getNextExternalSymbolAddress();
|
||||||
String extMemAddrString = (extAddr != null) ? extAddr.toString() : null;
|
|
||||||
if (isFunction) {
|
if (isFunction) {
|
||||||
Function function = functionMgr.createExternalFunction(externalSpaceAddress,
|
FunctionDB function = functionMgr.createExternalFunction(externalSpaceAddress,
|
||||||
extLabel, extNamespace, extMemAddrString, sourceType);
|
extLabel, extNamespace, null, extAddr, sourceType);
|
||||||
s = (SymbolDB) function.getSymbol();
|
s = (FunctionSymbol) function.getSymbol();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
s = (SymbolDB) symbolMgr.createCodeSymbol(externalSpaceAddress, extLabel,
|
s = symbolMgr.createExternalCodeSymbol(externalSpaceAddress, extLabel, extNamespace,
|
||||||
extNamespace, sourceType, extMemAddrString);
|
sourceType, null, extAddr);
|
||||||
}
|
}
|
||||||
return new ExternalLocationDB(this, s);
|
return new ExternalLocationDB(this, s);
|
||||||
}
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
program.dbError(e); // will not return
|
||||||
|
return null;
|
||||||
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
|
@ -377,66 +385,31 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
private ExternalLocation getExtLocation(Namespace library, String extLabel, Address extAddr,
|
private ExternalLocation getExtLocation(Namespace library, String extLabel, Address extAddr,
|
||||||
boolean reuseExisting) throws InvalidInputException {
|
boolean reuseExisting) throws InvalidInputException {
|
||||||
|
|
||||||
if (extLabel != null && (extLabel.length() == 0 ||
|
// Name match will also consider original import name if library is either null
|
||||||
SymbolUtilities.isReservedExternalDefaultName(extLabel, addrMap.getAddressFactory()))) {
|
// or a Library, otherwise only a specific namespaced name match will be considered.
|
||||||
extLabel = null; // force use of address
|
|
||||||
}
|
|
||||||
|
|
||||||
ExternalLocation match =
|
ExternalLocation match =
|
||||||
findMatchingLocationByName(library, extLabel, extAddr, reuseExisting);
|
findMatchingLocationByName(library, extLabel, extAddr, reuseExisting);
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
// So now get all the externalLocations for a library and search them
|
if (extLabel == null) { // assume extAddr is not null (already checked)
|
||||||
List<ExternalLocation> locations = getExternalLocations(library);
|
return findMatchingLocationByAddress(extAddr, reuseExisting);
|
||||||
|
|
||||||
if (extLabel == null) {
|
|
||||||
return findMatchingLocationByAddress(locations, extAddr, reuseExisting);
|
|
||||||
}
|
|
||||||
|
|
||||||
return findMatchingLocationByOriginalImportName(locations, extLabel, extAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the location whose original imported name matches the given extLabel name.
|
|
||||||
private ExternalLocation findMatchingLocationByOriginalImportName(
|
|
||||||
List<ExternalLocation> locations, String extLabel, Address extAddr) {
|
|
||||||
|
|
||||||
// this only makes sense if we have label and no address. If we have an address,
|
|
||||||
// then the address must match and we would have already found it.
|
|
||||||
if (extLabel != null && extAddr == null) {
|
|
||||||
for (ExternalLocation externalLocation : locations) {
|
|
||||||
if (extLabel.equals(externalLocation.getOriginalImportedName())) {
|
|
||||||
return externalLocation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ExternalLocation> getExternalLocations(Namespace library) {
|
|
||||||
List<ExternalLocation> list = new ArrayList<>();
|
|
||||||
SymbolIterator iter = symbolMgr.getSymbols(library);
|
|
||||||
for (Symbol symbol : iter) {
|
|
||||||
ExternalLocation extLoc = getExternalLocation(symbol);
|
|
||||||
if (extLoc != null) {
|
|
||||||
list.add(extLoc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find an external location in the given namespace with the given name and address. If
|
// Find an external location in the given namespace with the given name and address. If
|
||||||
// reuseExisting is true, then also find a match as long as the name and namespace match and
|
// reuseExisting is true, then also find a match as long as the name and namespace match and
|
||||||
// the address is null.
|
// the address is null.
|
||||||
private ExternalLocation findMatchingLocationByName(Namespace libScope, String extLabel,
|
private ExternalLocation findMatchingLocationByName(Namespace namespace, String extLabel,
|
||||||
Address extAddr, boolean reuseExisting) {
|
Address extAddr, boolean reuseExisting) {
|
||||||
if (extLabel == null) {
|
if (StringUtils.isBlank(extLabel)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ExternalLocation> externalLocations = getExternalLocations(libScope, extLabel);
|
Set<ExternalLocation> externalLocations = getExternalLocations(namespace, extLabel);
|
||||||
if (externalLocations.isEmpty()) {
|
if (externalLocations.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -460,14 +433,16 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// first look for one without an address
|
// first look for one without an address
|
||||||
|
ExternalLocation possibleExtLoc = null;
|
||||||
for (ExternalLocation externalLocation : externalLocations) {
|
for (ExternalLocation externalLocation : externalLocations) {
|
||||||
if (externalLocation.getAddress() == null) {
|
if (externalLocation.getAddress() == null) {
|
||||||
return externalLocation;
|
return externalLocation;
|
||||||
}
|
}
|
||||||
|
possibleExtLoc = externalLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if reuse existing, then return any
|
// if reuse existing, then return any
|
||||||
return reuseExisting ? externalLocations.get(0) : null;
|
return reuseExisting ? possibleExtLoc : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look through all the locations for one whose address matches the given address AND whose
|
// Look through all the locations for one whose address matches the given address AND whose
|
||||||
|
@ -475,91 +450,100 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
// location with a non-null address and a null label. So an exact match is when the address
|
// location with a non-null address and a null label. So an exact match is when the address
|
||||||
// matches and the label is null. If reuseExisting, then we are trying to find and suitable
|
// matches and the label is null. If reuseExisting, then we are trying to find and suitable
|
||||||
// location, so as long as the address matches, we can return it.
|
// location, so as long as the address matches, we can return it.
|
||||||
private ExternalLocation findMatchingLocationByAddress(List<ExternalLocation> locations,
|
private ExternalLocation findMatchingLocationByAddress(Address extAddr, boolean reuseExisting) {
|
||||||
Address extAddr, boolean reuseExisting) {
|
for (Symbol symbol : symbolMgr.getExternalSymbolByMemoryAddress(null, extAddr)) {
|
||||||
for (ExternalLocation externalLocation : locations) {
|
ExternalLocation externalLocation = getExternalLocation(symbol);
|
||||||
if (extAddr.equals(externalLocation.getAddress())) {
|
|
||||||
if (reuseExisting || externalLocation.getLabel() == null) {
|
if (reuseExisting || externalLocation.getLabel() == null) {
|
||||||
return externalLocation;
|
return externalLocation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ExternalLocation> getExternalLocations(Namespace libScope, String extLabel) {
|
public Set<ExternalLocation> getExternalLocations(Namespace namespace, String extLabel) {
|
||||||
List<ExternalLocation> externalLocations = new ArrayList<>();
|
if (namespace != null && !namespace.isExternal()) {
|
||||||
List<Symbol> symbols = symbolMgr.getSymbols(extLabel, libScope);
|
return Set.of();
|
||||||
|
}
|
||||||
|
Set<ExternalLocation> externalLocations = new HashSet<>();
|
||||||
|
if (namespace == null || namespace instanceof Library) {
|
||||||
|
// Check for matching original import name
|
||||||
|
SymbolIterator matchingSymbols =
|
||||||
|
symbolMgr.getExternalSymbolByOriginalImportName((Library) namespace, extLabel);
|
||||||
|
for (Symbol symbol : matchingSymbols) {
|
||||||
|
ExternalLocation externalLocation = getExternalLocation(symbol);
|
||||||
|
if (externalLocation != null) {
|
||||||
|
externalLocations.add(externalLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (namespace != null) {
|
||||||
|
List<Symbol> symbols = symbolMgr.getSymbols(extLabel, namespace);
|
||||||
for (Symbol symbol : symbols) {
|
for (Symbol symbol : symbols) {
|
||||||
ExternalLocation externalLocation = getExternalLocation(symbol);
|
ExternalLocation externalLocation = getExternalLocation(symbol);
|
||||||
if (externalLocation != null) {
|
if (externalLocation != null) {
|
||||||
externalLocations.add(externalLocation);
|
externalLocations.add(externalLocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return externalLocations;
|
}
|
||||||
|
else {
|
||||||
|
for (Symbol symbol : symbolMgr.getExternalSymbols(extLabel)) {
|
||||||
|
ExternalLocation externalLocation = getExternalLocation(symbol);
|
||||||
|
if (externalLocation != null) {
|
||||||
|
externalLocations.add(externalLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableSet(externalLocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ExternalLocation> getExternalLocations(String libraryName, String label) {
|
public Set<ExternalLocation> getExternalLocations(String libraryName, String label) {
|
||||||
Namespace libraryScope = getLibraryScope(libraryName);
|
Library library = getLibraryScope(libraryName);
|
||||||
if (libraryScope == null) {
|
if (library == null && !StringUtils.isBlank(libraryName)) {
|
||||||
return Collections.emptyList();
|
return Set.of();
|
||||||
}
|
}
|
||||||
return getExternalLocations(libraryScope, label);
|
return getExternalLocations(library, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExternalLocation getUniqueExternalLocation(Namespace namespace, String label) {
|
public ExternalLocation getUniqueExternalLocation(Namespace namespace, String label) {
|
||||||
List<ExternalLocation> externalLocations = getExternalLocations(namespace, label);
|
Set<ExternalLocation> externalLocations = getExternalLocations(namespace, label);
|
||||||
if (externalLocations.size() == 1) {
|
if (externalLocations.size() == 1) {
|
||||||
return externalLocations.get(0);
|
return externalLocations.iterator().next();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExternalLocation getUniqueExternalLocation(String libraryName, String label) {
|
public ExternalLocation getUniqueExternalLocation(String libraryName, String label) {
|
||||||
Namespace libScope = getLibraryScope(libraryName);
|
Library library = getLibraryScope(libraryName);
|
||||||
if (libScope == null) {
|
if (library == null && !StringUtils.isBlank(libraryName)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return getUniqueExternalLocation(libScope, label);
|
return getUniqueExternalLocation(library, label);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ExternalLocation getExternalLocation(String extName, String extLabel) {
|
|
||||||
Namespace libScope = getLibraryScope(extName);
|
|
||||||
return getExternalLocation(libScope, extLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ExternalLocation getExternalLocation(Namespace extNamespace, String extLabel) {
|
|
||||||
List<ExternalLocation> externalLocations = getExternalLocations(extNamespace, extLabel);
|
|
||||||
if (externalLocations.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return externalLocations.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default name for an external function or code symbol
|
* {@return the default name for an external function or code symbol}
|
||||||
* @param sym
|
* @param sym external label or function symbol
|
||||||
* @return default name
|
* @throws IllegalArgumentException if external label or function symbol not specified or
|
||||||
|
* external symbol does not have an external program address.
|
||||||
*/
|
*/
|
||||||
public static String getDefaultExternalName(SymbolDB sym) {
|
public static String getDefaultExternalName(SymbolDB sym) {
|
||||||
SymbolType type = sym.getSymbolType();
|
if (!(sym instanceof MemorySymbol) && !sym.isExternal()) {
|
||||||
if ((type != SymbolType.LABEL && type != SymbolType.FUNCTION) || !sym.isExternal()) {
|
throw new IllegalArgumentException("External label or function symbol required");
|
||||||
throw new AssertException();
|
|
||||||
}
|
}
|
||||||
ExternalData externalData = ExternalLocationDB.getExternalData(sym);
|
|
||||||
Address addr = externalData.getAddress(sym.getProgram().getAddressFactory());
|
Address addr = ((MemorySymbol) sym).getExternalProgramAddress();
|
||||||
if (addr == null) {
|
if (addr == null) {
|
||||||
throw new AssertException("External should not be default without memory address");
|
throw new IllegalArgumentException("Default External requires memory address");
|
||||||
}
|
}
|
||||||
if (type == SymbolType.FUNCTION) {
|
|
||||||
|
if (sym instanceof FunctionSymbol) {
|
||||||
return SymbolUtilities.getDefaultExternalFunctionName(addr);
|
return SymbolUtilities.getDefaultExternalFunctionName(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
long dataTypeID = sym.getDataTypeId();
|
long dataTypeID = sym.getDataTypeId();
|
||||||
DataType dt =
|
DataType dt =
|
||||||
(dataTypeID < 0) ? null : sym.getProgram().getDataTypeManager().getDataType(dataTypeID);
|
(dataTypeID < 0) ? null : sym.getProgram().getDataTypeManager().getDataType(dataTypeID);
|
||||||
|
@ -571,8 +555,9 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the external location associated with the given external address
|
* {@return the external location associated with the given external address or null}
|
||||||
* @param externalAddr the external address.
|
* @param externalAddr the external address.
|
||||||
|
* @throws IllegalArgumentException if address is not external
|
||||||
*/
|
*/
|
||||||
public ExternalLocation getExtLocation(Address externalAddr) {
|
public ExternalLocation getExtLocation(Address externalAddr) {
|
||||||
if (externalAddr.getAddressSpace() != AddressSpace.EXTERNAL_SPACE) {
|
if (externalAddr.getAddressSpace() != AddressSpace.EXTERNAL_SPACE) {
|
||||||
|
@ -582,7 +567,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
try {
|
try {
|
||||||
Symbol[] symbols = symbolMgr.getSymbols(externalAddr);
|
Symbol[] symbols = symbolMgr.getSymbols(externalAddr);
|
||||||
if (symbols.length == 1) {
|
if (symbols.length == 1) {
|
||||||
return new ExternalLocationDB(this, (SymbolDB) symbols[0]);
|
return new ExternalLocationDB(this, (MemorySymbol) symbols[0]);
|
||||||
}
|
}
|
||||||
if (symbols.length > 2) {
|
if (symbols.length > 2) {
|
||||||
throw new AssertException(
|
throw new AssertException(
|
||||||
|
@ -613,6 +598,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
/**
|
/**
|
||||||
* Removes the external location at the given external address
|
* Removes the external location at the given external address
|
||||||
* @param externalAddr the address at which to remove the external location.
|
* @param externalAddr the address at which to remove the external location.
|
||||||
|
* @return true if external location was successfully removed else false
|
||||||
*/
|
*/
|
||||||
public boolean removeExternalLocation(Address externalAddr) {
|
public boolean removeExternalLocation(Address externalAddr) {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
@ -651,15 +637,6 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the external program for all references.
|
|
||||||
* @param oldName old external program name
|
|
||||||
* @param newName new external program name
|
|
||||||
* @param source the source of this external library:
|
|
||||||
* Symbol.DEFAULT, Symbol.ANALYSIS, Symbol.IMPORTED, or Symbol.USER_DEFINED
|
|
||||||
* @throws DuplicateNameException
|
|
||||||
* @throws InvalidInputException
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void updateExternalLibraryName(String oldName, String newName, SourceType source)
|
public void updateExternalLibraryName(String oldName, String newName, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException {
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
@ -691,9 +668,9 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
return (Library) s.getObject();
|
return (Library) s.getObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Namespace getLibraryScope(String name) {
|
private Library getLibraryScope(String name) {
|
||||||
Symbol s = symbolMgr.getLibrarySymbol(name);
|
LibrarySymbol s = symbolMgr.getLibrarySymbol(name);
|
||||||
return s == null ? null : (Namespace) s.getObject();
|
return s == null ? null : s.getObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -723,9 +700,9 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getExternalLibraryPath(String externalName) {
|
public String getExternalLibraryPath(String externalName) {
|
||||||
SymbolDB s = (SymbolDB) symbolMgr.getLibrarySymbol(externalName);
|
LibrarySymbol s = symbolMgr.getLibrarySymbol(externalName);
|
||||||
if (s instanceof LibrarySymbol) {
|
if (s != null) {
|
||||||
return s.getSymbolStringData();
|
return s.getExternalLibraryPath();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -743,7 +720,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
SymbolDB s = (SymbolDB) symbolMgr.getLibrarySymbol(externalName);
|
LibrarySymbol s = symbolMgr.getLibrarySymbol(externalName);
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
try {
|
try {
|
||||||
addExternalName(externalName, externalPath,
|
addExternalName(externalName, externalPath,
|
||||||
|
@ -753,8 +730,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
throw new AssertException(e);
|
throw new AssertException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (s instanceof LibrarySymbol) {
|
else {
|
||||||
s.setSymbolStringData(externalPath);
|
s.setExternalLibraryPath(externalPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -784,8 +761,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
if (!(symbol instanceof CodeSymbol)) {
|
if (!(symbol instanceof CodeSymbol)) {
|
||||||
throw new IllegalStateException("Expected external code symbol");
|
throw new IllegalStateException("Expected external code symbol");
|
||||||
}
|
}
|
||||||
//long dtId = symbol.getSymbolData1();
|
Address extProgAddr = extLoc.getAddress();
|
||||||
String extData = symbol.getSymbolStringData();
|
String origImpName = extLoc.getOriginalImportedName();
|
||||||
String name = symbol.getName();
|
String name = symbol.getName();
|
||||||
Namespace namespace = symbol.getParentNamespace();
|
Namespace namespace = symbol.getParentNamespace();
|
||||||
Address extAddr = symbol.getAddress();
|
Address extAddr = symbol.getAddress();
|
||||||
|
@ -793,7 +770,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
|
|
||||||
((CodeSymbol) symbol).delete(true);
|
((CodeSymbol) symbol).delete(true);
|
||||||
|
|
||||||
return functionMgr.createExternalFunction(extAddr, name, namespace, extData, source);
|
return functionMgr.createExternalFunction(extAddr, name, namespace, origImpName,
|
||||||
|
extProgAddr, source);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
throw new RuntimeException("Unexpected exception", e);
|
throw new RuntimeException("Unexpected exception", e);
|
||||||
|
@ -809,12 +787,12 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExternalLocationIterator getExternalLocations(Address memoryAddress) {
|
public ExternalLocationIterator getExternalLocations(Address memoryAddress) {
|
||||||
return new ExternalLocationDBIterator(symbolMgr.getExternalSymbols(), memoryAddress);
|
return new ExternalLocationDBIterator(null, memoryAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExternalLocationIterator getExternalLocations(String externalName) {
|
public ExternalLocationIterator getExternalLocations(String externalName) {
|
||||||
Namespace scope = getLibraryScope(externalName);
|
Library scope = getLibraryScope(externalName);
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
return new ExternalLocationDBIterator(symbolMgr.getSymbols(scope));
|
return new ExternalLocationDBIterator(symbolMgr.getSymbols(scope));
|
||||||
}
|
}
|
||||||
|
@ -830,8 +808,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
ExternalLocationDBIterator() {
|
ExternalLocationDBIterator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalLocationDBIterator(SymbolIterator symIter, Address matchingAddress) {
|
ExternalLocationDBIterator(Library library, Address matchingAddress) {
|
||||||
this.symIter = symIter;
|
this.symIter = symbolMgr.getExternalSymbolByMemoryAddress(library, matchingAddress);
|
||||||
this.matchingAddress = matchingAddress;
|
this.matchingAddress = matchingAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -883,45 +861,4 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLanguage(LanguageTranslator translator, TaskMonitor monitor)
|
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
monitor.setMessage("Translate External Addresses...");
|
|
||||||
|
|
||||||
AddressFactory oldAddrFactory = translator.getOldLanguage().getAddressFactory();
|
|
||||||
SymbolIterator externalSymbols = symbolMgr.getExternalSymbols();
|
|
||||||
while (externalSymbols.hasNext()) {
|
|
||||||
monitor.checkCancelled();
|
|
||||||
SymbolDB s = (SymbolDB) externalSymbols.next();
|
|
||||||
ExternalData externalData = ExternalLocationDB.getExternalData(s);
|
|
||||||
String addrStr = externalData.getAddressString();
|
|
||||||
if (addrStr == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// skip addresses which do not parse by old language - could be
|
|
||||||
// overlay (although this should generally never occur)
|
|
||||||
Address addr = oldAddrFactory.getAddress(addrStr);
|
|
||||||
if (addr == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
AddressSpace newAddressSpace =
|
|
||||||
translator.getNewAddressSpace(addr.getAddressSpace().getName());
|
|
||||||
if (newAddressSpace == null || !newAddressSpace.isLoadedMemorySpace()) {
|
|
||||||
// can't really recover from this
|
|
||||||
throw new AssertException("Failed to map external memory address: " + addrStr);
|
|
||||||
}
|
|
||||||
addr = newAddressSpace.getAddress(addr.getOffset());
|
|
||||||
String newAddrStr = addr.toString();
|
|
||||||
if (!newAddrStr.equals(addrStr)) {
|
|
||||||
ExternalLocationDB.updateSymbolData(s, externalData.getOriginalImportedName(),
|
|
||||||
newAddrStr); // store translated external location address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SymbolDB createSymbolForOriginalName(Address address, Namespace namespace, String oldName,
|
|
||||||
SourceType oldType) throws InvalidInputException {
|
|
||||||
return (SymbolDB) symbolMgr.createCodeSymbol(address, oldName, namespace, oldType, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
|
|
||||||
private ProgramDB program;
|
private ProgramDB program;
|
||||||
private Address entryPoint;
|
private Address entryPoint;
|
||||||
private Symbol functionSymbol;
|
private FunctionSymbol functionSymbol;
|
||||||
private DBRecord rec;
|
private DBRecord rec;
|
||||||
|
|
||||||
private FunctionStackFrame frame;
|
private FunctionStackFrame frame;
|
||||||
|
@ -108,7 +108,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
thunkedFunction = manager.getThunkedFunction(this);
|
thunkedFunction = manager.getThunkedFunction(this);
|
||||||
functionSymbol = program.getSymbolTable().getSymbol(key);
|
functionSymbol = (FunctionSymbol) program.getSymbolTable().getSymbol(key);
|
||||||
entryPoint = functionSymbol.getAddress();
|
entryPoint = functionSymbol.getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -974,7 +974,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
symbolMap.put(v.symbol, v);
|
symbolMap.put(v.symbol, v);
|
||||||
}
|
}
|
||||||
if (var.getComment() != null) {
|
if (var.getComment() != null) {
|
||||||
v.symbol.setSymbolStringData(var.getComment());
|
v.symbol.setSymbolComment(var.getComment());
|
||||||
}
|
}
|
||||||
manager.functionChanged(this, null);
|
manager.functionChanged(this, null);
|
||||||
return v;
|
return v;
|
||||||
|
@ -1667,7 +1667,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
||||||
manager.functionChanged(this, PARAMETERS_CHANGED);
|
manager.functionChanged(this, PARAMETERS_CHANGED);
|
||||||
}
|
}
|
||||||
if (var.getComment() != null) {
|
if (var.getComment() != null) {
|
||||||
p.symbol.setSymbolStringData(var.getComment());
|
p.symbol.setSymbolComment(var.getComment());
|
||||||
}
|
}
|
||||||
updateSignatureSourceAfterVariableChange(source, p.getDataType());
|
updateSignatureSourceAfterVariableChange(source, p.getDataType());
|
||||||
return p;
|
return p;
|
||||||
|
|
|
@ -30,7 +30,6 @@ import ghidra.program.database.DBObjectCache;
|
||||||
import ghidra.program.database.ProgramDB;
|
import ghidra.program.database.ProgramDB;
|
||||||
import ghidra.program.database.code.CodeManager;
|
import ghidra.program.database.code.CodeManager;
|
||||||
import ghidra.program.database.data.DataTypeManagerDB;
|
import ghidra.program.database.data.DataTypeManagerDB;
|
||||||
import ghidra.program.database.external.ExternalLocationDB;
|
|
||||||
import ghidra.program.database.map.AddressMap;
|
import ghidra.program.database.map.AddressMap;
|
||||||
import ghidra.program.database.symbol.*;
|
import ghidra.program.database.symbol.*;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
|
@ -150,38 +149,40 @@ public class FunctionManagerDB implements FunctionManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform an existing external symbol into an external function.
|
* Transform an existing external symbol into an external function.
|
||||||
* This method should only be invoked by an ExternalSymbol
|
* This method should only be invoked by the Function Manager.
|
||||||
|
* The {@link ExternalLocation#getOriginalImportedName() original imported name} will initially
|
||||||
|
* be null.
|
||||||
|
*
|
||||||
* @param extSpaceAddr the external space address to use when creating this external. Any
|
* @param extSpaceAddr the external space address to use when creating this external. Any
|
||||||
* other symbol using this address must first be deleted. Results are unpredictable if this is
|
* other symbol using this address must first be deleted. Results are unpredictable if this is
|
||||||
* not done.
|
* not done.
|
||||||
* @param name the external function name
|
* @param name the external function name
|
||||||
* @param nameSpace the external function namespace
|
* @param nameSpace the external function namespace
|
||||||
* @param extData the external data string to store additional info (see {@link ExternalLocationDB})
|
* @param externalProgramAddress the external program address (may be null)
|
||||||
|
* @param originalImportName the original imported name if different from name (may be null)
|
||||||
* @param source the source of this external.
|
* @param source the source of this external.
|
||||||
* @return external function
|
* @return external function
|
||||||
* @throws InvalidInputException if the name is invalid
|
* @throws InvalidInputException if the name is invalid
|
||||||
*/
|
*/
|
||||||
public Function createExternalFunction(Address extSpaceAddr, String name, Namespace nameSpace,
|
public FunctionDB createExternalFunction(Address extSpaceAddr, String name, Namespace nameSpace,
|
||||||
String extData, SourceType source) throws InvalidInputException {
|
String originalImportName, Address externalProgramAddress, SourceType source)
|
||||||
|
throws InvalidInputException {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
Symbol symbol =
|
FunctionSymbol symbol = symbolMgr.createExternalFunctionSymbol(extSpaceAddr, name,
|
||||||
symbolMgr.createFunctionSymbol(extSpaceAddr, name, nameSpace, source, extData);
|
nameSpace, source, originalImportName, externalProgramAddress);
|
||||||
|
|
||||||
long returnDataTypeId = program.getDataTypeManager().getResolvedID(DataType.DEFAULT);
|
long returnDataTypeId = program.getDataTypeManager().getResolvedID(DataType.DEFAULT);
|
||||||
|
|
||||||
try {
|
|
||||||
DBRecord rec = adapter.createFunctionRecord(symbol.getID(), returnDataTypeId);
|
DBRecord rec = adapter.createFunctionRecord(symbol.getID(), returnDataTypeId);
|
||||||
|
|
||||||
FunctionDB funcDB = new FunctionDB(this, cache, addrMap, rec);
|
FunctionDB funcDB = new FunctionDB(this, cache, addrMap, rec);
|
||||||
|
|
||||||
program.setObjChanged(ProgramEvent.FUNCTION_ADDED, extSpaceAddr, funcDB, null,
|
program.setObjChanged(ProgramEvent.FUNCTION_ADDED, extSpaceAddr, funcDB, null, null);
|
||||||
null);
|
|
||||||
return funcDB;
|
return funcDB;
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
dbError(e);
|
dbError(e); // will not return
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -278,12 +279,13 @@ public class FunctionManagerDB implements FunctionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol symbol = symbolMgr.createFunctionSymbol(entryPoint, name, nameSpace, source,
|
|
||||||
((thunkedFunction != null) ? thunkedFunction.getEntryPoint().toString() : null));
|
|
||||||
|
|
||||||
long returnDataTypeId = program.getDataTypeManager().getResolvedID(DataType.DEFAULT);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Symbol symbol =
|
||||||
|
symbolMgr.createMemoryFunctionSymbol(entryPoint, name, nameSpace, source);
|
||||||
|
|
||||||
|
long returnDataTypeId =
|
||||||
|
program.getDataTypeManager().getResolvedID(DataType.DEFAULT);
|
||||||
|
|
||||||
if (refFunc != null) {
|
if (refFunc != null) {
|
||||||
|
|
||||||
String oldName = symbol.getName();
|
String oldName = symbol.getName();
|
||||||
|
|
|
@ -176,12 +176,12 @@ public abstract class VariableDB implements Variable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getComment() {
|
public String getComment() {
|
||||||
return symbol.getSymbolStringData();
|
return symbol.getSymbolComment();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setComment(String comment) {
|
public void setComment(String comment) {
|
||||||
symbol.setSymbolStringData(comment);
|
symbol.setSymbolComment(comment);
|
||||||
functionMgr.functionChanged(function, null);
|
functionMgr.functionChanged(function, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,8 +409,11 @@ public abstract class VariableDB implements Variable {
|
||||||
* Update variable storage and data-type associated with the underlying variable symbol.
|
* Update variable storage and data-type associated with the underlying variable symbol.
|
||||||
* If function does not use custom storage, the specified storage will be ignored and set
|
* If function does not use custom storage, the specified storage will be ignored and set
|
||||||
* to UNASSIGNED.
|
* to UNASSIGNED.
|
||||||
* @param newStorage
|
* <P>
|
||||||
* @param dt
|
* NOTE: Method will trigger a symbol changed event.
|
||||||
|
*
|
||||||
|
* @param newStorage variable storage
|
||||||
|
* @param dt variable datatype
|
||||||
*/
|
*/
|
||||||
void setStorageAndDataType(VariableStorage newStorage, DataType dt) {
|
void setStorageAndDataType(VariableStorage newStorage, DataType dt) {
|
||||||
if (this instanceof Parameter && !function.hasCustomVariableStorage()) {
|
if (this instanceof Parameter && !function.hasCustomVariableStorage()) {
|
||||||
|
|
|
@ -1548,10 +1548,13 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether the address is an external entry point
|
* Return whether the address is an external entry point
|
||||||
* @param toAddr the address to test for external entry point
|
* @param toAddr the memory address to test for external entry point
|
||||||
* @return true if the address is an external entry point
|
* @return true if the address is an external entry point
|
||||||
*/
|
*/
|
||||||
public boolean isExternalEntryPoint(Address toAddr) {
|
public boolean isExternalEntryPoint(Address toAddr) {
|
||||||
|
if (!toAddr.isMemoryAddress()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
RefList refList = getToRefs(toAddr);
|
RefList refList = getToRefs(toAddr);
|
||||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.program.database.symbol;
|
||||||
import db.DBRecord;
|
import db.DBRecord;
|
||||||
import ghidra.program.database.DBObjectCache;
|
import ghidra.program.database.DBObjectCache;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.GhidraClass;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,16 +29,13 @@ public class ClassSymbol extends SymbolDB {
|
||||||
private GhidraClassDB ghidraClass;
|
private GhidraClassDB ghidraClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new Class Symbol
|
* Construct a Ghidra Class symbol from an existing symbol record
|
||||||
* @param symbolMgr the symbol manager
|
* @param symbolMgr the symbol manager
|
||||||
* @param cache symbol object cache
|
* @param cache symbol object cache
|
||||||
* @param address the address to associate with the symbol
|
|
||||||
* @param record the record associated with the symbol.
|
* @param record the record associated with the symbol.
|
||||||
*/
|
*/
|
||||||
public ClassSymbol(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache, Address address,
|
ClassSymbol(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache, DBRecord record) {
|
||||||
DBRecord record) {
|
super(symbolMgr, cache, Address.NO_ADDRESS, record);
|
||||||
super(symbolMgr, cache, address, record);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,10 +44,12 @@ public class ClassSymbol extends SymbolDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public GhidraClass getObject() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
if (!checkIsValid()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (ghidraClass == null) {
|
if (ghidraClass == null) {
|
||||||
ghidraClass = new GhidraClassDB(this, symbolMgr.getProgram().getNamespaceManager());
|
ghidraClass = new GhidraClassDB(this, symbolMgr.getProgram().getNamespaceManager());
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,9 @@ import ghidra.program.util.LabelFieldLocation;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Symbols that represent "labels"
|
* Symbols that represent "labels" or external data locations
|
||||||
*
|
|
||||||
* Symbol data usage:
|
|
||||||
* EXTERNAL:
|
|
||||||
* String stringData - external memory address/label
|
|
||||||
*/
|
*/
|
||||||
public class CodeSymbol extends SymbolDB {
|
public class CodeSymbol extends MemorySymbol {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new CodeSymbol
|
* Constructs a new CodeSymbol
|
||||||
|
@ -74,11 +70,6 @@ public class CodeSymbol extends SymbolDB {
|
||||||
return symbolMgr.hasDynamicSymbol(address);
|
return symbolMgr.hasDynamicSymbol(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isExternal() {
|
|
||||||
return address.isExternalAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean delete() {
|
public boolean delete() {
|
||||||
boolean keepReferences = !isExternal();
|
boolean keepReferences = !isExternal();
|
||||||
|
@ -105,21 +96,6 @@ public class CodeSymbol extends SymbolDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPinned() {
|
|
||||||
if (!isExternal()) {
|
|
||||||
return doIsPinned();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPinned(boolean pinned) {
|
|
||||||
if (!isExternal()) {
|
|
||||||
doSetPinned(pinned);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Object getObject() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
@ -219,8 +195,8 @@ public class CodeSymbol extends SymbolDB {
|
||||||
}
|
}
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
if (newName == null || newName.length() == 0 || SymbolUtilities.isReservedDynamicLabelName(
|
if (newName == null || newName.length() == 0 || SymbolUtilities
|
||||||
newName, symbolMgr.getProgram().getAddressFactory())) {
|
.isReservedDynamicLabelName(newName, symbolMgr.getProgram().getAddressFactory())) {
|
||||||
return SourceType.DEFAULT;
|
return SourceType.DEFAULT;
|
||||||
}
|
}
|
||||||
return source;
|
return source;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.database.symbol;
|
package ghidra.program.database.symbol;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -35,12 +36,8 @@ import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Symbol class for functions.
|
* Symbol class for functions.
|
||||||
*
|
|
||||||
* Symbol Data Usage:
|
|
||||||
* EXTERNAL:
|
|
||||||
* String stringData - external memory address/label
|
|
||||||
*/
|
*/
|
||||||
public class FunctionSymbol extends SymbolDB {
|
public class FunctionSymbol extends MemorySymbol {
|
||||||
|
|
||||||
private FunctionManagerDB functionMgr;
|
private FunctionManagerDB functionMgr;
|
||||||
|
|
||||||
|
@ -62,11 +59,6 @@ public class FunctionSymbol extends SymbolDB {
|
||||||
return SymbolType.FUNCTION;
|
return SymbolType.FUNCTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isExternal() {
|
|
||||||
return address.isExternalAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isThunk() {
|
boolean isThunk() {
|
||||||
return functionMgr.isThunk(key);
|
return functionMgr.isThunk(key);
|
||||||
}
|
}
|
||||||
|
@ -93,9 +85,13 @@ public class FunctionSymbol extends SymbolDB {
|
||||||
try {
|
try {
|
||||||
boolean restoreLabel = isExternal() || (getSource() != SourceType.DEFAULT);
|
boolean restoreLabel = isExternal() || (getSource() != SourceType.DEFAULT);
|
||||||
String symName = getName();
|
String symName = getName();
|
||||||
String extData = null;
|
Symbol parentSymbol = getParentSymbol();
|
||||||
|
String extOrigImportName = null;
|
||||||
|
Address extProgramAddr = null;
|
||||||
if (isExternal()) {
|
if (isExternal()) {
|
||||||
extData = getSymbolStringData(); // preserve external data
|
// preserve external data
|
||||||
|
extOrigImportName = getExternalOriginalImportedName();
|
||||||
|
extProgramAddr = getExternalProgramAddress();
|
||||||
}
|
}
|
||||||
Namespace namespace = getParentNamespace();
|
Namespace namespace = getParentNamespace();
|
||||||
SourceType source = getSource();
|
SourceType source = getSource();
|
||||||
|
@ -109,54 +105,48 @@ public class FunctionSymbol extends SymbolDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (super.delete()) {
|
if (super.delete()) {
|
||||||
|
if ((parentSymbol instanceof SymbolDB) && ((SymbolDB) parentSymbol).isDeleting()) {
|
||||||
|
// do not replace function with label if parent namespace is getting removed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (restoreLabel) {
|
if (restoreLabel) {
|
||||||
boolean restored = createLabelForDeletedFunctionName(address, symName, extData,
|
// Recreate a symbol with the function symbol's name because deleting the function
|
||||||
namespace, source, pinned);
|
// does not mean that we want to lose the function name (that is our policy).
|
||||||
if (!restored && isExternal()) {
|
Symbol newSymbol;
|
||||||
// remove all associated external references if label not restored
|
if (isExternal()) {
|
||||||
|
newSymbol = symbolMgr.createExternalCodeSymbol(address, symName, namespace,
|
||||||
|
source, extOrigImportName, extProgramAddr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newSymbol = symbolMgr.createLabel(address, symName, namespace, source);
|
||||||
|
newSymbol.setPrimary();
|
||||||
|
if (pinned) {
|
||||||
|
newSymbol.setPinned(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newSymbol == null && isExternal()) {
|
||||||
|
// remove all associated external references if external symbol not restored
|
||||||
symbolMgr.getReferenceManager().removeAllReferencesTo(getAddress());
|
symbolMgr.getReferenceManager().removeAllReferencesTo(getAddress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (InvalidInputException e) {
|
||||||
|
// This shouldn't happen.
|
||||||
|
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
symbolMgr.dbError(e);
|
||||||
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Recreate a symbol with the function symbol's name because deleting the function
|
|
||||||
* does not mean that we want to lose the function name (that is our policy).
|
|
||||||
*/
|
|
||||||
private boolean createLabelForDeletedFunctionName(Address entryPoint, String symName,
|
|
||||||
String stringData, Namespace namespace, SourceType source, boolean pinned) {
|
|
||||||
|
|
||||||
Symbol parentSymbol = namespace.getSymbol();
|
|
||||||
if ((parentSymbol instanceof SymbolDB) && ((SymbolDB) parentSymbol).isDeleting()) {
|
|
||||||
// do not replace function with label if parent namespace is getting removed
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Symbol newSym =
|
|
||||||
symbolMgr.createCodeSymbol(entryPoint, symName, namespace, source, stringData);
|
|
||||||
newSym.setPrimary();
|
|
||||||
if (pinned) {
|
|
||||||
newSym.setPinned(true);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (InvalidInputException e) {
|
|
||||||
// This shouldn't happen.
|
|
||||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Function getObject() {
|
||||||
return functionMgr.getFunction(key);
|
return functionMgr.getFunction(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,21 +155,6 @@ public class FunctionSymbol extends SymbolDB {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPinned() {
|
|
||||||
if (!isExternal()) {
|
|
||||||
return doIsPinned();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPinned(boolean pinned) {
|
|
||||||
if (!isExternal()) {
|
|
||||||
doSetPinned(pinned);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgramLocation getProgramLocation() {
|
public ProgramLocation getProgramLocation() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
@ -187,7 +162,7 @@ public class FunctionSymbol extends SymbolDB {
|
||||||
if (!checkIsValid()) {
|
if (!checkIsValid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Function f = (Function) getObject();
|
Function f = getObject();
|
||||||
String signature = f.getPrototypeString(false, false);
|
String signature = f.getPrototypeString(false, false);
|
||||||
return new FunctionReturnTypeFieldLocation(getProgram(), address, 0, signature,
|
return new FunctionReturnTypeFieldLocation(getProgram(), address, 0, signature,
|
||||||
f.getReturnType().getName());
|
f.getReturnType().getName());
|
||||||
|
@ -340,27 +315,6 @@ public class FunctionSymbol extends SymbolDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasMultipleReferences() {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
|
|
||||||
if (super.hasMultipleReferences()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Long> thunkIds = functionMgr.getThunkFunctionIds(key);
|
|
||||||
if (thunkIds != null) {
|
|
||||||
return thunkIds.size() > 1;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasReferences() {
|
public boolean hasReferences() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class GhidraClassDB implements GhidraClass {
|
class GhidraClassDB implements GhidraClass {
|
||||||
private SymbolDB symbol;
|
private ClassSymbol symbol;
|
||||||
private NamespaceManager namespaceMgr;
|
private NamespaceManager namespaceMgr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,7 +35,7 @@ class GhidraClassDB implements GhidraClass {
|
||||||
* @param symbol the symbol for this GhidraClass
|
* @param symbol the symbol for this GhidraClass
|
||||||
* @param namespaceMgr the namespace manager
|
* @param namespaceMgr the namespace manager
|
||||||
*/
|
*/
|
||||||
GhidraClassDB(SymbolDB symbol, NamespaceManager namespaceMgr) {
|
GhidraClassDB(ClassSymbol symbol, NamespaceManager namespaceMgr) {
|
||||||
this.symbol = symbol;
|
this.symbol = symbol;
|
||||||
this.namespaceMgr = namespaceMgr;
|
this.namespaceMgr = namespaceMgr;
|
||||||
}
|
}
|
||||||
|
@ -126,8 +126,8 @@ class GhidraClassDB implements GhidraClass {
|
||||||
* @see ghidra.program.model.symbol.Namespace#setParentNamespace(ghidra.program.model.symbol.Namespace)
|
* @see ghidra.program.model.symbol.Namespace#setParentNamespace(ghidra.program.model.symbol.Namespace)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setParentNamespace(Namespace parentNamespace) throws DuplicateNameException,
|
public void setParentNamespace(Namespace parentNamespace)
|
||||||
InvalidInputException, CircularDependencyException {
|
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||||
symbol.setNamespace(parentNamespace);
|
symbol.setNamespace(parentNamespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class GlobalVariableSymbolDB extends VariableSymbolDB {
|
||||||
VariableStorageManagerDB variableMgr, Address address, DBRecord record) {
|
VariableStorageManagerDB variableMgr, Address address, DBRecord record) {
|
||||||
super(symbolMgr, cache, SymbolType.GLOBAL_VAR, variableMgr, address, record);
|
super(symbolMgr, cache, SymbolType.GLOBAL_VAR, variableMgr, address, record);
|
||||||
if (record.getLongValue(
|
if (record.getLongValue(
|
||||||
SymbolDatabaseAdapter.SYMBOL_PARENT_COL) != Namespace.GLOBAL_NAMESPACE_ID) {
|
SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL) != Namespace.GLOBAL_NAMESPACE_ID) {
|
||||||
throw new AssertException();
|
throw new AssertException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,15 +57,8 @@ public class GlobalVariableSymbolDB extends VariableSymbolDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Variable getObject() {
|
||||||
if (!checkIsValid()) {
|
throw new UnsupportedOperationException();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
VariableStorage storage = getVariableStorage();
|
|
||||||
if (storage == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return storage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
* Object to represent an external library.
|
* Object to represent an external library.
|
||||||
*/
|
*/
|
||||||
class LibraryDB implements Library {
|
class LibraryDB implements Library {
|
||||||
private SymbolDB symbol;
|
private LibrarySymbol symbol;
|
||||||
private NamespaceManager namespaceMgr;
|
private NamespaceManager namespaceMgr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,62 +35,46 @@ class LibraryDB implements Library {
|
||||||
* @param symbol the library symbol.
|
* @param symbol the library symbol.
|
||||||
* @param namespaceMgr the namespace manager
|
* @param namespaceMgr the namespace manager
|
||||||
*/
|
*/
|
||||||
LibraryDB(SymbolDB symbol, NamespaceManager namespaceMgr) {
|
LibraryDB(LibrarySymbol symbol, NamespaceManager namespaceMgr) {
|
||||||
this.symbol = symbol;
|
this.symbol = symbol;
|
||||||
this.namespaceMgr = namespaceMgr;
|
this.namespaceMgr = namespaceMgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getSymbol()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol getSymbol() {
|
public Symbol getSymbol() {
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getName()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return symbol.getName();
|
return symbol.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getID()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public long getID() {
|
public long getID() {
|
||||||
return symbol.getID();
|
return symbol.getID();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getParentNamespace()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Namespace getParentNamespace() {
|
public Namespace getParentNamespace() {
|
||||||
return symbol.getParentNamespace();
|
return symbol.getParentNamespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getBody()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSetView getBody() {
|
public AddressSetView getBody() {
|
||||||
return namespaceMgr.getAddressSet(this);
|
return namespaceMgr.getAddressSet(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getName(boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getName(boolean includeNamespacePath) {
|
public String getName(boolean includeNamespacePath) {
|
||||||
return symbol.getName(includeNamespacePath);
|
return symbol.getName(includeNamespacePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @see java.lang.Object#equals(java.lang.Object)
|
public int hashCode() {
|
||||||
*/
|
return symbol.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
|
@ -104,18 +88,15 @@ class LibraryDB implements Library {
|
||||||
return symbol == lib.symbol;
|
return symbol == lib.symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#setParentNamespace(ghidra.program.model.symbol.Namespace)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setParentNamespace(Namespace parentNamespace) throws DuplicateNameException,
|
public void setParentNamespace(Namespace parentNamespace)
|
||||||
InvalidInputException, CircularDependencyException {
|
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||||
symbol.setNamespace(parentNamespace);
|
symbol.setNamespace(parentNamespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAssociatedProgramPath() {
|
public String getAssociatedProgramPath() {
|
||||||
return symbol.getSymbolStringData();
|
return symbol.getExternalLibraryPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -40,13 +40,10 @@ public class LibrarySymbol extends SymbolDB {
|
||||||
* Constructs a new Library Symbol
|
* Constructs a new Library Symbol
|
||||||
* @param symbolMgr the symbol manager
|
* @param symbolMgr the symbol manager
|
||||||
* @param cache symbol object cache
|
* @param cache symbol object cache
|
||||||
* @param address the address for this symbol
|
|
||||||
* @param record the record for this symbol
|
* @param record the record for this symbol
|
||||||
*/
|
*/
|
||||||
public LibrarySymbol(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache, Address address,
|
public LibrarySymbol(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache, DBRecord record) {
|
||||||
DBRecord record) {
|
super(symbolMgr, cache, Address.NO_ADDRESS, record);
|
||||||
super(symbolMgr, cache, address, record);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -81,16 +78,6 @@ public class LibrarySymbol extends SymbolDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSymbolStringData(String newPath) {
|
|
||||||
String oldPath = getSymbolStringData();
|
|
||||||
|
|
||||||
super.setSymbolStringData(newPath);
|
|
||||||
|
|
||||||
symbolMgr.getProgram()
|
|
||||||
.setObjChanged(ProgramEvent.EXTERNAL_PATH_CHANGED, getName(), oldPath, newPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolType getSymbolType() {
|
public SymbolType getSymbolType() {
|
||||||
return SymbolType.LIBRARY;
|
return SymbolType.LIBRARY;
|
||||||
|
@ -102,12 +89,21 @@ public class LibrarySymbol extends SymbolDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Library getObject() {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
if (!checkIsValid()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (library == null) {
|
if (library == null) {
|
||||||
library = new LibraryDB(this, symbolMgr.getProgram().getNamespaceManager());
|
library = new LibraryDB(this, symbolMgr.getProgram().getNamespaceManager());
|
||||||
}
|
}
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPrimary() {
|
public boolean isPrimary() {
|
||||||
|
@ -119,4 +115,38 @@ public class LibrarySymbol extends SymbolDB {
|
||||||
return super.isValidParent(parent) &&
|
return super.isValidParent(parent) &&
|
||||||
SymbolType.LIBRARY.isValidParent(symbolMgr.getProgram(), parent, address, isExternal());
|
SymbolType.LIBRARY.isValidParent(symbolMgr.getProgram(), parent, address, isExternal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the library program path within the project (may be null)}
|
||||||
|
*/
|
||||||
|
public String getExternalLibraryPath() {
|
||||||
|
validate(lock);
|
||||||
|
return record.getString(SymbolDatabaseAdapter.SYMBOL_LIBPATH_COL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the library program path within the project.
|
||||||
|
* @param libraryPath library program path or null to clear
|
||||||
|
*/
|
||||||
|
public void setExternalLibraryPath(String libraryPath) {
|
||||||
|
|
||||||
|
String oldPath = getExternalLibraryPath();
|
||||||
|
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkDeleted();
|
||||||
|
setRecordFields(record, libraryPath);
|
||||||
|
updateRecord();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
symbolMgr.getProgram()
|
||||||
|
.setObjChanged(ProgramEvent.EXTERNAL_PATH_CHANGED, getName(), oldPath, libraryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setRecordFields(DBRecord record, String libraryPath) {
|
||||||
|
record.setString(SymbolDatabaseAdapter.SYMBOL_LIBPATH_COL, libraryPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,437 @@
|
||||||
|
/* ###
|
||||||
|
* 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.util.ArrayList;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import db.DBRecord;
|
||||||
|
import ghidra.program.database.DBObjectCache;
|
||||||
|
import ghidra.program.database.external.ExternalLocationDB;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.symbol.*;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
import ghidra.util.task.UnknownProgressWrappingTaskMonitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link MemorySymbol} corresponds to any symbol that resides at a memory location.
|
||||||
|
* The corresponding address may be either a {@link Address#isMemoryAddress() memory address}
|
||||||
|
* or a fake {@link Address#isExternalAddress() external address}. While an external address is
|
||||||
|
* not a memory address it corresponds to an {@link ExternalLocation} which may identify a
|
||||||
|
* specific memory address if known.
|
||||||
|
*/
|
||||||
|
public abstract class MemorySymbol extends SymbolDB {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new MemorySymbol which corresponds to the specified symbol record,
|
||||||
|
* @param mgr the symbol manager
|
||||||
|
* @param cache symbol object cache
|
||||||
|
* @param addr the address associated with the symbol
|
||||||
|
* @param record the record for this symbol
|
||||||
|
*/
|
||||||
|
protected MemorySymbol(SymbolManager mgr, DBObjectCache<SymbolDB> cache, Address addr,
|
||||||
|
DBRecord record) {
|
||||||
|
super(mgr, cache, addr, record);
|
||||||
|
if (!addr.isMemoryAddress() && !isExternal()) {
|
||||||
|
throw new IllegalArgumentException("memory or external address required");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new MemorySymbol which corresponds to the specified symbol key and has
|
||||||
|
* no record. This is intended to support dynamic label cases which do not have a record
|
||||||
|
* and do not support an external address.
|
||||||
|
* @param mgr the symbol manager
|
||||||
|
* @param cache symbol object cache
|
||||||
|
* @param addr the address associated with the symbol
|
||||||
|
* @param key this must be the absolute encoding of addr
|
||||||
|
*/
|
||||||
|
protected MemorySymbol(SymbolManager mgr, DBObjectCache<SymbolDB> cache, Address addr,
|
||||||
|
long key) {
|
||||||
|
super(mgr, cache, addr, key);
|
||||||
|
if (!addr.isMemoryAddress()) {
|
||||||
|
throw new IllegalArgumentException("memory address required");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isExternalEntryPoint() {
|
||||||
|
validate(lock);
|
||||||
|
return symbolMgr.isExternalEntryPoint(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isExternal() {
|
||||||
|
return address.isExternalAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isPinned() {
|
||||||
|
if (!isExternal()) {
|
||||||
|
return doIsPinned();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void setPinned(boolean pinned) {
|
||||||
|
if (!isExternal()) {
|
||||||
|
doSetPinned(pinned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean doIsPinned() {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkIsValid();
|
||||||
|
if (record == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
||||||
|
return ((flags & SymbolDatabaseAdapter.SYMBOL_PINNED_FLAG) != 0);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSetPinned(boolean pinned) {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkDeleted();
|
||||||
|
if (pinned == isPinned()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (record != null) {
|
||||||
|
updatePinnedFlag(pinned);
|
||||||
|
updateRecord();
|
||||||
|
symbolMgr.symbolAnchoredFlagChanged(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePinnedFlag(boolean pinned) {
|
||||||
|
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
||||||
|
if (pinned) {
|
||||||
|
flags |= SymbolDatabaseAdapter.SYMBOL_PINNED_FLAG;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
flags &= ~SymbolDatabaseAdapter.SYMBOL_PINNED_FLAG;
|
||||||
|
}
|
||||||
|
record.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* low level record adjustment to move a symbol. Used only when moving a memory block or
|
||||||
|
* changing the image base.
|
||||||
|
*
|
||||||
|
* @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 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();
|
||||||
|
|
||||||
|
// 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 (newNamespace != null) {
|
||||||
|
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL,
|
||||||
|
newNamespace.getID());
|
||||||
|
}
|
||||||
|
if (newSource != null) {
|
||||||
|
setSourceFlagBit(newSource);
|
||||||
|
}
|
||||||
|
updatePinnedFlag(pinned);
|
||||||
|
updateRecord();
|
||||||
|
setInvalid();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasExactlyOneSymbolAtAddress(Address addr) {
|
||||||
|
SymbolIterator it = symbolMgr.getSymbolsAsIterator(addr);
|
||||||
|
if (!it.hasNext()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
it.next();
|
||||||
|
return !it.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getReferenceCount() {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkIsValid();
|
||||||
|
ReferenceManager rm = symbolMgr.getReferenceManager();
|
||||||
|
|
||||||
|
// If there is only one symbol, then all the references to this address count
|
||||||
|
if (address.isExternalAddress() || hasExactlyOneSymbolAtAddress(address)) {
|
||||||
|
return rm.getReferenceCountTo(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// search through references and see which ones apply specifically to this symbol
|
||||||
|
ReferenceIterator iter = rm.getReferencesTo(address);
|
||||||
|
int count = 0;
|
||||||
|
boolean isPrimary = this.isPrimary();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Reference ref = iter.next();
|
||||||
|
long symbolID = ref.getSymbolID();
|
||||||
|
// references refer to me if it matches my key or I'm primary and it doesn't
|
||||||
|
// specify a specific symbol id
|
||||||
|
if (symbolID == key || (isPrimary && symbolID < 0)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasReferences() {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkIsValid();
|
||||||
|
ReferenceManager rm = symbolMgr.getReferenceManager();
|
||||||
|
ReferenceIterator iter = rm.getReferencesTo(address);
|
||||||
|
boolean isPrimary = this.isPrimary();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Reference ref = iter.next();
|
||||||
|
long symbolID = ref.getSymbolID();
|
||||||
|
if (symbolID == key || (isPrimary && symbolID < 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Reference[] getReferences(TaskMonitor monitor) {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkIsValid();
|
||||||
|
if (monitor == null) {
|
||||||
|
monitor = TaskMonitor.DUMMY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitor.getMaximum() == 0) {
|
||||||
|
// If the monitor has not been initialized, then the progress will not correctly
|
||||||
|
// display anything as setProgress() is called below. We can't know what to
|
||||||
|
// initialize to without counting all the references, which is as much work as
|
||||||
|
// this method.
|
||||||
|
monitor = new UnknownProgressWrappingTaskMonitor(monitor, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReferenceManager rm = symbolMgr.getReferenceManager();
|
||||||
|
ReferenceIterator iter = rm.getReferencesTo(address);
|
||||||
|
boolean isPrimary = this.isPrimary();
|
||||||
|
ArrayList<Reference> list = new ArrayList<>();
|
||||||
|
int cnt = 0;
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
if (monitor.isCancelled()) {
|
||||||
|
break; // return partial list
|
||||||
|
}
|
||||||
|
Reference ref = iter.next();
|
||||||
|
long symbolID = ref.getSymbolID();
|
||||||
|
if (symbolID == key || (isPrimary && symbolID < 0)) {
|
||||||
|
list.add(ref);
|
||||||
|
monitor.setProgress(cnt++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference[] refs = new Reference[list.size()];
|
||||||
|
return list.toArray(refs);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the optional field which is intended to store the original mangled name for an external
|
||||||
|
* {@link SymbolType#LABEL} or {@link SymbolType#FUNCTION} which has an
|
||||||
|
* {@link Address#isExternalAddress() external address}. These symbol types correspond
|
||||||
|
* to {@link CodeSymbol} and {@link FunctionSymbol} DB symbol implementations respectively.
|
||||||
|
* This is generally set when an {@link ExternalLocationDB} is renamed which generally
|
||||||
|
* corresponds the external symbol being demangled.
|
||||||
|
*
|
||||||
|
* @return original imported external name or null if not external or symbol has not been
|
||||||
|
* demangled or renamed.
|
||||||
|
*/
|
||||||
|
public final String getExternalOriginalImportedName() {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkIsValid();
|
||||||
|
if (record == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return record.getString(SymbolDatabaseAdapter.SYMBOL_ORIGINAL_IMPORTED_NAME_COL);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the symbol's original imported external name field for an external
|
||||||
|
* {@link SymbolType#LABEL} or {@link SymbolType#FUNCTION} which has an
|
||||||
|
* {@link Address#isExternalAddress() external address}. These symbol types correspond
|
||||||
|
* to {@link CodeSymbol} and {@link FunctionSymbol} DB symbol implementations respectively.
|
||||||
|
* This is generally set when an {@link ExternalLocationDB} is renamed which generally
|
||||||
|
* corresponds the external symbol being demangled.
|
||||||
|
*
|
||||||
|
* @param originalImportedName the original import name or null
|
||||||
|
* @param notify if true, a program change notification will be generated
|
||||||
|
* @throws UnsupportedOperationException if symbol is neither an external {@link SymbolType#LABEL}
|
||||||
|
* or {@link SymbolType#FUNCTION}.
|
||||||
|
*/
|
||||||
|
public final void setExternalOriginalImportedName(String originalImportedName, boolean notify) {
|
||||||
|
SymbolType type = getSymbolType();
|
||||||
|
if (!getAddress().isExternalAddress() ||
|
||||||
|
(type != SymbolType.LABEL && type != SymbolType.FUNCTION)) {
|
||||||
|
throw new javax.help.UnsupportedOperationException(
|
||||||
|
"Symbol does not support: originalImportedName");
|
||||||
|
}
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkDeleted();
|
||||||
|
if (record == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String oldData =
|
||||||
|
record.getString(SymbolDatabaseAdapter.SYMBOL_ORIGINAL_IMPORTED_NAME_COL);
|
||||||
|
if (!Objects.equals(originalImportedName, oldData)) {
|
||||||
|
record.setString(SymbolDatabaseAdapter.SYMBOL_ORIGINAL_IMPORTED_NAME_COL,
|
||||||
|
originalImportedName);
|
||||||
|
updateRecord();
|
||||||
|
if (notify) {
|
||||||
|
symbolMgr.symbolDataChanged(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the optional field which is intended to store the original mangled name for an external
|
||||||
|
* {@link SymbolType#LABEL} or {@link SymbolType#FUNCTION} which has an
|
||||||
|
* {@link Address#isExternalAddress() external address}. These symbol types correspond
|
||||||
|
* to {@link CodeSymbol} and {@link FunctionSymbol} DB symbol implementations respectively.
|
||||||
|
* This is generally set when an {@link ExternalLocationDB} is renamed which generally
|
||||||
|
* corresponds the external symbol being demangled.
|
||||||
|
*
|
||||||
|
* @return external Program address or null if not external or unknown
|
||||||
|
*/
|
||||||
|
public final Address getExternalProgramAddress() {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkIsValid();
|
||||||
|
if (record == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: String is used to avoid excessive AddressMap segmentation. This does
|
||||||
|
// prevent address space renaming as facilitated by Language upgrade and transition
|
||||||
|
// capabilities.
|
||||||
|
String addrStr = record.getString(SymbolDatabaseAdapter.SYMBOL_EXTERNAL_PROG_ADDR_COL);
|
||||||
|
if (addrStr == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return symbolMgr.getAddressMap().getAddressFactory().getAddress(addrStr);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the symbol's external Program Address field for an external
|
||||||
|
* {@link SymbolType#LABEL} or {@link SymbolType#FUNCTION} which has an
|
||||||
|
* {@link Address#isExternalAddress() external address}. These symbol types correspond
|
||||||
|
* to {@link CodeSymbol} and {@link FunctionSymbol} DB symbol implementations respectively.
|
||||||
|
*
|
||||||
|
* @param externalProgramAddress the external Program Address which corresponds to the
|
||||||
|
* externally linked location (may be null).
|
||||||
|
* @param notify if true, a program change notification will be generated
|
||||||
|
* @throws UnsupportedOperationException if symbol is neither an external {@link SymbolType#LABEL}
|
||||||
|
* or {@link SymbolType#FUNCTION}.
|
||||||
|
*/
|
||||||
|
public final void setExternalProgramAddress(Address externalProgramAddress, boolean notify) {
|
||||||
|
SymbolType type = getSymbolType();
|
||||||
|
if (!getAddress().isExternalAddress() ||
|
||||||
|
(type != SymbolType.LABEL && type != SymbolType.FUNCTION)) {
|
||||||
|
throw new javax.help.UnsupportedOperationException(
|
||||||
|
"Symbol does not support: external program address");
|
||||||
|
}
|
||||||
|
if (externalProgramAddress != null && !externalProgramAddress.isLoadedMemoryAddress()) {
|
||||||
|
throw new IllegalArgumentException("Memory address required for external program");
|
||||||
|
}
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkDeleted();
|
||||||
|
if (record == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String addrStr =
|
||||||
|
externalProgramAddress != null ? externalProgramAddress.toString() : null;
|
||||||
|
String oldData = record.getString(SymbolDatabaseAdapter.SYMBOL_EXTERNAL_PROG_ADDR_COL);
|
||||||
|
if (!Objects.equals(addrStr, oldData)) {
|
||||||
|
record.setString(SymbolDatabaseAdapter.SYMBOL_EXTERNAL_PROG_ADDR_COL, addrStr);
|
||||||
|
updateRecord();
|
||||||
|
if (notify) {
|
||||||
|
symbolMgr.symbolDataChanged(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setExternalFields(DBRecord record, String originalImportName,
|
||||||
|
Address externalProgramAddress) {
|
||||||
|
String addrStr = externalProgramAddress != null ? externalProgramAddress.toString() : null;
|
||||||
|
record.setString(SymbolDatabaseAdapter.SYMBOL_EXTERNAL_PROG_ADDR_COL, addrStr);
|
||||||
|
record.setString(SymbolDatabaseAdapter.SYMBOL_ORIGINAL_IMPORTED_NAME_COL,
|
||||||
|
originalImportName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class NamespaceDB implements Namespace {
|
class NamespaceDB implements Namespace {
|
||||||
private SymbolDB symbol;
|
private NamespaceSymbol symbol;
|
||||||
private NamespaceManager namespaceMgr;
|
private NamespaceManager namespaceMgr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,62 +36,46 @@ class NamespaceDB implements Namespace {
|
||||||
* @param symbol the symbol associated with this namespace.
|
* @param symbol the symbol associated with this namespace.
|
||||||
* @param namespaceMgr the namespace manager
|
* @param namespaceMgr the namespace manager
|
||||||
*/
|
*/
|
||||||
NamespaceDB(SymbolDB symbol, NamespaceManager namespaceMgr) {
|
NamespaceDB(NamespaceSymbol symbol, NamespaceManager namespaceMgr) {
|
||||||
this.symbol = symbol;
|
this.symbol = symbol;
|
||||||
this.namespaceMgr = namespaceMgr;
|
this.namespaceMgr = namespaceMgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getSymbol()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol getSymbol() {
|
public Symbol getSymbol() {
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getName()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return symbol.getName();
|
return symbol.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getID()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public long getID() {
|
public long getID() {
|
||||||
return symbol.getID();
|
return symbol.getID();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getParentNamespace()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Namespace getParentNamespace() {
|
public Namespace getParentNamespace() {
|
||||||
return symbol.getParentNamespace();
|
return symbol.getParentNamespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getBody()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSetView getBody() {
|
public AddressSetView getBody() {
|
||||||
return namespaceMgr.getAddressSet(this);
|
return namespaceMgr.getAddressSet(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#getName(boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String getName(boolean includeNamespacePath) {
|
public String getName(boolean includeNamespacePath) {
|
||||||
return symbol.getName(includeNamespacePath);
|
return symbol.getName(includeNamespacePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @see java.lang.Object#equals(java.lang.Object)
|
public int hashCode() {
|
||||||
*/
|
return symbol.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
|
@ -105,18 +89,12 @@ class NamespaceDB implements Namespace {
|
||||||
return symbol == nameSpace.symbol;
|
return symbol == nameSpace.symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Namespace#setParentNamespace(ghidra.program.model.symbol.Namespace)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setParentNamespace(Namespace parentNamespace) throws DuplicateNameException,
|
public void setParentNamespace(Namespace parentNamespace)
|
||||||
InvalidInputException, CircularDependencyException {
|
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||||
symbol.setNamespace(parentNamespace);
|
symbol.setNamespace(parentNamespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see java.lang.Object#toString()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getName(true);
|
return getName(true);
|
||||||
|
|
|
@ -31,12 +31,10 @@ public class NamespaceSymbol extends SymbolDB {
|
||||||
* Construct a new namespace symbol
|
* Construct a new namespace symbol
|
||||||
* @param mgr the symbol manager.
|
* @param mgr the symbol manager.
|
||||||
* @param cache symbol object cache
|
* @param cache symbol object cache
|
||||||
* @param addr the address for this symbol.
|
|
||||||
* @param record the record for this symbol.
|
* @param record the record for this symbol.
|
||||||
*/
|
*/
|
||||||
NamespaceSymbol(SymbolManager mgr, DBObjectCache<SymbolDB> cache, Address addr,
|
NamespaceSymbol(SymbolManager mgr, DBObjectCache<SymbolDB> cache, DBRecord record) {
|
||||||
DBRecord record) {
|
super(mgr, cache, Address.NO_ADDRESS, record);
|
||||||
super(mgr, cache, addr, record);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,16 +54,21 @@ public class NamespaceSymbol extends SymbolDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Namespace getObject() {
|
||||||
return getNamespace();
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
if (!checkIsValid()) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Namespace getNamespace() {
|
|
||||||
if (namespace == null) {
|
if (namespace == null) {
|
||||||
namespace = new NamespaceDB(this, symbolMgr.getProgram().getNamespaceManager());
|
namespace = new NamespaceDB(this, symbolMgr.getProgram().getNamespaceManager());
|
||||||
}
|
}
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidParent(Namespace parent) {
|
public boolean isValidParent(Namespace parent) {
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
package ghidra.program.database.symbol;
|
package ghidra.program.database.symbol;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import db.DBRecord;
|
import db.DBRecord;
|
||||||
import db.Field;
|
import db.Field;
|
||||||
|
@ -34,16 +35,15 @@ import ghidra.util.Lock;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
import ghidra.util.task.UnknownProgressWrappingTaskMonitor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for symbols
|
* Base class for symbols
|
||||||
*/
|
*/
|
||||||
public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
private DBRecord record;
|
|
||||||
private boolean isDeleting = false;
|
private boolean isDeleting = false;
|
||||||
|
|
||||||
|
protected DBRecord record;
|
||||||
protected Address address;
|
protected Address address;
|
||||||
protected SymbolManager symbolMgr;
|
protected SymbolManager symbolMgr;
|
||||||
protected Lock lock;
|
protected Lock lock;
|
||||||
|
@ -132,48 +132,6 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
addr);
|
addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* low level record adjustment to move a symbol. Used only when moving a memory block or
|
|
||||||
* changing the image base.
|
|
||||||
*
|
|
||||||
* @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 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();
|
|
||||||
|
|
||||||
// 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 (newNamespace != null) {
|
|
||||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, newNamespace.getID());
|
|
||||||
}
|
|
||||||
if (newSource != null) {
|
|
||||||
setSourceFlagBit(newSource);
|
|
||||||
}
|
|
||||||
updatePinnedFlag(pinned);
|
|
||||||
updateRecord();
|
|
||||||
setInvalid();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final String getName() {
|
public final String getName() {
|
||||||
String name = cachedName;
|
String name = cachedName;
|
||||||
|
@ -266,158 +224,11 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getReferenceCount() {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
ReferenceManager rm = symbolMgr.getReferenceManager();
|
|
||||||
|
|
||||||
// if there is only one symbol, then all the references to this address count
|
|
||||||
if (hasExactlyOneSymbolAtAddress(address)) {
|
|
||||||
return rm.getReferenceCountTo(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
// search through references and see which ones apply specifically to this symbol
|
|
||||||
ReferenceIterator iter = rm.getReferencesTo(address);
|
|
||||||
int count = 0;
|
|
||||||
boolean isPrimary = this.isPrimary();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Reference ref = iter.next();
|
|
||||||
long symbolID = ref.getSymbolID();
|
|
||||||
// references refer to me if it matches my key or I'm primary and it doesn't
|
|
||||||
// specify a specific symbol id
|
|
||||||
if (symbolID == key || (isPrimary && symbolID < 0)) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasExactlyOneSymbolAtAddress(Address addr) {
|
|
||||||
SymbolIterator it = symbolMgr.getSymbolsAsIterator(addr);
|
|
||||||
if (!it.hasNext()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
it.next();
|
|
||||||
return !it.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Reference[] getReferences(TaskMonitor monitor) {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
if (monitor == null) {
|
|
||||||
monitor = TaskMonitor.DUMMY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monitor.getMaximum() == 0) {
|
|
||||||
// If the monitor has not been initialized, then the progress will not correctly
|
|
||||||
// display anything as setProgress() is called below. We can't know what to
|
|
||||||
// initialize to without counting all the references, which is as much work as
|
|
||||||
// this method.
|
|
||||||
monitor = new UnknownProgressWrappingTaskMonitor(monitor, 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReferenceManager rm = symbolMgr.getReferenceManager();
|
|
||||||
ReferenceIterator iter = rm.getReferencesTo(address);
|
|
||||||
boolean isPrimary = this.isPrimary();
|
|
||||||
ArrayList<Reference> list = new ArrayList<>();
|
|
||||||
int cnt = 0;
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
if (monitor.isCancelled()) {
|
|
||||||
break; // return partial list
|
|
||||||
}
|
|
||||||
Reference ref = iter.next();
|
|
||||||
long symbolID = ref.getSymbolID();
|
|
||||||
if (symbolID == key || (isPrimary && symbolID < 0)) {
|
|
||||||
list.add(ref);
|
|
||||||
monitor.setProgress(cnt++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference[] refs = new Reference[list.size()];
|
|
||||||
return list.toArray(refs);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Reference[] getReferences() {
|
|
||||||
return getReferences(TaskMonitor.DUMMY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasMultipleReferences() {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
ReferenceManager rm = symbolMgr.getReferenceManager();
|
|
||||||
ReferenceIterator iter = rm.getReferencesTo(address);
|
|
||||||
boolean isPrimary = this.isPrimary();
|
|
||||||
int count = 0;
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Reference ref = iter.next();
|
|
||||||
long symbolID = ref.getSymbolID();
|
|
||||||
if (symbolID == key || (isPrimary && symbolID < 0)) {
|
|
||||||
count++;
|
|
||||||
if (count > 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasReferences() {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
ReferenceManager rm = symbolMgr.getReferenceManager();
|
|
||||||
ReferenceIterator iter = rm.getReferencesTo(address);
|
|
||||||
boolean isPrimary = this.isPrimary();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Reference ref = iter.next();
|
|
||||||
long symbolID = ref.getSymbolID();
|
|
||||||
if (symbolID == key || (isPrimary && symbolID < 0)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDynamic() {
|
public boolean isDynamic() {
|
||||||
return (record == null);
|
return (record == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isExternalEntryPoint() {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
return symbolMgr.isExternalEntryPoint(address);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract boolean isPrimary();
|
public abstract boolean isPrimary();
|
||||||
|
|
||||||
|
@ -452,7 +263,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSourceFlagBit(SourceType newSource) {
|
protected void setSourceFlagBit(SourceType newSource) {
|
||||||
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
||||||
byte clearBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
|
byte clearBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
|
||||||
byte setBits = (byte) newSource.ordinal();
|
byte setBits = (byte) newSource.ordinal();
|
||||||
|
@ -479,60 +290,6 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPinned() {
|
|
||||||
return false; //most symbols can't be pinned.
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean doIsPinned() {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
if (record == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
|
||||||
return ((flags & SymbolDatabaseAdapter.SYMBOL_PINNED_FLAG) != 0);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPinned(boolean pinned) {
|
|
||||||
throw new UnsupportedOperationException("Only Code and Function Symbols may be pinned.");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void doSetPinned(boolean pinned) {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkDeleted();
|
|
||||||
if (pinned == isPinned()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (record != null) {
|
|
||||||
updatePinnedFlag(pinned);
|
|
||||||
updateRecord();
|
|
||||||
symbolMgr.symbolAnchoredFlagChanged(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatePinnedFlag(boolean pinned) {
|
|
||||||
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
|
||||||
if (pinned) {
|
|
||||||
flags |= SymbolDatabaseAdapter.SYMBOL_PINNED_FLAG;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
flags &= ~SymbolDatabaseAdapter.SYMBOL_PINNED_FLAG;
|
|
||||||
}
|
|
||||||
record.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setName(String newName, SourceType source)
|
public void setName(String newName, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException {
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
@ -626,7 +383,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, newNamespace.getID());
|
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL,
|
||||||
|
newNamespace.getID());
|
||||||
record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName);
|
record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName);
|
||||||
updateSymbolSource(record, source);
|
updateSymbolSource(record, source);
|
||||||
updateRecord();
|
updateRecord();
|
||||||
|
@ -750,7 +508,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
return (int) key;
|
return (int) key;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateRecord() {
|
protected void updateRecord() {
|
||||||
try {
|
try {
|
||||||
symbolMgr.getDatabaseAdapter().updateSymbolRecord(record);
|
symbolMgr.getDatabaseAdapter().updateSymbolRecord(record);
|
||||||
}
|
}
|
||||||
|
@ -781,7 +539,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return symbolMgr
|
return symbolMgr
|
||||||
.getSymbol(record.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL));
|
.getSymbol(record.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL));
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
|
@ -795,7 +553,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
if (record == null) {
|
if (record == null) {
|
||||||
return Namespace.GLOBAL_NAMESPACE_ID;
|
return Namespace.GLOBAL_NAMESPACE_ID;
|
||||||
}
|
}
|
||||||
return record.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL);
|
return record.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
|
@ -811,51 +569,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return record.getLongValue(
|
return record.getLongValue(
|
||||||
SymbolDatabaseAdapter.SYMBOL_PARENT_COL) == Namespace.GLOBAL_NAMESPACE_ID;
|
SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL) == Namespace.GLOBAL_NAMESPACE_ID;
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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_STRING_DATA_COL);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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_STRING_DATA_COL);
|
|
||||||
if (Objects.equals(stringData, oldData)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
record.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL, stringData);
|
|
||||||
updateRecord();
|
|
||||||
symbolMgr.symbolDataChanged(this);
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
|
@ -863,22 +577,14 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getDataTypeId() {
|
public long getDataTypeId() {
|
||||||
lock.acquire();
|
validate(lock);
|
||||||
try {
|
// record always present when use of datatype ID is supported (i.e., external location)
|
||||||
checkIsValid();
|
|
||||||
if (record != null) {
|
|
||||||
Field value = record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
Field value = record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||||
if (value.isNull()) {
|
if (value.isNull()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return value.getLongValue();
|
return value.getLongValue();
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the generic symbol data 1.
|
* Sets the generic symbol data 1.
|
||||||
|
@ -899,44 +605,6 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gets the generic symbol data 2 data.
|
|
||||||
* @return the symbol data
|
|
||||||
*/
|
|
||||||
protected int getVariableOffset() {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkIsValid();
|
|
||||||
if (record != null) {
|
|
||||||
return record.getIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 setVariableOffset(int offset) {
|
|
||||||
lock.acquire();
|
|
||||||
try {
|
|
||||||
checkDeleted();
|
|
||||||
if (record != null) {
|
|
||||||
record.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, offset);
|
|
||||||
updateRecord();
|
|
||||||
symbolMgr.symbolDataChanged(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
lock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void doSetPrimary(boolean primary) {
|
protected void doSetPrimary(boolean primary) {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
|
@ -1023,4 +691,5 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
this.record = record;
|
this.record = record;
|
||||||
keyChanged(record.getKey());
|
keyChanged(record.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,24 +39,37 @@ abstract class SymbolDatabaseAdapter {
|
||||||
|
|
||||||
static final int SYMBOL_NAME_COL = 0;
|
static final int SYMBOL_NAME_COL = 0;
|
||||||
static final int SYMBOL_ADDR_COL = 1;
|
static final int SYMBOL_ADDR_COL = 1;
|
||||||
static final int SYMBOL_PARENT_COL = 2;
|
static final int SYMBOL_PARENT_ID_COL = 2;
|
||||||
static final int SYMBOL_TYPE_COL = 3;
|
static final int SYMBOL_TYPE_COL = 3;
|
||||||
static final int SYMBOL_STRING_DATA_COL = 4;
|
static final int SYMBOL_FLAGS_COL = 4;
|
||||||
static final int SYMBOL_FLAGS_COL = 5;
|
|
||||||
|
|
||||||
// sparse fields - the following fields are not always applicable so they are optional and
|
// 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.
|
// don't consume space in the database if they aren't used.
|
||||||
static final int SYMBOL_HASH_COL = 6;
|
static final int SYMBOL_HASH_COL = 5;
|
||||||
static final int SYMBOL_PRIMARY_COL = 7;
|
static final int SYMBOL_PRIMARY_COL = 6;
|
||||||
static final int SYMBOL_DATATYPE_COL = 8;
|
static final int SYMBOL_DATATYPE_COL = 7;
|
||||||
static final int SYMBOL_VAROFFSET_COL = 9;
|
static final int SYMBOL_VAROFFSET_COL = 8;
|
||||||
|
static final int SYMBOL_ORIGINAL_IMPORTED_NAME_COL = 9;
|
||||||
|
static final int SYMBOL_EXTERNAL_PROG_ADDR_COL = 10;
|
||||||
|
static final int SYMBOL_COMMENT_COL = 11;
|
||||||
|
static final int SYMBOL_LIBPATH_COL = 12;
|
||||||
|
|
||||||
static final Schema SYMBOL_SCHEMA = SymbolDatabaseAdapterV3.V3_SYMBOL_SCHEMA;
|
static final Schema SYMBOL_SCHEMA = SymbolDatabaseAdapterV4.V4_SYMBOL_SCHEMA;
|
||||||
|
|
||||||
// Bits 0 & 1 are used for the source of the symbol.
|
// Bits 0 & 1 are used for the source of the symbol.
|
||||||
static final byte SYMBOL_SOURCE_BITS = (byte) 0x3;
|
static final byte SYMBOL_SOURCE_BITS = (byte) 0x3;
|
||||||
static final byte SYMBOL_PINNED_FLAG = (byte) 0x4; // Bit 2 is flag for "anchored to address".
|
static final byte SYMBOL_PINNED_FLAG = (byte) 0x4; // Bit 2 is flag for "anchored to address".
|
||||||
|
|
||||||
|
// Symbol type constants
|
||||||
|
static final int SYMBOL_TYPE_LABEL = SymbolType.LABEL.getID();
|
||||||
|
static final int SYMBOL_TYPE_LIBRARY = SymbolType.LIBRARY.getID();
|
||||||
|
static final int SYMBOL_TYPE_NAMESPACE = SymbolType.NAMESPACE.getID();
|
||||||
|
static final int SYMBOL_TYPE_CLASS = SymbolType.CLASS.getID();
|
||||||
|
static final int SYMBOL_TYPE_FUNCTION = SymbolType.FUNCTION.getID();
|
||||||
|
static final int SYMBOL_TYPE_PARAMETER = SymbolType.PARAMETER.getID();
|
||||||
|
static final int SYMBOL_TYPE_LOCAL_VAR = SymbolType.LOCAL_VAR.getID();
|
||||||
|
static final int SYMBOL_TYPE_GLOBAL_VAR = SymbolType.GLOBAL_VAR.getID();
|
||||||
|
|
||||||
// TODO: NEXT UPGRADE: remove all variable/parameter symbols with NO_ADDRESS
|
// TODO: NEXT UPGRADE: remove all variable/parameter symbols with NO_ADDRESS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,11 +88,11 @@ abstract class SymbolDatabaseAdapter {
|
||||||
throws VersionException, CancelledException, IOException {
|
throws VersionException, CancelledException, IOException {
|
||||||
|
|
||||||
if (openMode == OpenMode.CREATE) {
|
if (openMode == OpenMode.CREATE) {
|
||||||
return new SymbolDatabaseAdapterV3(dbHandle, addrMap, true);
|
return new SymbolDatabaseAdapterV4(dbHandle, addrMap, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV3(dbHandle, addrMap, false);
|
SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV4(dbHandle, addrMap, false);
|
||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
catch (VersionException e) {
|
catch (VersionException e) {
|
||||||
|
@ -99,26 +112,33 @@ abstract class SymbolDatabaseAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SymbolDatabaseAdapter findReadOnlyAdapter(DBHandle handle, AddressMap addrMap)
|
private static SymbolDatabaseAdapter findReadOnlyAdapter(DBHandle handle, AddressMap addrMap)
|
||||||
throws VersionException, IOException {
|
throws VersionException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new SymbolDatabaseAdapterV3(handle, addrMap.getOldAddressMap());
|
||||||
|
}
|
||||||
|
catch (VersionException e) {
|
||||||
|
// failed try older version
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap());
|
return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap());
|
||||||
}
|
}
|
||||||
catch (VersionException e1) {
|
catch (VersionException e) {
|
||||||
// failed try older version
|
// failed try older version
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new SymbolDatabaseAdapterV1(handle, addrMap.getOldAddressMap());
|
return new SymbolDatabaseAdapterV1(handle, addrMap.getOldAddressMap());
|
||||||
}
|
}
|
||||||
catch (VersionException e1) {
|
catch (VersionException e) {
|
||||||
// failed try older version
|
// failed try older version
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new SymbolDatabaseAdapterV0(handle, addrMap.getOldAddressMap());
|
return new SymbolDatabaseAdapterV0(handle, addrMap.getOldAddressMap());
|
||||||
}
|
}
|
||||||
catch (VersionException e1) {
|
catch (VersionException e) {
|
||||||
// failed - can't handle whatever version this is trying to open
|
// failed - can't handle whatever version this is trying to open
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +160,7 @@ abstract class SymbolDatabaseAdapter {
|
||||||
|
|
||||||
dbHandle.deleteTable(SYMBOL_TABLE_NAME);
|
dbHandle.deleteTable(SYMBOL_TABLE_NAME);
|
||||||
|
|
||||||
SymbolDatabaseAdapter newAdapter = new SymbolDatabaseAdapterV3(dbHandle, addrMap, true);
|
SymbolDatabaseAdapter newAdapter = new SymbolDatabaseAdapterV4(dbHandle, addrMap, true);
|
||||||
|
|
||||||
copyTempToNewAdapter(tmpAdapter, newAdapter, monitor);
|
copyTempToNewAdapter(tmpAdapter, newAdapter, monitor);
|
||||||
return newAdapter;
|
return newAdapter;
|
||||||
|
@ -166,7 +186,7 @@ abstract class SymbolDatabaseAdapter {
|
||||||
((SymbolDatabaseAdapterV0) oldAdapter).extractLocalSymbols(tmpHandle, monitor);
|
((SymbolDatabaseAdapterV0) oldAdapter).extractLocalSymbols(tmpHandle, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolDatabaseAdapterV3 tmpAdapter = new SymbolDatabaseAdapterV3(tmpHandle, addrMap, true);
|
SymbolDatabaseAdapterV4 tmpAdapter = new SymbolDatabaseAdapterV4(tmpHandle, addrMap, true);
|
||||||
RecordIterator iter = oldAdapter.getSymbols();
|
RecordIterator iter = oldAdapter.getSymbols();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
@ -200,26 +220,22 @@ abstract class SymbolDatabaseAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new symbol
|
* Instantiate a new basic symbol record. Caller is responsible for updating any related
|
||||||
|
* optional record fields and then adding to the table via the
|
||||||
|
* {@link #updateSymbolRecord(DBRecord)} method.
|
||||||
|
*
|
||||||
* @param name name of the symbol
|
* @param name name of the symbol
|
||||||
* @param address the address for the symbol
|
|
||||||
* @param namespaceID the id of the containing namespace symbol
|
* @param namespaceID the id of the containing namespace symbol
|
||||||
|
* @param address the address for the symbol
|
||||||
* @param symbolType the type of this symbol
|
* @param symbolType the type of this symbol
|
||||||
* @param stringData place to store a String value that depends on the symbol type
|
* @param isPrimary if true, symbol record will be tagged as primary (relavent for label and
|
||||||
|
* function symbols only).
|
||||||
* @param source the source type of this symbol
|
* @param source the source type of this symbol
|
||||||
* Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT
|
* 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
|
* @return new symbol record (not yet added to symbol table)
|
||||||
* @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
|
|
||||||
*/
|
*/
|
||||||
abstract DBRecord createSymbol(String name, Address address, long namespaceID,
|
abstract DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||||
SymbolType symbolType, String stringData, Long dataTypeId, Integer varOffset,
|
SymbolType symbolType, boolean isPrimary, SourceType source);
|
||||||
SourceType source, boolean isPrimary) throws IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the record with the given symbol ID
|
* Get the record with the given symbol ID
|
||||||
|
@ -372,10 +388,29 @@ abstract class SymbolDatabaseAdapter {
|
||||||
* This only includes memory-based stored symbols.
|
* This only includes memory-based stored symbols.
|
||||||
*
|
*
|
||||||
* @param startName the starting name to search
|
* @param startName the starting name to search
|
||||||
|
* @return a symbol record iterator over the symbols
|
||||||
* @throws IOException if a database io error occurs
|
* @throws IOException if a database io error occurs
|
||||||
*/
|
*/
|
||||||
abstract RecordIterator scanSymbolsByName(String startName) throws IOException;
|
abstract RecordIterator scanSymbolsByName(String startName) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get symbol records which match the specified external original import name.
|
||||||
|
* @param extLabel external import name label
|
||||||
|
* @return matching external symbol records (forward iteration only, delete not supported)
|
||||||
|
* @throws IOException if a database io error occurs
|
||||||
|
*/
|
||||||
|
abstract RecordIterator getExternalSymbolsByOriginalImportName(String extLabel)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get symbol records which match the specified external original import name.
|
||||||
|
* @param extProgAddr external program address
|
||||||
|
* @return matching external symbol records (forward iteration only, delete not supported)
|
||||||
|
* @throws IOException if a database io error occurs
|
||||||
|
*/
|
||||||
|
abstract RecordIterator getExternalSymbolsByMemoryAddress(Address extProgAddr)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all symbols contained in the given {@link Namespace} that have the given name
|
* Get all symbols contained in the given {@link Namespace} that have the given name
|
||||||
* @param name the symbol name
|
* @param name the symbol name
|
||||||
|
@ -439,7 +474,8 @@ abstract class SymbolDatabaseAdapter {
|
||||||
protected static RecordIterator getNameAndNamespaceFilterIterator(String name, long namespaceId,
|
protected static RecordIterator getNameAndNamespaceFilterIterator(String name, long namespaceId,
|
||||||
RecordIterator it) {
|
RecordIterator it) {
|
||||||
Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name));
|
Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name));
|
||||||
Query namespaceQuery = new FieldMatchQuery(SYMBOL_PARENT_COL, new LongField(namespaceId));
|
Query namespaceQuery =
|
||||||
|
new FieldMatchQuery(SYMBOL_PARENT_ID_COL, new LongField(namespaceId));
|
||||||
Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery);
|
Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery);
|
||||||
return new QueryRecordIterator(it, nameAndNamespaceQuery);
|
return new QueryRecordIterator(it, nameAndNamespaceQuery);
|
||||||
}
|
}
|
||||||
|
@ -457,7 +493,8 @@ abstract class SymbolDatabaseAdapter {
|
||||||
protected static RecordIterator getNameNamespaceAddressFilterIterator(String name,
|
protected static RecordIterator getNameNamespaceAddressFilterIterator(String name,
|
||||||
long namespaceId, long addressKey, RecordIterator it) {
|
long namespaceId, long addressKey, RecordIterator it) {
|
||||||
Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name));
|
Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name));
|
||||||
Query namespaceQuery = new FieldMatchQuery(SYMBOL_PARENT_COL, new LongField(namespaceId));
|
Query namespaceQuery =
|
||||||
|
new FieldMatchQuery(SYMBOL_PARENT_ID_COL, new LongField(namespaceId));
|
||||||
Query addressQuery = new FieldMatchQuery(SYMBOL_ADDR_COL, new LongField(addressKey));
|
Query addressQuery = new FieldMatchQuery(SYMBOL_ADDR_COL, new LongField(addressKey));
|
||||||
Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery);
|
Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery);
|
||||||
Query fullQuery = new AndQuery(nameAndNamespaceQuery, addressQuery);
|
Query fullQuery = new AndQuery(nameAndNamespaceQuery, addressQuery);
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Set;
|
||||||
import db.*;
|
import db.*;
|
||||||
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
||||||
import ghidra.program.database.map.AddressMap;
|
import ghidra.program.database.map.AddressMap;
|
||||||
|
import ghidra.program.database.util.EmptyRecordIterator;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
|
@ -105,7 +106,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
||||||
return symbolTable.getKey();
|
return symbolTable.getKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
private DBRecord convertRecord(DBRecord record) {
|
private DBRecord convertV0Record(DBRecord record) {
|
||||||
if (record == null) {
|
if (record == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -118,32 +119,34 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
||||||
String symbolName = record.getString(V0_SYMBOL_NAME_COL);
|
String symbolName = record.getString(V0_SYMBOL_NAME_COL);
|
||||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
|
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
|
||||||
long addressKey = record.getLongValue(V0_SYMBOL_ADDR_COL);
|
long addressKey = record.getLongValue(V0_SYMBOL_ADDR_COL);
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL,
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, addressKey);
|
||||||
addressKey);
|
|
||||||
|
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, SymbolType.LABEL.getID());
|
||||||
|
|
||||||
|
long namespaceId = Namespace.GLOBAL_NAMESPACE_ID;
|
||||||
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL, namespaceId);
|
||||||
|
|
||||||
|
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL,
|
||||||
|
(byte) SourceType.USER_DEFINED.ordinal());
|
||||||
|
|
||||||
|
//
|
||||||
|
// Convert sparse columns
|
||||||
|
//
|
||||||
|
|
||||||
|
Field hash = computeLocatorHash(symbolName, namespaceId, addressKey);
|
||||||
|
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||||
|
|
||||||
boolean isPrimary = record.getBooleanValue(V0_SYMBOL_PRIMARY_COL);
|
boolean isPrimary = record.getBooleanValue(V0_SYMBOL_PRIMARY_COL);
|
||||||
if (isPrimary) {
|
if (isPrimary) {
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey);
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, SymbolType.LABEL.getID());
|
|
||||||
|
|
||||||
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;
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
SymbolType symbolType, boolean isPrimary, SourceType source) {
|
||||||
boolean isPrimary) throws IOException {
|
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +167,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
DBRecord getSymbolRecord(long symbolID) throws IOException {
|
DBRecord getSymbolRecord(long symbolID) throws IOException {
|
||||||
return convertRecord(symbolTable.getRecord(symbolID));
|
return convertV0Record(symbolTable.getRecord(symbolID));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -210,8 +213,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward) throws IOException {
|
||||||
throws IOException {
|
|
||||||
KeyToRecordIterator it =
|
KeyToRecordIterator it =
|
||||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||||
|
@ -240,8 +242,17 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
RecordIterator getExternalSymbolsByMemoryAddress(Address extProgAddr) throws IOException {
|
||||||
|
return EmptyRecordIterator.INSTANCE; // External symbols were not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RecordIterator getExternalSymbolsByOriginalImportName(String extLabel) throws IOException {
|
||||||
|
return EmptyRecordIterator.INSTANCE; // External symbols were not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||||
if (id == Namespace.GLOBAL_NAMESPACE_ID) {
|
if (id == Namespace.GLOBAL_NAMESPACE_ID) {
|
||||||
return new V0ConvertedRecordIterator(symbolTable.iterator());
|
return new V0ConvertedRecordIterator(symbolTable.iterator());
|
||||||
}
|
}
|
||||||
|
@ -299,7 +310,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
||||||
if (hasNext()) {
|
if (hasNext()) {
|
||||||
DBRecord r = rec;
|
DBRecord r = rec;
|
||||||
rec = null;
|
rec = null;
|
||||||
return convertRecord(r);
|
return convertV0Record(r);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -337,8 +348,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
||||||
StringField value = new StringField(name);
|
StringField value = new StringField(name);
|
||||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true);
|
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true);
|
||||||
long addressKey = addrMap.getKey(address, false);
|
long addressKey = addrMap.getKey(address, false);
|
||||||
RecordIterator filtered =
|
RecordIterator filtered = getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||||
getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
|
||||||
if (filtered.hasNext()) {
|
if (filtered.hasNext()) {
|
||||||
return filtered.next();
|
return filtered.next();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Set;
|
||||||
import db.*;
|
import db.*;
|
||||||
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
||||||
import ghidra.program.database.map.AddressMap;
|
import ghidra.program.database.map.AddressMap;
|
||||||
|
import ghidra.program.database.util.EmptyRecordIterator;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -46,8 +47,8 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
||||||
private static final int V1_SYMBOL_ADDR_COL = 1;
|
private static final int V1_SYMBOL_ADDR_COL = 1;
|
||||||
private static final int V1_SYMBOL_PARENT_COL = 2;
|
private static final int V1_SYMBOL_PARENT_COL = 2;
|
||||||
private static final int V1_SYMBOL_TYPE_COL = 3;
|
private static final int V1_SYMBOL_TYPE_COL = 3;
|
||||||
private static final int V1_SYMBOL_DATA1_COL = 4;
|
private static final int V1_SYMBOL_DATA1_COL = 4; // Long data (variable dataTypeId)
|
||||||
private static final int V1_SYMBOL_DATA2_COL = 5;
|
private static final int V1_SYMBOL_DATA2_COL = 5; // Int data (primary flag, variable-offset)
|
||||||
private static final int V1_SYMBOL_COMMENT_COL = 6;
|
private static final int V1_SYMBOL_COMMENT_COL = 6;
|
||||||
|
|
||||||
private Table symbolTable;
|
private Table symbolTable;
|
||||||
|
@ -70,9 +71,8 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
SymbolType symbolType, boolean isPrimary, SourceType source) {
|
||||||
boolean isPrimary) throws IOException {
|
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,14 +121,11 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
||||||
|
|
||||||
long namespaceId = record.getLongValue(V1_SYMBOL_PARENT_COL);
|
long namespaceId = record.getLongValue(V1_SYMBOL_PARENT_COL);
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId);
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL, namespaceId);
|
||||||
|
|
||||||
byte symbolTypeId = record.getByteValue(V1_SYMBOL_TYPE_COL);
|
byte symbolTypeId = record.getByteValue(V1_SYMBOL_TYPE_COL);
|
||||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId);
|
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;
|
SourceType source = SourceType.USER_DEFINED;
|
||||||
if (symbolTypeId == SymbolType.FUNCTION.getID()) {
|
if (symbolTypeId == SymbolType.FUNCTION.getID()) {
|
||||||
Address symbolAddress = addrMap.decodeAddress(symbolAddrKey);
|
Address symbolAddress = addrMap.decodeAddress(symbolAddrKey);
|
||||||
|
@ -139,6 +136,13 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
||||||
}
|
}
|
||||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal());
|
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal());
|
||||||
|
|
||||||
|
//
|
||||||
|
// Convert sparse columns
|
||||||
|
//
|
||||||
|
|
||||||
|
SymbolDatabaseAdapterV3.convertSymbolStringData(symbolTypeId, rec,
|
||||||
|
record.getString(V1_SYMBOL_COMMENT_COL));
|
||||||
|
|
||||||
long dataTypeId = record.getLongValue(V1_SYMBOL_DATA1_COL);
|
long dataTypeId = record.getLongValue(V1_SYMBOL_DATA1_COL);
|
||||||
if (dataTypeId != -1) {
|
if (dataTypeId != -1) {
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
||||||
|
@ -161,7 +165,9 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
||||||
// also need to store primary for functions
|
// also need to store primary for functions
|
||||||
if (SymbolType.FUNCTION.equals(type)) {
|
if (SymbolType.FUNCTION.equals(type)) {
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey);
|
Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey);
|
||||||
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||||
|
|
||||||
|
@ -211,8 +217,7 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward) throws IOException {
|
||||||
throws IOException {
|
|
||||||
KeyToRecordIterator it =
|
KeyToRecordIterator it =
|
||||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||||
|
@ -240,6 +245,16 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RecordIterator getExternalSymbolsByMemoryAddress(Address extProgAddr) throws IOException {
|
||||||
|
return EmptyRecordIterator.INSTANCE; // External symbols were not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RecordIterator getExternalSymbolsByOriginalImportName(String extLabel) throws IOException {
|
||||||
|
return EmptyRecordIterator.INSTANCE; // External symbols were not supported
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||||
LongField field = new LongField(id);
|
LongField field = new LongField(id);
|
||||||
|
@ -293,8 +308,7 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
||||||
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
||||||
RecordIterator it = getSymbolsByName(name);
|
RecordIterator it = getSymbolsByName(name);
|
||||||
long addressKey = addrMap.getKey(address, false);
|
long addressKey = addrMap.getKey(address, false);
|
||||||
RecordIterator filtered =
|
RecordIterator filtered = getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||||
getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
|
||||||
if (filtered.hasNext()) {
|
if (filtered.hasNext()) {
|
||||||
return filtered.next();
|
return filtered.next();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,11 @@
|
||||||
package ghidra.program.database.symbol;
|
package ghidra.program.database.symbol;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import db.*;
|
import db.*;
|
||||||
import ghidra.program.database.map.*;
|
import ghidra.program.database.map.*;
|
||||||
import ghidra.program.database.util.RecordFilter;
|
import ghidra.program.database.util.EmptyRecordIterator;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.program.model.symbol.SymbolType;
|
import ghidra.program.model.symbol.SymbolType;
|
||||||
|
@ -43,20 +42,20 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||||
// "SymbolData3", "Flags" });
|
// "SymbolData3", "Flags" });
|
||||||
|
|
||||||
private static final int SYMBOL_VERSION = 2;
|
private static final int SYMBOL_VERSION = 2;
|
||||||
|
|
||||||
|
private static final int V2_SYMBOL_NAME_COL = 0;
|
||||||
|
private static final int V2_SYMBOL_ADDR_COL = 1;
|
||||||
|
private static final int V2_SYMBOL_PARENT_ID_COL = 2;
|
||||||
|
private static final int V2_SYMBOL_TYPE_COL = 3;
|
||||||
|
private static final int V2_SYMBOL_DATA1_COL = 4; // Long data (variable dataTypeId)
|
||||||
|
private static final int V2_SYMBOL_DATA2_COL = 5; // Int data (primary flag, variable-offset)
|
||||||
|
private static final int V2_SYMBOL_DATA3_COL = 6; // String data (external address)
|
||||||
|
private static final int V2_SYMBOL_FLAGS_COL = 7;
|
||||||
|
|
||||||
private Table symbolTable;
|
private Table symbolTable;
|
||||||
private AddressMap addrMap;
|
private AddressMap addrMap;
|
||||||
|
|
||||||
static final int V2_SYMBOL_NAME_COL = 0;
|
SymbolDatabaseAdapterV2(DBHandle handle, AddressMap addrMap) throws VersionException {
|
||||||
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;
|
this.addrMap = addrMap;
|
||||||
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
||||||
|
@ -73,9 +72,8 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
SymbolType symbolType, boolean isPrimary, SourceType source) {
|
||||||
boolean isPrimary) throws IOException {
|
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,8 +152,7 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward) throws IOException {
|
||||||
throws IOException {
|
|
||||||
KeyToRecordIterator it =
|
KeyToRecordIterator it =
|
||||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||||
|
@ -174,51 +171,58 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void moveAddress(Address oldAddr, Address newAddr) throws IOException {
|
void moveAddress(Address oldAddr, Address newAddr) throws IOException {
|
||||||
LongField oldKey = new LongField(addrMap.getKey(oldAddr, false));
|
throw new UnsupportedOperationException();
|
||||||
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
|
@Override
|
||||||
Set<Address> deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
Set<Address> deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
AnchoredSymbolRecordFilter filter = new AnchoredSymbolRecordFilter();
|
|
||||||
AddressRecordDeleter.deleteRecords(symbolTable, SYMBOL_ADDR_COL, addrMap, startAddr,
|
|
||||||
endAddr, filter);
|
|
||||||
|
|
||||||
return filter.getAddressesForSkippedRecords();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AnchoredSymbolRecordFilter implements RecordFilter {
|
private String getExternalStringData(DBRecord rec) {
|
||||||
private Set<Address> set = new HashSet<Address>();
|
long addrKey = rec.getLongValue(V2_SYMBOL_ADDR_COL);
|
||||||
|
Address addr = addrMap.decodeAddress(addrKey);
|
||||||
|
if (addr == null || !addr.isExternalAddress()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
byte symbolTypeId = rec.getByteValue(V2_SYMBOL_TYPE_COL);
|
||||||
|
if (symbolTypeId != SYMBOL_TYPE_FUNCTION && symbolTypeId != SYMBOL_TYPE_LABEL) {
|
||||||
|
// NOTE: I don't think external functions were supported with this version
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec.getString(V2_SYMBOL_DATA3_COL);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(DBRecord record) {
|
RecordIterator getExternalSymbolsByMemoryAddress(Address extProgAddr) throws IOException {
|
||||||
// only move symbols whose anchor flag is not on
|
if (extProgAddr == null) {
|
||||||
Address addr = addrMap.decodeAddress(record.getLongValue(SYMBOL_ADDR_COL));
|
return EmptyRecordIterator.INSTANCE;
|
||||||
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
|
||||||
if (((flags & SymbolDatabaseAdapter.SYMBOL_PINNED_FLAG) == 0)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
set.add(addr);
|
String matchAddrStr = extProgAddr.toString();
|
||||||
return false;
|
return new ConstrainedForwardRecordIterator(symbolTable.iterator(), rec -> {
|
||||||
|
String str = getExternalStringData(rec);
|
||||||
|
if (str != null) {
|
||||||
|
int indexOf = str.indexOf(","); // [address][,importName]
|
||||||
|
String addressString = indexOf >= 0 ? str.substring(0, indexOf) : str;
|
||||||
|
if (matchAddrStr.equals(addressString)) {
|
||||||
|
return convertV2Record(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Address> getAddressesForSkippedRecords() {
|
@Override
|
||||||
return set;
|
RecordIterator getExternalSymbolsByOriginalImportName(String extLabel) throws IOException {
|
||||||
}
|
return EmptyRecordIterator.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||||
LongField field = new LongField(id);
|
LongField field = new LongField(id);
|
||||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true);
|
RecordIterator it = symbolTable.indexIterator(SYMBOL_PARENT_ID_COL, field, field, true);
|
||||||
return new V2ConvertedRecordIterator(it);
|
return new V2ConvertedRecordIterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,6 +240,24 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||||
return new V2ConvertedRecordIterator(it);
|
return new V2ConvertedRecordIterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
||||||
|
RecordIterator it = scanSymbolsByName(name);
|
||||||
|
RecordIterator filtered = getNameAndNamespaceFilterIterator(name, id, it);
|
||||||
|
return new V2ConvertedRecordIterator(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
||||||
|
RecordIterator it = scanSymbolsByName(name);
|
||||||
|
long addressKey = addrMap.getKey(address, false);
|
||||||
|
RecordIterator filtered = getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||||
|
if (filtered.hasNext()) {
|
||||||
|
return filtered.next();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Address getMaxSymbolAddress(AddressSpace space) throws IOException {
|
Address getMaxSymbolAddress(AddressSpace space) throws IOException {
|
||||||
if (space.isMemorySpace()) {
|
if (space.isMemorySpace()) {
|
||||||
|
@ -265,27 +287,6 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||||
return symbolTable;
|
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.
|
* Returns a record matching the current database schema from the version 2 record.
|
||||||
* @param record the record matching the version 2 schema.
|
* @param record the record matching the version 2 schema.
|
||||||
|
@ -303,21 +304,25 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||||
long symbolAddrKey = record.getLongValue(V2_SYMBOL_ADDR_COL);
|
long symbolAddrKey = record.getLongValue(V2_SYMBOL_ADDR_COL);
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
||||||
|
|
||||||
long namespaceId = record.getLongValue(V2_SYMBOL_PARENT_COL);
|
long namespaceId = record.getLongValue(V2_SYMBOL_PARENT_ID_COL);
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId);
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL, namespaceId);
|
||||||
|
|
||||||
byte symbolTypeId = record.getByteValue(V2_SYMBOL_TYPE_COL);
|
byte symbolTypeId = record.getByteValue(V2_SYMBOL_TYPE_COL);
|
||||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId);
|
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId);
|
||||||
|
|
||||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL,
|
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL,
|
||||||
|
record.getByteValue(V2_SYMBOL_FLAGS_COL));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Convert sparse columns
|
||||||
|
//
|
||||||
|
|
||||||
|
SymbolDatabaseAdapterV3.convertSymbolStringData(symbolTypeId, rec,
|
||||||
record.getString(V2_SYMBOL_DATA3_COL));
|
record.getString(V2_SYMBOL_DATA3_COL));
|
||||||
|
|
||||||
Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey);
|
Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey);
|
||||||
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
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);
|
long dataTypeId = record.getLongValue(V2_SYMBOL_DATA1_COL);
|
||||||
if (dataTypeId != -1) {
|
if (dataTypeId != -1) {
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
||||||
|
@ -325,7 +330,7 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||||
|
|
||||||
SymbolType type = SymbolType.getSymbolType(symbolTypeId);
|
SymbolType type = SymbolType.getSymbolType(symbolTypeId);
|
||||||
int data2 = record.getIntValue(V2_SYMBOL_DATA2_COL);
|
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
|
// The data2 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
|
// for non-primary. If the type was a parameter or variable, it stored the ordinal or
|
||||||
// first use offset respectively
|
// first use offset respectively
|
||||||
if (SymbolType.LABEL.equals(type)) {
|
if (SymbolType.LABEL.equals(type)) {
|
||||||
|
|
|
@ -16,13 +16,13 @@
|
||||||
package ghidra.program.database.symbol;
|
package ghidra.program.database.symbol;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import db.*;
|
import db.*;
|
||||||
import ghidra.program.database.map.*;
|
import ghidra.program.database.map.*;
|
||||||
import ghidra.program.database.util.EmptyRecordIterator;
|
import ghidra.program.database.util.EmptyRecordIterator;
|
||||||
import ghidra.program.database.util.RecordFilter;
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.program.model.symbol.SymbolType;
|
import ghidra.program.model.symbol.SymbolType;
|
||||||
|
@ -33,9 +33,10 @@ import ghidra.util.task.TaskMonitor;
|
||||||
/**
|
/**
|
||||||
* SymbolDatabaseAdapter for version 3
|
* SymbolDatabaseAdapter for version 3
|
||||||
*
|
*
|
||||||
* This version provides for fast symbol lookup by namespace and name.
|
* This version provides for fast symbol lookup by namespace and name and introduced the use of
|
||||||
|
* sparse table columns for storing optional symbol data (hash, primary, datatype-ID, variable-offset).
|
||||||
* It was created in June 2021 with ProgramDB version 24.
|
* It was created in June 2021 with ProgramDB version 24.
|
||||||
* It will be included in Ghidra starting at version 10.1
|
* It was first in affect within Ghidra starting at version 10.1
|
||||||
*/
|
*/
|
||||||
class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||||
|
|
||||||
|
@ -49,28 +50,36 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||||
// allows us to index this field and quickly find the primary symbols. The field is sparse
|
// 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.
|
// so that non-primary symbols don't consume any space for this field.
|
||||||
|
|
||||||
static final Schema V3_SYMBOL_SCHEMA = new Schema(SYMBOL_VERSION, "Key",
|
/* Do not remove the following commented out schema! It shows the version 3 symbol table schema. */
|
||||||
new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
// static final Schema V3_SYMBOL_SCHEMA = new Schema(SYMBOL_VERSION, "Key",
|
||||||
ByteField.INSTANCE, StringField.INSTANCE, ByteField.INSTANCE,
|
// new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||||
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE },
|
// ByteField.INSTANCE, StringField.INSTANCE, ByteField.INSTANCE, LongField.INSTANCE,
|
||||||
new String[] { "Name", "Address", "Namespace", "Symbol Type", "String Data", "Flags",
|
// LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE },
|
||||||
"Locator Hash", "Primary", "Datatype", "Variable Offset" },
|
// new String[] { "Name", "Address", "Namespace", "Symbol Type", "String Data", "Flags",
|
||||||
new int[] { SYMBOL_HASH_COL, SYMBOL_PRIMARY_COL, SYMBOL_DATATYPE_COL,
|
// "Locator Hash", "Primary", "Datatype", "Variable Offset" },
|
||||||
SYMBOL_VAROFFSET_COL });
|
// new int[] { SYMBOL_HASH_COL, SYMBOL_PRIMARY_COL, SYMBOL_DATATYPE_COL,
|
||||||
|
// SYMBOL_VAROFFSET_COL });
|
||||||
|
|
||||||
|
private static final int V3_SYMBOL_NAME_COL = 0;
|
||||||
|
private static final int V3_SYMBOL_ADDR_COL = 1;
|
||||||
|
private static final int V3_SYMBOL_PARENT_ID_COL = 2;
|
||||||
|
private static final int V3_SYMBOL_TYPE_COL = 3;
|
||||||
|
private static final int V3_SYMBOL_STRING_DATA_COL = 4; // removed with V4; External [address][,importName]
|
||||||
|
private static final int V3_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.
|
||||||
|
private static final int V3_SYMBOL_HASH_COL = 6;
|
||||||
|
private static final int V3_SYMBOL_PRIMARY_COL = 7;
|
||||||
|
private static final int V3_SYMBOL_DATATYPE_COL = 8; // External and variable symbol use
|
||||||
|
private static final int V3_SYMBOL_VAROFFSET_COL = 9;
|
||||||
|
|
||||||
private Table symbolTable;
|
private Table symbolTable;
|
||||||
private AddressMap addrMap;
|
private AddressMap addrMap;
|
||||||
|
|
||||||
SymbolDatabaseAdapterV3(DBHandle handle, AddressMap addrMap, boolean create)
|
SymbolDatabaseAdapterV3(DBHandle handle, AddressMap addrMap) throws VersionException {
|
||||||
throws VersionException, IOException {
|
|
||||||
|
|
||||||
this.addrMap = addrMap;
|
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);
|
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
||||||
if (symbolTable == null) {
|
if (symbolTable == null) {
|
||||||
throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME);
|
throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME);
|
||||||
|
@ -83,61 +92,16 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||||
throw new VersionException(VersionException.NEWER_VERSION, false);
|
throw new VersionException(VersionException.NEWER_VERSION, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
SymbolType symbolType, boolean isPrimary, SourceType source) {
|
||||||
boolean isPrimary) throws IOException {
|
throw new UnsupportedOperationException();
|
||||||
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
|
@Override
|
||||||
void removeSymbol(long symbolID) throws IOException {
|
void removeSymbol(long symbolID) throws IOException {
|
||||||
symbolTable.deleteRecord(symbolID);
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -160,7 +124,7 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
DBRecord getSymbolRecord(long symbolID) throws IOException {
|
DBRecord getSymbolRecord(long symbolID) throws IOException {
|
||||||
return symbolTable.getRecord(symbolID);
|
return convertV3Record(symbolTable.getRecord(symbolID));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -170,49 +134,52 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getSymbolsByAddress(boolean forward) throws IOException {
|
RecordIterator getSymbolsByAddress(boolean forward) throws IOException {
|
||||||
return new KeyToRecordIterator(symbolTable,
|
KeyToRecordIterator it = new KeyToRecordIterator(symbolTable,
|
||||||
new AddressIndexPrimaryKeyIterator(symbolTable, SYMBOL_ADDR_COL, addrMap, forward));
|
new AddressIndexPrimaryKeyIterator(symbolTable, SYMBOL_ADDR_COL, addrMap, forward));
|
||||||
|
return new V3ConvertedRecordIterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException {
|
RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException {
|
||||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
KeyToRecordIterator it =
|
||||||
|
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||||
SYMBOL_ADDR_COL, addrMap, startAddr, forward));
|
SYMBOL_ADDR_COL, addrMap, startAddr, forward));
|
||||||
|
return new V3ConvertedRecordIterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void updateSymbolRecord(DBRecord record) throws IOException {
|
void updateSymbolRecord(DBRecord record) throws IOException {
|
||||||
// make sure hash is updated to current name and name space
|
throw new UnsupportedOperationException();
|
||||||
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
|
@Override
|
||||||
RecordIterator getSymbols() throws IOException {
|
RecordIterator getSymbols() throws IOException {
|
||||||
return symbolTable.iterator();
|
return new V3ConvertedRecordIterator(symbolTable.iterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException {
|
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException {
|
||||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
KeyToRecordIterator it =
|
||||||
|
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||||
SYMBOL_ADDR_COL, addrMap, start, end, forward));
|
SYMBOL_ADDR_COL, addrMap, start, end, forward));
|
||||||
|
return new V3ConvertedRecordIterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
||||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
KeyToRecordIterator it =
|
||||||
|
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||||
|
return new V3ConvertedRecordIterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
protected RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
KeyToRecordIterator it =
|
||||||
|
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||||
SYMBOL_PRIMARY_COL, addrMap, set, forward));
|
SYMBOL_PRIMARY_COL, addrMap, set, forward));
|
||||||
|
return new V3ConvertedRecordIterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -220,54 +187,92 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||||
AddressIndexPrimaryKeyIterator it = new AddressIndexPrimaryKeyIterator(symbolTable,
|
AddressIndexPrimaryKeyIterator it = new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||||
SYMBOL_PRIMARY_COL, addrMap, address, address, true);
|
SYMBOL_PRIMARY_COL, addrMap, address, address, true);
|
||||||
if (it.hasNext()) {
|
if (it.hasNext()) {
|
||||||
return symbolTable.getRecord(it.next());
|
return convertV3Record(symbolTable.getRecord(it.next()));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteExternalEntries(Address start, Address end) throws IOException {
|
|
||||||
AddressRecordDeleter.deleteRecords(symbolTable, SYMBOL_ADDR_COL, addrMap, start, end, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void moveAddress(Address oldAddr, Address newAddr) throws IOException {
|
void moveAddress(Address oldAddr, Address newAddr) throws IOException {
|
||||||
LongField oldKey = new LongField(addrMap.getKey(oldAddr, false));
|
throw new UnsupportedOperationException();
|
||||||
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
|
@Override
|
||||||
Set<Address> deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
Set<Address> deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
AnchoredSymbolRecordFilter filter = new AnchoredSymbolRecordFilter();
|
private String getExternalStringData(DBRecord rec) {
|
||||||
AddressRecordDeleter.deleteRecords(symbolTable, SYMBOL_ADDR_COL, addrMap, startAddr,
|
long addrKey = rec.getLongValue(V3_SYMBOL_ADDR_COL);
|
||||||
endAddr, filter);
|
Address addr = addrMap.decodeAddress(addrKey);
|
||||||
|
if (addr == null || !addr.isExternalAddress()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
byte symbolTypeId = rec.getByteValue(V3_SYMBOL_TYPE_COL);
|
||||||
|
if (symbolTypeId != SYMBOL_TYPE_FUNCTION && symbolTypeId != SYMBOL_TYPE_LABEL) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return filter.getAddressesForSkippedRecords();
|
return rec.getString(V3_SYMBOL_STRING_DATA_COL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RecordIterator getExternalSymbolsByMemoryAddress(Address extProgAddr) throws IOException {
|
||||||
|
if (extProgAddr == null) {
|
||||||
|
return EmptyRecordIterator.INSTANCE;
|
||||||
|
}
|
||||||
|
String matchAddrStr = extProgAddr.toString();
|
||||||
|
return new ConstrainedForwardRecordIterator(symbolTable.iterator(), rec -> {
|
||||||
|
String str = getExternalStringData(rec);
|
||||||
|
if (str != null) {
|
||||||
|
int indexOf = str.indexOf(","); // [address][,importName]
|
||||||
|
String addressString = indexOf >= 0 ? str.substring(0, indexOf) : str;
|
||||||
|
if (matchAddrStr.equals(addressString)) {
|
||||||
|
return convertV3Record(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RecordIterator getExternalSymbolsByOriginalImportName(String extLabel) throws IOException {
|
||||||
|
if (StringUtils.isBlank(extLabel)) {
|
||||||
|
return EmptyRecordIterator.INSTANCE;
|
||||||
|
}
|
||||||
|
return new ConstrainedForwardRecordIterator(symbolTable.iterator(), rec -> {
|
||||||
|
String str = getExternalStringData(rec);
|
||||||
|
if (str != null) {
|
||||||
|
int indexOf = str.indexOf(","); // [address][,importName]
|
||||||
|
String originalImportedName = indexOf >= 0 ? str.substring(indexOf + 1) : null;
|
||||||
|
if (extLabel.equals(originalImportedName)) {
|
||||||
|
return convertV3Record(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||||
LongField field = new LongField(id);
|
LongField field = new LongField(id);
|
||||||
return symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true);
|
RecordIterator it = symbolTable.indexIterator(SYMBOL_PARENT_ID_COL, field, field, true);
|
||||||
|
return new V3ConvertedRecordIterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator getSymbolsByName(String name) throws IOException {
|
RecordIterator getSymbolsByName(String name) throws IOException {
|
||||||
StringField field = new StringField(name);
|
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 V3ConvertedRecordIterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
RecordIterator scanSymbolsByName(String startName) throws IOException {
|
RecordIterator scanSymbolsByName(String startName) throws IOException {
|
||||||
StringField field = new StringField(startName);
|
StringField field = new StringField(startName);
|
||||||
return symbolTable.indexIterator(SYMBOL_NAME_COL, field, null, true);
|
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, field, null, true);
|
||||||
|
return new V3ConvertedRecordIterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -282,7 +287,10 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||||
Field end = computeLocatorHash(name, id, MAX_ADDRESS_OFFSET);
|
Field end = computeLocatorHash(name, id, MAX_ADDRESS_OFFSET);
|
||||||
|
|
||||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_HASH_COL, start, end, true);
|
RecordIterator it = symbolTable.indexIterator(SYMBOL_HASH_COL, start, end, true);
|
||||||
return getNameAndNamespaceFilterIterator(name, id, it);
|
it = new V3ConvertedRecordIterator(it);
|
||||||
|
|
||||||
|
RecordIterator filtered = getNameAndNamespaceFilterIterator(name, id, it);
|
||||||
|
return new V3ConvertedRecordIterator(filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -293,6 +301,8 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_HASH_COL, search, search, true);
|
RecordIterator it = symbolTable.indexIterator(SYMBOL_HASH_COL, search, search, true);
|
||||||
|
it = new V3ConvertedRecordIterator(it);
|
||||||
|
|
||||||
RecordIterator filtered =
|
RecordIterator filtered =
|
||||||
getNameNamespaceAddressFilterIterator(name, namespaceId, addressKey, it);
|
getNameNamespaceAddressFilterIterator(name, namespaceId, addressKey, it);
|
||||||
if (filtered.hasNext()) {
|
if (filtered.hasNext()) {
|
||||||
|
@ -330,24 +340,96 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||||
return symbolTable;
|
return symbolTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AnchoredSymbolRecordFilter implements RecordFilter {
|
/**
|
||||||
private Set<Address> set = new HashSet<Address>();
|
* 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 convertV3Record(DBRecord record) {
|
||||||
|
if (record == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey());
|
||||||
|
|
||||||
|
String symbolName = record.getString(V3_SYMBOL_NAME_COL);
|
||||||
|
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
|
||||||
|
|
||||||
|
long symbolAddrKey = record.getLongValue(V3_SYMBOL_ADDR_COL);
|
||||||
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
||||||
|
|
||||||
|
long namespaceId = record.getLongValue(V3_SYMBOL_PARENT_ID_COL);
|
||||||
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL, namespaceId);
|
||||||
|
|
||||||
|
byte symbolTypeId = record.getByteValue(V3_SYMBOL_TYPE_COL);
|
||||||
|
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId);
|
||||||
|
|
||||||
|
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL,
|
||||||
|
record.getByteValue(V3_SYMBOL_FLAGS_COL));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Convert sparse columns
|
||||||
|
//
|
||||||
|
|
||||||
|
convertSymbolStringData(symbolTypeId, rec, record.getString(V3_SYMBOL_STRING_DATA_COL));
|
||||||
|
|
||||||
|
Field hash = record.getFieldValue(V3_SYMBOL_HASH_COL);
|
||||||
|
if (hash != null) {
|
||||||
|
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
Field primaryAddr = record.getFieldValue(V3_SYMBOL_PRIMARY_COL);
|
||||||
|
if (primaryAddr != null) {
|
||||||
|
rec.setField(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, primaryAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Field dataTypeId = record.getFieldValue(V3_SYMBOL_DATATYPE_COL);
|
||||||
|
if (dataTypeId != null) {
|
||||||
|
rec.setField(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Field varOffset = record.getFieldValue(V3_SYMBOL_VAROFFSET_COL);
|
||||||
|
if (varOffset != null) {
|
||||||
|
rec.setField(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, varOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convertSymbolStringData(byte symbolTypeId, DBRecord record, String str) {
|
||||||
|
|
||||||
|
// Adhoc String field use/format
|
||||||
|
// External location (label or function): "[<addressStr>][,<originalImportedName>]"
|
||||||
|
// Library: [externalLibraryPath]
|
||||||
|
// Variables: [comment]
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(str)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbolTypeId == SYMBOL_TYPE_LABEL || symbolTypeId == SYMBOL_TYPE_FUNCTION) {
|
||||||
|
int indexOf = str.indexOf(",");
|
||||||
|
String originalImportedName = indexOf >= 0 ? str.substring(indexOf + 1) : null;
|
||||||
|
String addressString = indexOf >= 0 ? str.substring(0, indexOf) : str;
|
||||||
|
record.setString(SYMBOL_EXTERNAL_PROG_ADDR_COL, addressString);
|
||||||
|
record.setString(SYMBOL_ORIGINAL_IMPORTED_NAME_COL, originalImportedName);
|
||||||
|
}
|
||||||
|
else if (symbolTypeId == SYMBOL_TYPE_LOCAL_VAR || symbolTypeId == SYMBOL_TYPE_PARAMETER) {
|
||||||
|
record.setString(SYMBOL_COMMENT_COL, str);
|
||||||
|
}
|
||||||
|
else if (symbolTypeId == SYMBOL_TYPE_LIBRARY) {
|
||||||
|
record.setString(SYMBOL_LIBPATH_COL, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class V3ConvertedRecordIterator extends ConvertedRecordIterator {
|
||||||
|
|
||||||
|
V3ConvertedRecordIterator(RecordIterator originalIterator) {
|
||||||
|
super(originalIterator, false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(DBRecord record) {
|
protected DBRecord convertRecord(DBRecord record) {
|
||||||
// only move symbols whose anchor flag is not on
|
return convertV3Record(record);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,364 @@
|
||||||
|
/* ###
|
||||||
|
* 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 added additional sparse columns to store optional data specific to certain
|
||||||
|
* symbol types. The adhoc string data column was eliminated.
|
||||||
|
*/
|
||||||
|
class SymbolDatabaseAdapterV4 extends SymbolDatabaseAdapter {
|
||||||
|
|
||||||
|
static final int SYMBOL_VERSION = 4;
|
||||||
|
|
||||||
|
// 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 V4_SYMBOL_SCHEMA = new Schema(SYMBOL_VERSION, "Key",
|
||||||
|
new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||||
|
ByteField.INSTANCE, ByteField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||||
|
LongField.INSTANCE, IntField.INSTANCE, StringField.INSTANCE, StringField.INSTANCE,
|
||||||
|
StringField.INSTANCE, StringField.INSTANCE },
|
||||||
|
new String[] { "Name", "Address", "Namespace", "Symbol Type", "Flags", "Locator Hash",
|
||||||
|
"Primary", "Datatype", "Variable Offset", "ExtOrigImportName", "ExtProgAddr", "Comment",
|
||||||
|
"LibPath" },
|
||||||
|
new int[] { SYMBOL_HASH_COL, SYMBOL_PRIMARY_COL, SYMBOL_DATATYPE_COL, SYMBOL_VAROFFSET_COL,
|
||||||
|
SYMBOL_ORIGINAL_IMPORTED_NAME_COL, SYMBOL_EXTERNAL_PROG_ADDR_COL, SYMBOL_COMMENT_COL,
|
||||||
|
SYMBOL_LIBPATH_COL });
|
||||||
|
|
||||||
|
private Table symbolTable;
|
||||||
|
private AddressMap addrMap;
|
||||||
|
|
||||||
|
SymbolDatabaseAdapterV4(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_ID_COL, SYMBOL_HASH_COL,
|
||||||
|
SYMBOL_PRIMARY_COL, SYMBOL_ORIGINAL_IMPORTED_NAME_COL,
|
||||||
|
SYMBOL_EXTERNAL_PROG_ADDR_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,
|
||||||
|
// 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, (byte) source.ordinal(),
|
||||||
|
// isPrimary);
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||||
|
SymbolType symbolType, boolean isPrimary, SourceType source) {
|
||||||
|
|
||||||
|
long nextID = symbolTable.getKey();
|
||||||
|
|
||||||
|
// Avoid key 0, as it is reserved for the global namespace
|
||||||
|
if (nextID == 0) {
|
||||||
|
nextID++;
|
||||||
|
}
|
||||||
|
|
||||||
|
long addressKey = addrMap.getKey(address, true);
|
||||||
|
|
||||||
|
DBRecord rec = symbolTable.getSchema().createRecord(nextID);
|
||||||
|
rec.setString(SYMBOL_NAME_COL, name);
|
||||||
|
rec.setLongValue(SYMBOL_ADDR_COL, addressKey);
|
||||||
|
rec.setLongValue(SYMBOL_PARENT_ID_COL, namespaceID);
|
||||||
|
rec.setByteValue(SYMBOL_TYPE_COL, symbolType.getID());
|
||||||
|
rec.setByteValue(SYMBOL_FLAGS_COL, (byte) source.ordinal());
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_ID_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_ID_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 scanSymbolsByName(String startName) throws IOException {
|
||||||
|
StringField field = new StringField(startName);
|
||||||
|
return symbolTable.indexIterator(SYMBOL_NAME_COL, field, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RecordIterator getExternalSymbolsByOriginalImportName(String extLabel) throws IOException {
|
||||||
|
StringField extLabelField = new StringField(extLabel);
|
||||||
|
return symbolTable.indexIterator(SYMBOL_ORIGINAL_IMPORTED_NAME_COL, extLabelField,
|
||||||
|
extLabelField, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RecordIterator getExternalSymbolsByMemoryAddress(Address extProgAddr) throws IOException {
|
||||||
|
StringField addrField = new StringField(extProgAddr.toString());
|
||||||
|
return symbolTable.indexIterator(SYMBOL_EXTERNAL_PROG_ADDR_COL, addrField, addrField, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -303,7 +303,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
Symbol parent =
|
Symbol parent =
|
||||||
getSymbol(rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL));
|
getSymbol(rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL));
|
||||||
Msg.warn(this, "Variable symbol upgrade problem: " + parent.getName() + ":" +
|
Msg.warn(this, "Variable symbol upgrade problem: " + parent.getName() + ":" +
|
||||||
rec.getString(SymbolDatabaseAdapter.SYMBOL_NAME_COL));
|
rec.getString(SymbolDatabaseAdapter.SYMBOL_NAME_COL));
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
Symbol parent =
|
Symbol parent =
|
||||||
getSymbol(rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL));
|
getSymbol(rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL));
|
||||||
Msg.warn(this, "Variable symbol upgrade problem: " + parent.getName() +
|
Msg.warn(this, "Variable symbol upgrade problem: " + parent.getName() +
|
||||||
":" + rec.getString(SymbolDatabaseAdapter.SYMBOL_NAME_COL));
|
":" + rec.getString(SymbolDatabaseAdapter.SYMBOL_NAME_COL));
|
||||||
curVarAddr = null;
|
curVarAddr = null;
|
||||||
|
@ -527,8 +527,11 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
Address address = symbol.getAddress();
|
Address address = symbol.getAddress();
|
||||||
symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID,
|
symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID,
|
||||||
null);
|
null);
|
||||||
DBRecord record = adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL,
|
|
||||||
null, null, null, source, true);
|
DBRecord record = adapter.createSymbolRecord(newName, newParentID, address,
|
||||||
|
SymbolType.LABEL, true, source);
|
||||||
|
adapter.updateSymbolRecord(record);
|
||||||
|
|
||||||
symbol.setRecord(record);
|
symbol.setRecord(record);
|
||||||
symbolAdded(symbol);
|
symbolAdded(symbol);
|
||||||
}
|
}
|
||||||
|
@ -571,7 +574,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, name);
|
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, name);
|
||||||
long addressKey = addrMap.getKey(addr, true);
|
long addressKey = addrMap.getKey(addr, true);
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, addressKey);
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, addressKey);
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespace.getID());
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL, namespace.getID());
|
||||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, type.getID());
|
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, type.getID());
|
||||||
if (isPrimary) {
|
if (isPrimary) {
|
||||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey);
|
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey);
|
||||||
|
@ -587,19 +590,19 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
addrMap.decodeAddress(record.getLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL));
|
addrMap.decodeAddress(record.getLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL));
|
||||||
}
|
}
|
||||||
if (type == SymbolType.CLASS) {
|
if (type == SymbolType.CLASS) {
|
||||||
return new ClassSymbol(this, cache, addr, record);
|
return new ClassSymbol(this, cache, record); // uses NO_ADDRESS
|
||||||
}
|
}
|
||||||
else if (type == SymbolType.LABEL) {
|
else if (type == SymbolType.LABEL) {
|
||||||
return new CodeSymbol(this, cache, addr, record);
|
return new CodeSymbol(this, cache, addr, record); // uses NO_ADDRESS
|
||||||
}
|
}
|
||||||
else if (type == SymbolType.NAMESPACE) {
|
else if (type == SymbolType.NAMESPACE) {
|
||||||
return new NamespaceSymbol(this, cache, addr, record);
|
return new NamespaceSymbol(this, cache, record);
|
||||||
}
|
}
|
||||||
else if (type == SymbolType.FUNCTION) {
|
else if (type == SymbolType.FUNCTION) {
|
||||||
return new FunctionSymbol(this, cache, addr, record);
|
return new FunctionSymbol(this, cache, addr, record);
|
||||||
}
|
}
|
||||||
else if (type == SymbolType.LIBRARY) {
|
else if (type == SymbolType.LIBRARY) {
|
||||||
return new LibrarySymbol(this, cache, addr, record);
|
return new LibrarySymbol(this, cache, record); // uses NO_ADDRESS
|
||||||
}
|
}
|
||||||
else if (type == SymbolType.PARAMETER || type == SymbolType.LOCAL_VAR) {
|
else if (type == SymbolType.PARAMETER || type == SymbolType.LOCAL_VAR) {
|
||||||
return new VariableSymbolDB(this, cache, type, variableStorageMgr, addr, record);
|
return new VariableSymbolDB(this, cache, type, variableStorageMgr, addr, record);
|
||||||
|
@ -970,12 +973,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol getLibrarySymbol(String name) {
|
public LibrarySymbol getLibrarySymbol(String name) {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
for (Symbol s : getSymbols(name)) {
|
for (Symbol s : getSymbols(name)) {
|
||||||
if (s.getSymbolType() == SymbolType.LIBRARY) {
|
if (s.getSymbolType() == SymbolType.LIBRARY) {
|
||||||
return s;
|
return (LibrarySymbol) s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1111,6 +1114,83 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all external symbols whose original import name matches the specified extLabel with an
|
||||||
|
* optional constraint on a matching Library.
|
||||||
|
* @param library optional Library constraint (may be null to ignore).
|
||||||
|
* @param extLabel external original import name
|
||||||
|
* @return external symbol iterator
|
||||||
|
*/
|
||||||
|
public SymbolIterator getExternalSymbolByOriginalImportName(Library library, String extLabel) {
|
||||||
|
if (library != null) {
|
||||||
|
checkValidNamespaceArgument(library);
|
||||||
|
}
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
long matchLibraryId = library != null ? library.getID() : -1;
|
||||||
|
RecordIterator recordIter = adapter.getExternalSymbolsByOriginalImportName(extLabel);
|
||||||
|
return new SymbolRecordConstraintIterator(recordIter, rec -> {
|
||||||
|
if (matchLibraryId > 0) {
|
||||||
|
long parentId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL);
|
||||||
|
if (parentId == matchLibraryId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Symbol s = getSymbol(parentId);
|
||||||
|
Library lib = Library.getContainingLibrary(s);
|
||||||
|
return lib != null && lib.getID() == matchLibraryId;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
program.dbError(e);
|
||||||
|
return null; // will not occur
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all external symbols whose original import name matches the specified extLabel with an
|
||||||
|
* optional constraint on a matching Library.
|
||||||
|
* @param library optional Library constraint (may be null to ignore).
|
||||||
|
* @param extProgAddr external program memory address
|
||||||
|
* @return external symbol iterator
|
||||||
|
*/
|
||||||
|
public SymbolIterator getExternalSymbolByMemoryAddress(Library library, Address extProgAddr) {
|
||||||
|
if (extProgAddr == null || !extProgAddr.isLoadedMemoryAddress()) {
|
||||||
|
return SymbolIterator.EMPTY_ITERATOR;
|
||||||
|
}
|
||||||
|
if (library != null) {
|
||||||
|
checkValidNamespaceArgument(library);
|
||||||
|
}
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
long matchLibraryId = library != null ? library.getID() : -1;
|
||||||
|
RecordIterator recordIter = adapter.getExternalSymbolsByMemoryAddress(extProgAddr);
|
||||||
|
return new SymbolRecordConstraintIterator(recordIter, rec -> {
|
||||||
|
if (matchLibraryId > 0) {
|
||||||
|
long parentId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL);
|
||||||
|
if (parentId == matchLibraryId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Symbol s = getSymbol(parentId);
|
||||||
|
Library lib = Library.getContainingLibrary(s);
|
||||||
|
return lib != null && lib.getID() == matchLibraryId;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
program.dbError(e);
|
||||||
|
return null; // will not occur
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Namespace getNamespace(String name, Namespace namespace) {
|
public Namespace getNamespace(String name, Namespace namespace) {
|
||||||
List<Symbol> symbols = getSymbols(name, namespace);
|
List<Symbol> symbols = getSymbols(name, namespace);
|
||||||
|
@ -1804,8 +1884,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
try {
|
||||||
while (nextSymbol == null && (forward ? it.hasNext() : it.hasPrevious())) {
|
while (nextSymbol == null && (forward ? it.hasNext() : it.hasPrevious())) {
|
||||||
DBRecord rec = forward ? it.next() : it.previous();
|
DBRecord rec = forward ? it.next() : it.previous();
|
||||||
Symbol sym = getSymbol(rec);
|
Symbol sym = getSymbol(rec);
|
||||||
|
@ -1845,6 +1925,66 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class SymbolRecordConstraintIterator implements SymbolIterator {
|
||||||
|
private Symbol nextSymbol;
|
||||||
|
|
||||||
|
private final RecordIterator it;
|
||||||
|
private final Predicate<DBRecord> predicate;
|
||||||
|
private final boolean forward;
|
||||||
|
|
||||||
|
SymbolRecordConstraintIterator(RecordIterator it, Predicate<DBRecord> predicate,
|
||||||
|
boolean forward) {
|
||||||
|
this.it = it;
|
||||||
|
this.predicate = predicate;
|
||||||
|
this.forward = forward;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
if (nextSymbol != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
while (nextSymbol == null && (forward ? it.hasNext() : it.hasPrevious())) {
|
||||||
|
DBRecord rec = forward ? it.next() : it.previous();
|
||||||
|
if (predicate == null || predicate.test(rec)) {
|
||||||
|
nextSymbol = getSymbol(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nextSymbol != null;
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
program.dbError(e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Symbol next() {
|
||||||
|
if (hasNext()) {
|
||||||
|
Symbol returnedSymbol = nextSymbol;
|
||||||
|
nextSymbol = null;
|
||||||
|
return returnedSymbol;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Symbol> iterator() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class SymbolQueryIterator implements SymbolIterator {
|
private class SymbolQueryIterator implements SymbolIterator {
|
||||||
private SymbolIterator it;
|
private SymbolIterator it;
|
||||||
private Symbol nextMatch;
|
private Symbol nextMatch;
|
||||||
|
@ -2204,6 +2344,45 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
dynamicSymbolAddressMap = new AddressMapImpl((byte) 0x40, addrMap.getAddressFactory());
|
dynamicSymbolAddressMap = new AddressMapImpl((byte) 0x40, addrMap.getAddressFactory());
|
||||||
invalidateCache(true);
|
invalidateCache(true);
|
||||||
variableStorageMgr.setLanguage(translator, monitor);
|
variableStorageMgr.setLanguage(translator, monitor);
|
||||||
|
|
||||||
|
monitor.setMessage("Translate External Addresses...");
|
||||||
|
try {
|
||||||
|
AddressFactory oldAddrFactory = translator.getOldLanguage().getAddressFactory();
|
||||||
|
SymbolIterator externalSymbols = getExternalSymbols();
|
||||||
|
while (externalSymbols.hasNext()) {
|
||||||
|
monitor.checkCancelled();
|
||||||
|
SymbolDB s = (SymbolDB) externalSymbols.next();
|
||||||
|
|
||||||
|
String extAddrStr =
|
||||||
|
s.record.getString(SymbolDatabaseAdapter.SYMBOL_EXTERNAL_PROG_ADDR_COL);
|
||||||
|
if (extAddrStr == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// skip addresses which do not parse by old language - could be
|
||||||
|
// overlay (although this should generally never occur)
|
||||||
|
Address addr = oldAddrFactory.getAddress(extAddrStr);
|
||||||
|
if (addr == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AddressSpace newAddressSpace =
|
||||||
|
translator.getNewAddressSpace(addr.getAddressSpace().getName());
|
||||||
|
if (newAddressSpace == null || !newAddressSpace.isLoadedMemorySpace()) {
|
||||||
|
// can't really recover from this
|
||||||
|
throw new AssertException(
|
||||||
|
"Failed to map external memory address: " + extAddrStr);
|
||||||
|
}
|
||||||
|
addr = newAddressSpace.getAddress(addr.getOffset());
|
||||||
|
String newAddrStr = addr.toString();
|
||||||
|
if (!newAddrStr.equals(extAddrStr)) {
|
||||||
|
s.record.setString(SymbolDatabaseAdapter.SYMBOL_EXTERNAL_PROG_ADDR_COL,
|
||||||
|
newAddrStr);
|
||||||
|
adapter.updateSymbolRecord(s.record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
program.dbError(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replaceDataTypes(Map<Long, Long> dataTypeReplacementMap) {
|
public void replaceDataTypes(Map<Long, Long> dataTypeReplacementMap) {
|
||||||
|
@ -2255,6 +2434,10 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
@Override
|
@Override
|
||||||
public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
|
public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
if (!fromAddr.isMemoryAddress() || !toAddr.isMemoryAddress()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"moveAddressRange only supported for memory addresses");
|
||||||
|
}
|
||||||
if (fromAddr.equals(toAddr)) {
|
if (fromAddr.equals(toAddr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2274,14 +2457,18 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
if (!range.contains(symbol.getAddress())) {
|
if (!range.contains(symbol.getAddress())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Address newAddress = toAddr.add(symbol.getAddress().subtract(fromAddr));
|
if (!(symbol instanceof MemorySymbol memSym)) {
|
||||||
|
throw new AssertionError(
|
||||||
|
"Unexpected symbol type within memory range: " + symbol.getClass());
|
||||||
|
}
|
||||||
|
Address newAddress = toAddr.add(memSym.getAddress().subtract(fromAddr));
|
||||||
|
|
||||||
// any address that has symbols added or removed may have a corrupted primary
|
// any address that has symbols added or removed may have a corrupted primary
|
||||||
// (too many or non-existent)
|
// (too many or non-existent)
|
||||||
primaryFixups.add(symbol.getAddress());
|
primaryFixups.add(memSym.getAddress());
|
||||||
primaryFixups.add(newAddress);
|
primaryFixups.add(newAddress);
|
||||||
|
|
||||||
moveSymbolForMemoryBlockMove((SymbolDB) symbol, newAddress);
|
moveSymbolForMemoryBlockMove(memSym, newAddress);
|
||||||
}
|
}
|
||||||
// go back and make sure there is a valid primary symbol at touched addresses
|
// go back and make sure there is a valid primary symbol at touched addresses
|
||||||
fixupPrimarySymbols(primaryFixups);
|
fixupPrimarySymbols(primaryFixups);
|
||||||
|
@ -2295,17 +2482,17 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
// Since this is a memory block move, the destination range can not contain any functions, but
|
// Since this is a memory block move, the destination range can not contain any functions, but
|
||||||
// it may contain labels so we may have to deal with collisions. The other complication we have
|
// it may contain labels so we may have to deal with collisions. The other complication we have
|
||||||
// to deal with is functions in the moved block that are currently pinned.
|
// to deal with is functions in the moved block that are currently pinned.
|
||||||
private void moveSymbolForMemoryBlockMove(SymbolDB symbol, Address newAddress) {
|
private void moveSymbolForMemoryBlockMove(MemorySymbol memSymbol, Address newAddress) {
|
||||||
Address oldAddress = symbol.getAddress();
|
Address oldAddress = memSymbol.getAddress();
|
||||||
|
|
||||||
// If the symbol is not pinned go ahead and move it. Only wrinkle is that there may
|
// If the symbol is not pinned go ahead and move it. Only wrinkle is that there may
|
||||||
// be a matching symbol at the destination. In that unlikely event, remove it, but preserve
|
// be a matching symbol at the destination. In that unlikely event, remove it, but preserve
|
||||||
// its pinned status
|
// its pinned status
|
||||||
if (!symbol.isPinned()) {
|
if (!memSymbol.isPinned()) {
|
||||||
// if we conflict with a symbol at the destination, delete it (it can't be a function)
|
// if we conflict with a symbol at the destination, delete it (it can't be a function)
|
||||||
// and retain its pinned status if it had one.
|
// and retain its pinned status if it had one.
|
||||||
boolean shouldPin = deleteMatchingSymbolAndCheckPinnedStatus(symbol, newAddress);
|
boolean shouldPin = deleteMatchingSymbolAndCheckPinnedStatus(memSymbol, newAddress);
|
||||||
symbol.moveLowLevel(newAddress, null, null, null, shouldPin);
|
memSymbol.moveLowLevel(newAddress, null, null, null, shouldPin);
|
||||||
moveLabelHistory(oldAddress, newAddress);
|
moveLabelHistory(oldAddress, newAddress);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2314,10 +2501,10 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
// the function symbol, but create a replacement label in the pinned source location. Also,
|
// the function symbol, but create a replacement label in the pinned source location. Also,
|
||||||
// if there is a primary symbol at the destination, we need to remove it and set the
|
// if there is a primary symbol at the destination, we need to remove it and set the
|
||||||
// function's symbol to that name.
|
// function's symbol to that name.
|
||||||
if (symbol.getSymbolType() == SymbolType.FUNCTION) {
|
if (memSymbol.getSymbolType() == SymbolType.FUNCTION) {
|
||||||
String originalName = symbol.getName();
|
String originalName = memSymbol.getName();
|
||||||
Namespace originalNamespace = symbol.getParentNamespace();
|
Namespace originalNamespace = memSymbol.getParentNamespace();
|
||||||
SourceType originalSource = symbol.getSource();
|
SourceType originalSource = memSymbol.getSource();
|
||||||
String newName = "";
|
String newName = "";
|
||||||
Namespace newNamespace = namespaceMgr.getGlobalNamespace();
|
Namespace newNamespace = namespaceMgr.getGlobalNamespace();
|
||||||
SourceType newSource = SourceType.DEFAULT;
|
SourceType newSource = SourceType.DEFAULT;
|
||||||
|
@ -2335,7 +2522,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// so move the symbol to the new address and update namespace, source, and pinned state
|
// so move the symbol to the new address and update namespace, source, and pinned state
|
||||||
symbol.moveLowLevel(newAddress, newName, newNamespace, newSource, newPinned);
|
memSymbol.moveLowLevel(newAddress, newName, newNamespace, newSource, newPinned);
|
||||||
|
|
||||||
// create a pinned label to replace the pinned function symbol at the source.
|
// create a pinned label to replace the pinned function symbol at the source.
|
||||||
Symbol newSymbol =
|
Symbol newSymbol =
|
||||||
|
@ -2444,45 +2631,48 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void imageBaseChanged(Address oldBase, Address newBase) {
|
public void imageBaseChanged(Address oldBase, Address newBase) {
|
||||||
|
if (!oldBase.isLoadedMemoryAddress() || !newBase.isLoadedMemoryAddress()) {
|
||||||
|
throw new IllegalArgumentException("Loaded memory addresses required");
|
||||||
|
}
|
||||||
AddressSpace space = newBase.getAddressSpace();
|
AddressSpace space = newBase.getAddressSpace();
|
||||||
fixupPinnedSymbolsAfterRebase(oldBase, newBase, space.getMinAddress(),
|
fixupPinnedMemorySymbolsAfterRebase(oldBase, newBase, space.getMinAddress(),
|
||||||
space.getMaxAddress());
|
space.getMaxAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fixupPinnedSymbolsAfterRebase(Address oldBase, Address base, Address minAddr,
|
private void fixupPinnedMemorySymbolsAfterRebase(Address oldBase, Address base, Address minAddr,
|
||||||
Address maxAddr) {
|
Address maxAddr) {
|
||||||
|
|
||||||
List<SymbolDB> fixupPinnedSymbols = findPinnedSymbols(minAddr, maxAddr);
|
List<MemorySymbol> fixupPinnedSymbols = findPinnedMemorySymbols(minAddr, maxAddr);
|
||||||
|
|
||||||
Set<Address> primaryFixups = new HashSet<>();
|
Set<Address> primaryFixups = new HashSet<>();
|
||||||
for (SymbolDB symbol : fixupPinnedSymbols) {
|
for (MemorySymbol memSymbol : fixupPinnedSymbols) {
|
||||||
Address currentAddress = symbol.getAddress();
|
Address currentAddress = memSymbol.getAddress();
|
||||||
Address beforeBaseChangeAddress = oldBase.addWrap(currentAddress.subtract(base));
|
Address beforeBaseChangeAddress = oldBase.addWrap(currentAddress.subtract(base));
|
||||||
primaryFixups.add(currentAddress);
|
primaryFixups.add(currentAddress);
|
||||||
primaryFixups.add(beforeBaseChangeAddress);
|
primaryFixups.add(beforeBaseChangeAddress);
|
||||||
|
|
||||||
// see if there is a name collision for the pinned symbol we are about to move back
|
// see if there is a name collision for the pinned symbol we are about to move back
|
||||||
Symbol match =
|
Symbol match = getSymbol(memSymbol.getName(), beforeBaseChangeAddress,
|
||||||
getSymbol(symbol.getName(), beforeBaseChangeAddress, symbol.getParentNamespace());
|
memSymbol.getParentNamespace());
|
||||||
|
|
||||||
if (symbol.getSymbolType() == SymbolType.FUNCTION) {
|
if (memSymbol.getSymbolType() == SymbolType.FUNCTION) {
|
||||||
fixupPinnedFunctionSymbolAfterRebase(symbol, beforeBaseChangeAddress, match);
|
fixupPinnedFunctionSymbolAfterRebase(memSymbol, beforeBaseChangeAddress, match);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fixupPinnedLabelSymbolAfterRebase(symbol, beforeBaseChangeAddress, match);
|
fixupPinnedLabelSymbolAfterRebase(memSymbol, beforeBaseChangeAddress, match);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fixupPrimarySymbols(primaryFixups);
|
fixupPrimarySymbols(primaryFixups);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fixupPinnedLabelSymbolAfterRebase(SymbolDB symbol, Address newAddress,
|
private void fixupPinnedLabelSymbolAfterRebase(MemorySymbol memSymbol, Address newAddress,
|
||||||
Symbol match) {
|
Symbol match) {
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
match.setPinned(true);
|
match.setPinned(true);
|
||||||
symbol.delete();
|
memSymbol.delete();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
symbol.moveLowLevel(newAddress, null, null, null, true);
|
memSymbol.moveLowLevel(newAddress, null, null, null, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2526,14 +2716,18 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SymbolDB> findPinnedSymbols(Address minAddr, Address maxAddr) {
|
private List<MemorySymbol> findPinnedMemorySymbols(Address minAddr, Address maxAddr) {
|
||||||
List<SymbolDB> pinnedSymbols = new ArrayList<>();
|
List<MemorySymbol> pinnedSymbols = new ArrayList<>();
|
||||||
for (Symbol symbol : getSymbolIterator(minAddr, true)) {
|
for (Symbol symbol : getSymbolIterator(minAddr, true)) {
|
||||||
if (symbol.getAddress().compareTo(maxAddr) > 0) {
|
if (!(symbol instanceof MemorySymbol memSym)) {
|
||||||
|
throw new AssertionError(
|
||||||
|
"Unexpected symbol type within memory range: " + symbol.getClass());
|
||||||
|
}
|
||||||
|
if (memSym.getAddress().compareTo(maxAddr) > 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (symbol.isPinned()) {
|
if (memSym.isPinned()) {
|
||||||
pinnedSymbols.add((SymbolDB) symbol);
|
pinnedSymbols.add(memSym);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pinnedSymbols;
|
return pinnedSymbols;
|
||||||
|
@ -2589,16 +2783,24 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
try {
|
try {
|
||||||
source = adjustSourceTypeIfNecessary(name, type, source, storage);
|
source = adjustSourceTypeIfNecessary(name, type, source, storage);
|
||||||
Address varAddr = variableStorageMgr.getVariableStorageAddress(storage, true);
|
Address varAddr = variableStorageMgr.getVariableStorageAddress(storage, true);
|
||||||
return (VariableSymbolDB) doCreateSpecialSymbol(varAddr, name, function, type, null,
|
DBRecord record =
|
||||||
Integer.valueOf(firstUseOffsetOrOrdinal), null, source, true);
|
doCreateBasicSymbolRecord(name, function, varAddr, type, false, source, true);
|
||||||
|
VariableSymbolDB.setRecordFields(record, firstUseOffsetOrOrdinal, null);
|
||||||
|
adapter.updateSymbolRecord(record);
|
||||||
|
|
||||||
|
VariableSymbolDB newSymbol =
|
||||||
|
new VariableSymbolDB(this, cache, type, variableStorageMgr, varAddr, record);
|
||||||
|
|
||||||
|
symbolAdded(newSymbol);
|
||||||
|
return newSymbol;
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
dbError(e);
|
program.dbError(e); // will not return
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SourceType adjustSourceTypeIfNecessary(String name, SymbolType type, SourceType source,
|
private SourceType adjustSourceTypeIfNecessary(String name, SymbolType type, SourceType source,
|
||||||
|
@ -2616,21 +2818,21 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
@Override
|
@Override
|
||||||
public GhidraClass createClass(Namespace parent, String name, SourceType source)
|
public GhidraClass createClass(Namespace parent, String name, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException {
|
throws DuplicateNameException, InvalidInputException {
|
||||||
SymbolDB s = createClassSymbol(name, parent, source, true);
|
ClassSymbol s = createClassSymbol(name, parent, source, true);
|
||||||
return new GhidraClassDB(s, namespaceMgr);
|
return new GhidraClassDB(s, namespaceMgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Library createExternalLibrary(String name, SourceType source)
|
public Library createExternalLibrary(String name, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException {
|
throws DuplicateNameException, InvalidInputException {
|
||||||
SymbolDB s = createLibrarySymbol(name, null, source);
|
LibrarySymbol s = createLibrarySymbol(name, null, source);
|
||||||
return new LibraryDB(s, namespaceMgr);
|
return new LibraryDB(s, namespaceMgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Namespace createNameSpace(Namespace parent, String name, SourceType source)
|
public Namespace createNameSpace(Namespace parent, String name, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException {
|
throws DuplicateNameException, InvalidInputException {
|
||||||
SymbolDB s = createNamespaceSymbol(name, parent, source, true);
|
NamespaceSymbol s = createNamespaceSymbol(name, parent, source, true);
|
||||||
return new NamespaceDB(s, namespaceMgr);
|
return new NamespaceDB(s, namespaceMgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2657,7 +2859,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
// no duplicate check, since this class name will be set to that of the existing namespace
|
// no duplicate check, since this class name will be set to that of the existing namespace
|
||||||
String tempName = "_temp_" + System.nanoTime();
|
String tempName = "_temp_" + System.nanoTime();
|
||||||
SymbolDB classSymbol = createClassSymbol(tempName, namespace.getParentNamespace(),
|
ClassSymbol classSymbol = createClassSymbol(tempName, namespace.getParentNamespace(),
|
||||||
originalSource, false /*check for duplicate */);
|
originalSource, false /*check for duplicate */);
|
||||||
GhidraClassDB classNamespace = new GhidraClassDB(classSymbol, namespaceMgr);
|
GhidraClassDB classNamespace = new GhidraClassDB(classSymbol, namespaceMgr);
|
||||||
|
|
||||||
|
@ -2705,7 +2907,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
// Note: We know there are no namespaces with the name; do we still have to check for
|
// 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.
|
// duplicates? Assuming yes, as another symbol type may exist with this name.
|
||||||
SymbolDB s = createNamespaceSymbol(name, parent, source, true /*check for duplicates*/);
|
NamespaceSymbol s =
|
||||||
|
createNamespaceSymbol(name, parent, source, true /*check for duplicates*/);
|
||||||
|
|
||||||
return new NamespaceDB(s, namespaceMgr);
|
return new NamespaceDB(s, namespaceMgr);
|
||||||
}
|
}
|
||||||
|
@ -2728,10 +2931,27 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
* or if the given parent namespace is from a different program than that of this
|
* or if the given parent namespace is from a different program than that of this
|
||||||
* symbol table.
|
* symbol table.
|
||||||
*/
|
*/
|
||||||
public SymbolDB createLibrarySymbol(String name, String pathname, SourceType source)
|
public LibrarySymbol createLibrarySymbol(String name, String pathname, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException {
|
throws DuplicateNameException, InvalidInputException {
|
||||||
return doCreateSpecialSymbol(Address.NO_ADDRESS, name, null, SymbolType.LIBRARY, null, null,
|
lock.acquire();
|
||||||
pathname, source, true);
|
try {
|
||||||
|
DBRecord record = doCreateBasicSymbolRecord(name, null, Address.NO_ADDRESS,
|
||||||
|
SymbolType.LIBRARY, false, source, true);
|
||||||
|
LibrarySymbol.setRecordFields(record, pathname);
|
||||||
|
adapter.updateSymbolRecord(record);
|
||||||
|
|
||||||
|
LibrarySymbol newSymbol = new LibrarySymbol(this, cache, record);
|
||||||
|
|
||||||
|
symbolAdded(newSymbol);
|
||||||
|
return newSymbol;
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
program.dbError(e); // will not return
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2749,10 +2969,26 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
* or if the given parent namespace is from a different program than that of this
|
* or if the given parent namespace is from a different program than that of this
|
||||||
* symbol table.
|
* symbol table.
|
||||||
*/
|
*/
|
||||||
SymbolDB createClassSymbol(String name, Namespace parent, SourceType source,
|
ClassSymbol createClassSymbol(String name, Namespace parent, SourceType source,
|
||||||
boolean checkForDuplicates) throws DuplicateNameException, InvalidInputException {
|
boolean checkForDuplicates) throws DuplicateNameException, InvalidInputException {
|
||||||
return doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.CLASS, null, null,
|
lock.acquire();
|
||||||
null, source, true);
|
try {
|
||||||
|
DBRecord record = doCreateBasicSymbolRecord(name, parent, Address.NO_ADDRESS,
|
||||||
|
SymbolType.CLASS, false, source, checkForDuplicates);
|
||||||
|
adapter.updateSymbolRecord(record);
|
||||||
|
|
||||||
|
ClassSymbol newSymbol = new ClassSymbol(this, cache, record);
|
||||||
|
|
||||||
|
symbolAdded(newSymbol);
|
||||||
|
return newSymbol;
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
program.dbError(e); // will not return
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2770,79 +3006,173 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
* if the given parent namespace is from a different program than that of this
|
* if the given parent namespace is from a different program than that of this
|
||||||
* symbol table.
|
* symbol table.
|
||||||
*/
|
*/
|
||||||
SymbolDB createNamespaceSymbol(String name, Namespace parent, SourceType source,
|
NamespaceSymbol createNamespaceSymbol(String name, Namespace parent, SourceType source,
|
||||||
boolean checkForDuplicates) throws DuplicateNameException, InvalidInputException {
|
boolean checkForDuplicates) throws DuplicateNameException, InvalidInputException {
|
||||||
return doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, null,
|
|
||||||
null, null, source, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SymbolDB doCreateSpecialSymbol(Address addr, String name, Namespace parent,
|
|
||||||
SymbolType symbolType, Long dataTypeId, Integer variableOffset, String stringData,
|
|
||||||
SourceType source, boolean checkForDuplicates)
|
|
||||||
throws DuplicateNameException, InvalidInputException {
|
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
parent = validateNamespace(parent, addr, symbolType);
|
DBRecord record = doCreateBasicSymbolRecord(name, parent, Address.NO_ADDRESS,
|
||||||
source = validateSource(source, name, addr, symbolType);
|
SymbolType.NAMESPACE, false, source, checkForDuplicates);
|
||||||
name = validateName(name, source);
|
adapter.updateSymbolRecord(record);
|
||||||
|
|
||||||
if (checkForDuplicates) {
|
NamespaceSymbol newSymbol = new NamespaceSymbol(this, cache, record);
|
||||||
checkDuplicateSymbolName(addr, name, parent, symbolType);
|
|
||||||
|
symbolAdded(newSymbol);
|
||||||
|
return newSymbol;
|
||||||
}
|
}
|
||||||
|
catch (IOException e) {
|
||||||
return doCreateSymbol(name, addr, parent, symbolType, stringData, dataTypeId,
|
program.dbError(e); // will not return
|
||||||
variableOffset, source, false);
|
return null;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a basic symbol record with required fields. Caller is responsible for updating
|
||||||
|
* any related optional record fields and then adding to the DB table via the
|
||||||
|
* {@link SymbolDatabaseAdapter#updateSymbolRecord(DBRecord)} method.
|
||||||
|
* @param name symbol name
|
||||||
|
* @param parent symbol parent namespace (glabel namespace assumed if null)
|
||||||
|
* @param address symbol address
|
||||||
|
* @param symbolType symbol type
|
||||||
|
* @param isPrimary if true, symbol record will be tagged as primary (relavent for label and
|
||||||
|
* function symbols only).
|
||||||
|
* @param source symbol source type
|
||||||
|
* @param checkForDuplicates if true a duplicate name check will be performed within the
|
||||||
|
* specified parent namespace.
|
||||||
|
* @return return new record
|
||||||
|
* @throws DuplicateNameException if checkForDuplicates is true and name conflicts with
|
||||||
|
* another symbol.
|
||||||
|
* @throws InvalidInputException if name contains invalid characters.
|
||||||
|
* See {@link SymbolUtilities#validateName(String)}.
|
||||||
|
*/
|
||||||
|
private DBRecord doCreateBasicSymbolRecord(String name, Namespace parent, Address address,
|
||||||
|
SymbolType symbolType, boolean isPrimary, SourceType source, boolean checkForDuplicates)
|
||||||
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
|
||||||
|
// Only one symbol per external address is allowed
|
||||||
|
if (address.isExternalAddress()) {
|
||||||
|
Symbol primary = getPrimarySymbol(address);
|
||||||
|
if (primary != null) {
|
||||||
|
throw new IllegalArgumentException("external address already used");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = validateNamespace(parent, address, symbolType);
|
||||||
|
source = validateSource(source, name, address, symbolType);
|
||||||
|
name = validateName(name, source);
|
||||||
|
|
||||||
|
if (checkForDuplicates) {
|
||||||
|
checkDuplicateSymbolName(address, name, parent, symbolType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapter.createSymbolRecord(name, parent.getID(), address, symbolType, isPrimary,
|
||||||
|
source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method for creating external data/code symbol.
|
||||||
|
* <p>
|
||||||
|
* NOTE: Any name conflict concerns must be checked before invoking this method.
|
||||||
|
*
|
||||||
|
* @param addr the address for the new symbol
|
||||||
|
* @param name the name of the new symbol
|
||||||
|
* @param namespace the namespace for the new symbol (null may be specified for global
|
||||||
|
* namespace)
|
||||||
|
* @param source the SourceType of the new symbol
|
||||||
|
* @param externalProgramAddress associated external program memory address (may be null)
|
||||||
|
* @param originalImportName original imported name (i.e., mangled name)
|
||||||
|
* @return the new symbol
|
||||||
|
* @throws IOException if IO error occurs
|
||||||
|
* @throws InvalidInputException if the name contains illegal characters (i.e. space)
|
||||||
|
*/
|
||||||
|
public CodeSymbol createExternalCodeSymbol(Address addr, String name, Namespace namespace,
|
||||||
|
SourceType source, String originalImportName, Address externalProgramAddress)
|
||||||
|
throws IOException, InvalidInputException {
|
||||||
|
if (!addr.isExternalAddress()) {
|
||||||
|
throw new IllegalArgumentException("External address required");
|
||||||
|
}
|
||||||
|
if (externalProgramAddress != null && !externalProgramAddress.isLoadedMemoryAddress()) {
|
||||||
|
throw new IllegalArgumentException("Memory address required for external program");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
DBRecord record = doCreateBasicSymbolRecord(name, namespace, addr, SymbolType.LABEL,
|
||||||
|
true, source, false);
|
||||||
|
MemorySymbol.setExternalFields(record, originalImportName, externalProgramAddress);
|
||||||
|
adapter.updateSymbolRecord(record);
|
||||||
|
|
||||||
|
CodeSymbol newSymbol = new CodeSymbol(this, cache, addr, record);
|
||||||
|
|
||||||
|
symbolAdded(newSymbol);
|
||||||
|
return newSymbol;
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException e) {
|
||||||
|
throw new RuntimeException("Unexpected", e); // duplicate was avoided by caller
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method for creating external function symbol.
|
||||||
|
* <p>
|
||||||
|
* NOTE: Any name conflict concerns must be checked before invoking this method.
|
||||||
|
*
|
||||||
|
* @param addr the address for the new symbol
|
||||||
|
* @param name the name of the new symbol
|
||||||
|
* @param namespace the namespace for the new symbol (null may be specified for global
|
||||||
|
* namespace)
|
||||||
|
* @param source the SourceType of the new symbol
|
||||||
|
* @param externalProgramAddress associated external program memory address (may be null)
|
||||||
|
* @param originalImportName original imported name (i.e., mangled name)
|
||||||
|
* @return the new symbol
|
||||||
|
* @throws IOException if IO error occurs
|
||||||
|
* @throws InvalidInputException if the name contains illegal characters (i.e. space)
|
||||||
|
*/
|
||||||
|
public FunctionSymbol createExternalFunctionSymbol(Address addr, String name,
|
||||||
|
Namespace namespace, SourceType source, String originalImportName,
|
||||||
|
Address externalProgramAddress) throws IOException, InvalidInputException {
|
||||||
|
if (!addr.isExternalAddress()) {
|
||||||
|
throw new IllegalArgumentException("External address required");
|
||||||
|
}
|
||||||
|
if (externalProgramAddress != null && !externalProgramAddress.isLoadedMemoryAddress()) {
|
||||||
|
throw new IllegalArgumentException("Memory address required for external program");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
DBRecord record = doCreateBasicSymbolRecord(name, namespace, addr, SymbolType.FUNCTION,
|
||||||
|
true, source, false);
|
||||||
|
MemorySymbol.setExternalFields(record, originalImportName, externalProgramAddress);
|
||||||
|
adapter.updateSymbolRecord(record);
|
||||||
|
|
||||||
|
FunctionSymbol newSymbol = new FunctionSymbol(this, cache, addr, record);
|
||||||
|
|
||||||
|
symbolAdded(newSymbol);
|
||||||
|
return newSymbol;
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException e) {
|
||||||
|
throw new RuntimeException("Unexpected", e); // duplicate was avoided by caller
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol createLabel(Address addr, String name, SourceType source)
|
public Symbol createLabel(Address addr, String name, SourceType source)
|
||||||
throws InvalidInputException {
|
throws IllegalArgumentException, InvalidInputException {
|
||||||
return createLabel(addr, name, null, source);
|
return createLabel(addr, name, null, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol createLabel(Address addr, String name, Namespace namespace, SourceType source)
|
public Symbol createLabel(Address addr, String name, Namespace namespace, SourceType source)
|
||||||
throws InvalidInputException {
|
throws IllegalArgumentException, InvalidInputException {
|
||||||
|
|
||||||
if (!addr.isMemoryAddress()) {
|
if (!addr.isMemoryAddress()) {
|
||||||
throw new IllegalArgumentException("Invalid memory address: " + addr);
|
throw new IllegalArgumentException("Invalid memory address: " + addr);
|
||||||
}
|
}
|
||||||
return createCodeSymbol(addr, name, namespace, source, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal method for creating label symbols.
|
|
||||||
* <p>
|
|
||||||
* If identical memory symbol already exists it will be returned.
|
|
||||||
*
|
|
||||||
* @param addr the address for the new symbol (memory or external)
|
|
||||||
* @param name the name of the new symbol
|
|
||||||
* @param namespace the namespace for the new symbol (null may be specified for global
|
|
||||||
* namespace)
|
|
||||||
* @param source the SourceType of the new symbol
|
|
||||||
* @param stringData special use depending on the symbol type and whether or not it is external
|
|
||||||
* @return the new symbol
|
|
||||||
* @throws InvalidInputException if name contains white space, is zero length, or is null for
|
|
||||||
* non-default source. Also thrown if invalid parent namespace is specified.
|
|
||||||
* @throws IllegalArgumentException if {@link SourceType#DEFAULT} is improperly specified, or
|
|
||||||
* an invalid address, or if the given parent namespace is from a different
|
|
||||||
* program than that of this symbol table.
|
|
||||||
*/
|
|
||||||
public Symbol createCodeSymbol(Address addr, String name, Namespace namespace,
|
|
||||||
SourceType source, String stringData) throws InvalidInputException {
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
namespace = validateNamespace(namespace, addr, SymbolType.LABEL);
|
namespace = validateNamespace(namespace, addr, SymbolType.LABEL);
|
||||||
source = validateSource(source, name, addr, SymbolType.LABEL);
|
source = validateSource(source, name, addr, SymbolType.LABEL);
|
||||||
name = validateName(name, source);
|
name = validateName(name, source);
|
||||||
|
|
||||||
boolean makePrimary = true;
|
|
||||||
if (addr.isMemoryAddress()) {
|
|
||||||
|
|
||||||
Symbol symbol = getSymbol(name, addr, namespace);
|
Symbol symbol = getSymbol(name, addr, namespace);
|
||||||
if (symbol != null) {
|
if (symbol != null) {
|
||||||
return symbol;
|
return symbol;
|
||||||
|
@ -2860,71 +3190,44 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
deleteDynamicSymbol(primary);
|
deleteDynamicSymbol(primary);
|
||||||
primary = null;
|
primary = null;
|
||||||
}
|
}
|
||||||
makePrimary = (primary == null);
|
boolean makePrimary = (primary == null);
|
||||||
}
|
|
||||||
else if (addr.isExternalAddress()) {
|
|
||||||
// TODO: remove support for external symbol creation from this method (see GP-3045)
|
|
||||||
Symbol primary = getPrimarySymbol(addr);
|
|
||||||
if (primary != null) { // only one symbol per external address is allowed
|
|
||||||
throw new IllegalArgumentException("external address already used");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException("Invalid memory address: " + addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, stringData, null, null,
|
DBRecord record = doCreateBasicSymbolRecord(name, namespace, addr, SymbolType.LABEL,
|
||||||
source, makePrimary);
|
makePrimary, source, false);
|
||||||
|
adapter.updateSymbolRecord(record);
|
||||||
|
|
||||||
|
CodeSymbol newSymbol = new CodeSymbol(this, cache, addr, record);
|
||||||
|
|
||||||
|
symbolAdded(newSymbol);
|
||||||
|
return newSymbol;
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException e) {
|
||||||
|
throw new RuntimeException("Unexpected", e); // duplicate was avoided above
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
program.dbError(e);
|
||||||
|
return null; // will not occur
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public FunctionSymbol createMemoryFunctionSymbol(Address addr, String name, Namespace namespace,
|
||||||
* Internal method for creating function symbols
|
SourceType source) throws IOException, InvalidInputException {
|
||||||
*
|
|
||||||
* @param addr the address for the new symbol
|
if (!addr.isMemoryAddress()) {
|
||||||
* @param name the name of the new symbol
|
throw new IllegalArgumentException("memory address required");
|
||||||
* @param namespace the namespace for the new symbol (null may be specified for global
|
}
|
||||||
* namespace)
|
|
||||||
* @param source the SourceType of the new symbol
|
|
||||||
* @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 stringData) throws InvalidInputException {
|
|
||||||
|
|
||||||
namespace = validateNamespace(namespace, addr, SymbolType.FUNCTION);
|
namespace = validateNamespace(namespace, addr, SymbolType.FUNCTION);
|
||||||
source = validateSource(source, name, addr, SymbolType.FUNCTION);
|
source = validateSource(source, name, addr, SymbolType.FUNCTION);
|
||||||
name = validateName(name, source);
|
name = validateName(name, source);
|
||||||
|
|
||||||
if (addr.isMemoryAddress()) {
|
|
||||||
return doCreateMemoryFunctionSymbol(addr, name, namespace, source, stringData);
|
|
||||||
}
|
|
||||||
else if (addr.isExternalAddress()) {
|
|
||||||
// only one symbol per external address is allowed
|
|
||||||
Symbol primary = getPrimarySymbol(addr);
|
|
||||||
if (primary != null) {
|
|
||||||
throw new IllegalArgumentException("external address already used");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException("bad function address");
|
|
||||||
}
|
|
||||||
|
|
||||||
return doCreateSymbol(name, addr, namespace, SymbolType.FUNCTION, stringData, null, null,
|
|
||||||
source, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Symbol doCreateMemoryFunctionSymbol(Address addr, String name, Namespace namespace,
|
|
||||||
SourceType source, String stringData) throws InvalidInputException {
|
|
||||||
|
|
||||||
// if there is already a FUNCTION symbol with that name and namespace here, just return it.
|
// if there is already a FUNCTION symbol with that name and namespace here, just return it.
|
||||||
Symbol matching = getSymbol(name, addr, namespace);
|
Symbol matching = getSymbol(name, addr, namespace);
|
||||||
if (matching != null && matching.getSymbolType() == SymbolType.FUNCTION) {
|
if (matching instanceof FunctionSymbol funcSymbol) {
|
||||||
return matching;
|
return funcSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is another function at the same address, throw InvalidInputException
|
// if there is another function at the same address, throw InvalidInputException
|
||||||
|
@ -2947,14 +3250,25 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
// delete any promoted symbol, dynamic symbol, and make sure all others are not primary
|
// delete any promoted symbol, dynamic symbol, and make sure all others are not primary
|
||||||
cleanUpSymbols(addr, symbolToPromote, primary);
|
cleanUpSymbols(addr, symbolToPromote, primary);
|
||||||
|
|
||||||
Symbol symbol = doCreateSymbol(name, addr, namespace, SymbolType.FUNCTION, stringData, null,
|
DBRecord record;
|
||||||
null, source, true);
|
try {
|
||||||
|
record = doCreateBasicSymbolRecord(name, namespace, addr, SymbolType.FUNCTION, true,
|
||||||
if (needsPinning) {
|
source, false);
|
||||||
symbol.setPinned(true);
|
adapter.updateSymbolRecord(record);
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException e) {
|
||||||
|
throw new RuntimeException("Unexpected", e); // duplicate was avoided above
|
||||||
}
|
}
|
||||||
|
|
||||||
return symbol;
|
FunctionSymbol newSymbol = new FunctionSymbol(this, cache, addr, record);
|
||||||
|
|
||||||
|
symbolAdded(newSymbol);
|
||||||
|
|
||||||
|
if (needsPinning) {
|
||||||
|
newSymbol.setPinned(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3011,24 +3325,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SymbolDB doCreateSymbol(String name, Address addr, Namespace namespace, SymbolType type,
|
|
||||||
String stringData, Long dataTypeId, Integer variableOffset, SourceType source,
|
|
||||||
boolean isPrimary) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
DBRecord record = adapter.createSymbol(name, addr, namespace.getID(), type, stringData,
|
|
||||||
dataTypeId, variableOffset, source, isPrimary);
|
|
||||||
|
|
||||||
SymbolDB newSymbol = makeSymbol(addr, record, type);
|
|
||||||
symbolAdded(newSymbol);
|
|
||||||
return newSymbol;
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
program.dbError(e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String validateName(String name, SourceType source) throws InvalidInputException {
|
private String validateName(String name, SourceType source) throws InvalidInputException {
|
||||||
if (source == SourceType.DEFAULT) {
|
if (source == SourceType.DEFAULT) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -3171,9 +3467,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
void checkValidNamespaceArgument(Namespace namespace) throws IllegalArgumentException {
|
void checkValidNamespaceArgument(Namespace namespace) throws IllegalArgumentException {
|
||||||
if (!isMyNamespace(namespace)) {
|
if (!isMyNamespace(namespace)) {
|
||||||
String kind = (namespace instanceof Function) ? "function" : "namespace";
|
throw new IllegalArgumentException(namespace.getType().friendlyName() +
|
||||||
throw new IllegalArgumentException(
|
" is from a different program instance: " + namespace);
|
||||||
kind + " is from different program instance: " + namespace);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Variable getObject() {
|
||||||
FunctionDB func = getFunction();
|
FunctionDB func = getFunction();
|
||||||
if (func != null) {
|
if (func != null) {
|
||||||
return func.getVariable(this);
|
return func.getVariable(this);
|
||||||
|
@ -159,13 +159,12 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
|
|
||||||
public FunctionDB getFunction() {
|
public FunctionDB getFunction() {
|
||||||
return (FunctionDB) symbolMgr.getFunctionManager()
|
return (FunctionDB) symbolMgr.getFunctionManager()
|
||||||
.getFunction(
|
.getFunction(getParentNamespace().getID());
|
||||||
getParentNamespace().getID());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgramLocation getProgramLocation() {
|
public ProgramLocation getProgramLocation() {
|
||||||
Variable var = (Variable) getObject();
|
Variable var = getObject();
|
||||||
if (var != null) {
|
if (var != null) {
|
||||||
return new VariableNameFieldLocation(var.getProgram(), var, 0);
|
return new VariableNameFieldLocation(var.getProgram(), var, 0);
|
||||||
}
|
}
|
||||||
|
@ -311,20 +310,90 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
ReferenceManager rm = symbolMgr.getReferenceManager();
|
ReferenceManager rm = symbolMgr.getReferenceManager();
|
||||||
return rm.getReferencesTo((Variable) getObject());
|
return rm.getReferencesTo(getObject());
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasMultipleReferences() {
|
|
||||||
return getReferences(null).length > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasReferences() {
|
public boolean hasReferences() {
|
||||||
return getReferences(null).length != 0;
|
return getReferences(null).length != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the generic symbol data 2 data.
|
||||||
|
* @return the symbol data
|
||||||
|
*/
|
||||||
|
protected int getVariableOffset() {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkIsValid();
|
||||||
|
if (record != null) {
|
||||||
|
return record.getIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 setVariableOffset(int offset) {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkDeleted();
|
||||||
|
if (record != null) {
|
||||||
|
record.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, offset);
|
||||||
|
updateRecord();
|
||||||
|
symbolMgr.symbolDataChanged(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return variable symbol comment}
|
||||||
|
*/
|
||||||
|
public String getSymbolComment() {
|
||||||
|
validate(lock);
|
||||||
|
return record.getString(SymbolDatabaseAdapter.SYMBOL_COMMENT_COL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update variable symbol comment (no change event is issued)
|
||||||
|
* @param comment variable comment
|
||||||
|
*/
|
||||||
|
public void setSymbolComment(String comment) {
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
checkDeleted();
|
||||||
|
record.setString(SymbolDatabaseAdapter.SYMBOL_COMMENT_COL, comment);
|
||||||
|
updateRecord();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update variable symbol record fields
|
||||||
|
* @param record variable symbol record
|
||||||
|
* @param firstUseOffsetOrOrdinal first use offset or param ordinal (ignored if null)
|
||||||
|
* @param comment variable comment
|
||||||
|
*/
|
||||||
|
static void setRecordFields(DBRecord record, Integer firstUseOffsetOrOrdinal, String comment) {
|
||||||
|
if (firstUseOffsetOrOrdinal != null) {
|
||||||
|
record.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, firstUseOffsetOrOrdinal);
|
||||||
|
}
|
||||||
|
record.setString(SymbolDatabaseAdapter.SYMBOL_COMMENT_COL, comment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,21 +115,11 @@ public class GlobalSymbol implements Symbol {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasMultipleReferences() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasReferences() {
|
public boolean hasReferences() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Reference[] getReferences() {
|
|
||||||
return new Reference[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Reference[] getReferences(TaskMonitor monitor) {
|
public Reference[] getReferences(TaskMonitor monitor) {
|
||||||
return new Reference[0];
|
return new Reference[0];
|
||||||
|
|
|
@ -81,6 +81,11 @@ public interface Function extends Namespace {
|
||||||
public final static int UNKNOWN_STACK_DEPTH_CHANGE = Integer.MAX_VALUE;
|
public final static int UNKNOWN_STACK_DEPTH_CHANGE = Integer.MAX_VALUE;
|
||||||
public final static int INVALID_STACK_DEPTH_CHANGE = Integer.MAX_VALUE - 1;
|
public final static int INVALID_STACK_DEPTH_CHANGE = Integer.MAX_VALUE - 1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default Type getType() {
|
||||||
|
return Type.FUNCTION;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of this function.
|
* Get the name of this function.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,10 +17,13 @@ package ghidra.program.model.listing;
|
||||||
|
|
||||||
import ghidra.program.model.symbol.Namespace;
|
import ghidra.program.model.symbol.Namespace;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for representing class objects in the program.
|
* Interface for representing class objects in the program.
|
||||||
*/
|
*/
|
||||||
public interface GhidraClass extends Namespace {
|
public interface GhidraClass extends Namespace {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public default Type getType() {
|
||||||
|
return Type.CLASS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.listing;
|
package ghidra.program.model.listing;
|
||||||
|
|
||||||
import ghidra.program.model.symbol.Namespace;
|
import ghidra.program.model.symbol.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for a Library namespace.
|
* Interface for a Library namespace.
|
||||||
|
@ -24,9 +24,39 @@ public interface Library extends Namespace {
|
||||||
|
|
||||||
public static final String UNKNOWN = "<EXTERNAL>";
|
public static final String UNKNOWN = "<EXTERNAL>";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public default Type getType() {
|
||||||
|
return Type.LIBRARY;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the associated program within the project which corresponds to this library
|
* @return the associated program within the project which corresponds to this library
|
||||||
*/
|
*/
|
||||||
public String getAssociatedProgramPath();
|
public String getAssociatedProgramPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Library which contains the specified external symbol.
|
||||||
|
* @param symbol external symbol
|
||||||
|
* @return null if symbol is null or not external
|
||||||
|
*/
|
||||||
|
public static Library getContainingLibrary(Symbol symbol) {
|
||||||
|
if (symbol == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (symbol.getSymbolType() == SymbolType.LIBRARY) {
|
||||||
|
return (Library) symbol.getObject();
|
||||||
|
}
|
||||||
|
if (symbol.getSymbolType() == SymbolType.NAMESPACE ||
|
||||||
|
symbol.getSymbolType() == SymbolType.CLASS) {
|
||||||
|
while (symbol != null && symbol.isExternal()) {
|
||||||
|
Namespace n = (Namespace) symbol.getObject();
|
||||||
|
if (n instanceof Library lib) {
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
symbol = n.getParentNamespace().getSymbol();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.symbol;
|
package ghidra.program.model.symbol;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
|
@ -74,15 +74,15 @@ public interface ExternalManager {
|
||||||
* @param oldName the old name of the external library name.
|
* @param oldName the old name of the external library name.
|
||||||
* @param newName the new name of the external library name.
|
* @param newName the new name of the external library name.
|
||||||
* @param source the source of this external library
|
* @param source the source of this external library
|
||||||
* @throws DuplicateNameException if another namespace has the same name
|
* @throws DuplicateNameException if name conflicts with another symbol.
|
||||||
* @throws InvalidInputException on invalid input
|
* @throws InvalidInputException if an invalid or null name specified (see
|
||||||
|
* {@link SymbolUtilities#validateName}).
|
||||||
*/
|
*/
|
||||||
public void updateExternalLibraryName(String oldName, String newName, SourceType source)
|
public void updateExternalLibraryName(String oldName, String newName, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException;
|
throws DuplicateNameException, InvalidInputException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an iterator over all external locations associated with the specified
|
* Get an iterator over all external locations associated with the specified Library.
|
||||||
* externalName.
|
|
||||||
* @param libraryName the name of the library to get locations for
|
* @param libraryName the name of the library to get locations for
|
||||||
* @return external location iterator
|
* @return external location iterator
|
||||||
*/
|
*/
|
||||||
|
@ -97,54 +97,46 @@ public interface ExternalManager {
|
||||||
public ExternalLocationIterator getExternalLocations(Address memoryAddress);
|
public ExternalLocationIterator getExternalLocations(Address memoryAddress);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an external location.
|
* Returns a set of External Locations matching the given label name in the specified Library.
|
||||||
* @param libraryName the name of the library for which to get an external location
|
* If searching for an original import name which should not be constrained to a specific
|
||||||
* @param label the name of the external location.
|
* library (e.g., mangled name), null may be specified for the libraryName.
|
||||||
* @return first matching external location
|
*
|
||||||
* @deprecated Use {@link #getExternalLocations(String, String)} or
|
|
||||||
* {@link #getUniqueExternalLocation(String, String)} since duplicate names may exist
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public ExternalLocation getExternalLocation(String libraryName, String label);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an external location.
|
|
||||||
* @param namespace the namespace containing the external label.
|
|
||||||
* @param label the name of the external location.
|
|
||||||
* @return first matching external location
|
|
||||||
* @deprecated Use {@link #getExternalLocations(Namespace, String)} or
|
|
||||||
* {@link #getUniqueExternalLocation(Namespace, String)} since duplicate names may exist
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public ExternalLocation getExternalLocation(Namespace namespace, String label);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of External Locations matching the given label name in the given Library.
|
|
||||||
* @param libraryName the name of the library
|
* @param libraryName the name of the library
|
||||||
* @param label the name of the label
|
* @param label the name of the label
|
||||||
* @return a list of External Locations matching the given label name in the given Library.
|
* @return a list of External Locations matching the given label name in the given Library.
|
||||||
*/
|
*/
|
||||||
public List<ExternalLocation> getExternalLocations(String libraryName, String label);
|
public Set<ExternalLocation> getExternalLocations(String libraryName, String label);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of External Locations matching the given label name in the given Namespace.
|
* Returns a set of External Locations matching the given label name in the given Namespace.
|
||||||
* @param namespace the Namespace to search
|
* If searching for an original import name which should not be constrained to a specific
|
||||||
|
* library (e.g., mangled name), null may be specified for the namespace. If a library
|
||||||
|
* sub-namespace is specified the original import name will not be searched.
|
||||||
|
*
|
||||||
|
* @param namespace the external Namespace to search or null
|
||||||
* @param label the name of the labels to search for.
|
* @param label the name of the labels to search for.
|
||||||
* @return a list of External Locations matching the given label name in the given Namespace.
|
* @return a list of External Locations matching the given label name in the given Namespace.
|
||||||
*/
|
*/
|
||||||
public List<ExternalLocation> getExternalLocations(Namespace namespace, String label);
|
public Set<ExternalLocation> getExternalLocations(Namespace namespace, String label);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the unique external location associated with the given library name and label
|
* Returns the unique external location associated with the given library name and label.
|
||||||
* @param libraryName the library name
|
* If searching for an original import name which should not be constrained to a specific
|
||||||
|
* library (e.g., mangled name), null may be specified for the libraryName.
|
||||||
|
*
|
||||||
|
* @param libraryName the library name or null
|
||||||
* @param label the label of the external location
|
* @param label the label of the external location
|
||||||
* @return the unique external location or null
|
* @return the unique external location or null
|
||||||
*/
|
*/
|
||||||
public ExternalLocation getUniqueExternalLocation(String libraryName, String label);
|
public ExternalLocation getUniqueExternalLocation(String libraryName, String label);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the unique external location associated with the given namespace and label
|
* Returns the unique external location associated with the given namespace and label.
|
||||||
* @param namespace the namespace
|
* If searching for an original import name which should not be constrained to a specific
|
||||||
|
* library (e.g., mangled name), null may be specified for the namespace. If a library
|
||||||
|
* sub-namespace is specified the original import name will not be searched.
|
||||||
|
*
|
||||||
|
* @param namespace the namespace or null
|
||||||
* @param label the label of the external location
|
* @param label the label of the external location
|
||||||
* @return the unique external location or null
|
* @return the unique external location or null
|
||||||
*/
|
*/
|
||||||
|
@ -229,8 +221,7 @@ public interface ExternalManager {
|
||||||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||||
*/
|
*/
|
||||||
public ExternalLocation addExtLocation(Namespace extNamespace, String extLabel, Address extAddr,
|
public ExternalLocation addExtLocation(Namespace extNamespace, String extLabel, Address extAddr,
|
||||||
SourceType sourceType, boolean reuseExisting)
|
SourceType sourceType, boolean reuseExisting) throws InvalidInputException;
|
||||||
throws InvalidInputException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an external {@link Function} in the external {@link Library} namespace
|
* Create an external {@link Function} in the external {@link Library} namespace
|
||||||
|
@ -285,7 +276,6 @@ public interface ExternalManager {
|
||||||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||||
*/
|
*/
|
||||||
public ExternalLocation addExtFunction(Namespace extNamespace, String extLabel, Address extAddr,
|
public ExternalLocation addExtFunction(Namespace extNamespace, String extLabel, Address extAddr,
|
||||||
SourceType sourceType, boolean reuseExisting)
|
SourceType sourceType, boolean reuseExisting) throws InvalidInputException;
|
||||||
throws InvalidInputException;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,26 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
*/
|
*/
|
||||||
public interface Namespace {
|
public interface Namespace {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of {@link Namespace}.
|
||||||
|
*/
|
||||||
|
public enum Type {
|
||||||
|
NAMESPACE("Namespace"), LIBRARY("Library"), CLASS("Class"), FUNCTION("Function");
|
||||||
|
|
||||||
|
private final String friendlyName;
|
||||||
|
|
||||||
|
private Type(String friendlyName) {
|
||||||
|
this.friendlyName = friendlyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return a friendly name for use in messages}
|
||||||
|
*/
|
||||||
|
public String friendlyName() {
|
||||||
|
return friendlyName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static final long GLOBAL_NAMESPACE_ID = 0;
|
static final long GLOBAL_NAMESPACE_ID = 0;
|
||||||
/**
|
/**
|
||||||
* The delimiter that is used to separate namespace nodes in a namespace
|
* The delimiter that is used to separate namespace nodes in a namespace
|
||||||
|
@ -47,6 +67,13 @@ public interface Namespace {
|
||||||
*/
|
*/
|
||||||
public Symbol getSymbol();
|
public Symbol getSymbol();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the type of namespace, e.g., Library, Class, Namespace, Function}
|
||||||
|
*/
|
||||||
|
public default Type getType() {
|
||||||
|
return Type.NAMESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this namespace is external (i.e., associated with a Library)
|
* Returns true if this namespace is external (i.e., associated with a Library)
|
||||||
* @return true if this namespace is external (i.e., associated with a Library)
|
* @return true if this namespace is external (i.e., associated with a Library)
|
||||||
|
|
|
@ -93,19 +93,26 @@ public interface Symbol {
|
||||||
public SymbolType getSymbolType();
|
public SymbolType getSymbolType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the number of References to this symbol.
|
* Get the number of References to this symbol or its address.
|
||||||
|
* <P>
|
||||||
|
* NOTE: this method differ from {@link #hasReferences()} behavior for memory symbols since this
|
||||||
|
* method will return {@link ReferenceManager#getReferenceCountTo(Address)} if this is the only
|
||||||
|
* symbol at its address.
|
||||||
|
*
|
||||||
|
* @return the number of References to this symbol or its address.
|
||||||
*/
|
*/
|
||||||
public int getReferenceCount();
|
public default int getReferenceCount() {
|
||||||
|
return 0;
|
||||||
/**
|
}
|
||||||
* @return true if this symbol has more than one reference to it.
|
|
||||||
*/
|
|
||||||
public boolean hasMultipleReferences();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if this symbol has at least one reference to it.
|
* @return true if this symbol has at least one reference to it.
|
||||||
|
* Explicit references to other symbols at the same address are not considered
|
||||||
|
* (see {@link Reference#getSymbolID()} which indicates a specific symbol reference).
|
||||||
*/
|
*/
|
||||||
public boolean hasReferences();
|
public default boolean hasReferences() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all memory references to the address of this symbol. If you do not have a
|
* Returns all memory references to the address of this symbol. If you do not have a
|
||||||
|
@ -117,7 +124,9 @@ public interface Symbol {
|
||||||
* @param monitor the monitor that is used to report progress and to cancel this
|
* @param monitor the monitor that is used to report progress and to cancel this
|
||||||
* potentially long-running call
|
* potentially long-running call
|
||||||
*/
|
*/
|
||||||
public Reference[] getReferences(TaskMonitor monitor);
|
public default Reference[] getReferences(TaskMonitor monitor) {
|
||||||
|
return new Reference[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all memory references to the address of this symbol.
|
* Returns all memory references to the address of this symbol.
|
||||||
|
@ -125,7 +134,9 @@ public interface Symbol {
|
||||||
* @return all memory references to the address of this symbol
|
* @return all memory references to the address of this symbol
|
||||||
* @see #getReferences(TaskMonitor)
|
* @see #getReferences(TaskMonitor)
|
||||||
*/
|
*/
|
||||||
public Reference[] getReferences();
|
public default Reference[] getReferences() {
|
||||||
|
return getReferences(TaskMonitor.DUMMY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a program location for this symbol; may be null. This allows implementations to
|
* Returns a program location for this symbol; may be null. This allows implementations to
|
||||||
|
@ -145,10 +156,9 @@ public interface Symbol {
|
||||||
* @param source the source of this symbol
|
* @param source the source of this symbol
|
||||||
* <br>Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT.
|
* <br>Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT.
|
||||||
*
|
*
|
||||||
* @throws DuplicateNameException
|
* @throws DuplicateNameException if name conflicts with another symbol.
|
||||||
* if name already exists as the name of another symbol or alias.
|
* @throws InvalidInputException if an invalid or null name specified (see
|
||||||
* @throws InvalidInputException
|
* {@link SymbolUtilities#validateName}).
|
||||||
* if alias contains blank characters, is zero length, or is null
|
|
||||||
* @throws IllegalArgumentException if you try to set the source to DEFAULT for a symbol type
|
* @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.
|
||||||
*/
|
*/
|
||||||
|
@ -199,7 +209,9 @@ public interface Symbol {
|
||||||
*
|
*
|
||||||
* @return true if the symbol is pinned to its current address.
|
* @return true if the symbol is pinned to its current address.
|
||||||
*/
|
*/
|
||||||
public boolean isPinned();
|
public default boolean isPinned() {
|
||||||
|
return false; //most symbols can't be pinned.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Sets whether or not this symbol is pinned to its associated address.</p>
|
* <p>Sets whether or not this symbol is pinned to its associated address.</p>
|
||||||
|
@ -215,7 +227,9 @@ public interface Symbol {
|
||||||
* @param pinned true indicates this symbol is anchored to its address.
|
* @param pinned true indicates this symbol is anchored to its address.
|
||||||
* false indicates this symbol is not anchored to its address.
|
* false indicates this symbol is not anchored to its address.
|
||||||
*/
|
*/
|
||||||
public void setPinned(boolean pinned);
|
public default void setPinned(boolean pinned) {
|
||||||
|
throw new UnsupportedOperationException("Only Code and Function Symbols may be pinned.");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if this symbol is a dynamic symbol (not actually defined in the database).
|
* @return true if this symbol is a dynamic symbol (not actually defined in the database).
|
||||||
|
@ -246,7 +260,9 @@ public interface Symbol {
|
||||||
* @return true if the symbol is at an address
|
* @return true if the symbol is at an address
|
||||||
* set as a external entry point.
|
* set as a external entry point.
|
||||||
*/
|
*/
|
||||||
public boolean isExternalEntryPoint();
|
public default boolean isExternalEntryPoint() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return this symbol's ID.
|
* @return this symbol's ID.
|
||||||
|
@ -259,7 +275,7 @@ public interface Symbol {
|
||||||
public Object getObject();
|
public Object getObject();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the symbol is global
|
* @return true if the symbol is contained within the global namespace
|
||||||
*/
|
*/
|
||||||
public boolean isGlobal();
|
public boolean isGlobal();
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ public interface SymbolTable {
|
||||||
* returned without changing the source type. If this is the first non-dynamic symbol defined
|
* returned without changing the source type. If this is the first non-dynamic symbol defined
|
||||||
* for the address it becomes the primary symbol.
|
* for the address it becomes the primary symbol.
|
||||||
*
|
*
|
||||||
* @param addr the address at which to create a symbol
|
* @param addr the memory address at which to create a symbol
|
||||||
* @param name the name of the symbol
|
* @param name the name of the symbol
|
||||||
* @param namespace the parent namespace of the symbol, or null for the global namespace.
|
* @param namespace the parent namespace of the symbol, or null for the global namespace.
|
||||||
* @param source the source of this symbol. In general, a source of {@link SourceType#DEFAULT}
|
* @param source the source of this symbol. In general, a source of {@link SourceType#DEFAULT}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import ghidra.program.model.listing.CircularDependencyException;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
|
|
||||||
// Simple symbol test implementation
|
// Simple symbol test implementation
|
||||||
public class StubSymbol implements Symbol {
|
public class StubSymbol implements Symbol {
|
||||||
|
@ -106,31 +105,6 @@ public class StubSymbol implements Symbol {
|
||||||
return SymbolType.LABEL;
|
return SymbolType.LABEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getReferenceCount() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasMultipleReferences() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasReferences() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Reference[] getReferences(TaskMonitor monitor) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Reference[] getReferences() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setName(String newName, SourceType source)
|
public void setName(String newName, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException {
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
@ -154,16 +128,6 @@ public class StubSymbol implements Symbol {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPinned() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPinned(boolean pinned) {
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDynamic() {
|
public boolean isDynamic() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -184,11 +148,6 @@ public class StubSymbol implements Symbol {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isExternalEntryPoint() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getID() {
|
public long getID() {
|
||||||
return name.hashCode();
|
return name.hashCode();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue