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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMultipleReferences() {
|
||||
// TODO: Could be slightly more efficient by just iterating twice?
|
||||
return getReferenceCount() > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasReferences() {
|
||||
return !getReferenceCollection().isEmpty();
|
||||
|
@ -564,8 +558,4 @@ public abstract class AbstractDBTraceSymbol extends DBAnnotatedObject
|
|||
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
|
||||
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
||||
*/
|
||||
@Deprecated(since = "11.1")
|
||||
@Deprecated(forRemoval = true, since = "11.1")
|
||||
public class AddMemoryParameterCommand extends AddParameterCommand {
|
||||
|
||||
private final Address memAddr;
|
||||
|
|
|
@ -34,7 +34,7 @@ import ghidra.util.exception.InvalidInputException;
|
|||
* @deprecated function signatures should be modified in their entirety using
|
||||
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
||||
*/
|
||||
@Deprecated(since = "11.1")
|
||||
@Deprecated(forRemoval = true, since = "11.1")
|
||||
public class AddParameterCommand implements Command<Program> {
|
||||
|
||||
protected final Function function;
|
||||
|
|
|
@ -27,7 +27,7 @@ import ghidra.util.exception.InvalidInputException;
|
|||
* @deprecated function signatures should be modified in their entirety using
|
||||
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
||||
*/
|
||||
@Deprecated(since = "11.1")
|
||||
@Deprecated(forRemoval = true, since = "11.1")
|
||||
public class AddRegisterParameterCommand extends AddParameterCommand {
|
||||
|
||||
private final Register register;
|
||||
|
|
|
@ -26,7 +26,7 @@ import ghidra.util.exception.InvalidInputException;
|
|||
* @deprecated function signatures should be modified in their entirety using
|
||||
* either {@link UpdateFunctionCommand} or {@link ApplyFunctionSignatureCmd}.
|
||||
*/
|
||||
@Deprecated(since = "11.1")
|
||||
@Deprecated(forRemoval = true, since = "11.1")
|
||||
public class AddStackParameterCommand extends AddParameterCommand {
|
||||
|
||||
private final int stackOffset;
|
||||
|
|
|
@ -48,8 +48,6 @@ import ghidra.framework.options.OptionsChangeListener;
|
|||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
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.listing.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
|
@ -736,7 +734,11 @@ public class CodeBrowserClipboardProvider extends ByteCopier
|
|||
|
||||
SymbolTable symbolTable = currentProgram.getSymbolTable();
|
||||
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);
|
||||
return tool.execute(cmd, currentProgram);
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@ import ghidra.app.context.ListingActionContext;
|
|||
import ghidra.app.context.ListingContextAction;
|
||||
import ghidra.program.database.symbol.CodeSymbol;
|
||||
import ghidra.program.database.symbol.FunctionSymbol;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.*;
|
||||
|
||||
/**
|
||||
* <CODE>RemoveLabelAction</CODE> allows the user to remove a label.
|
||||
|
@ -63,8 +62,12 @@ class RemoveLabelAction extends ListingContextAction {
|
|||
|
||||
boolean isOnSymbol(ListingActionContext context) {
|
||||
Symbol s = plugin.getSymbol(context);
|
||||
return ((s instanceof CodeSymbol) && !s.isDynamic()) ||
|
||||
((s instanceof FunctionSymbol) && s.getSource() != SourceType.DEFAULT);
|
||||
if (s == null) {
|
||||
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.event.ItemListener;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.*;
|
||||
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.
|
||||
*/
|
||||
private void popupProgramChooser() {
|
||||
DataTreeDialog d =
|
||||
new DataTreeDialog(this.getParent(), "Choose External Program", OPEN);
|
||||
DataTreeDialog d = new DataTreeDialog(this.getParent(), "Choose External Program", OPEN);
|
||||
final DataTreeDialog dialog = d;
|
||||
d.addOkActionListener(e -> {
|
||||
DomainFile df = dialog.getDomainFile();
|
||||
|
@ -402,10 +401,9 @@ class EditExternalLocationPanel extends JPanel {
|
|||
String locationName = getLocationName();
|
||||
if (locationName != null && locationName.length() > 0) {
|
||||
ExternalManager externalManager = program.getExternalManager();
|
||||
List<ExternalLocation> externalLocations =
|
||||
Set<ExternalLocation> externalLocations =
|
||||
externalManager.getExternalLocations(extLibName, locationName);
|
||||
externalLocations.remove(externalLocation);
|
||||
if (!externalLocations.isEmpty()) {
|
||||
if (externalLocations.size() == 1 && !externalLocations.contains(externalLocation)) {
|
||||
int result = OptionDialog.showYesNoDialog(null, "Duplicate External Name",
|
||||
"Another symbol named '" + locationName + "' already exists in the '" +
|
||||
extLibName + "' library. Are you sure you want to create another?");
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,32 +15,37 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.symboltree.actions;
|
||||
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.context.ProgramSymbolActionContext;
|
||||
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.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.util.HelpLocation;
|
||||
import docking.action.MenuData;
|
||||
|
||||
public class PinSymbolAction extends ProgramSymbolContextAction {
|
||||
|
||||
public PinSymbolAction(String owner, String popupGroup) {
|
||||
super("Pin Symbol", owner);
|
||||
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"));
|
||||
}
|
||||
|
||||
private boolean canPinSymbol(Symbol symbol) {
|
||||
SymbolType type = symbol.getSymbolType();
|
||||
return (type == SymbolType.LABEL || type == SymbolType.FUNCTION) && !symbol.isExternal() &&
|
||||
!symbol.isPinned();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(ProgramSymbolActionContext context) {
|
||||
Program program = context.getProgram();
|
||||
int transactionID = program.startTransaction("Pin Symbol(s)");
|
||||
try {
|
||||
for (Symbol symbol : context.getSymbols()) {
|
||||
if ((symbol instanceof CodeSymbol || symbol instanceof FunctionSymbol) &&
|
||||
!symbol.isExternal() && !symbol.isPinned()) {
|
||||
if (canPinSymbol(symbol)) {
|
||||
symbol.setPinned(true);
|
||||
}
|
||||
}
|
||||
|
@ -54,8 +58,7 @@ public class PinSymbolAction extends ProgramSymbolContextAction {
|
|||
@Override
|
||||
protected boolean isEnabledForContext(ProgramSymbolActionContext context) {
|
||||
for (Symbol symbol : context.getSymbols()) {
|
||||
if ((symbol instanceof CodeSymbol || symbol instanceof FunctionSymbol) &&
|
||||
!symbol.isExternal() && !symbol.isPinned()) {
|
||||
if (canPinSymbol(symbol)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import static org.junit.Assert.*;
|
|||
import java.awt.Component;
|
||||
import java.awt.Window;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.border.Border;
|
||||
|
@ -926,4 +927,33 @@ public abstract class AbstractExternalMergerTest extends AbstractListingMergeMan
|
|||
}
|
||||
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 java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.app.cmd.function.AddRegisterParameterCommand;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
|
@ -1604,35 +1603,18 @@ public class ExternalFunctionMergeManagerTest extends AbstractExternalMergerTest
|
|||
waitForMergeCompletion();
|
||||
|
||||
ExternalManager externalManager = resultProgram.getExternalManager();
|
||||
List<ExternalLocation> externalLocations =
|
||||
Set<ExternalLocation> externalLocations =
|
||||
externalManager.getExternalLocations("user32.dll", "BETTY");
|
||||
assertEquals(2, externalLocations.size());
|
||||
assertHasDifferentAddresses(externalLocations, "1002239", "10063b4");
|
||||
assertHasExtAddresses(externalLocations, "1002239", "10063b4");
|
||||
|
||||
List<ExternalLocation> externalLocations2 =
|
||||
Set<ExternalLocation> externalLocations2 =
|
||||
externalManager.getExternalLocations("user32.dll", "BARNEY");
|
||||
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
|
||||
public void testAddExternalFunctionsWithFunctionConflicts() throws Exception {
|
||||
|
||||
|
@ -1674,15 +1656,14 @@ public class ExternalFunctionMergeManagerTest extends AbstractExternalMergerTest
|
|||
waitForMergeCompletion();
|
||||
|
||||
ExternalManager externalManager = resultProgram.getExternalManager();
|
||||
List<ExternalLocation> externalLocations =
|
||||
Set<ExternalLocation> externalLocations =
|
||||
externalManager.getExternalLocations("user32.dll", "BARNEY");
|
||||
assertEquals(2, externalLocations.size());
|
||||
assertHasDifferentAddresses(externalLocations, "1002239", "77db1020");
|
||||
assertHasExtAddresses(externalLocations, "1002239", "77db1020");
|
||||
|
||||
externalLocations = externalManager.getExternalLocations("user32.dll", "BETTY");
|
||||
assertEquals(1, externalLocations.size());
|
||||
assertEquals("01002239", externalLocations.get(0).getAddress().toString());
|
||||
|
||||
assertHasExtAddresses(externalLocations, "01002239");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.merge.listing;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -438,8 +439,11 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
|
|||
|
||||
ExternalManager externalManager = resultProgram.getExternalManager();
|
||||
assertTrue(externalManager.contains(libname));
|
||||
List<ExternalLocation> externals = externalManager.getExternalLocations(libname, label);
|
||||
assertEquals(2, externals.size());
|
||||
Set<ExternalLocation> externalLocations =
|
||||
externalManager.getExternalLocations(libname, label);
|
||||
assertEquals(2, externalLocations.size());
|
||||
assertHasExtAddresses(externalLocations, address1, address2);
|
||||
|
||||
ExternalLocationIterator loc1It = externalManager.getExternalLocations(addr(address1));
|
||||
assertTrue(loc1It.hasNext());
|
||||
assertEquals(label, loc1It.next().getLabel());
|
||||
|
@ -3403,13 +3407,16 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
|
|||
ExternalManager externalManager = resultProgram.getExternalManager();
|
||||
assertTrue(externalManager.contains(libname));
|
||||
|
||||
List<ExternalLocation> externalLocations =
|
||||
Set<ExternalLocation> externalLocations =
|
||||
externalManager.getExternalLocations(libname, label);
|
||||
assertEquals(2, externalLocations.size());
|
||||
assertHasExtAddresses(externalLocations, "00000100", "00000110");
|
||||
|
||||
List<ExternalLocation> externalLocations2 =
|
||||
Set<ExternalLocation> externalLocations2 =
|
||||
externalManager.getExternalLocations(BLUE_PATH[0], BLUE_PATH[1]);
|
||||
assertEquals(2, externalLocations2.size());
|
||||
assertHasExtAddresses(externalLocations, "00000100", "00000110");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -3484,13 +3491,15 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
|
|||
ExternalManager externalManager = resultProgram.getExternalManager();
|
||||
assertTrue(externalManager.contains(libname));
|
||||
|
||||
List<ExternalLocation> externalLocations =
|
||||
Set<ExternalLocation> externalLocations =
|
||||
externalManager.getExternalLocations(libname, label);
|
||||
assertEquals(2, externalLocations.size());
|
||||
assertHasExtAddresses(externalLocations, "00000100", "00000110");
|
||||
|
||||
List<ExternalLocation> externalLocations2 =
|
||||
Set<ExternalLocation> externalLocations2 =
|
||||
externalManager.getExternalLocations(BLUE_PATH[0], BLUE_PATH[1]);
|
||||
assertEquals(2, externalLocations2.size());
|
||||
assertHasExtAddresses(externalLocations, "00000100", "00000110");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.app.merge.listing;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
@ -50,10 +51,10 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
|||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
try {
|
||||
program.getExternalManager().setExternalPath("COMDLG32.DLL", "//comdlg32.dll",
|
||||
true);
|
||||
program.getExternalManager().setExternalPath("KERNEL32.DLL", "//kernel32.dll",
|
||||
true);
|
||||
program.getExternalManager()
|
||||
.setExternalPath("COMDLG32.DLL", "//comdlg32.dll", true);
|
||||
program.getExternalManager()
|
||||
.setExternalPath("KERNEL32.DLL", "//kernel32.dll", true);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// TODO Auto-generated catch block
|
||||
|
@ -65,8 +66,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
|||
public void modifyPrivate(ProgramDB program) {
|
||||
try {
|
||||
program.getExternalManager().setExternalPath("GDI32.DLL", "//gdi32.dll", true);
|
||||
program.getExternalManager().setExternalPath("KERNEL32.DLL", "//kernel32.dll",
|
||||
true);
|
||||
program.getExternalManager()
|
||||
.setExternalPath("KERNEL32.DLL", "//kernel32.dll", true);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// TODO Auto-generated catch block
|
||||
|
@ -104,8 +105,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
|||
public void modifyLatest(ProgramDB program) {
|
||||
try {
|
||||
program.getExternalManager().setExternalPath("ADVAPI32.DLL", "//foo.dll", true);
|
||||
program.getExternalManager().setExternalPath("KERNEL32.DLL", "//latest.dll",
|
||||
true);
|
||||
program.getExternalManager()
|
||||
.setExternalPath("KERNEL32.DLL", "//latest.dll", true);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// TODO Auto-generated catch block
|
||||
|
@ -191,8 +192,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
|||
public void modifyLatest(ProgramDB program) {
|
||||
try {
|
||||
removeExternalLibrary(program, "ADVAPI32.DLL");
|
||||
program.getExternalManager().setExternalPath("USER32.DLL", "//latest.dll",
|
||||
true);
|
||||
program.getExternalManager()
|
||||
.setExternalPath("USER32.DLL", "//latest.dll", true);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// TODO Auto-generated catch block
|
||||
|
@ -251,8 +252,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
|||
public void modifyLatest(ProgramDB program) {
|
||||
try {
|
||||
removeExternalLibrary(program, "ADVAPI32.DLL");
|
||||
program.getExternalManager().setExternalPath("USER32.DLL", "//latest.dll",
|
||||
true);
|
||||
program.getExternalManager()
|
||||
.setExternalPath("USER32.DLL", "//latest.dll", true);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// TODO Auto-generated catch block
|
||||
|
@ -311,8 +312,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
|||
public void modifyLatest(ProgramDB program) {
|
||||
try {
|
||||
removeExternalLibrary(program, "ADVAPI32.DLL");
|
||||
program.getExternalManager().setExternalPath("USER32.DLL", "//latest.dll",
|
||||
true);
|
||||
program.getExternalManager()
|
||||
.setExternalPath("USER32.DLL", "//latest.dll", true);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// TODO Auto-generated catch block
|
||||
|
@ -487,7 +488,7 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
|||
try {
|
||||
removeExternalLibrary(program, "ADVAPI32.DLL");
|
||||
Reference[] refs =
|
||||
program.getReferenceManager().getReferencesFrom(addr(program, "0x10011e4")); // SetCursor
|
||||
program.getReferenceManager().getReferencesFrom(addr(program, "0x10011e4")); // setCursor
|
||||
SymbolTable symTab = program.getSymbolTable();
|
||||
Symbol s = symTab.getSymbol(refs[0]);
|
||||
s.setName("SetCursor99", SourceType.USER_DEFINED);
|
||||
|
@ -538,13 +539,24 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
|||
// Check that the 2 renames happened.
|
||||
ExternalLocation extLoc =
|
||||
resultExtMgr.getUniqueExternalLocation("ADVAPI32.DLL", "RegCreateKeyW");
|
||||
assertNull(extLoc);
|
||||
assertNotNull(extLoc);
|
||||
assertEquals("RegCreateKeyW", extLoc.getOriginalImportedName());
|
||||
assertEquals("RegCreateKeyW99", extLoc.getLabel());
|
||||
|
||||
extLoc = resultExtMgr.getUniqueExternalLocation("ADVAPI32.DLL", "RegCreateKeyW99");
|
||||
assertNotNull(extLoc);
|
||||
extLoc = resultExtMgr.getUniqueExternalLocation("USER32.DLL", "SetCursor");
|
||||
assertNull(extLoc);
|
||||
assertEquals("RegCreateKeyW", extLoc.getOriginalImportedName());
|
||||
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");
|
||||
assertNotNull(extLoc);
|
||||
assertEquals("setCursor", extLoc.getOriginalImportedName());
|
||||
assertEquals("SetCursor99", extLoc.getLabel());
|
||||
|
||||
}
|
||||
|
||||
|
@ -614,8 +626,8 @@ public class ExternalProgramMergerTest extends AbstractListingMergeManagerTest {
|
|||
ExternalLocationIterator iter = extMgr.getExternalLocations(libName);
|
||||
while (iter.hasNext()) {
|
||||
ExternalLocation loc = iter.next();
|
||||
if (!((ExternalManagerDB) extMgr).removeExternalLocation(
|
||||
loc.getExternalSpaceAddress())) {
|
||||
if (!((ExternalManagerDB) extMgr)
|
||||
.removeExternalLocation(loc.getExternalSpaceAddress())) {
|
||||
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 java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.JDialog;
|
||||
|
||||
|
@ -944,27 +944,10 @@ public class FunctionMergerThunkTest extends AbstractExternalMergerTest {
|
|||
ExternalLocation externalLocation = thunkedFunction.getExternalLocation();
|
||||
assertEquals(addr(resultProgram, "77db1020"), externalLocation.getAddress());
|
||||
|
||||
List<ExternalLocation> externalLocations =
|
||||
Set<ExternalLocation> externalLocations =
|
||||
resultProgram.getExternalManager().getExternalLocations("user32.dll", "printf");
|
||||
assertEquals(2, externalLocations.size());
|
||||
Address address1 = externalLocations.get(0).getAddress();
|
||||
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;
|
||||
assertHasExtAddresses(externalLocations, "77db1020", "77db1130");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -99,7 +99,7 @@ public class ExternalCodeBrowserNavigationTest extends AbstractCodeBrowserNaviga
|
|||
private void addThunkToExternalFunction(String libraryName, String label,
|
||||
Address thunkAddress) {
|
||||
ExternalLocation externalLocation =
|
||||
program.getExternalManager().getExternalLocation(libraryName, label);
|
||||
program.getExternalManager().getUniqueExternalLocation(libraryName, label);
|
||||
Function extFunction = externalLocation.getFunction();
|
||||
|
||||
CreateThunkFunctionCmd cmd = new CreateThunkFunctionCmd(thunkAddress,
|
||||
|
|
|
@ -109,10 +109,8 @@ public class SymbolTreeLocationReferencesTest extends AbstractLocationReferences
|
|||
private Function addExternalFunctionReference(Address refAddr, String libraryName,
|
||||
String extLabel, RefType refType) throws Exception {
|
||||
|
||||
List<ExternalLocation> locations =
|
||||
program.getExternalManager().getExternalLocations(libraryName, extLabel);
|
||||
assertEquals(1, locations.size());
|
||||
ExternalLocation externalLocation = locations.get(0);
|
||||
ExternalLocation externalLocation =
|
||||
program.getExternalManager().getUniqueExternalLocation(libraryName, extLabel);
|
||||
|
||||
assertNotNull("External location not found: " + libraryName + "::" + extLabel,
|
||||
externalLocation);
|
||||
|
|
|
@ -387,6 +387,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
|||
assertEquals(addr(0x0100688c), loc.getByteAddress());
|
||||
assertTrue(loc instanceof CommentFieldLocation);
|
||||
//
|
||||
assertTrue("Search result not found: " + addr(0x01006890), searcher.hasNext());
|
||||
loc = searcher.next().programLocation();
|
||||
assertNotNull(loc);
|
||||
assertEquals(addr(0x01006890), loc.getByteAddress());
|
||||
|
@ -394,11 +395,13 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
|||
MnemonicFieldLocation mloc = (MnemonicFieldLocation) loc;
|
||||
assertEquals("float", mloc.getMnemonic());
|
||||
//
|
||||
assertTrue("Search result not found: " + addr(0x01006890), searcher.hasNext());
|
||||
loc = searcher.next().programLocation();
|
||||
assertNotNull(loc);
|
||||
assertEquals(addr(0x01006890), loc.getByteAddress());
|
||||
assertTrue(loc instanceof CommentFieldLocation);
|
||||
//
|
||||
assertTrue("Search result not found: " + addr(0x0100689b), searcher.hasNext());
|
||||
loc = searcher.next().programLocation();
|
||||
assertNotNull(loc);
|
||||
assertEquals(addr(0x0100689b), loc.getByteAddress());
|
||||
|
@ -406,6 +409,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
|||
mloc = (MnemonicFieldLocation) loc;
|
||||
assertEquals("float", mloc.getMnemonic());
|
||||
//
|
||||
assertTrue("Search result not found: " + addr(0x0100689f), searcher.hasNext());
|
||||
loc = searcher.next().programLocation();
|
||||
assertNotNull(loc);
|
||||
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
||||
|
@ -413,6 +417,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
|||
mloc = (MnemonicFieldLocation) loc;
|
||||
assertEquals("float", mloc.getMnemonic());
|
||||
//
|
||||
assertTrue("Search result not found: " + addr(0x0100689f), searcher.hasNext());
|
||||
loc = searcher.next().programLocation();
|
||||
assertNotNull(loc);
|
||||
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
||||
|
@ -478,6 +483,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
|||
assertEquals(addr(0x0100688c), loc.getByteAddress());
|
||||
assertTrue(loc instanceof CommentFieldLocation);
|
||||
//
|
||||
assertTrue("Search result not found: " + addr(0x0100689b), searcher.hasNext());
|
||||
loc = searcher.next().programLocation();
|
||||
assertNotNull(loc);
|
||||
assertEquals(addr(0x0100689b), loc.getByteAddress());
|
||||
|
@ -485,6 +491,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
|||
MnemonicFieldLocation mloc = (MnemonicFieldLocation) loc;
|
||||
assertEquals("float", mloc.getMnemonic());
|
||||
//
|
||||
assertTrue("Search result not found: " + addr(0x0100689f), searcher.hasNext());
|
||||
loc = searcher.next().programLocation();
|
||||
assertNotNull(loc);
|
||||
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
||||
|
@ -492,6 +499,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
|||
mloc = (MnemonicFieldLocation) loc;
|
||||
assertEquals("float", mloc.getMnemonic());
|
||||
//
|
||||
assertTrue("Search result not found: " + addr(0x0100689f), searcher.hasNext());
|
||||
loc = searcher.next().programLocation();
|
||||
assertNotNull(loc);
|
||||
assertEquals(addr(0x0100689f), loc.getByteAddress());
|
||||
|
@ -819,6 +827,7 @@ public class ListingDisplaySearcherTest extends AbstractGhidraHeadedIntegrationT
|
|||
private void checkTextFound(ArrayList<Address> startList, Class<?> fieldClass) {
|
||||
|
||||
for (Address start : startList) {
|
||||
assertTrue("Search result not found: " + start, searcher.hasNext());
|
||||
ProgramLocation loc = searcher.next().programLocation();
|
||||
assertNotNull(loc);
|
||||
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.
|
||||
* Multiple blocks are permitted within a single overlay space.
|
||||
* 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
|
||||
|
@ -2103,7 +2104,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
|
||||
monitor.setMessage("Updating symbols...");
|
||||
getSymbolTable().setLanguage(translator, monitor);
|
||||
getExternalManager().setLanguage(translator, monitor);
|
||||
getFunctionManager().setLanguage(translator, monitor);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@ import ghidra.docking.settings.Settings;
|
|||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.model.address.Address;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,9 +17,9 @@ package ghidra.program.database.external;
|
|||
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
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.AddressFactory;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
|
@ -28,19 +28,18 @@ import ghidra.util.exception.*;
|
|||
|
||||
public class ExternalLocationDB implements ExternalLocation {
|
||||
|
||||
private static final char ORIGINAL_IMPORTED_DELIMITER = ',';
|
||||
private ExternalManagerDB extMgr;
|
||||
private SymbolDB symbol;
|
||||
private MemorySymbol symbol;
|
||||
|
||||
/**
|
||||
* Creates an externalLocationDB using a symbol
|
||||
* at the same external space address.
|
||||
* @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
|
||||
* 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.symbol = symbol;
|
||||
}
|
||||
|
@ -50,9 +49,6 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
return symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.ExternalLocation#getLibraryName()
|
||||
*/
|
||||
@Override
|
||||
public String getLibraryName() {
|
||||
Library library = getLibrary();
|
||||
|
@ -68,17 +64,11 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.ExternalLocation#getParentNameSpace()
|
||||
*/
|
||||
@Override
|
||||
public Namespace getParentNameSpace() {
|
||||
return symbol.getParentNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.ExternalLocation#getParentName()
|
||||
*/
|
||||
@Override
|
||||
public String getParentName() {
|
||||
return symbol.getParentNamespace().getName();
|
||||
|
@ -88,9 +78,6 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
return symbol.getParentNamespace().getID();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.ExternalLocation#getLabel()
|
||||
*/
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return symbol.getName();
|
||||
|
@ -98,7 +85,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
|
||||
@Override
|
||||
public String getOriginalImportedName() {
|
||||
return getExternalData(symbol).getOriginalImportedName();
|
||||
return symbol.getExternalOriginalImportedName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -106,17 +93,11 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
return symbol.getSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.ExternalLocation#getAddress()
|
||||
*/
|
||||
@Override
|
||||
public Address getAddress() {
|
||||
return getExternalData(symbol).getAddress(extMgr.getAddressMap().getAddressFactory());
|
||||
return symbol.getExternalProgramAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.ExternalLocation#getExternalSpaceAddress()
|
||||
*/
|
||||
@Override
|
||||
public Address getExternalSpaceAddress() {
|
||||
return symbol.getAddress();
|
||||
|
@ -136,9 +117,6 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
return symbol.getSymbolType() == SymbolType.FUNCTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.ExternalLocation#getDataType()
|
||||
*/
|
||||
@Override
|
||||
public DataType getDataType() {
|
||||
long dataTypeID = symbol.getDataTypeId();
|
||||
|
@ -148,15 +126,10 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
return extMgr.getProgram().getDataTypeManager().getDataType(dataTypeID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.ExternalLocation#setDataType(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void setDataType(DataType dt) {
|
||||
long dataTypeID = extMgr.getProgram().getDataTypeManager().getResolvedID(dt);
|
||||
symbol.setDataTypeId(dataTypeID);
|
||||
|
||||
// TODO: change notification may be required
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -173,7 +146,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
return getFunction();
|
||||
}
|
||||
Function function = extMgr.createFunction(this);
|
||||
symbol = (SymbolDB) function.getSymbol();
|
||||
symbol = (FunctionSymbol) function.getSymbol();
|
||||
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.
|
||||
* @param source the source of this external symbol:
|
||||
* Symbol.DEFAULT, Symbol.ANALYSIS, Symbol.IMPORTED, or Symbol.USER_DEFINED
|
||||
* @throws InvalidInputException
|
||||
* @see ghidra.program.model.symbol.ExternalLocation#setLabel(java.lang.String)
|
||||
* @throws InvalidInputException if the name contains illegal characters (space for example)
|
||||
*/
|
||||
void setLabel(String label, SourceType source) throws InvalidInputException {
|
||||
if (label == null) {
|
||||
|
@ -223,12 +195,10 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
|
||||
@Override
|
||||
public void setAddress(Address address) throws InvalidInputException {
|
||||
String addressString = address != null ? address.toString() : null;
|
||||
if (addressString == null && getSource() == SourceType.DEFAULT) {
|
||||
if (address == null && getSource() == SourceType.DEFAULT) {
|
||||
throw new InvalidInputException("Either an external label or address is required");
|
||||
}
|
||||
updateSymbolData(symbol, getExternalData(symbol).getOriginalImportedName(),
|
||||
addressString);
|
||||
symbol.setExternalProgramAddress(address, true);
|
||||
}
|
||||
|
||||
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
|
||||
String originalImportedName = getOriginalImportedName();
|
||||
if (getLabel().equals(originalImportedName)) {
|
||||
setOriginalImportedName(symbol, null);
|
||||
symbol.setExternalOriginalImportedName(null, false);
|
||||
}
|
||||
else if (wasInLibrary && getSource() != SourceType.DEFAULT &&
|
||||
oldSource == SourceType.IMPORTED && originalImportedName == null) {
|
||||
setOriginalImportedName(symbol, oldName);
|
||||
symbol.setExternalOriginalImportedName(oldName, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,8 +258,8 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
}
|
||||
try {
|
||||
Library library = NamespaceUtils.getLibrary(symbol.getParentNamespace());
|
||||
symbol.setExternalOriginalImportedName(null, false); // clear orig imported name
|
||||
symbol.setNameAndNamespace(originalName, library, SourceType.IMPORTED);
|
||||
setOriginalImportedName(symbol, null);
|
||||
}
|
||||
catch (CircularDependencyException | DuplicateNameException | InvalidInputException 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.program.database.ManagerDB;
|
||||
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.map.AddressMap;
|
||||
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.listing.Function;
|
||||
import ghidra.program.model.listing.Library;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.util.LanguageTranslator;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.*;
|
||||
|
@ -46,7 +46,6 @@ import ghidra.util.task.TaskMonitor;
|
|||
public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
||||
|
||||
private AddressMap addrMap;
|
||||
private NamespaceManager scopeMgr;
|
||||
private SymbolManager symbolMgr;
|
||||
private FunctionManagerDB functionMgr;
|
||||
|
||||
|
@ -95,7 +94,6 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
this.program = program;
|
||||
symbolMgr = program.getSymbolTable();
|
||||
functionMgr = program.getFunctionManager();
|
||||
scopeMgr = program.getNamespaceManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -202,7 +200,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
SourceType locSourceType = checkExternalLabel(extLabel, extAddr, sourceType);
|
||||
lock.acquire();
|
||||
try {
|
||||
Namespace libraryScope = getLibraryScope(extLibraryName);
|
||||
Library libraryScope = getLibraryScope(extLibraryName);
|
||||
if (libraryScope == null) {
|
||||
libraryScope = addExternalName(extLibraryName, null, sourceType);
|
||||
}
|
||||
|
@ -245,7 +243,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
SourceType locSourceType = checkExternalLabel(extLabel, extAddr, sourceType);
|
||||
lock.acquire();
|
||||
try {
|
||||
Namespace libraryScope = getLibraryScope(extLibraryName);
|
||||
Library libraryScope = getLibraryScope(extLibraryName);
|
||||
if (libraryScope == null) {
|
||||
libraryScope = addExternalName(extLibraryName, null,
|
||||
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)
|
||||
throws InvalidInputException {
|
||||
if (extLabel != null && (StringUtils.isBlank(extLabel) ||
|
||||
SymbolUtilities.isReservedExternalDefaultName(extLabel, addrMap.getAddressFactory()))) {
|
||||
extLabel = null;
|
||||
if (StringUtils.isBlank(extLabel) ||
|
||||
SymbolUtilities.isReservedExternalDefaultName(extLabel, addrMap.getAddressFactory())) {
|
||||
extLabel = null; // force use of address
|
||||
}
|
||||
if (extLabel == null && extAddr == null) {
|
||||
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) {
|
||||
extLabel = null;
|
||||
}
|
||||
ExternalLocationDB extLoc =
|
||||
(ExternalLocationDB) getExtLocation(extNamespace, extLabel, extAddr, reuseExisting);
|
||||
else if (StringUtils.isBlank(extLabel) || SymbolUtilities
|
||||
.isReservedExternalDefaultName(extLabel, addrMap.getAddressFactory())) {
|
||||
extLabel = null; // force use of address
|
||||
}
|
||||
if (extAddr != null || reuseExisting) {
|
||||
|
||||
if (extLoc != null) {
|
||||
// if there is already a location with the address, then we must use it
|
||||
if (extAddr != null || reuseExisting) {
|
||||
ExternalLocationDB extLoc = (ExternalLocationDB) getExtLocation(extNamespace,
|
||||
extLabel, extAddr, reuseExisting);
|
||||
|
||||
if (extLoc != null) {
|
||||
|
||||
// if there is already a location with the address, then we must use it
|
||||
if (extLabel != null && !extLabel.equals(extLoc.getLabel())) {
|
||||
extLoc.setLabel(extLabel, sourceType);
|
||||
}
|
||||
|
@ -345,21 +349,25 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
return extLoc;
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
String extMemAddrString = (extAddr != null) ? extAddr.toString() : null;
|
||||
if (isFunction) {
|
||||
Function function = functionMgr.createExternalFunction(externalSpaceAddress,
|
||||
extLabel, extNamespace, extMemAddrString, sourceType);
|
||||
s = (SymbolDB) function.getSymbol();
|
||||
FunctionDB function = functionMgr.createExternalFunction(externalSpaceAddress,
|
||||
extLabel, extNamespace, null, extAddr, sourceType);
|
||||
s = (FunctionSymbol) function.getSymbol();
|
||||
}
|
||||
else {
|
||||
s = (SymbolDB) symbolMgr.createCodeSymbol(externalSpaceAddress, extLabel,
|
||||
extNamespace, sourceType, extMemAddrString);
|
||||
s = symbolMgr.createExternalCodeSymbol(externalSpaceAddress, extLabel, extNamespace,
|
||||
sourceType, null, extAddr);
|
||||
}
|
||||
return new ExternalLocationDB(this, s);
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e); // will not return
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
@ -377,66 +385,31 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
private ExternalLocation getExtLocation(Namespace library, String extLabel, Address extAddr,
|
||||
boolean reuseExisting) throws InvalidInputException {
|
||||
|
||||
if (extLabel != null && (extLabel.length() == 0 ||
|
||||
SymbolUtilities.isReservedExternalDefaultName(extLabel, addrMap.getAddressFactory()))) {
|
||||
extLabel = null; // force use of address
|
||||
}
|
||||
|
||||
// Name match will also consider original import name if library is either null
|
||||
// or a Library, otherwise only a specific namespaced name match will be considered.
|
||||
ExternalLocation match =
|
||||
findMatchingLocationByName(library, extLabel, extAddr, reuseExisting);
|
||||
if (match != null) {
|
||||
return match;
|
||||
}
|
||||
|
||||
// So now get all the externalLocations for a library and search them
|
||||
List<ExternalLocation> locations = getExternalLocations(library);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (extLabel == null) { // assume extAddr is not null (already checked)
|
||||
return findMatchingLocationByAddress(extAddr, reuseExisting);
|
||||
}
|
||||
|
||||
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
|
||||
// reuseExisting is true, then also find a match as long as the name and namespace match and
|
||||
// the address is null.
|
||||
private ExternalLocation findMatchingLocationByName(Namespace libScope, String extLabel,
|
||||
private ExternalLocation findMatchingLocationByName(Namespace namespace, String extLabel,
|
||||
Address extAddr, boolean reuseExisting) {
|
||||
if (extLabel == null) {
|
||||
if (StringUtils.isBlank(extLabel)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ExternalLocation> externalLocations = getExternalLocations(libScope, extLabel);
|
||||
Set<ExternalLocation> externalLocations = getExternalLocations(namespace, extLabel);
|
||||
if (externalLocations.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -460,14 +433,16 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
}
|
||||
|
||||
// first look for one without an address
|
||||
ExternalLocation possibleExtLoc = null;
|
||||
for (ExternalLocation externalLocation : externalLocations) {
|
||||
if (externalLocation.getAddress() == null) {
|
||||
return externalLocation;
|
||||
}
|
||||
possibleExtLoc = externalLocation;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -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
|
||||
// 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.
|
||||
private ExternalLocation findMatchingLocationByAddress(List<ExternalLocation> locations,
|
||||
Address extAddr, boolean reuseExisting) {
|
||||
for (ExternalLocation externalLocation : locations) {
|
||||
if (extAddr.equals(externalLocation.getAddress())) {
|
||||
if (reuseExisting || externalLocation.getLabel() == null) {
|
||||
return externalLocation;
|
||||
}
|
||||
private ExternalLocation findMatchingLocationByAddress(Address extAddr, boolean reuseExisting) {
|
||||
for (Symbol symbol : symbolMgr.getExternalSymbolByMemoryAddress(null, extAddr)) {
|
||||
ExternalLocation externalLocation = getExternalLocation(symbol);
|
||||
if (reuseExisting || externalLocation.getLabel() == null) {
|
||||
return externalLocation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExternalLocation> getExternalLocations(Namespace libScope, String extLabel) {
|
||||
List<ExternalLocation> externalLocations = new ArrayList<>();
|
||||
List<Symbol> symbols = symbolMgr.getSymbols(extLabel, libScope);
|
||||
for (Symbol symbol : symbols) {
|
||||
ExternalLocation externalLocation = getExternalLocation(symbol);
|
||||
if (externalLocation != null) {
|
||||
externalLocations.add(externalLocation);
|
||||
public Set<ExternalLocation> getExternalLocations(Namespace namespace, String extLabel) {
|
||||
if (namespace != null && !namespace.isExternal()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return externalLocations;
|
||||
if (namespace != null) {
|
||||
List<Symbol> symbols = symbolMgr.getSymbols(extLabel, namespace);
|
||||
for (Symbol symbol : symbols) {
|
||||
ExternalLocation externalLocation = getExternalLocation(symbol);
|
||||
if (externalLocation != null) {
|
||||
externalLocations.add(externalLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (Symbol symbol : symbolMgr.getExternalSymbols(extLabel)) {
|
||||
ExternalLocation externalLocation = getExternalLocation(symbol);
|
||||
if (externalLocation != null) {
|
||||
externalLocations.add(externalLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(externalLocations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExternalLocation> getExternalLocations(String libraryName, String label) {
|
||||
Namespace libraryScope = getLibraryScope(libraryName);
|
||||
if (libraryScope == null) {
|
||||
return Collections.emptyList();
|
||||
public Set<ExternalLocation> getExternalLocations(String libraryName, String label) {
|
||||
Library library = getLibraryScope(libraryName);
|
||||
if (library == null && !StringUtils.isBlank(libraryName)) {
|
||||
return Set.of();
|
||||
}
|
||||
return getExternalLocations(libraryScope, label);
|
||||
return getExternalLocations(library, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalLocation getUniqueExternalLocation(Namespace namespace, String label) {
|
||||
List<ExternalLocation> externalLocations = getExternalLocations(namespace, label);
|
||||
Set<ExternalLocation> externalLocations = getExternalLocations(namespace, label);
|
||||
if (externalLocations.size() == 1) {
|
||||
return externalLocations.get(0);
|
||||
return externalLocations.iterator().next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalLocation getUniqueExternalLocation(String libraryName, String label) {
|
||||
Namespace libScope = getLibraryScope(libraryName);
|
||||
if (libScope == null) {
|
||||
Library library = getLibraryScope(libraryName);
|
||||
if (library == null && !StringUtils.isBlank(libraryName)) {
|
||||
return null;
|
||||
}
|
||||
return getUniqueExternalLocation(libScope, 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);
|
||||
return getUniqueExternalLocation(library, label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default name for an external function or code symbol
|
||||
* @param sym
|
||||
* @return default name
|
||||
* {@return the default name for an external function or code symbol}
|
||||
* @param sym external label or function symbol
|
||||
* @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) {
|
||||
SymbolType type = sym.getSymbolType();
|
||||
if ((type != SymbolType.LABEL && type != SymbolType.FUNCTION) || !sym.isExternal()) {
|
||||
throw new AssertException();
|
||||
if (!(sym instanceof MemorySymbol) && !sym.isExternal()) {
|
||||
throw new IllegalArgumentException("External label or function symbol required");
|
||||
}
|
||||
ExternalData externalData = ExternalLocationDB.getExternalData(sym);
|
||||
Address addr = externalData.getAddress(sym.getProgram().getAddressFactory());
|
||||
|
||||
Address addr = ((MemorySymbol) sym).getExternalProgramAddress();
|
||||
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);
|
||||
}
|
||||
|
||||
long dataTypeID = sym.getDataTypeId();
|
||||
DataType dt =
|
||||
(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.
|
||||
* @throws IllegalArgumentException if address is not external
|
||||
*/
|
||||
public ExternalLocation getExtLocation(Address externalAddr) {
|
||||
if (externalAddr.getAddressSpace() != AddressSpace.EXTERNAL_SPACE) {
|
||||
|
@ -582,7 +567,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
try {
|
||||
Symbol[] symbols = symbolMgr.getSymbols(externalAddr);
|
||||
if (symbols.length == 1) {
|
||||
return new ExternalLocationDB(this, (SymbolDB) symbols[0]);
|
||||
return new ExternalLocationDB(this, (MemorySymbol) symbols[0]);
|
||||
}
|
||||
if (symbols.length > 2) {
|
||||
throw new AssertException(
|
||||
|
@ -613,6 +598,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
/**
|
||||
* Removes the external location at the given external address
|
||||
* @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) {
|
||||
lock.acquire();
|
||||
|
@ -651,15 +637,6 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
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
|
||||
public void updateExternalLibraryName(String oldName, String newName, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
@ -691,9 +668,9 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
return (Library) s.getObject();
|
||||
}
|
||||
|
||||
private Namespace getLibraryScope(String name) {
|
||||
Symbol s = symbolMgr.getLibrarySymbol(name);
|
||||
return s == null ? null : (Namespace) s.getObject();
|
||||
private Library getLibraryScope(String name) {
|
||||
LibrarySymbol s = symbolMgr.getLibrarySymbol(name);
|
||||
return s == null ? null : s.getObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -723,9 +700,9 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
|
||||
@Override
|
||||
public String getExternalLibraryPath(String externalName) {
|
||||
SymbolDB s = (SymbolDB) symbolMgr.getLibrarySymbol(externalName);
|
||||
if (s instanceof LibrarySymbol) {
|
||||
return s.getSymbolStringData();
|
||||
LibrarySymbol s = symbolMgr.getLibrarySymbol(externalName);
|
||||
if (s != null) {
|
||||
return s.getExternalLibraryPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -743,7 +720,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
|
||||
lock.acquire();
|
||||
try {
|
||||
SymbolDB s = (SymbolDB) symbolMgr.getLibrarySymbol(externalName);
|
||||
LibrarySymbol s = symbolMgr.getLibrarySymbol(externalName);
|
||||
if (s == null) {
|
||||
try {
|
||||
addExternalName(externalName, externalPath,
|
||||
|
@ -753,8 +730,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
throw new AssertException(e);
|
||||
}
|
||||
}
|
||||
else if (s instanceof LibrarySymbol) {
|
||||
s.setSymbolStringData(externalPath);
|
||||
else {
|
||||
s.setExternalLibraryPath(externalPath);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -784,8 +761,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
if (!(symbol instanceof CodeSymbol)) {
|
||||
throw new IllegalStateException("Expected external code symbol");
|
||||
}
|
||||
//long dtId = symbol.getSymbolData1();
|
||||
String extData = symbol.getSymbolStringData();
|
||||
Address extProgAddr = extLoc.getAddress();
|
||||
String origImpName = extLoc.getOriginalImportedName();
|
||||
String name = symbol.getName();
|
||||
Namespace namespace = symbol.getParentNamespace();
|
||||
Address extAddr = symbol.getAddress();
|
||||
|
@ -793,7 +770,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
|
||||
((CodeSymbol) symbol).delete(true);
|
||||
|
||||
return functionMgr.createExternalFunction(extAddr, name, namespace, extData, source);
|
||||
return functionMgr.createExternalFunction(extAddr, name, namespace, origImpName,
|
||||
extProgAddr, source);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Unexpected exception", e);
|
||||
|
@ -809,12 +787,12 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
|
||||
@Override
|
||||
public ExternalLocationIterator getExternalLocations(Address memoryAddress) {
|
||||
return new ExternalLocationDBIterator(symbolMgr.getExternalSymbols(), memoryAddress);
|
||||
return new ExternalLocationDBIterator(null, memoryAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalLocationIterator getExternalLocations(String externalName) {
|
||||
Namespace scope = getLibraryScope(externalName);
|
||||
Library scope = getLibraryScope(externalName);
|
||||
if (scope != null) {
|
||||
return new ExternalLocationDBIterator(symbolMgr.getSymbols(scope));
|
||||
}
|
||||
|
@ -830,8 +808,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
ExternalLocationDBIterator() {
|
||||
}
|
||||
|
||||
ExternalLocationDBIterator(SymbolIterator symIter, Address matchingAddress) {
|
||||
this.symIter = symIter;
|
||||
ExternalLocationDBIterator(Library library, Address matchingAddress) {
|
||||
this.symIter = symbolMgr.getExternalSymbolByMemoryAddress(library, 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 Address entryPoint;
|
||||
private Symbol functionSymbol;
|
||||
private FunctionSymbol functionSymbol;
|
||||
private DBRecord rec;
|
||||
|
||||
private FunctionStackFrame frame;
|
||||
|
@ -108,7 +108,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
|||
|
||||
private void init() {
|
||||
thunkedFunction = manager.getThunkedFunction(this);
|
||||
functionSymbol = program.getSymbolTable().getSymbol(key);
|
||||
functionSymbol = (FunctionSymbol) program.getSymbolTable().getSymbol(key);
|
||||
entryPoint = functionSymbol.getAddress();
|
||||
}
|
||||
|
||||
|
@ -974,7 +974,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
|||
symbolMap.put(v.symbol, v);
|
||||
}
|
||||
if (var.getComment() != null) {
|
||||
v.symbol.setSymbolStringData(var.getComment());
|
||||
v.symbol.setSymbolComment(var.getComment());
|
||||
}
|
||||
manager.functionChanged(this, null);
|
||||
return v;
|
||||
|
@ -1667,7 +1667,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
|||
manager.functionChanged(this, PARAMETERS_CHANGED);
|
||||
}
|
||||
if (var.getComment() != null) {
|
||||
p.symbol.setSymbolStringData(var.getComment());
|
||||
p.symbol.setSymbolComment(var.getComment());
|
||||
}
|
||||
updateSignatureSourceAfterVariableChange(source, p.getDataType());
|
||||
return p;
|
||||
|
|
|
@ -30,7 +30,6 @@ import ghidra.program.database.DBObjectCache;
|
|||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.code.CodeManager;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
import ghidra.program.database.external.ExternalLocationDB;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.database.symbol.*;
|
||||
import ghidra.program.model.address.*;
|
||||
|
@ -150,38 +149,40 @@ public class FunctionManagerDB implements FunctionManager {
|
|||
|
||||
/**
|
||||
* 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
|
||||
* other symbol using this address must first be deleted. Results are unpredictable if this is
|
||||
* not done.
|
||||
* @param name the external function name
|
||||
* @param nameSpace the external function namespace
|
||||
* @param extData the external data string to store additional info (see {@link ExternalLocationDB})
|
||||
* @param 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.
|
||||
* @return external function
|
||||
* @throws InvalidInputException if the name is invalid
|
||||
*/
|
||||
public Function createExternalFunction(Address extSpaceAddr, String name, Namespace nameSpace,
|
||||
String extData, SourceType source) throws InvalidInputException {
|
||||
public FunctionDB createExternalFunction(Address extSpaceAddr, String name, Namespace nameSpace,
|
||||
String originalImportName, Address externalProgramAddress, SourceType source)
|
||||
throws InvalidInputException {
|
||||
lock.acquire();
|
||||
try {
|
||||
Symbol symbol =
|
||||
symbolMgr.createFunctionSymbol(extSpaceAddr, name, nameSpace, source, extData);
|
||||
FunctionSymbol symbol = symbolMgr.createExternalFunctionSymbol(extSpaceAddr, name,
|
||||
nameSpace, source, originalImportName, externalProgramAddress);
|
||||
|
||||
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,
|
||||
null);
|
||||
return funcDB;
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
program.setObjChanged(ProgramEvent.FUNCTION_ADDED, extSpaceAddr, funcDB, null, null);
|
||||
return funcDB;
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e); // will not return
|
||||
return null;
|
||||
}
|
||||
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 {
|
||||
Symbol symbol =
|
||||
symbolMgr.createMemoryFunctionSymbol(entryPoint, name, nameSpace, source);
|
||||
|
||||
long returnDataTypeId =
|
||||
program.getDataTypeManager().getResolvedID(DataType.DEFAULT);
|
||||
|
||||
if (refFunc != null) {
|
||||
|
||||
String oldName = symbol.getName();
|
||||
|
|
|
@ -176,12 +176,12 @@ public abstract class VariableDB implements Variable {
|
|||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return symbol.getSymbolStringData();
|
||||
return symbol.getSymbolComment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComment(String comment) {
|
||||
symbol.setSymbolStringData(comment);
|
||||
symbol.setSymbolComment(comment);
|
||||
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.
|
||||
* If function does not use custom storage, the specified storage will be ignored and set
|
||||
* to UNASSIGNED.
|
||||
* @param newStorage
|
||||
* @param dt
|
||||
* <P>
|
||||
* NOTE: Method will trigger a symbol changed event.
|
||||
*
|
||||
* @param newStorage variable storage
|
||||
* @param dt variable datatype
|
||||
*/
|
||||
void setStorageAndDataType(VariableStorage newStorage, DataType dt) {
|
||||
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
|
||||
* @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
|
||||
*/
|
||||
public boolean isExternalEntryPoint(Address toAddr) {
|
||||
if (!toAddr.isMemoryAddress()) {
|
||||
return false;
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
RefList refList = getToRefs(toAddr);
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.program.database.symbol;
|
|||
import db.DBRecord;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.GhidraClass;
|
||||
import ghidra.program.model.symbol.*;
|
||||
|
||||
/**
|
||||
|
@ -28,16 +29,13 @@ public class ClassSymbol extends SymbolDB {
|
|||
private GhidraClassDB ghidraClass;
|
||||
|
||||
/**
|
||||
* Construct a new Class Symbol
|
||||
* Construct a Ghidra Class symbol from an existing symbol record
|
||||
* @param symbolMgr the symbol manager
|
||||
* @param cache symbol object cache
|
||||
* @param address the address to associate with the symbol
|
||||
* @param record the record associated with the symbol.
|
||||
*/
|
||||
public ClassSymbol(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache, Address address,
|
||||
DBRecord record) {
|
||||
super(symbolMgr, cache, address, record);
|
||||
|
||||
ClassSymbol(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache, DBRecord record) {
|
||||
super(symbolMgr, cache, Address.NO_ADDRESS, record);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,10 +44,12 @@ public class ClassSymbol extends SymbolDB {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() {
|
||||
public GhidraClass getObject() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (!checkIsValid()) {
|
||||
return null;
|
||||
}
|
||||
if (ghidraClass == null) {
|
||||
ghidraClass = new GhidraClassDB(this, symbolMgr.getProgram().getNamespaceManager());
|
||||
}
|
||||
|
|
|
@ -26,13 +26,9 @@ import ghidra.program.util.LabelFieldLocation;
|
|||
import ghidra.program.util.ProgramLocation;
|
||||
|
||||
/**
|
||||
* Symbols that represent "labels"
|
||||
*
|
||||
* Symbol data usage:
|
||||
* EXTERNAL:
|
||||
* String stringData - external memory address/label
|
||||
* Symbols that represent "labels" or external data locations
|
||||
*/
|
||||
public class CodeSymbol extends SymbolDB {
|
||||
public class CodeSymbol extends MemorySymbol {
|
||||
|
||||
/**
|
||||
* Constructs a new CodeSymbol
|
||||
|
@ -74,11 +70,6 @@ public class CodeSymbol extends SymbolDB {
|
|||
return symbolMgr.hasDynamicSymbol(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExternal() {
|
||||
return address.isExternalAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
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
|
||||
public Object getObject() {
|
||||
lock.acquire();
|
||||
|
@ -219,8 +195,8 @@ public class CodeSymbol extends SymbolDB {
|
|||
}
|
||||
return source;
|
||||
}
|
||||
if (newName == null || newName.length() == 0 || SymbolUtilities.isReservedDynamicLabelName(
|
||||
newName, symbolMgr.getProgram().getAddressFactory())) {
|
||||
if (newName == null || newName.length() == 0 || SymbolUtilities
|
||||
.isReservedDynamicLabelName(newName, symbolMgr.getProgram().getAddressFactory())) {
|
||||
return SourceType.DEFAULT;
|
||||
}
|
||||
return source;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.database.symbol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -35,12 +36,8 @@ import ghidra.util.task.TaskMonitor;
|
|||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
|
@ -62,11 +59,6 @@ public class FunctionSymbol extends SymbolDB {
|
|||
return SymbolType.FUNCTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExternal() {
|
||||
return address.isExternalAddress();
|
||||
}
|
||||
|
||||
boolean isThunk() {
|
||||
return functionMgr.isThunk(key);
|
||||
}
|
||||
|
@ -93,9 +85,13 @@ public class FunctionSymbol extends SymbolDB {
|
|||
try {
|
||||
boolean restoreLabel = isExternal() || (getSource() != SourceType.DEFAULT);
|
||||
String symName = getName();
|
||||
String extData = null;
|
||||
Symbol parentSymbol = getParentSymbol();
|
||||
String extOrigImportName = null;
|
||||
Address extProgramAddr = null;
|
||||
if (isExternal()) {
|
||||
extData = getSymbolStringData(); // preserve external data
|
||||
// preserve external data
|
||||
extOrigImportName = getExternalOriginalImportedName();
|
||||
extProgramAddr = getExternalProgramAddress();
|
||||
}
|
||||
Namespace namespace = getParentNamespace();
|
||||
SourceType source = getSource();
|
||||
|
@ -109,54 +105,48 @@ public class FunctionSymbol extends SymbolDB {
|
|||
}
|
||||
|
||||
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) {
|
||||
boolean restored = createLabelForDeletedFunctionName(address, symName, extData,
|
||||
namespace, source, pinned);
|
||||
if (!restored && isExternal()) {
|
||||
// remove all associated external references if label not restored
|
||||
// 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).
|
||||
Symbol newSymbol;
|
||||
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());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// This shouldn't happen.
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
symbolMgr.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
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
|
||||
public Object getObject() {
|
||||
public Function getObject() {
|
||||
return functionMgr.getFunction(key);
|
||||
}
|
||||
|
||||
|
@ -165,21 +155,6 @@ public class FunctionSymbol extends SymbolDB {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPinned() {
|
||||
if (!isExternal()) {
|
||||
return doIsPinned();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPinned(boolean pinned) {
|
||||
if (!isExternal()) {
|
||||
doSetPinned(pinned);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProgramLocation getProgramLocation() {
|
||||
lock.acquire();
|
||||
|
@ -187,7 +162,7 @@ public class FunctionSymbol extends SymbolDB {
|
|||
if (!checkIsValid()) {
|
||||
return null;
|
||||
}
|
||||
Function f = (Function) getObject();
|
||||
Function f = getObject();
|
||||
String signature = f.getPrototypeString(false, false);
|
||||
return new FunctionReturnTypeFieldLocation(getProgram(), address, 0, signature,
|
||||
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
|
||||
public boolean hasReferences() {
|
||||
lock.acquire();
|
||||
|
|
|
@ -27,7 +27,7 @@ import ghidra.util.exception.InvalidInputException;
|
|||
*/
|
||||
|
||||
class GhidraClassDB implements GhidraClass {
|
||||
private SymbolDB symbol;
|
||||
private ClassSymbol symbol;
|
||||
private NamespaceManager namespaceMgr;
|
||||
|
||||
/**
|
||||
|
@ -35,7 +35,7 @@ class GhidraClassDB implements GhidraClass {
|
|||
* @param symbol the symbol for this GhidraClass
|
||||
* @param namespaceMgr the namespace manager
|
||||
*/
|
||||
GhidraClassDB(SymbolDB symbol, NamespaceManager namespaceMgr) {
|
||||
GhidraClassDB(ClassSymbol symbol, NamespaceManager namespaceMgr) {
|
||||
this.symbol = symbol;
|
||||
this.namespaceMgr = namespaceMgr;
|
||||
}
|
||||
|
@ -126,8 +126,8 @@ class GhidraClassDB implements GhidraClass {
|
|||
* @see ghidra.program.model.symbol.Namespace#setParentNamespace(ghidra.program.model.symbol.Namespace)
|
||||
*/
|
||||
@Override
|
||||
public void setParentNamespace(Namespace parentNamespace) throws DuplicateNameException,
|
||||
InvalidInputException, CircularDependencyException {
|
||||
public void setParentNamespace(Namespace parentNamespace)
|
||||
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||
symbol.setNamespace(parentNamespace);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public class GlobalVariableSymbolDB extends VariableSymbolDB {
|
|||
VariableStorageManagerDB variableMgr, Address address, DBRecord record) {
|
||||
super(symbolMgr, cache, SymbolType.GLOBAL_VAR, variableMgr, address, record);
|
||||
if (record.getLongValue(
|
||||
SymbolDatabaseAdapter.SYMBOL_PARENT_COL) != Namespace.GLOBAL_NAMESPACE_ID) {
|
||||
SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL) != Namespace.GLOBAL_NAMESPACE_ID) {
|
||||
throw new AssertException();
|
||||
}
|
||||
}
|
||||
|
@ -57,15 +57,8 @@ public class GlobalVariableSymbolDB extends VariableSymbolDB {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() {
|
||||
if (!checkIsValid()) {
|
||||
return null;
|
||||
}
|
||||
VariableStorage storage = getVariableStorage();
|
||||
if (storage == null) {
|
||||
return null;
|
||||
}
|
||||
return storage;
|
||||
public Variable getObject() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,7 +27,7 @@ import ghidra.util.exception.InvalidInputException;
|
|||
* Object to represent an external library.
|
||||
*/
|
||||
class LibraryDB implements Library {
|
||||
private SymbolDB symbol;
|
||||
private LibrarySymbol symbol;
|
||||
private NamespaceManager namespaceMgr;
|
||||
|
||||
/**
|
||||
|
@ -35,62 +35,46 @@ class LibraryDB implements Library {
|
|||
* @param symbol the library symbol.
|
||||
* @param namespaceMgr the namespace manager
|
||||
*/
|
||||
LibraryDB(SymbolDB symbol, NamespaceManager namespaceMgr) {
|
||||
LibraryDB(LibrarySymbol symbol, NamespaceManager namespaceMgr) {
|
||||
this.symbol = symbol;
|
||||
this.namespaceMgr = namespaceMgr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getSymbol()
|
||||
*/
|
||||
@Override
|
||||
public Symbol getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return symbol.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getID()
|
||||
*/
|
||||
@Override
|
||||
public long getID() {
|
||||
return symbol.getID();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getParentNamespace()
|
||||
*/
|
||||
@Override
|
||||
public Namespace getParentNamespace() {
|
||||
return symbol.getParentNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getBody()
|
||||
*/
|
||||
@Override
|
||||
public AddressSetView getBody() {
|
||||
return namespaceMgr.getAddressSet(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getName(boolean)
|
||||
*/
|
||||
@Override
|
||||
public String getName(boolean includeNamespacePath) {
|
||||
return symbol.getName(includeNamespacePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return symbol.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
|
@ -104,18 +88,15 @@ class LibraryDB implements Library {
|
|||
return symbol == lib.symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#setParentNamespace(ghidra.program.model.symbol.Namespace)
|
||||
*/
|
||||
@Override
|
||||
public void setParentNamespace(Namespace parentNamespace) throws DuplicateNameException,
|
||||
InvalidInputException, CircularDependencyException {
|
||||
public void setParentNamespace(Namespace parentNamespace)
|
||||
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||
symbol.setNamespace(parentNamespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAssociatedProgramPath() {
|
||||
return symbol.getSymbolStringData();
|
||||
return symbol.getExternalLibraryPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -40,13 +40,10 @@ public class LibrarySymbol extends SymbolDB {
|
|||
* Constructs a new Library Symbol
|
||||
* @param symbolMgr the symbol manager
|
||||
* @param cache symbol object cache
|
||||
* @param address the address for this symbol
|
||||
* @param record the record for this symbol
|
||||
*/
|
||||
public LibrarySymbol(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache, Address address,
|
||||
DBRecord record) {
|
||||
super(symbolMgr, cache, address, record);
|
||||
|
||||
public LibrarySymbol(SymbolManager symbolMgr, DBObjectCache<SymbolDB> cache, DBRecord record) {
|
||||
super(symbolMgr, cache, Address.NO_ADDRESS, record);
|
||||
}
|
||||
|
||||
@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
|
||||
public SymbolType getSymbolType() {
|
||||
return SymbolType.LIBRARY;
|
||||
|
@ -102,11 +89,20 @@ public class LibrarySymbol extends SymbolDB {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() {
|
||||
if (library == null) {
|
||||
library = new LibraryDB(this, symbolMgr.getProgram().getNamespaceManager());
|
||||
public Library getObject() {
|
||||
lock.acquire();
|
||||
try {
|
||||
if (!checkIsValid()) {
|
||||
return null;
|
||||
}
|
||||
if (library == null) {
|
||||
library = new LibraryDB(this, symbolMgr.getProgram().getNamespaceManager());
|
||||
}
|
||||
return library;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return library;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -119,4 +115,38 @@ public class LibrarySymbol extends SymbolDB {
|
|||
return super.isValidParent(parent) &&
|
||||
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 {
|
||||
private SymbolDB symbol;
|
||||
private NamespaceSymbol symbol;
|
||||
private NamespaceManager namespaceMgr;
|
||||
|
||||
/**
|
||||
|
@ -36,62 +36,46 @@ class NamespaceDB implements Namespace {
|
|||
* @param symbol the symbol associated with this namespace.
|
||||
* @param namespaceMgr the namespace manager
|
||||
*/
|
||||
NamespaceDB(SymbolDB symbol, NamespaceManager namespaceMgr) {
|
||||
NamespaceDB(NamespaceSymbol symbol, NamespaceManager namespaceMgr) {
|
||||
this.symbol = symbol;
|
||||
this.namespaceMgr = namespaceMgr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getSymbol()
|
||||
*/
|
||||
@Override
|
||||
public Symbol getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return symbol.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getID()
|
||||
*/
|
||||
@Override
|
||||
public long getID() {
|
||||
return symbol.getID();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getParentNamespace()
|
||||
*/
|
||||
@Override
|
||||
public Namespace getParentNamespace() {
|
||||
return symbol.getParentNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getBody()
|
||||
*/
|
||||
@Override
|
||||
public AddressSetView getBody() {
|
||||
return namespaceMgr.getAddressSet(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#getName(boolean)
|
||||
*/
|
||||
@Override
|
||||
public String getName(boolean includeNamespacePath) {
|
||||
return symbol.getName(includeNamespacePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return symbol.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
|
@ -105,18 +89,12 @@ class NamespaceDB implements Namespace {
|
|||
return symbol == nameSpace.symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Namespace#setParentNamespace(ghidra.program.model.symbol.Namespace)
|
||||
*/
|
||||
@Override
|
||||
public void setParentNamespace(Namespace parentNamespace) throws DuplicateNameException,
|
||||
InvalidInputException, CircularDependencyException {
|
||||
public void setParentNamespace(Namespace parentNamespace)
|
||||
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||
symbol.setNamespace(parentNamespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName(true);
|
||||
|
|
|
@ -31,12 +31,10 @@ public class NamespaceSymbol extends SymbolDB {
|
|||
* Construct a new namespace symbol
|
||||
* @param mgr the symbol manager.
|
||||
* @param cache symbol object cache
|
||||
* @param addr the address for this symbol.
|
||||
* @param record the record for this symbol.
|
||||
*/
|
||||
NamespaceSymbol(SymbolManager mgr, DBObjectCache<SymbolDB> cache, Address addr,
|
||||
DBRecord record) {
|
||||
super(mgr, cache, addr, record);
|
||||
NamespaceSymbol(SymbolManager mgr, DBObjectCache<SymbolDB> cache, DBRecord record) {
|
||||
super(mgr, cache, Address.NO_ADDRESS, record);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,15 +54,20 @@ public class NamespaceSymbol extends SymbolDB {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() {
|
||||
return getNamespace();
|
||||
}
|
||||
|
||||
private Namespace getNamespace() {
|
||||
if (namespace == null) {
|
||||
namespace = new NamespaceDB(this, symbolMgr.getProgram().getNamespaceManager());
|
||||
public Namespace getObject() {
|
||||
lock.acquire();
|
||||
try {
|
||||
if (!checkIsValid()) {
|
||||
return null;
|
||||
}
|
||||
if (namespace == null) {
|
||||
namespace = new NamespaceDB(this, symbolMgr.getProgram().getNamespaceManager());
|
||||
}
|
||||
return namespace;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
package ghidra.program.database.symbol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import db.DBRecord;
|
||||
import db.Field;
|
||||
|
@ -34,16 +35,15 @@ import ghidra.util.Lock;
|
|||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.UnknownProgressWrappingTaskMonitor;
|
||||
|
||||
/**
|
||||
* Base class for symbols
|
||||
*/
|
||||
public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||
|
||||
private DBRecord record;
|
||||
private boolean isDeleting = false;
|
||||
|
||||
protected DBRecord record;
|
||||
protected Address address;
|
||||
protected SymbolManager symbolMgr;
|
||||
protected Lock lock;
|
||||
|
@ -132,48 +132,6 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
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
|
||||
public final String getName() {
|
||||
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
|
||||
public boolean isDynamic() {
|
||||
return (record == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExternalEntryPoint() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
return symbolMgr.isExternalEntryPoint(address);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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 clearBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
|
||||
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
|
||||
public void setName(String newName, SourceType source)
|
||||
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);
|
||||
updateSymbolSource(record, source);
|
||||
updateRecord();
|
||||
|
@ -750,7 +508,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
return (int) key;
|
||||
}
|
||||
|
||||
private void updateRecord() {
|
||||
protected void updateRecord() {
|
||||
try {
|
||||
symbolMgr.getDatabaseAdapter().updateSymbolRecord(record);
|
||||
}
|
||||
|
@ -781,7 +539,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
return null;
|
||||
}
|
||||
return symbolMgr
|
||||
.getSymbol(record.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL));
|
||||
.getSymbol(record.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL));
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -795,7 +553,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
if (record == null) {
|
||||
return Namespace.GLOBAL_NAMESPACE_ID;
|
||||
}
|
||||
return record.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL);
|
||||
return record.getLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -811,51 +569,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
return true;
|
||||
}
|
||||
return record.getLongValue(
|
||||
SymbolDatabaseAdapter.SYMBOL_PARENT_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);
|
||||
SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL) == Namespace.GLOBAL_NAMESPACE_ID;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -863,21 +577,13 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
}
|
||||
|
||||
public long getDataTypeId() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (record != null) {
|
||||
Field value = record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||
if (value.isNull()) {
|
||||
return -1;
|
||||
}
|
||||
return value.getLongValue();
|
||||
}
|
||||
validate(lock);
|
||||
// record always present when use of datatype ID is supported (i.e., external location)
|
||||
Field value = record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||
if (value.isNull()) {
|
||||
return -1;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return value.getLongValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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) {
|
||||
lock.acquire();
|
||||
try {
|
||||
|
@ -1023,4 +691,5 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
this.record = record;
|
||||
keyChanged(record.getKey());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,24 +39,37 @@ abstract class SymbolDatabaseAdapter {
|
|||
|
||||
static final int SYMBOL_NAME_COL = 0;
|
||||
static final int SYMBOL_ADDR_COL = 1;
|
||||
static final int SYMBOL_PARENT_COL = 2;
|
||||
static final int SYMBOL_PARENT_ID_COL = 2;
|
||||
static final int SYMBOL_TYPE_COL = 3;
|
||||
static final int SYMBOL_STRING_DATA_COL = 4;
|
||||
static final int SYMBOL_FLAGS_COL = 5;
|
||||
static final int SYMBOL_FLAGS_COL = 4;
|
||||
|
||||
// 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.
|
||||
static final int SYMBOL_HASH_COL = 6;
|
||||
static final int SYMBOL_PRIMARY_COL = 7;
|
||||
static final int SYMBOL_DATATYPE_COL = 8;
|
||||
static final int SYMBOL_VAROFFSET_COL = 9;
|
||||
static final int SYMBOL_HASH_COL = 5;
|
||||
static final int SYMBOL_PRIMARY_COL = 6;
|
||||
static final int SYMBOL_DATATYPE_COL = 7;
|
||||
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.
|
||||
static final byte SYMBOL_SOURCE_BITS = (byte) 0x3;
|
||||
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
|
||||
|
||||
/**
|
||||
|
@ -75,11 +88,11 @@ abstract class SymbolDatabaseAdapter {
|
|||
throws VersionException, CancelledException, IOException {
|
||||
|
||||
if (openMode == OpenMode.CREATE) {
|
||||
return new SymbolDatabaseAdapterV3(dbHandle, addrMap, true);
|
||||
return new SymbolDatabaseAdapterV4(dbHandle, addrMap, true);
|
||||
}
|
||||
|
||||
try {
|
||||
SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV3(dbHandle, addrMap, false);
|
||||
SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV4(dbHandle, addrMap, false);
|
||||
return adapter;
|
||||
}
|
||||
catch (VersionException e) {
|
||||
|
@ -99,26 +112,33 @@ abstract class SymbolDatabaseAdapter {
|
|||
}
|
||||
|
||||
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 {
|
||||
return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap());
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
catch (VersionException e) {
|
||||
// failed try older version
|
||||
}
|
||||
|
||||
try {
|
||||
return new SymbolDatabaseAdapterV1(handle, addrMap.getOldAddressMap());
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
catch (VersionException e) {
|
||||
// failed try older version
|
||||
}
|
||||
|
||||
try {
|
||||
return new SymbolDatabaseAdapterV0(handle, addrMap.getOldAddressMap());
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
catch (VersionException e) {
|
||||
// failed - can't handle whatever version this is trying to open
|
||||
}
|
||||
|
||||
|
@ -140,7 +160,7 @@ abstract class SymbolDatabaseAdapter {
|
|||
|
||||
dbHandle.deleteTable(SYMBOL_TABLE_NAME);
|
||||
|
||||
SymbolDatabaseAdapter newAdapter = new SymbolDatabaseAdapterV3(dbHandle, addrMap, true);
|
||||
SymbolDatabaseAdapter newAdapter = new SymbolDatabaseAdapterV4(dbHandle, addrMap, true);
|
||||
|
||||
copyTempToNewAdapter(tmpAdapter, newAdapter, monitor);
|
||||
return newAdapter;
|
||||
|
@ -166,7 +186,7 @@ abstract class SymbolDatabaseAdapter {
|
|||
((SymbolDatabaseAdapterV0) oldAdapter).extractLocalSymbols(tmpHandle, monitor);
|
||||
}
|
||||
|
||||
SymbolDatabaseAdapterV3 tmpAdapter = new SymbolDatabaseAdapterV3(tmpHandle, addrMap, true);
|
||||
SymbolDatabaseAdapterV4 tmpAdapter = new SymbolDatabaseAdapterV4(tmpHandle, addrMap, true);
|
||||
RecordIterator iter = oldAdapter.getSymbols();
|
||||
while (iter.hasNext()) {
|
||||
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 address the address for the 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 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
|
||||
* Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT
|
||||
* @param dataTypeId the id of an associated datatype or null if there is no associated datatype
|
||||
* @param varOffset the variable offset will be the ordinal for a parameter or first use offset
|
||||
* for a local variable
|
||||
* @param isPrimary true if the symbol is primary. Only applicable for labels and functions
|
||||
* @return the new record
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
* @throws IllegalArgumentException if you try to set the source to DEFAULT for a symbol type
|
||||
* that doesn't allow it
|
||||
* @return new symbol record (not yet added to symbol table)
|
||||
*/
|
||||
abstract DBRecord createSymbol(String name, Address address, long namespaceID,
|
||||
SymbolType symbolType, String stringData, Long dataTypeId, Integer varOffset,
|
||||
SourceType source, boolean isPrimary) throws IOException;
|
||||
abstract DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||
SymbolType symbolType, boolean isPrimary, SourceType source);
|
||||
|
||||
/**
|
||||
* Get the record with the given symbol ID
|
||||
|
@ -372,10 +388,29 @@ abstract class SymbolDatabaseAdapter {
|
|||
* This only includes memory-based stored symbols.
|
||||
*
|
||||
* @param startName the starting name to search
|
||||
* @return a symbol record iterator over the symbols
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
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
|
||||
* @param name the symbol name
|
||||
|
@ -439,7 +474,8 @@ abstract class SymbolDatabaseAdapter {
|
|||
protected static RecordIterator getNameAndNamespaceFilterIterator(String name, long namespaceId,
|
||||
RecordIterator it) {
|
||||
Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name));
|
||||
Query namespaceQuery = new FieldMatchQuery(SYMBOL_PARENT_COL, new LongField(namespaceId));
|
||||
Query namespaceQuery =
|
||||
new FieldMatchQuery(SYMBOL_PARENT_ID_COL, new LongField(namespaceId));
|
||||
Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery);
|
||||
return new QueryRecordIterator(it, nameAndNamespaceQuery);
|
||||
}
|
||||
|
@ -457,7 +493,8 @@ abstract class SymbolDatabaseAdapter {
|
|||
protected static RecordIterator getNameNamespaceAddressFilterIterator(String name,
|
||||
long namespaceId, long addressKey, RecordIterator it) {
|
||||
Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name));
|
||||
Query namespaceQuery = new FieldMatchQuery(SYMBOL_PARENT_COL, new LongField(namespaceId));
|
||||
Query namespaceQuery =
|
||||
new FieldMatchQuery(SYMBOL_PARENT_ID_COL, new LongField(namespaceId));
|
||||
Query addressQuery = new FieldMatchQuery(SYMBOL_ADDR_COL, new LongField(addressKey));
|
||||
Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery);
|
||||
Query fullQuery = new AndQuery(nameAndNamespaceQuery, addressQuery);
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Set;
|
|||
import db.*;
|
||||
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.database.util.EmptyRecordIterator;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.*;
|
||||
|
@ -105,7 +106,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
return symbolTable.getKey();
|
||||
}
|
||||
|
||||
private DBRecord convertRecord(DBRecord record) {
|
||||
private DBRecord convertV0Record(DBRecord record) {
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -118,32 +119,34 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
String symbolName = record.getString(V0_SYMBOL_NAME_COL);
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
|
||||
long addressKey = record.getLongValue(V0_SYMBOL_ADDR_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL,
|
||||
addressKey);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, 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);
|
||||
if (isPrimary) {
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||
SymbolType symbolType, boolean isPrimary, SourceType source) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -164,7 +167,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(long symbolID) throws IOException {
|
||||
return convertRecord(symbolTable.getRecord(symbolID));
|
||||
return convertV0Record(symbolTable.getRecord(symbolID));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -210,8 +213,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
|
@ -240,8 +242,17 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
|
||||
@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) {
|
||||
return new V0ConvertedRecordIterator(symbolTable.iterator());
|
||||
}
|
||||
|
@ -299,7 +310,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
if (hasNext()) {
|
||||
DBRecord r = rec;
|
||||
rec = null;
|
||||
return convertRecord(r);
|
||||
return convertV0Record(r);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -337,8 +348,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
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);
|
||||
RecordIterator filtered = getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Set;
|
|||
import db.*;
|
||||
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.database.util.EmptyRecordIterator;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
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_PARENT_COL = 2;
|
||||
private static final int V1_SYMBOL_TYPE_COL = 3;
|
||||
private static final int V1_SYMBOL_DATA1_COL = 4;
|
||||
private static final int V1_SYMBOL_DATA2_COL = 5;
|
||||
private static final int V1_SYMBOL_DATA1_COL = 4; // Long data (variable dataTypeId)
|
||||
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 Table symbolTable;
|
||||
|
@ -70,9 +71,8 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||
SymbolType symbolType, boolean isPrimary, SourceType source) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -121,14 +121,11 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
||||
|
||||
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);
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId);
|
||||
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL,
|
||||
record.getString(V1_SYMBOL_COMMENT_COL));
|
||||
|
||||
SourceType source = SourceType.USER_DEFINED;
|
||||
if (symbolTypeId == SymbolType.FUNCTION.getID()) {
|
||||
Address symbolAddress = addrMap.decodeAddress(symbolAddrKey);
|
||||
|
@ -139,6 +136,13 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
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);
|
||||
if (dataTypeId != -1) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
||||
|
@ -161,7 +165,9 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
// also need to store primary for functions
|
||||
if (SymbolType.FUNCTION.equals(type)) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
||||
|
||||
}
|
||||
|
||||
Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey);
|
||||
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||
|
||||
|
@ -211,8 +217,7 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
|
@ -240,6 +245,16 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
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
|
||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||
LongField field = new LongField(id);
|
||||
|
@ -293,8 +308,7 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
||||
RecordIterator it = getSymbolsByName(name);
|
||||
long addressKey = addrMap.getKey(address, false);
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||
RecordIterator filtered = getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
|
|
|
@ -16,12 +16,11 @@
|
|||
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.RecordFilter;
|
||||
import ghidra.program.database.util.EmptyRecordIterator;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
|
@ -43,20 +42,20 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
// "SymbolData3", "Flags" });
|
||||
|
||||
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 AddressMap addrMap;
|
||||
|
||||
static final int V2_SYMBOL_NAME_COL = 0;
|
||||
static final int V2_SYMBOL_ADDR_COL = 1;
|
||||
static final int V2_SYMBOL_PARENT_COL = 2;
|
||||
static final int V2_SYMBOL_TYPE_COL = 3;
|
||||
static final int V2_SYMBOL_DATA1_COL = 4;
|
||||
static final int V2_SYMBOL_DATA2_COL = 5;
|
||||
static final int V2_SYMBOL_DATA3_COL = 6;
|
||||
static final int V2_SYMBOL_FLAGS_COL = 7;
|
||||
|
||||
SymbolDatabaseAdapterV2(DBHandle handle, AddressMap addrMap)
|
||||
throws VersionException {
|
||||
SymbolDatabaseAdapterV2(DBHandle handle, AddressMap addrMap) throws VersionException {
|
||||
|
||||
this.addrMap = addrMap;
|
||||
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
||||
|
@ -73,9 +72,8 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||
SymbolType symbolType, boolean isPrimary, SourceType source) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -154,8 +152,7 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
|
@ -174,51 +171,58 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
|
||||
@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);
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@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();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
class AnchoredSymbolRecordFilter implements RecordFilter {
|
||||
private Set<Address> set = new HashSet<Address>();
|
||||
private String getExternalStringData(DBRecord rec) {
|
||||
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;
|
||||
}
|
||||
|
||||
@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);
|
||||
if (((flags & SymbolDatabaseAdapter.SYMBOL_PINNED_FLAG) == 0)) {
|
||||
return true;
|
||||
return rec.getString(V2_SYMBOL_DATA3_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 convertV2Record(rec);
|
||||
}
|
||||
}
|
||||
set.add(addr);
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
Set<Address> getAddressesForSkippedRecords() {
|
||||
return set;
|
||||
}
|
||||
@Override
|
||||
RecordIterator getExternalSymbolsByOriginalImportName(String extLabel) throws IOException {
|
||||
return EmptyRecordIterator.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -236,6 +240,24 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
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
|
||||
Address getMaxSymbolAddress(AddressSpace space) throws IOException {
|
||||
if (space.isMemorySpace()) {
|
||||
|
@ -265,27 +287,6 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
return symbolTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
||||
StringField value = new StringField(name);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true);
|
||||
RecordIterator filtered = getNameAndNamespaceFilterIterator(name, id, it);
|
||||
return new V2ConvertedRecordIterator(filtered);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
||||
StringField value = new StringField(name);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true);
|
||||
long addressKey = addrMap.getKey(address, false);
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a record matching the current database schema from the version 2 record.
|
||||
* @param record the record matching the version 2 schema.
|
||||
|
@ -303,21 +304,25 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
long symbolAddrKey = record.getLongValue(V2_SYMBOL_ADDR_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
||||
|
||||
long namespaceId = record.getLongValue(V2_SYMBOL_PARENT_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId);
|
||||
long namespaceId = record.getLongValue(V2_SYMBOL_PARENT_ID_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_ID_COL, namespaceId);
|
||||
|
||||
byte symbolTypeId = record.getByteValue(V2_SYMBOL_TYPE_COL);
|
||||
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));
|
||||
|
||||
Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey);
|
||||
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL,
|
||||
record.getByteValue(V2_SYMBOL_FLAGS_COL));
|
||||
|
||||
long dataTypeId = record.getLongValue(V2_SYMBOL_DATA1_COL);
|
||||
if (dataTypeId != -1) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
||||
|
@ -325,7 +330,7 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
|
||||
SymbolType type = SymbolType.getSymbolType(symbolTypeId);
|
||||
int data2 = record.getIntValue(V2_SYMBOL_DATA2_COL);
|
||||
// The data1 field was used in two ways for label symbols, it stored a 1 for primary and 0
|
||||
// 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
|
||||
// first use offset respectively
|
||||
if (SymbolType.LABEL.equals(type)) {
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
package ghidra.program.database.symbol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
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;
|
||||
|
@ -33,9 +33,10 @@ import ghidra.util.task.TaskMonitor;
|
|||
/**
|
||||
* 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 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 {
|
||||
|
||||
|
@ -49,95 +50,58 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
|||
// allows us to index this field and quickly find the primary symbols. The field is sparse
|
||||
// so that non-primary symbols don't consume any space for this field.
|
||||
|
||||
static final Schema V3_SYMBOL_SCHEMA = new Schema(SYMBOL_VERSION, "Key",
|
||||
new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||
ByteField.INSTANCE, StringField.INSTANCE, ByteField.INSTANCE,
|
||||
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE },
|
||||
new String[] { "Name", "Address", "Namespace", "Symbol Type", "String Data", "Flags",
|
||||
"Locator Hash", "Primary", "Datatype", "Variable Offset" },
|
||||
new int[] { SYMBOL_HASH_COL, SYMBOL_PRIMARY_COL, SYMBOL_DATATYPE_COL,
|
||||
SYMBOL_VAROFFSET_COL });
|
||||
/* Do not remove the following commented out schema! It shows the version 3 symbol table schema. */
|
||||
// static final Schema V3_SYMBOL_SCHEMA = new Schema(SYMBOL_VERSION, "Key",
|
||||
// new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||
// ByteField.INSTANCE, StringField.INSTANCE, ByteField.INSTANCE, LongField.INSTANCE,
|
||||
// LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE },
|
||||
// new String[] { "Name", "Address", "Namespace", "Symbol Type", "String Data", "Flags",
|
||||
// "Locator Hash", "Primary", "Datatype", "Variable Offset" },
|
||||
// new int[] { SYMBOL_HASH_COL, SYMBOL_PRIMARY_COL, SYMBOL_DATATYPE_COL,
|
||||
// SYMBOL_VAROFFSET_COL });
|
||||
|
||||
private 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 AddressMap addrMap;
|
||||
|
||||
SymbolDatabaseAdapterV3(DBHandle handle, AddressMap addrMap, boolean create)
|
||||
throws VersionException, IOException {
|
||||
SymbolDatabaseAdapterV3(DBHandle handle, AddressMap addrMap) throws VersionException {
|
||||
|
||||
this.addrMap = addrMap;
|
||||
if (create) {
|
||||
symbolTable = handle.createTable(SYMBOL_TABLE_NAME, SYMBOL_SCHEMA,
|
||||
new int[] { SYMBOL_ADDR_COL, SYMBOL_NAME_COL, SYMBOL_PARENT_COL, SYMBOL_HASH_COL,
|
||||
SYMBOL_PRIMARY_COL });
|
||||
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
||||
if (symbolTable == null) {
|
||||
throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME);
|
||||
}
|
||||
else {
|
||||
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
||||
if (symbolTable == null) {
|
||||
throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME);
|
||||
}
|
||||
if (symbolTable.getSchema().getVersion() != SYMBOL_VERSION) {
|
||||
int version = symbolTable.getSchema().getVersion();
|
||||
if (version < SYMBOL_VERSION) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
throw new VersionException(VersionException.NEWER_VERSION, false);
|
||||
if (symbolTable.getSchema().getVersion() != SYMBOL_VERSION) {
|
||||
int version = symbolTable.getSchema().getVersion();
|
||||
if (version < SYMBOL_VERSION) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
throw new VersionException(VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
long nextID = symbolTable.getKey();
|
||||
|
||||
// avoiding key 0, as it is reserved for the global namespace
|
||||
if (nextID == 0) {
|
||||
nextID++;
|
||||
}
|
||||
return createSymbol(nextID, name, address, namespaceID, symbolType, stringData,
|
||||
(byte) source.ordinal(), dataTypeId, varOffset, isPrimary);
|
||||
}
|
||||
|
||||
private DBRecord createSymbol(long id, String name, Address address, long namespaceID,
|
||||
SymbolType symbolType, String stringData, byte flags,
|
||||
Long dataTypeId, Integer varOffset, boolean isPrimary) throws IOException {
|
||||
|
||||
long addressKey = addrMap.getKey(address, true);
|
||||
|
||||
DBRecord rec = symbolTable.getSchema().createRecord(id);
|
||||
rec.setString(SYMBOL_NAME_COL, name);
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, addressKey);
|
||||
rec.setLongValue(SYMBOL_PARENT_COL, namespaceID);
|
||||
rec.setByteValue(SYMBOL_TYPE_COL, symbolType.getID());
|
||||
rec.setString(SYMBOL_STRING_DATA_COL, stringData);
|
||||
rec.setByteValue(SYMBOL_FLAGS_COL, flags);
|
||||
|
||||
// sparse columns - these columns don't apply to all symbols.
|
||||
// they default to null unless specifically set. Null values don't consume space.
|
||||
|
||||
rec.setField(SYMBOL_HASH_COL,
|
||||
computeLocatorHash(name, namespaceID, addressKey));
|
||||
|
||||
if (isPrimary) {
|
||||
rec.setLongValue(SYMBOL_PRIMARY_COL, addressKey);
|
||||
}
|
||||
|
||||
if (dataTypeId != null) {
|
||||
rec.setLongValue(SYMBOL_DATATYPE_COL, dataTypeId);
|
||||
}
|
||||
|
||||
if (varOffset != null) {
|
||||
rec.setIntValue(SYMBOL_VAROFFSET_COL, varOffset);
|
||||
}
|
||||
|
||||
symbolTable.putRecord(rec);
|
||||
return rec;
|
||||
DBRecord createSymbolRecord(String name, long namespaceID, Address address,
|
||||
SymbolType symbolType, boolean isPrimary, SourceType source) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
void removeSymbol(long symbolID) throws IOException {
|
||||
symbolTable.deleteRecord(symbolID);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -160,7 +124,7 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(long symbolID) throws IOException {
|
||||
return symbolTable.getRecord(symbolID);
|
||||
return convertV3Record(symbolTable.getRecord(symbolID));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -170,49 +134,52 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
RecordIterator getSymbolsByAddress(boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable,
|
||||
KeyToRecordIterator it = new KeyToRecordIterator(symbolTable,
|
||||
new AddressIndexPrimaryKeyIterator(symbolTable, SYMBOL_ADDR_COL, addrMap, forward));
|
||||
return new V3ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, startAddr, forward));
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, startAddr, forward));
|
||||
return new V3ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateSymbolRecord(DBRecord record) throws IOException {
|
||||
// make sure hash is updated to current name and name space
|
||||
String name = record.getString(SYMBOL_NAME_COL);
|
||||
long namespaceId = record.getLongValue(SYMBOL_PARENT_COL);
|
||||
long addressKey = record.getLongValue(SYMBOL_ADDR_COL);
|
||||
record.setField(SYMBOL_HASH_COL,
|
||||
computeLocatorHash(name, namespaceId, addressKey));
|
||||
symbolTable.putRecord(record);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols() throws IOException {
|
||||
return symbolTable.iterator();
|
||||
return new V3ConvertedRecordIterator(symbolTable.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, start, end, forward));
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, start, end, forward));
|
||||
return new V3ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
return new V3ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_PRIMARY_COL, addrMap, set, forward));
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_PRIMARY_COL, addrMap, set, forward));
|
||||
return new V3ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -220,54 +187,92 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
|||
AddressIndexPrimaryKeyIterator it = new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_PRIMARY_COL, addrMap, address, address, true);
|
||||
if (it.hasNext()) {
|
||||
return symbolTable.getRecord(it.next());
|
||||
return convertV3Record(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);
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Address> deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
AnchoredSymbolRecordFilter filter = new AnchoredSymbolRecordFilter();
|
||||
AddressRecordDeleter.deleteRecords(symbolTable, SYMBOL_ADDR_COL, addrMap, startAddr,
|
||||
endAddr, filter);
|
||||
private String getExternalStringData(DBRecord rec) {
|
||||
long addrKey = rec.getLongValue(V3_SYMBOL_ADDR_COL);
|
||||
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
|
||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||
LongField field = new LongField(id);
|
||||
return symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_PARENT_ID_COL, field, field, true);
|
||||
return new V3ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByName(String name) throws IOException {
|
||||
StringField field = new StringField(name);
|
||||
return symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true);
|
||||
return new V3ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator scanSymbolsByName(String startName) throws IOException {
|
||||
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
|
||||
|
@ -282,7 +287,10 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
|||
Field end = computeLocatorHash(name, id, MAX_ADDRESS_OFFSET);
|
||||
|
||||
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
|
||||
|
@ -293,6 +301,8 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
|||
return null;
|
||||
}
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_HASH_COL, search, search, true);
|
||||
it = new V3ConvertedRecordIterator(it);
|
||||
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, namespaceId, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
|
@ -330,24 +340,96 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
|||
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());
|
||||
|
||||
@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;
|
||||
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);
|
||||
}
|
||||
|
||||
Set<Address> getAddressesForSkippedRecords() {
|
||||
return set;
|
||||
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
|
||||
protected DBRecord convertRecord(DBRecord record) {
|
||||
return convertV3Record(record);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
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() + ":" +
|
||||
rec.getString(SymbolDatabaseAdapter.SYMBOL_NAME_COL));
|
||||
}
|
||||
|
@ -356,7 +356,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
catch (InvalidInputException e) {
|
||||
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() +
|
||||
":" + rec.getString(SymbolDatabaseAdapter.SYMBOL_NAME_COL));
|
||||
curVarAddr = null;
|
||||
|
@ -527,8 +527,11 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
Address address = symbol.getAddress();
|
||||
symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID,
|
||||
null);
|
||||
DBRecord record = adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL,
|
||||
null, null, null, source, true);
|
||||
|
||||
DBRecord record = adapter.createSymbolRecord(newName, newParentID, address,
|
||||
SymbolType.LABEL, true, source);
|
||||
adapter.updateSymbolRecord(record);
|
||||
|
||||
symbol.setRecord(record);
|
||||
symbolAdded(symbol);
|
||||
}
|
||||
|
@ -571,7 +574,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, name);
|
||||
long addressKey = addrMap.getKey(addr, true);
|
||||
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());
|
||||
if (isPrimary) {
|
||||
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));
|
||||
}
|
||||
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) {
|
||||
return new CodeSymbol(this, cache, addr, record);
|
||||
return new CodeSymbol(this, cache, addr, record); // uses NO_ADDRESS
|
||||
}
|
||||
else if (type == SymbolType.NAMESPACE) {
|
||||
return new NamespaceSymbol(this, cache, addr, record);
|
||||
return new NamespaceSymbol(this, cache, record);
|
||||
}
|
||||
else if (type == SymbolType.FUNCTION) {
|
||||
return new FunctionSymbol(this, cache, addr, record);
|
||||
}
|
||||
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) {
|
||||
return new VariableSymbolDB(this, cache, type, variableStorageMgr, addr, record);
|
||||
|
@ -970,12 +973,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Symbol getLibrarySymbol(String name) {
|
||||
public LibrarySymbol getLibrarySymbol(String name) {
|
||||
lock.acquire();
|
||||
try {
|
||||
for (Symbol s : getSymbols(name)) {
|
||||
if (s.getSymbolType() == SymbolType.LIBRARY) {
|
||||
return s;
|
||||
return (LibrarySymbol) s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1111,6 +1114,83 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
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
|
||||
public Namespace getNamespace(String name, Namespace namespace) {
|
||||
List<Symbol> symbols = getSymbols(name, namespace);
|
||||
|
@ -1804,8 +1884,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
return true;
|
||||
}
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
lock.acquire();
|
||||
while (nextSymbol == null && (forward ? it.hasNext() : it.hasPrevious())) {
|
||||
DBRecord rec = forward ? it.next() : it.previous();
|
||||
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 SymbolIterator it;
|
||||
private Symbol nextMatch;
|
||||
|
@ -2204,6 +2344,45 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
dynamicSymbolAddressMap = new AddressMapImpl((byte) 0x40, addrMap.getAddressFactory());
|
||||
invalidateCache(true);
|
||||
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) {
|
||||
|
@ -2255,6 +2434,10 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
@Override
|
||||
public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
if (!fromAddr.isMemoryAddress() || !toAddr.isMemoryAddress()) {
|
||||
throw new IllegalArgumentException(
|
||||
"moveAddressRange only supported for memory addresses");
|
||||
}
|
||||
if (fromAddr.equals(toAddr)) {
|
||||
return;
|
||||
}
|
||||
|
@ -2274,14 +2457,18 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
if (!range.contains(symbol.getAddress())) {
|
||||
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
|
||||
// (too many or non-existent)
|
||||
primaryFixups.add(symbol.getAddress());
|
||||
primaryFixups.add(memSym.getAddress());
|
||||
primaryFixups.add(newAddress);
|
||||
|
||||
moveSymbolForMemoryBlockMove((SymbolDB) symbol, newAddress);
|
||||
moveSymbolForMemoryBlockMove(memSym, newAddress);
|
||||
}
|
||||
// go back and make sure there is a valid primary symbol at touched addresses
|
||||
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
|
||||
// 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.
|
||||
private void moveSymbolForMemoryBlockMove(SymbolDB symbol, Address newAddress) {
|
||||
Address oldAddress = symbol.getAddress();
|
||||
private void moveSymbolForMemoryBlockMove(MemorySymbol memSymbol, Address newAddress) {
|
||||
Address oldAddress = memSymbol.getAddress();
|
||||
|
||||
// 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
|
||||
// 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)
|
||||
// and retain its pinned status if it had one.
|
||||
boolean shouldPin = deleteMatchingSymbolAndCheckPinnedStatus(symbol, newAddress);
|
||||
symbol.moveLowLevel(newAddress, null, null, null, shouldPin);
|
||||
boolean shouldPin = deleteMatchingSymbolAndCheckPinnedStatus(memSymbol, newAddress);
|
||||
memSymbol.moveLowLevel(newAddress, null, null, null, shouldPin);
|
||||
moveLabelHistory(oldAddress, newAddress);
|
||||
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,
|
||||
// if there is a primary symbol at the destination, we need to remove it and set the
|
||||
// function's symbol to that name.
|
||||
if (symbol.getSymbolType() == SymbolType.FUNCTION) {
|
||||
String originalName = symbol.getName();
|
||||
Namespace originalNamespace = symbol.getParentNamespace();
|
||||
SourceType originalSource = symbol.getSource();
|
||||
if (memSymbol.getSymbolType() == SymbolType.FUNCTION) {
|
||||
String originalName = memSymbol.getName();
|
||||
Namespace originalNamespace = memSymbol.getParentNamespace();
|
||||
SourceType originalSource = memSymbol.getSource();
|
||||
String newName = "";
|
||||
Namespace newNamespace = namespaceMgr.getGlobalNamespace();
|
||||
SourceType newSource = SourceType.DEFAULT;
|
||||
|
@ -2335,7 +2522,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
try {
|
||||
// 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.
|
||||
Symbol newSymbol =
|
||||
|
@ -2444,45 +2631,48 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
|
||||
public void imageBaseChanged(Address oldBase, Address newBase) {
|
||||
if (!oldBase.isLoadedMemoryAddress() || !newBase.isLoadedMemoryAddress()) {
|
||||
throw new IllegalArgumentException("Loaded memory addresses required");
|
||||
}
|
||||
AddressSpace space = newBase.getAddressSpace();
|
||||
fixupPinnedSymbolsAfterRebase(oldBase, newBase, space.getMinAddress(),
|
||||
fixupPinnedMemorySymbolsAfterRebase(oldBase, newBase, space.getMinAddress(),
|
||||
space.getMaxAddress());
|
||||
}
|
||||
|
||||
private void fixupPinnedSymbolsAfterRebase(Address oldBase, Address base, Address minAddr,
|
||||
private void fixupPinnedMemorySymbolsAfterRebase(Address oldBase, Address base, Address minAddr,
|
||||
Address maxAddr) {
|
||||
|
||||
List<SymbolDB> fixupPinnedSymbols = findPinnedSymbols(minAddr, maxAddr);
|
||||
List<MemorySymbol> fixupPinnedSymbols = findPinnedMemorySymbols(minAddr, maxAddr);
|
||||
|
||||
Set<Address> primaryFixups = new HashSet<>();
|
||||
for (SymbolDB symbol : fixupPinnedSymbols) {
|
||||
Address currentAddress = symbol.getAddress();
|
||||
for (MemorySymbol memSymbol : fixupPinnedSymbols) {
|
||||
Address currentAddress = memSymbol.getAddress();
|
||||
Address beforeBaseChangeAddress = oldBase.addWrap(currentAddress.subtract(base));
|
||||
primaryFixups.add(currentAddress);
|
||||
primaryFixups.add(beforeBaseChangeAddress);
|
||||
|
||||
// see if there is a name collision for the pinned symbol we are about to move back
|
||||
Symbol match =
|
||||
getSymbol(symbol.getName(), beforeBaseChangeAddress, symbol.getParentNamespace());
|
||||
Symbol match = getSymbol(memSymbol.getName(), beforeBaseChangeAddress,
|
||||
memSymbol.getParentNamespace());
|
||||
|
||||
if (symbol.getSymbolType() == SymbolType.FUNCTION) {
|
||||
fixupPinnedFunctionSymbolAfterRebase(symbol, beforeBaseChangeAddress, match);
|
||||
if (memSymbol.getSymbolType() == SymbolType.FUNCTION) {
|
||||
fixupPinnedFunctionSymbolAfterRebase(memSymbol, beforeBaseChangeAddress, match);
|
||||
}
|
||||
else {
|
||||
fixupPinnedLabelSymbolAfterRebase(symbol, beforeBaseChangeAddress, match);
|
||||
fixupPinnedLabelSymbolAfterRebase(memSymbol, beforeBaseChangeAddress, match);
|
||||
}
|
||||
}
|
||||
fixupPrimarySymbols(primaryFixups);
|
||||
}
|
||||
|
||||
private void fixupPinnedLabelSymbolAfterRebase(SymbolDB symbol, Address newAddress,
|
||||
private void fixupPinnedLabelSymbolAfterRebase(MemorySymbol memSymbol, Address newAddress,
|
||||
Symbol match) {
|
||||
if (match != null) {
|
||||
match.setPinned(true);
|
||||
symbol.delete();
|
||||
memSymbol.delete();
|
||||
}
|
||||
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) {
|
||||
List<SymbolDB> pinnedSymbols = new ArrayList<>();
|
||||
private List<MemorySymbol> findPinnedMemorySymbols(Address minAddr, Address maxAddr) {
|
||||
List<MemorySymbol> pinnedSymbols = new ArrayList<>();
|
||||
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;
|
||||
}
|
||||
if (symbol.isPinned()) {
|
||||
pinnedSymbols.add((SymbolDB) symbol);
|
||||
if (memSym.isPinned()) {
|
||||
pinnedSymbols.add(memSym);
|
||||
}
|
||||
}
|
||||
return pinnedSymbols;
|
||||
|
@ -2589,16 +2783,24 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
try {
|
||||
source = adjustSourceTypeIfNecessary(name, type, source, storage);
|
||||
Address varAddr = variableStorageMgr.getVariableStorageAddress(storage, true);
|
||||
return (VariableSymbolDB) doCreateSpecialSymbol(varAddr, name, function, type, null,
|
||||
Integer.valueOf(firstUseOffsetOrOrdinal), null, source, true);
|
||||
DBRecord record =
|
||||
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) {
|
||||
dbError(e);
|
||||
program.dbError(e); // will not return
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private SourceType adjustSourceTypeIfNecessary(String name, SymbolType type, SourceType source,
|
||||
|
@ -2616,21 +2818,21 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
@Override
|
||||
public GhidraClass createClass(Namespace parent, String name, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
SymbolDB s = createClassSymbol(name, parent, source, true);
|
||||
ClassSymbol s = createClassSymbol(name, parent, source, true);
|
||||
return new GhidraClassDB(s, namespaceMgr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Library createExternalLibrary(String name, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
SymbolDB s = createLibrarySymbol(name, null, source);
|
||||
LibrarySymbol s = createLibrarySymbol(name, null, source);
|
||||
return new LibraryDB(s, namespaceMgr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Namespace createNameSpace(Namespace parent, String name, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
SymbolDB s = createNamespaceSymbol(name, parent, source, true);
|
||||
NamespaceSymbol s = createNamespaceSymbol(name, parent, source, true);
|
||||
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
|
||||
String tempName = "_temp_" + System.nanoTime();
|
||||
SymbolDB classSymbol = createClassSymbol(tempName, namespace.getParentNamespace(),
|
||||
ClassSymbol classSymbol = createClassSymbol(tempName, namespace.getParentNamespace(),
|
||||
originalSource, false /*check for duplicate */);
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
|
@ -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
|
||||
* symbol table.
|
||||
*/
|
||||
public SymbolDB createLibrarySymbol(String name, String pathname, SourceType source)
|
||||
public LibrarySymbol createLibrarySymbol(String name, String pathname, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
return doCreateSpecialSymbol(Address.NO_ADDRESS, name, null, SymbolType.LIBRARY, null, null,
|
||||
pathname, source, true);
|
||||
lock.acquire();
|
||||
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
|
||||
* symbol table.
|
||||
*/
|
||||
SymbolDB createClassSymbol(String name, Namespace parent, SourceType source,
|
||||
ClassSymbol createClassSymbol(String name, Namespace parent, SourceType source,
|
||||
boolean checkForDuplicates) throws DuplicateNameException, InvalidInputException {
|
||||
return doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.CLASS, null, null,
|
||||
null, source, true);
|
||||
lock.acquire();
|
||||
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,161 +3006,228 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* if the given parent namespace is from a different program than that of this
|
||||
* symbol table.
|
||||
*/
|
||||
SymbolDB createNamespaceSymbol(String name, Namespace parent, SourceType source,
|
||||
NamespaceSymbol createNamespaceSymbol(String name, Namespace parent, SourceType source,
|
||||
boolean checkForDuplicates) throws DuplicateNameException, InvalidInputException {
|
||||
return doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, null,
|
||||
null, null, source, true);
|
||||
lock.acquire();
|
||||
try {
|
||||
DBRecord record = doCreateBasicSymbolRecord(name, parent, Address.NO_ADDRESS,
|
||||
SymbolType.NAMESPACE, false, source, checkForDuplicates);
|
||||
adapter.updateSymbolRecord(record);
|
||||
|
||||
NamespaceSymbol newSymbol = new NamespaceSymbol(this, cache, record);
|
||||
|
||||
symbolAdded(newSymbol);
|
||||
return newSymbol;
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e); // will not return
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
private SymbolDB doCreateSpecialSymbol(Address addr, String name, Namespace parent,
|
||||
SymbolType symbolType, Long dataTypeId, Integer variableOffset, String stringData,
|
||||
SourceType source, boolean checkForDuplicates)
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
parent = validateNamespace(parent, addr, symbolType);
|
||||
source = validateSource(source, name, addr, symbolType);
|
||||
name = validateName(name, source);
|
||||
|
||||
if (checkForDuplicates) {
|
||||
checkDuplicateSymbolName(addr, name, parent, symbolType);
|
||||
// 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");
|
||||
}
|
||||
|
||||
return doCreateSymbol(name, addr, parent, symbolType, stringData, dataTypeId,
|
||||
variableOffset, source, false);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol createLabel(Address addr, String name, SourceType source)
|
||||
throws InvalidInputException {
|
||||
return createLabel(addr, name, null, source);
|
||||
}
|
||||
parent = validateNamespace(parent, address, symbolType);
|
||||
source = validateSource(source, name, address, symbolType);
|
||||
name = validateName(name, source);
|
||||
|
||||
@Override
|
||||
public Symbol createLabel(Address addr, String name, Namespace namespace, SourceType source)
|
||||
throws InvalidInputException {
|
||||
if (!addr.isMemoryAddress()) {
|
||||
throw new IllegalArgumentException("Invalid memory address: " + addr);
|
||||
if (checkForDuplicates) {
|
||||
checkDuplicateSymbolName(address, name, parent, symbolType);
|
||||
}
|
||||
return createCodeSymbol(addr, name, namespace, source, null);
|
||||
|
||||
return adapter.createSymbolRecord(name, parent.getID(), address, symbolType, isPrimary,
|
||||
source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method for creating label symbols.
|
||||
* Internal method for creating external data/code symbol.
|
||||
* <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();
|
||||
try {
|
||||
namespace = validateNamespace(namespace, addr, SymbolType.LABEL);
|
||||
source = validateSource(source, name, addr, SymbolType.LABEL);
|
||||
name = validateName(name, source);
|
||||
|
||||
boolean makePrimary = true;
|
||||
if (addr.isMemoryAddress()) {
|
||||
|
||||
Symbol symbol = getSymbol(name, addr, namespace);
|
||||
if (symbol != null) {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// If there is a default named function, rename it to the new symbol name
|
||||
Symbol functionSymbol = tryUpdatingDefaultFunction(addr, name, namespace, source);
|
||||
if (functionSymbol != null) {
|
||||
return functionSymbol;
|
||||
}
|
||||
|
||||
// if there is a dynamic symbol, delete it and make the new symbol primary.
|
||||
Symbol primary = getPrimarySymbol(addr);
|
||||
if (primary != null && primary.isDynamic()) {
|
||||
deleteDynamicSymbol(primary);
|
||||
primary = null;
|
||||
}
|
||||
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,
|
||||
source, makePrimary);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method for creating function symbols
|
||||
* 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 stringData special use depending on the symbol type and whether or not it is external.
|
||||
* @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 Symbol createFunctionSymbol(Address addr, String name, Namespace namespace,
|
||||
SourceType source, String stringData) throws InvalidInputException {
|
||||
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
|
||||
public Symbol createLabel(Address addr, String name, SourceType source)
|
||||
throws IllegalArgumentException, InvalidInputException {
|
||||
return createLabel(addr, name, null, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol createLabel(Address addr, String name, Namespace namespace, SourceType source)
|
||||
throws IllegalArgumentException, InvalidInputException {
|
||||
|
||||
if (!addr.isMemoryAddress()) {
|
||||
throw new IllegalArgumentException("Invalid memory address: " + addr);
|
||||
}
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
namespace = validateNamespace(namespace, addr, SymbolType.LABEL);
|
||||
source = validateSource(source, name, addr, SymbolType.LABEL);
|
||||
name = validateName(name, source);
|
||||
|
||||
Symbol symbol = getSymbol(name, addr, namespace);
|
||||
if (symbol != null) {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// If there is a default named function, rename it to the new symbol name
|
||||
Symbol functionSymbol = tryUpdatingDefaultFunction(addr, name, namespace, source);
|
||||
if (functionSymbol != null) {
|
||||
return functionSymbol;
|
||||
}
|
||||
|
||||
// if there is a dynamic symbol, delete it and make the new symbol primary.
|
||||
Symbol primary = getPrimarySymbol(addr);
|
||||
if (primary != null && primary.isDynamic()) {
|
||||
deleteDynamicSymbol(primary);
|
||||
primary = null;
|
||||
}
|
||||
boolean makePrimary = (primary == null);
|
||||
|
||||
DBRecord record = doCreateBasicSymbolRecord(name, namespace, addr, SymbolType.LABEL,
|
||||
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 {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
public FunctionSymbol createMemoryFunctionSymbol(Address addr, String name, Namespace namespace,
|
||||
SourceType source) throws IOException, InvalidInputException {
|
||||
|
||||
if (!addr.isMemoryAddress()) {
|
||||
throw new IllegalArgumentException("memory address required");
|
||||
}
|
||||
|
||||
namespace = validateNamespace(namespace, addr, SymbolType.FUNCTION);
|
||||
source = validateSource(source, name, addr, SymbolType.FUNCTION);
|
||||
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.
|
||||
Symbol matching = getSymbol(name, addr, namespace);
|
||||
if (matching != null && matching.getSymbolType() == SymbolType.FUNCTION) {
|
||||
return matching;
|
||||
if (matching instanceof FunctionSymbol funcSymbol) {
|
||||
return funcSymbol;
|
||||
}
|
||||
|
||||
// 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
|
||||
cleanUpSymbols(addr, symbolToPromote, primary);
|
||||
|
||||
Symbol symbol = doCreateSymbol(name, addr, namespace, SymbolType.FUNCTION, stringData, null,
|
||||
null, source, true);
|
||||
|
||||
if (needsPinning) {
|
||||
symbol.setPinned(true);
|
||||
DBRecord record;
|
||||
try {
|
||||
record = doCreateBasicSymbolRecord(name, namespace, addr, SymbolType.FUNCTION, true,
|
||||
source, false);
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
if (source == SourceType.DEFAULT) {
|
||||
return "";
|
||||
|
@ -3171,9 +3467,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
|
||||
void checkValidNamespaceArgument(Namespace namespace) throws IllegalArgumentException {
|
||||
if (!isMyNamespace(namespace)) {
|
||||
String kind = (namespace instanceof Function) ? "function" : "namespace";
|
||||
throw new IllegalArgumentException(
|
||||
kind + " is from different program instance: " + namespace);
|
||||
throw new IllegalArgumentException(namespace.getType().friendlyName() +
|
||||
" is from a different program instance: " + namespace);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() {
|
||||
public Variable getObject() {
|
||||
FunctionDB func = getFunction();
|
||||
if (func != null) {
|
||||
return func.getVariable(this);
|
||||
|
@ -159,13 +159,12 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
|
||||
public FunctionDB getFunction() {
|
||||
return (FunctionDB) symbolMgr.getFunctionManager()
|
||||
.getFunction(
|
||||
getParentNamespace().getID());
|
||||
.getFunction(getParentNamespace().getID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProgramLocation getProgramLocation() {
|
||||
Variable var = (Variable) getObject();
|
||||
Variable var = getObject();
|
||||
if (var != null) {
|
||||
return new VariableNameFieldLocation(var.getProgram(), var, 0);
|
||||
}
|
||||
|
@ -311,20 +310,90 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
try {
|
||||
checkIsValid();
|
||||
ReferenceManager rm = symbolMgr.getReferenceManager();
|
||||
return rm.getReferencesTo((Variable) getObject());
|
||||
return rm.getReferencesTo(getObject());
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMultipleReferences() {
|
||||
return getReferences(null).length > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasReferences() {
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMultipleReferences() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasReferences() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reference[] getReferences() {
|
||||
return new Reference[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reference[] getReferences(TaskMonitor monitor) {
|
||||
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 INVALID_STACK_DEPTH_CHANGE = Integer.MAX_VALUE - 1;
|
||||
|
||||
@Override
|
||||
default Type getType() {
|
||||
return Type.FUNCTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this function.
|
||||
*
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,10 +17,13 @@ package ghidra.program.model.listing;
|
|||
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for representing class objects in the program.
|
||||
*/
|
||||
public interface GhidraClass extends Namespace {
|
||||
|
||||
@Override
|
||||
public default Type getType() {
|
||||
return Type.CLASS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.model.listing;
|
||||
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.*;
|
||||
|
||||
/**
|
||||
* Interface for a Library namespace.
|
||||
|
@ -24,9 +24,39 @@ public interface Library extends Namespace {
|
|||
|
||||
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
|
||||
*/
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
@ -74,15 +74,15 @@ public interface ExternalManager {
|
|||
* @param oldName the old name of the external library name.
|
||||
* @param newName the new name of the external library name.
|
||||
* @param source the source of this external library
|
||||
* @throws DuplicateNameException if another namespace has the same name
|
||||
* @throws InvalidInputException on invalid input
|
||||
* @throws DuplicateNameException if name conflicts with another symbol.
|
||||
* @throws InvalidInputException if an invalid or null name specified (see
|
||||
* {@link SymbolUtilities#validateName}).
|
||||
*/
|
||||
public void updateExternalLibraryName(String oldName, String newName, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException;
|
||||
|
||||
/**
|
||||
* Get an iterator over all external locations associated with the specified
|
||||
* externalName.
|
||||
* Get an iterator over all external locations associated with the specified Library.
|
||||
* @param libraryName the name of the library to get locations for
|
||||
* @return external location iterator
|
||||
*/
|
||||
|
@ -97,54 +97,46 @@ public interface ExternalManager {
|
|||
public ExternalLocationIterator getExternalLocations(Address memoryAddress);
|
||||
|
||||
/**
|
||||
* Get an external location.
|
||||
* @param libraryName the name of the library for which to get an external location
|
||||
* @param label the name of the external location.
|
||||
* @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.
|
||||
* Returns a set of External Locations matching the given label name in the specified Library.
|
||||
* 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 name of the library
|
||||
* @param label the name of the label
|
||||
* @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.
|
||||
* @param namespace the Namespace to search
|
||||
* Returns a set of External Locations matching the given label name in the given 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 external Namespace to search or null
|
||||
* @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.
|
||||
*/
|
||||
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
|
||||
* @param libraryName the library name
|
||||
* Returns the unique external location associated with the given library name and label.
|
||||
* 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
|
||||
* @return the unique external location or null
|
||||
*/
|
||||
public ExternalLocation getUniqueExternalLocation(String libraryName, String label);
|
||||
|
||||
/**
|
||||
* Returns the unique external location associated with the given namespace and label
|
||||
* @param namespace the namespace
|
||||
* Returns the unique external location associated with the given namespace and label.
|
||||
* 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
|
||||
* @return the unique external location or null
|
||||
*/
|
||||
|
@ -229,8 +221,7 @@ public interface ExternalManager {
|
|||
* @throws IllegalArgumentException if an invalid {@code extAddr} was specified.
|
||||
*/
|
||||
public ExternalLocation addExtLocation(Namespace extNamespace, String extLabel, Address extAddr,
|
||||
SourceType sourceType, boolean reuseExisting)
|
||||
throws InvalidInputException;
|
||||
SourceType sourceType, boolean reuseExisting) throws InvalidInputException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public ExternalLocation addExtFunction(Namespace extNamespace, String extLabel, Address extAddr,
|
||||
SourceType sourceType, boolean reuseExisting)
|
||||
throws InvalidInputException;
|
||||
SourceType sourceType, boolean reuseExisting) throws InvalidInputException;
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,26 @@ import ghidra.util.exception.InvalidInputException;
|
|||
*/
|
||||
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;
|
||||
/**
|
||||
* The delimiter that is used to separate namespace nodes in a namespace
|
||||
|
@ -47,6 +67,13 @@ public interface Namespace {
|
|||
*/
|
||||
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)
|
||||
* @return true if this namespace is external (i.e., associated with a Library)
|
||||
|
|
|
@ -93,19 +93,26 @@ public interface Symbol {
|
|||
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();
|
||||
|
||||
/**
|
||||
* @return true if this symbol has more than one reference to it.
|
||||
*/
|
||||
public boolean hasMultipleReferences();
|
||||
public default int getReferenceCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
@ -117,7 +124,9 @@ public interface Symbol {
|
|||
* @param monitor the monitor that is used to report progress and to cancel this
|
||||
* 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.
|
||||
|
@ -125,7 +134,9 @@ public interface Symbol {
|
|||
* @return all memory references to the address of this symbol
|
||||
* @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
|
||||
|
@ -145,10 +156,9 @@ public interface Symbol {
|
|||
* @param source the source of this symbol
|
||||
* <br>Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT.
|
||||
*
|
||||
* @throws DuplicateNameException
|
||||
* if name already exists as the name of another symbol or alias.
|
||||
* @throws InvalidInputException
|
||||
* if alias contains blank characters, is zero length, or is null
|
||||
* @throws DuplicateNameException if name conflicts with another symbol.
|
||||
* @throws InvalidInputException if an invalid or null name specified (see
|
||||
* {@link SymbolUtilities#validateName}).
|
||||
* @throws IllegalArgumentException if you try to set the source to DEFAULT for a symbol type
|
||||
* that doesn't allow it.
|
||||
*/
|
||||
|
@ -199,7 +209,9 @@ public interface Symbol {
|
|||
*
|
||||
* @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>
|
||||
|
@ -215,7 +227,9 @@ public interface Symbol {
|
|||
* @param pinned true indicates this symbol is 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).
|
||||
|
@ -246,7 +260,9 @@ public interface Symbol {
|
|||
* @return true if the symbol is at an address
|
||||
* set as a external entry point.
|
||||
*/
|
||||
public boolean isExternalEntryPoint();
|
||||
public default boolean isExternalEntryPoint() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return this symbol's ID.
|
||||
|
@ -259,7 +275,7 @@ public interface Symbol {
|
|||
public Object getObject();
|
||||
|
||||
/**
|
||||
* @return true if the symbol is global
|
||||
* @return true if the symbol is contained within the global namespace
|
||||
*/
|
||||
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
|
||||
* 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 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}
|
||||
|
|
|
@ -23,7 +23,6 @@ import ghidra.program.model.listing.CircularDependencyException;
|
|||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
// Simple symbol test implementation
|
||||
public class StubSymbol implements Symbol {
|
||||
|
@ -106,31 +105,6 @@ public class StubSymbol implements Symbol {
|
|||
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
|
||||
public void setName(String newName, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
@ -154,16 +128,6 @@ public class StubSymbol implements Symbol {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPinned() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPinned(boolean pinned) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamic() {
|
||||
return false;
|
||||
|
@ -184,11 +148,6 @@ public class StubSymbol implements Symbol {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExternalEntryPoint() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getID() {
|
||||
return name.hashCode();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue