mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge remote-tracking branch 'origin/Ghidra_9.2'
This commit is contained in:
commit
1c9d7d89d0
40 changed files with 727 additions and 431 deletions
|
@ -184,6 +184,13 @@
|
||||||
<P>Shows all locations that reference the given symbol.</P>
|
<P>Shows all locations that reference the given symbol.</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<H2><A name="Convert_to_Class"></A>Convert Namespace to Class</H2>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>You can convert a <I>Namespace</I> to a <I>Class</I>.
|
||||||
|
Right mouse click on a namespace and choose the <B>Convert To Class</B> option.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H2><A name="Create_Class"></A>Create a Class</H2>
|
<H2><A name="Create_Class"></A>Create a Class</H2>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
|
|
|
@ -316,8 +316,6 @@ public class StringTableProvider extends ComponentProviderAdapter implements Dom
|
||||||
};
|
};
|
||||||
|
|
||||||
selectionNavigationAction = new SelectionNavigationAction(plugin, table);
|
selectionNavigationAction = new SelectionNavigationAction(plugin, table);
|
||||||
selectionNavigationAction.setHelpLocation(
|
|
||||||
new HelpLocation(HelpTopics.SEARCH, "Strings_Selection_Navigation"));
|
|
||||||
|
|
||||||
addLocalAction(selectionNavigationAction);
|
addLocalAction(selectionNavigationAction);
|
||||||
addLocalAction(selectAction);
|
addLocalAction(selectAction);
|
||||||
|
|
|
@ -206,8 +206,15 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
|
||||||
DockingAction setExternalProgramAction = new SetExternalProgramAction(plugin, this);
|
DockingAction setExternalProgramAction = new SetExternalProgramAction(plugin, this);
|
||||||
DockingAction createExternalLocationAction = new CreateExternalLocationAction(plugin);
|
DockingAction createExternalLocationAction = new CreateExternalLocationAction(plugin);
|
||||||
DockingAction editExternalLocationAction = new EditExternalLocationAction(plugin);
|
DockingAction editExternalLocationAction = new EditExternalLocationAction(plugin);
|
||||||
DockingAction createClassAction = new CreateClassAction(plugin);
|
|
||||||
DockingAction createNamespaceAction = new CreateNamespaceAction(plugin);
|
String createGroup = "0Create";
|
||||||
|
int createGroupIndex = 0;
|
||||||
|
DockingAction createNamespaceAction = new CreateNamespaceAction(plugin, createGroup,
|
||||||
|
Integer.toString(createGroupIndex++));
|
||||||
|
DockingAction createClassAction = new CreateClassAction(plugin, createGroup,
|
||||||
|
Integer.toString(createGroupIndex++));
|
||||||
|
DockingAction convertToClassAction = new ConvertToClassAction(plugin, createGroup,
|
||||||
|
Integer.toString(createGroupIndex++));
|
||||||
|
|
||||||
DockingAction renameAction = new RenameAction(plugin);
|
DockingAction renameAction = new RenameAction(plugin);
|
||||||
DockingAction cutAction = new CutAction(plugin, this);
|
DockingAction cutAction = new CutAction(plugin, this);
|
||||||
|
@ -231,6 +238,7 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
|
||||||
tool.addLocalAction(this, editExternalLocationAction);
|
tool.addLocalAction(this, editExternalLocationAction);
|
||||||
tool.addLocalAction(this, createClassAction);
|
tool.addLocalAction(this, createClassAction);
|
||||||
tool.addLocalAction(this, createNamespaceAction);
|
tool.addLocalAction(this, createNamespaceAction);
|
||||||
|
tool.addLocalAction(this, convertToClassAction);
|
||||||
tool.addLocalAction(this, renameAction);
|
tool.addLocalAction(this, renameAction);
|
||||||
tool.addLocalAction(this, cutAction);
|
tool.addLocalAction(this, cutAction);
|
||||||
tool.addLocalAction(this, pasteAction);
|
tool.addLocalAction(this, pasteAction);
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
/* ###
|
||||||
|
* 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.app.plugin.core.symboltree.actions;
|
||||||
|
|
||||||
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
|
import docking.action.MenuData;
|
||||||
|
import docking.widgets.tree.GTreeNode;
|
||||||
|
import ghidra.app.plugin.core.symboltree.*;
|
||||||
|
import ghidra.app.plugin.core.symboltree.nodes.SymbolNode;
|
||||||
|
import ghidra.app.util.NamespaceUtils;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.*;
|
||||||
|
import ghidra.util.exception.AssertException;
|
||||||
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Symbol tree action for converting a namespace to a class
|
||||||
|
*/
|
||||||
|
public class ConvertToClassAction extends SymbolTreeContextAction {
|
||||||
|
|
||||||
|
private static final String NAME = "Convert to Class";
|
||||||
|
|
||||||
|
public ConvertToClassAction(SymbolTreePlugin plugin, String group, String subGroup) {
|
||||||
|
super(NAME, plugin.getName());
|
||||||
|
MenuData menuData = new MenuData(new String[] { NAME }, group);
|
||||||
|
menuData.setMenuSubGroup(subGroup);
|
||||||
|
setPopupMenuData(menuData);
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabledForContext(SymbolTreeActionContext context) {
|
||||||
|
TreePath[] selectionPaths = context.getSelectedSymbolTreePaths();
|
||||||
|
if (selectionPaths.length != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object object = selectionPaths[0].getLastPathComponent();
|
||||||
|
if (object instanceof SymbolNode) {
|
||||||
|
SymbolNode symbolNode = (SymbolNode) object;
|
||||||
|
Symbol symbol = symbolNode.getSymbol();
|
||||||
|
return symbol.getSymbolType() == SymbolType.NAMESPACE;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void actionPerformed(SymbolTreeActionContext context) {
|
||||||
|
TreePath[] selectionPaths = context.getSelectedSymbolTreePaths();
|
||||||
|
|
||||||
|
Program program = context.getProgram();
|
||||||
|
GTreeNode node = (GTreeNode) selectionPaths[0].getLastPathComponent();
|
||||||
|
|
||||||
|
SymbolGTree tree = context.getSymbolTree();
|
||||||
|
GTreeNode root = tree.getViewRoot();
|
||||||
|
GTreeNode classesNode = root.getChild(SymbolCategory.CLASS_CATEGORY.getName());
|
||||||
|
|
||||||
|
Symbol symbol = ((SymbolNode) node).getSymbol();
|
||||||
|
Namespace namespace = (Namespace) symbol.getObject();
|
||||||
|
if (namespace != null) {
|
||||||
|
String name = namespace.getName();
|
||||||
|
convertToClass(program, namespace);
|
||||||
|
program.flushEvents();
|
||||||
|
context.getSymbolTree().startEditing(classesNode, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void convertToClass(Program program, Namespace ns) {
|
||||||
|
int id = program.startTransaction(NAME);
|
||||||
|
boolean success = false;
|
||||||
|
try {
|
||||||
|
NamespaceUtils.convertNamespaceToClass(ns);
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
catch (InvalidInputException e) {
|
||||||
|
// This is thrown when the provided namespace is a function
|
||||||
|
// It was checked in isEnabledForContext and thus cannot occur
|
||||||
|
throw new AssertException(e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
program.endTransaction(id, success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -33,9 +33,11 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
public class CreateClassAction extends SymbolTreeContextAction {
|
public class CreateClassAction extends SymbolTreeContextAction {
|
||||||
|
|
||||||
public CreateClassAction(SymbolTreePlugin plugin) {
|
public CreateClassAction(SymbolTreePlugin plugin, String group, String subGroup) {
|
||||||
super("Create Class", plugin.getName());
|
super("Create Class", plugin.getName());
|
||||||
setPopupMenuData(new MenuData(new String[] { "Create Class" }, "0Create"));
|
MenuData menuData = new MenuData(new String[] { "Create Class" }, group);
|
||||||
|
menuData.setMenuSubGroup(subGroup);
|
||||||
|
setPopupMenuData(menuData);
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +56,10 @@ public class CreateClassAction extends SymbolTreeContextAction {
|
||||||
protected boolean isEnabledForContext(SymbolTreeActionContext context) {
|
protected boolean isEnabledForContext(SymbolTreeActionContext context) {
|
||||||
|
|
||||||
TreePath[] selectionPaths = context.getSelectedSymbolTreePaths();
|
TreePath[] selectionPaths = context.getSelectedSymbolTreePaths();
|
||||||
if (selectionPaths.length == 1) {
|
if (selectionPaths.length != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Object object = selectionPaths[0].getLastPathComponent();
|
Object object = selectionPaths[0].getLastPathComponent();
|
||||||
if (object instanceof ClassCategoryNode) {
|
if (object instanceof ClassCategoryNode) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -71,7 +76,6 @@ public class CreateClassAction extends SymbolTreeContextAction {
|
||||||
}
|
}
|
||||||
return (symbolType == SymbolType.CLASS || symbolType == SymbolType.LIBRARY);
|
return (symbolType == SymbolType.CLASS || symbolType == SymbolType.LIBRARY);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,11 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
public class CreateNamespaceAction extends SymbolTreeContextAction {
|
public class CreateNamespaceAction extends SymbolTreeContextAction {
|
||||||
|
|
||||||
public CreateNamespaceAction(SymbolTreePlugin plugin) {
|
public CreateNamespaceAction(SymbolTreePlugin plugin, String group, String subGroup) {
|
||||||
super("Create Namespace", plugin.getName());
|
super("Create Namespace", plugin.getName());
|
||||||
setPopupMenuData(new MenuData(new String[] { "Create Namespace" }, "0Create"));
|
MenuData menuData = new MenuData(new String[] { "Create Namespace" }, group);
|
||||||
|
menuData.setMenuSubGroup(subGroup);
|
||||||
|
setPopupMenuData(menuData);
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1193,7 +1193,8 @@ public class HeadlessAnalyzer {
|
||||||
// This can never happen because there is no user interaction in headless!
|
// This can never happen because there is no user interaction in headless!
|
||||||
}
|
}
|
||||||
catch (Exception exc) {
|
catch (Exception exc) {
|
||||||
Msg.error(this, domFile.getPathname() + " Error during analysis: " + exc.getMessage());
|
Msg.error(this, domFile.getPathname() + " Error during analysis: " + exc.getMessage(),
|
||||||
|
exc);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ public class ImportBatchTask extends Task {
|
||||||
Msg.debug(this, "Batch Import cancelled");
|
Msg.debug(this, "Batch Import cancelled");
|
||||||
}
|
}
|
||||||
catch (DuplicateNameException | InvalidNameException | VersionException
|
catch (DuplicateNameException | InvalidNameException | VersionException
|
||||||
| IOException e) {
|
| IOException | IllegalArgumentException e) {
|
||||||
Msg.error(this, "Import failed for " + batchLoadConfig.getPreferredFileName(), e);
|
Msg.error(this, "Import failed for " + batchLoadConfig.getPreferredFileName(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ public class GTreeEventTest extends AbstractDockingTest {
|
||||||
|
|
||||||
private DockingWindowManager winMgr;
|
private DockingWindowManager winMgr;
|
||||||
|
|
||||||
private List<TreeEvent> events = new ArrayList<TreeEvent>();
|
private List<TreeEvent> events = new ArrayList<>();
|
||||||
private GTreeNode root;
|
private GTreeNode root;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -55,7 +55,7 @@ public class GTreeEventTest extends AbstractDockingTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNodeAdded() {
|
public void testNodeAdded() {
|
||||||
root.addNode(new LeafNode("ABC"));
|
root.addNode(new LeafNode("NEW ABC"));
|
||||||
assertEquals(1, events.size());
|
assertEquals(1, events.size());
|
||||||
TreeEvent treeEvent = events.get(0);
|
TreeEvent treeEvent = events.get(0);
|
||||||
assertEquals(EventType.INSERTED, treeEvent.eventType);
|
assertEquals(EventType.INSERTED, treeEvent.eventType);
|
||||||
|
|
|
@ -62,6 +62,7 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
private DockingActionIf selectionAction;
|
private DockingActionIf selectionAction;
|
||||||
private DockingActionIf createNamespaceAction;
|
private DockingActionIf createNamespaceAction;
|
||||||
private DockingActionIf createClassAction;
|
private DockingActionIf createClassAction;
|
||||||
|
private DockingActionIf convertToClassAction;
|
||||||
private ToggleDockingAction goToToggleAction;
|
private ToggleDockingAction goToToggleAction;
|
||||||
private SymbolTreeTestUtils util;
|
private SymbolTreeTestUtils util;
|
||||||
private SymbolGTree tree;
|
private SymbolGTree tree;
|
||||||
|
@ -225,7 +226,7 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
for (int i = 0; i < count - 1; i++) {
|
for (int i = 0; i < count - 1; i++) {
|
||||||
GTreeNode n = ghidraNode.getChild(i);
|
GTreeNode n = ghidraNode.getChild(i);
|
||||||
Symbol s = ((SymbolNode) n).getSymbol();
|
Symbol s = ((SymbolNode) n).getSymbol();
|
||||||
assertTrue(!s.getName().equals("AnotherLocal"));
|
assertFalse(s.getName().equals("AnotherLocal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// test undo/redo
|
// test undo/redo
|
||||||
|
@ -254,7 +255,7 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
for (int i = 0; i < count - 1; i++) {
|
for (int i = 0; i < count - 1; i++) {
|
||||||
GTreeNode n = ghidraNode.getChild(i);
|
GTreeNode n = ghidraNode.getChild(i);
|
||||||
Symbol s = ((SymbolNode) n).getSymbol();
|
Symbol s = ((SymbolNode) n).getSymbol();
|
||||||
assertTrue(!s.getName().equals("AnotherLocal"));
|
assertNotEquals("AnotherLocal", s.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,11 +296,21 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performTreeAction(DockingActionIf action, ActionContext context) {
|
@Test
|
||||||
assertTrue(action.isEnabledForContext(context));
|
public void testConvertNamespaceToClass() throws Exception {
|
||||||
performAction(action, context, true);
|
String classNodeName = "MyClass";
|
||||||
program.flushEvents();
|
GTreeNode nsNode = rootNode.getChild(SymbolCategory.NAMESPACE_CATEGORY.getName());
|
||||||
util.waitForTree();
|
GTreeNode classNode = util.createObject(
|
||||||
|
nsNode, classNodeName, createNamespaceAction);
|
||||||
|
|
||||||
|
util.selectNode(classNode);
|
||||||
|
ActionContext context = util.getSymbolTreeContext();
|
||||||
|
performTreeAction(convertToClassAction, context);
|
||||||
|
|
||||||
|
GTreeNode classRootNode = rootNode.getChild(SymbolCategory.CLASS_CATEGORY.getName());
|
||||||
|
classNode = classRootNode.getChild(classNodeName);
|
||||||
|
assertNotNull(classNode);
|
||||||
|
waitForCondition(tree::isEditing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -313,13 +324,13 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
util.selectNode(lNode);
|
util.selectNode(lNode);
|
||||||
|
|
||||||
ActionContext context = util.getSymbolTreeContext();
|
ActionContext context = util.getSymbolTreeContext();
|
||||||
assertTrue(!renameAction.isEnabledForContext(context));
|
assertFalse(renameAction.isEnabledForContext(context));
|
||||||
assertTrue(!cutAction.isEnabledForContext(context));
|
assertFalse(cutAction.isEnabledForContext(context));
|
||||||
assertTrue(!pasteAction.isEnabledForContext(context));
|
assertFalse(pasteAction.isEnabledForContext(context));
|
||||||
assertTrue(!deleteAction.isEnabledForContext(context));
|
assertFalse(deleteAction.isEnabledForContext(context));
|
||||||
assertTrue(!selectionAction.isEnabledForContext(context));
|
assertFalse(selectionAction.isEnabledForContext(context));
|
||||||
assertTrue(!createNamespaceAction.isEnabledForContext(context));
|
assertFalse(createNamespaceAction.isEnabledForContext(context));
|
||||||
assertTrue(!createClassAction.isEnabledForContext(context));
|
assertFalse(createClassAction.isEnabledForContext(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -329,16 +340,11 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
util.expandNode(lNode);
|
util.expandNode(lNode);
|
||||||
|
|
||||||
// add a label
|
// add a label
|
||||||
|
tx(program, () -> {
|
||||||
SymbolTable symTable = program.getSymbolTable();
|
SymbolTable symTable = program.getSymbolTable();
|
||||||
int transactionID = program.startTransaction("test");
|
|
||||||
try {
|
|
||||||
symTable.createLabel(util.addr(0x010048a1L), "abcdefg", SourceType.USER_DEFINED);
|
symTable.createLabel(util.addr(0x010048a1L), "abcdefg", SourceType.USER_DEFINED);
|
||||||
}
|
});
|
||||||
finally {
|
|
||||||
program.endTransaction(transactionID, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
program.flushEvents();
|
|
||||||
util.waitForTree();
|
util.waitForTree();
|
||||||
|
|
||||||
lNode = rootNode.getChild(3);
|
lNode = rootNode.getChild(3);
|
||||||
|
@ -355,18 +361,13 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
// verify that the tree updates
|
// verify that the tree updates
|
||||||
|
|
||||||
Function f = program.getFunctionManager().getFunctionAt(util.addr(0x01002cf5L));
|
Function f = program.getFunctionManager().getFunctionAt(util.addr(0x01002cf5L));
|
||||||
|
|
||||||
Symbol s = getUniqueSymbol(program, "AnotherLocal", f);
|
Symbol s = getUniqueSymbol(program, "AnotherLocal", f);
|
||||||
assertNotNull(s);
|
assertNotNull(s);
|
||||||
int transactionID = program.startTransaction("test");
|
|
||||||
try {
|
tx(program, () -> {
|
||||||
s.setName("MyAnotherLocal", SourceType.USER_DEFINED);
|
s.setName("MyAnotherLocal", SourceType.USER_DEFINED);
|
||||||
}
|
});
|
||||||
finally {
|
|
||||||
program.endTransaction(transactionID, true);
|
|
||||||
}
|
|
||||||
program.flushEvents();
|
|
||||||
waitForSwing();
|
|
||||||
util.waitForTree();
|
util.waitForTree();
|
||||||
|
|
||||||
GTreeNode fNode = getFunctionsNode();
|
GTreeNode fNode = getFunctionsNode();
|
||||||
|
@ -421,11 +422,20 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertNotNull(createClassAction);
|
assertNotNull(createClassAction);
|
||||||
createNamespaceAction = getAction(plugin, "Create Namespace");
|
createNamespaceAction = getAction(plugin, "Create Namespace");
|
||||||
assertNotNull(createNamespaceAction);
|
assertNotNull(createNamespaceAction);
|
||||||
|
convertToClassAction = getAction(plugin, "Convert to Class");
|
||||||
|
assertNotNull(convertToClassAction);
|
||||||
|
|
||||||
goToToggleAction = (ToggleDockingAction) getAction(plugin, "Navigation");
|
goToToggleAction = (ToggleDockingAction) getAction(plugin, "Navigation");
|
||||||
assertNotNull(goToToggleAction);
|
assertNotNull(goToToggleAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void performTreeAction(DockingActionIf action, ActionContext context) {
|
||||||
|
assertTrue(action.isEnabledForContext(context));
|
||||||
|
performAction(action, context, true);
|
||||||
|
program.flushEvents();
|
||||||
|
util.waitForTree();
|
||||||
|
}
|
||||||
|
|
||||||
private void clickOnNode(GTreeNode node) throws Exception {
|
private void clickOnNode(GTreeNode node) throws Exception {
|
||||||
JTree jTree = (JTree) AbstractGenericTest.getInstanceField("tree", tree);
|
JTree jTree = (JTree) AbstractGenericTest.getInstanceField("tree", tree);
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ Architecture::Architecture(void)
|
||||||
commentdb = (CommentDatabase *)0;
|
commentdb = (CommentDatabase *)0;
|
||||||
stringManager = (StringManager *)0;
|
stringManager = (StringManager *)0;
|
||||||
cpool = (ConstantPool *)0;
|
cpool = (ConstantPool *)0;
|
||||||
symboltab = new Database(this);
|
symboltab = (Database *)0;
|
||||||
context = (ContextDatabase *)0;
|
context = (ContextDatabase *)0;
|
||||||
print = PrintLanguageCapability::getDefault()->buildLanguage(this);
|
print = PrintLanguageCapability::getDefault()->buildLanguage(this);
|
||||||
printlist.push_back(print);
|
printlist.push_back(print);
|
||||||
|
@ -131,6 +131,7 @@ Architecture::~Architecture(void)
|
||||||
for(int4 i=0;i<extra_pool_rules.size();++i)
|
for(int4 i=0;i<extra_pool_rules.size();++i)
|
||||||
delete extra_pool_rules[i];
|
delete extra_pool_rules[i];
|
||||||
|
|
||||||
|
if (symboltab != (Database *)0)
|
||||||
delete symboltab;
|
delete symboltab;
|
||||||
for(int4 i=0;i<(int4)printlist.size();++i)
|
for(int4 i=0;i<(int4)printlist.size();++i)
|
||||||
delete printlist[i];
|
delete printlist[i];
|
||||||
|
@ -371,7 +372,7 @@ void Architecture::setPrintLanguage(const string &nm)
|
||||||
void Architecture::globalify(void)
|
void Architecture::globalify(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
Scope *scope = buildGlobalScope();
|
Scope *scope = symboltab->getGlobalScope();
|
||||||
int4 nm = numSpaces();
|
int4 nm = numSpaces();
|
||||||
|
|
||||||
for(int4 i=0;i<nm;++i) {
|
for(int4 i=0;i<nm;++i) {
|
||||||
|
@ -528,16 +529,16 @@ void Architecture::buildContext(DocumentStorage &store)
|
||||||
context = new ContextInternal();
|
context = new ContextInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If it does not already exist create the glocal Scope object
|
/// Create the database object, which currently doesn't not depend on any configuration
|
||||||
|
/// data. Then create the root (global) scope and attach it to the database.
|
||||||
|
/// \param store is the storage for any configuration data
|
||||||
/// \return the global Scope object
|
/// \return the global Scope object
|
||||||
Scope *Architecture::buildGlobalScope(void)
|
Scope *Architecture::buildDatabase(DocumentStorage &store)
|
||||||
|
|
||||||
{
|
{
|
||||||
Scope *globscope = symboltab->getGlobalScope();
|
symboltab = new Database(this,true);
|
||||||
if (globscope == (Scope *)0) { // Make sure global scope exists
|
Scope *globscope = new ScopeInternal(0,"",this);
|
||||||
globscope = new ScopeInternal("",this);
|
|
||||||
symboltab->attachScope(globscope,(Scope *)0);
|
symboltab->attachScope(globscope,(Scope *)0);
|
||||||
}
|
|
||||||
return globscope;
|
return globscope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,7 +803,7 @@ void Architecture::parseDefaultProto(const Element *el)
|
||||||
void Architecture::parseGlobal(const Element *el)
|
void Architecture::parseGlobal(const Element *el)
|
||||||
|
|
||||||
{
|
{
|
||||||
Scope *scope = buildGlobalScope();
|
Scope *scope = symboltab->getGlobalScope();
|
||||||
const List &list(el->getChildren());
|
const List &list(el->getChildren());
|
||||||
List::const_iterator iter;
|
List::const_iterator iter;
|
||||||
|
|
||||||
|
@ -829,15 +830,15 @@ void Architecture::parseGlobal(const Element *el)
|
||||||
void Architecture::addOtherSpace(void)
|
void Architecture::addOtherSpace(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
Scope *scope = buildGlobalScope();
|
Scope *scope = symboltab->getGlobalScope();
|
||||||
AddrSpace *otherSpace = getSpaceByName("OTHER");
|
AddrSpace *otherSpace = getSpaceByName("OTHER");
|
||||||
symboltab->addRange(scope,otherSpace,0,otherSpace->getHighest());
|
symboltab->addRange(scope,otherSpace,0,otherSpace->getHighest());
|
||||||
if (otherSpace->isOverlayBase()) {
|
if (otherSpace->isOverlayBase()) {
|
||||||
int4 num = numSpaces();
|
int4 num = numSpaces();
|
||||||
for(int4 i=0;i<num;++i){
|
for(int4 i=0;i<num;++i){
|
||||||
OverlaySpace *ospc = (OverlaySpace *)getSpace(i);
|
AddrSpace *ospc = getSpace(i);
|
||||||
if (ospc->getBaseSpace() != otherSpace) continue;
|
if (!ospc->isOverlay()) continue;
|
||||||
if (ospc->getBaseSpace() != otherSpace) continue;
|
if (((OverlaySpace *)ospc)->getBaseSpace() != otherSpace) continue;
|
||||||
symboltab->addRange(scope,ospc,0,otherSpace->getHighest());
|
symboltab->addRange(scope,ospc,0,otherSpace->getHighest());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1279,9 +1280,11 @@ void Architecture::init(DocumentStorage &store)
|
||||||
buildCommentDB(store);
|
buildCommentDB(store);
|
||||||
buildStringManager(store);
|
buildStringManager(store);
|
||||||
buildConstantPool(store);
|
buildConstantPool(store);
|
||||||
|
buildDatabase(store);
|
||||||
|
|
||||||
restoreFromSpec(store);
|
restoreFromSpec(store);
|
||||||
print->getCastStrategy()->setTypeFactory(types);
|
print->getCastStrategy()->setTypeFactory(types);
|
||||||
|
symboltab->adjustCaches(); // In case the specs created additional address spaces
|
||||||
postSpecFile(); // Let subclasses do things after translate is ready
|
postSpecFile(); // Let subclasses do things after translate is ready
|
||||||
|
|
||||||
buildInstructions(store); // Must be called after translate is built
|
buildInstructions(store); // Must be called after translate is built
|
||||||
|
|
|
@ -206,7 +206,7 @@ protected:
|
||||||
void addNoHighPtr(const Range &rng); ///< Add a new region where pointers do not exist
|
void addNoHighPtr(const Range &rng); ///< Add a new region where pointers do not exist
|
||||||
|
|
||||||
// Factory routines for building this architecture
|
// Factory routines for building this architecture
|
||||||
virtual Scope *buildGlobalScope(void); ///< Build the global scope for this executable
|
virtual Scope *buildDatabase(DocumentStorage &store); ///< Build the database and global scope for this executable
|
||||||
|
|
||||||
/// \brief Build the Translator object
|
/// \brief Build the Translator object
|
||||||
///
|
///
|
||||||
|
|
|
@ -4244,7 +4244,7 @@ Datatype *ActionInferTypes::propagateAddIn2Out(TypeFactory *typegrp,PcodeOp *op,
|
||||||
int4 offset = propagateAddPointer(op,inslot);
|
int4 offset = propagateAddPointer(op,inslot);
|
||||||
if (offset==-1) return op->getOut()->getTempType(); // Doesn't look like a good pointer add
|
if (offset==-1) return op->getOut()->getTempType(); // Doesn't look like a good pointer add
|
||||||
uintb uoffset = AddrSpace::addressToByte(offset,((TypePointer *)rettype)->getWordSize());
|
uintb uoffset = AddrSpace::addressToByte(offset,((TypePointer *)rettype)->getWordSize());
|
||||||
if (tstruct->getSize() > 0)
|
if (tstruct->getSize() > 0 && !tstruct->isVariableLength())
|
||||||
uoffset = uoffset % tstruct->getSize();
|
uoffset = uoffset % tstruct->getSize();
|
||||||
if (uoffset==0) {
|
if (uoffset==0) {
|
||||||
if (op->code() == CPUI_PTRSUB) // Go down at least one level
|
if (op->code() == CPUI_PTRSUB) // Go down at least one level
|
||||||
|
@ -4419,7 +4419,7 @@ bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 i
|
||||||
}
|
}
|
||||||
else if (alttype->getMetatype()==TYPE_PTR) {
|
else if (alttype->getMetatype()==TYPE_PTR) {
|
||||||
newtype = ((TypePointer *)alttype)->getPtrTo();
|
newtype = ((TypePointer *)alttype)->getPtrTo();
|
||||||
if (newtype->getSize() != outvn->getTempType()->getSize()) // Size must be appropriate
|
if (newtype->getSize() != outvn->getTempType()->getSize() || newtype->isVariableLength()) // Size must be appropriate
|
||||||
newtype = outvn->getTempType();
|
newtype = outvn->getTempType();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -4432,7 +4432,7 @@ bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 i
|
||||||
}
|
}
|
||||||
else if (alttype->getMetatype()==TYPE_PTR) {
|
else if (alttype->getMetatype()==TYPE_PTR) {
|
||||||
newtype = ((TypePointer *)alttype)->getPtrTo();
|
newtype = ((TypePointer *)alttype)->getPtrTo();
|
||||||
if (newtype->getSize() != outvn->getTempType()->getSize())
|
if (newtype->getSize() != outvn->getTempType()->getSize() || newtype->isVariableLength())
|
||||||
newtype = outvn->getTempType();
|
newtype = outvn->getTempType();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
#include "database.hh"
|
#include "database.hh"
|
||||||
#include "funcdata.hh"
|
#include "funcdata.hh"
|
||||||
|
#include "crc32.hh"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
uint8 Symbol::ID_BASE = 0x4000000000000000L;
|
uint8 Symbol::ID_BASE = 0x4000000000000000L;
|
||||||
|
@ -812,38 +813,14 @@ MapIterator MapIterator::operator++(int4 i) {
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sort first on name, then on dedupId
|
|
||||||
/// \param op2 is the key to compare with \b this
|
|
||||||
/// \return \b true if \b this should be ordered before the other key
|
|
||||||
bool ScopeKey::operator<(const ScopeKey &op2) const
|
|
||||||
|
|
||||||
{
|
|
||||||
int4 comp = name.compare(op2.name);
|
|
||||||
if (comp < 0) return true;
|
|
||||||
if (comp > 0) return false;
|
|
||||||
return (dedupId < op2.dedupId); // Use dedupId to (possibly) allow scopes with same name
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attach the child as an immediate sub-scope of \b this.
|
/// Attach the child as an immediate sub-scope of \b this.
|
||||||
/// Take responsibility of the child's memory: the child will be freed when this is freed.
|
/// Take responsibility of the child's memory: the child will be freed when this is freed.
|
||||||
/// May throw RecovError if there is a duplicate name issue
|
|
||||||
/// \param child is the Scope to make a child
|
/// \param child is the Scope to make a child
|
||||||
void Scope::attachScope(Scope *child)
|
void Scope::attachScope(Scope *child)
|
||||||
|
|
||||||
{
|
{
|
||||||
child->parent = this;
|
child->parent = this;
|
||||||
pair<const ScopeKey,Scope *> value(ScopeKey(child->name,child->uniqueId),child);
|
children[child->uniqueId] = child; // uniqueId is guaranteed to be unique by Database
|
||||||
pair<ScopeMap::iterator,bool> res;
|
|
||||||
if (child->name.size()==0)
|
|
||||||
throw LowlevelError("Non-global scope has empty name");
|
|
||||||
res = children.insert(value);
|
|
||||||
if (res.second==false) {
|
|
||||||
ostringstream s;
|
|
||||||
s << "Duplicate scope name: ";
|
|
||||||
s << child->getFullName();
|
|
||||||
delete child;
|
|
||||||
throw RecovError(s.str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The indicated child Scope is deleted
|
/// The indicated child Scope is deleted
|
||||||
|
@ -856,6 +833,29 @@ void Scope::detachScope(ScopeMap::iterator iter)
|
||||||
delete child;
|
delete child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Create a Scope id based on the scope's name and its parent's id
|
||||||
|
///
|
||||||
|
/// Create a globally unique id for a scope simply from its name.
|
||||||
|
/// \param baseId is the scope id of the parent scope
|
||||||
|
/// \param nm is the name of scope
|
||||||
|
/// \return the hash of the parent id and name
|
||||||
|
uint8 Scope::hashScopeName(uint8 baseId,const string &nm)
|
||||||
|
|
||||||
|
{
|
||||||
|
uint4 reg1 = (uint4)(baseId>>32);
|
||||||
|
uint4 reg2 = (uint4)baseId;
|
||||||
|
reg1 = crc_update(reg1, 0xa9);
|
||||||
|
reg2 = crc_update(reg2, reg1);
|
||||||
|
for(int4 i=0;i<nm.size();++i) {
|
||||||
|
uint4 val = nm[i];
|
||||||
|
reg1 = crc_update(reg1, val);
|
||||||
|
reg2 = crc_update(reg2, reg1);
|
||||||
|
}
|
||||||
|
uint8 res = reg1;
|
||||||
|
res = (res << 32) | reg2;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Query for Symbols starting at a given address, which match a given \b usepoint
|
/// \brief Query for Symbols starting at a given address, which match a given \b usepoint
|
||||||
///
|
///
|
||||||
/// Searching starts at a first scope, continuing thru parents up to a second scope,
|
/// Searching starts at a first scope, continuing thru parents up to a second scope,
|
||||||
|
@ -1270,19 +1270,39 @@ LabSymbol *Scope::queryCodeLabel(const Address &addr) const
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look for the (last) immediate child of \b this with a given name
|
/// Look for the immediate child of \b this with a given name
|
||||||
/// \param name is the child's name
|
/// \param name is the child's name
|
||||||
|
/// \param strategy is \b true if hash of the name determines id
|
||||||
/// \return the child Scope or NULL if there is no child with that name
|
/// \return the child Scope or NULL if there is no child with that name
|
||||||
Scope *Scope::resolveScope(const string &name) const
|
Scope *Scope::resolveScope(const string &name,bool strategy) const
|
||||||
|
|
||||||
{
|
{
|
||||||
ScopeKey key(name,0xffffffff);
|
if (strategy) {
|
||||||
ScopeMap::const_iterator iter = children.upper_bound(key);
|
uint8 key = hashScopeName(uniqueId, name);
|
||||||
if (iter == children.begin()) return (Scope *)0; // All children are after -name-
|
ScopeMap::const_iterator iter = children.find(key);
|
||||||
--iter;
|
if (iter == children.end()) return (Scope *)0;
|
||||||
Scope *scope = (*iter).second;
|
Scope *scope = (*iter).second;
|
||||||
if (scope->name == name)
|
if (scope->name == name)
|
||||||
return scope;
|
return scope;
|
||||||
|
}
|
||||||
|
else if (name.length() > 0 && name[0] <= '9' && name[0] >= '0') {
|
||||||
|
// Allow the string to directly specify the id
|
||||||
|
istringstream s(name);
|
||||||
|
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||||
|
uint8 key;
|
||||||
|
s >> key;
|
||||||
|
ScopeMap::const_iterator iter = children.find(key);
|
||||||
|
if (iter == children.end()) return (Scope *)0;
|
||||||
|
return (*iter).second;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ScopeMap::const_iterator iter;
|
||||||
|
for(iter=children.begin();iter!=children.end();++iter) {
|
||||||
|
Scope *scope = (*iter).second;
|
||||||
|
if (scope->name == name)
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
}
|
||||||
return (Scope *)0;
|
return (Scope *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1395,27 +1415,6 @@ string Scope::getFullName(void) const
|
||||||
return fname;
|
return fname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Put the names of \b this and all its parent Scopes into an array in order.
|
|
||||||
/// The name of the first entry will generally be the name of the global Scope
|
|
||||||
/// \param vec is the array in which to store the names
|
|
||||||
void Scope::getNameSegments(vector<string> &vec) const
|
|
||||||
|
|
||||||
{
|
|
||||||
int4 count = 0;
|
|
||||||
const Scope *cur = this;
|
|
||||||
while(cur != (Scope *)0) { // Count number of segments
|
|
||||||
count += 1;
|
|
||||||
cur = cur->parent;
|
|
||||||
}
|
|
||||||
vec.resize(count);
|
|
||||||
cur = this;
|
|
||||||
while(cur != (Scope *)0) { // Copy each segment
|
|
||||||
count -= 1;
|
|
||||||
vec[count] = cur->name;
|
|
||||||
cur = cur->parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Put the parent scopes of \b this into an array in order, starting with the global scope.
|
/// Put the parent scopes of \b this into an array in order, starting with the global scope.
|
||||||
/// \param vec is storage for the array of scopes
|
/// \param vec is storage for the array of scopes
|
||||||
void Scope::getScopePath(vector<const Scope *> &vec) const
|
void Scope::getScopePath(vector<const Scope *> &vec) const
|
||||||
|
@ -1718,17 +1717,17 @@ bool Scope::isReadOnly(const Address &addr,int4 size,const Address &usepoint) co
|
||||||
return ((flags & Varnode::readonly)!=0);
|
return ((flags & Varnode::readonly)!=0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope *ScopeInternal::buildSubScope(const string &nm)
|
Scope *ScopeInternal::buildSubScope(uint8 id,const string &nm)
|
||||||
|
|
||||||
{
|
{
|
||||||
return new ScopeInternal(nm,glb);
|
return new ScopeInternal(id,nm,glb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopeInternal::addSymbolInternal(Symbol *sym)
|
void ScopeInternal::addSymbolInternal(Symbol *sym)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (sym->symbolId == 0) {
|
if (sym->symbolId == 0) {
|
||||||
sym->symbolId = Symbol::ID_BASE + (((uint8)uniqueId & 0xffff) << 40) + nextUniqueId;
|
sym->symbolId = Symbol::ID_BASE + ((uniqueId & 0xffff) << 40) + nextUniqueId;
|
||||||
nextUniqueId += 1;
|
nextUniqueId += 1;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -1857,17 +1856,18 @@ list<SymbolEntry>::iterator ScopeInternal::endDynamic(void)
|
||||||
return dynamicentry.end();
|
return dynamicentry.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \param id is the globally unique id associated with the scope
|
||||||
/// \param nm is the name of the Scope
|
/// \param nm is the name of the Scope
|
||||||
/// \param g is the Architecture it belongs to
|
/// \param g is the Architecture it belongs to
|
||||||
ScopeInternal::ScopeInternal(const string &nm,Architecture *g)
|
ScopeInternal::ScopeInternal(uint8 id,const string &nm,Architecture *g)
|
||||||
: Scope(nm,g,this)
|
: Scope(id,nm,g,this)
|
||||||
{
|
{
|
||||||
nextUniqueId = 0;
|
nextUniqueId = 0;
|
||||||
maptable.resize(g->numSpaces(),(EntryMap *)0);
|
maptable.resize(g->numSpaces(),(EntryMap *)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeInternal::ScopeInternal(const string &nm,Architecture *g, Scope *own)
|
ScopeInternal::ScopeInternal(uint8 id,const string &nm,Architecture *g, Scope *own)
|
||||||
: Scope(nm,g,own)
|
: Scope(id,nm,g,own)
|
||||||
{
|
{
|
||||||
nextUniqueId = 0;
|
nextUniqueId = 0;
|
||||||
maptable.resize(g->numSpaces(),(EntryMap *)0);
|
maptable.resize(g->numSpaces(),(EntryMap *)0);
|
||||||
|
@ -2015,6 +2015,12 @@ void ScopeInternal::clearUnlockedCategory(int4 cat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScopeInternal::adjustCaches(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
maptable.resize(glb->numSpaces(),(EntryMap *)0);
|
||||||
|
}
|
||||||
|
|
||||||
void ScopeInternal::removeSymbolMappings(Symbol *symbol)
|
void ScopeInternal::removeSymbolMappings(Symbol *symbol)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -2509,45 +2515,18 @@ string ScopeInternal::makeNameUnique(const string &nm) const
|
||||||
return resString;
|
return resString;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a list of name strings, write out each one in an XML \<val> tag.
|
|
||||||
/// \param s is the output stream
|
|
||||||
/// \param vec is the list of names
|
|
||||||
void ScopeInternal::savePathXml(ostream &s,const vector<string> &vec)
|
|
||||||
|
|
||||||
{
|
|
||||||
for(int4 i=0;i<vec.size();++i) {
|
|
||||||
s << "<val>";
|
|
||||||
xml_escape(s,vec[i].c_str());
|
|
||||||
s << "</val>\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given an element, parse all of its children (as \<val> tags) and
|
|
||||||
/// put each of their content into a string array.
|
|
||||||
/// \param vec will hold the resulting string array
|
|
||||||
/// \param el is the XML element
|
|
||||||
void ScopeInternal::restorePathXml(vector<string> &vec,const Element *el)
|
|
||||||
|
|
||||||
{
|
|
||||||
const List &list(el->getChildren());
|
|
||||||
List::const_iterator iter;
|
|
||||||
|
|
||||||
for(iter=list.begin();iter!=list.end();++iter)
|
|
||||||
vec.push_back( (*iter)->getContent() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScopeInternal::saveXml(ostream &s) const
|
void ScopeInternal::saveXml(ostream &s) const
|
||||||
|
|
||||||
{
|
{
|
||||||
s << "<scope";
|
s << "<scope";
|
||||||
a_v(s,"name",name);
|
a_v(s,"name",name);
|
||||||
|
a_v_u(s,"id",uniqueId);
|
||||||
s << ">\n";
|
s << ">\n";
|
||||||
vector<string> fname;
|
if (getParent() != (const Scope *)0) {
|
||||||
getNameSegments(fname);
|
s << "<parent";
|
||||||
fname.pop_back(); // Pop 1 level to get parent path
|
a_v_u(s, "id", getParent()->getId());
|
||||||
s << "<parent>\n";
|
s << "/>\n";
|
||||||
savePathXml(s,fname);
|
}
|
||||||
s << "</parent>\n";
|
|
||||||
getRangeTree().saveXml(s);
|
getRangeTree().saveXml(s);
|
||||||
|
|
||||||
if (!nametree.empty()) {
|
if (!nametree.empty()) {
|
||||||
|
@ -2669,8 +2648,11 @@ void ScopeInternal::restoreXml(const Element *el)
|
||||||
const Element *subel;
|
const Element *subel;
|
||||||
|
|
||||||
iter = list.begin();
|
iter = list.begin();
|
||||||
++iter; // Skip <parent>, processed elsewhere
|
|
||||||
subel = *iter;
|
subel = *iter;
|
||||||
|
if (subel->getName() == "parent") {
|
||||||
|
++iter; // Skip <parent> tag processed elsewhere
|
||||||
|
subel = *iter;
|
||||||
|
}
|
||||||
if (subel->getName() == "rangelist") {
|
if (subel->getName() == "rangelist") {
|
||||||
RangeList newrangetree;
|
RangeList newrangetree;
|
||||||
newrangetree.restoreXml(subel,glb);
|
newrangetree.restoreXml(subel,glb);
|
||||||
|
@ -2804,17 +2786,18 @@ void Database::clearResolve(Scope *scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This recursively performs clearResolve() on the Scope and any sub-scopes
|
/// This recursively clears references in idmap or in resolvemap.
|
||||||
/// \param scope is the given Scope to clear
|
/// \param scope is the given Scope to clear
|
||||||
void Database::clearResolveRecursive(Scope *scope)
|
void Database::clearReferences(Scope *scope)
|
||||||
|
|
||||||
{
|
{
|
||||||
ScopeMap::const_iterator iter = scope->children.begin();
|
ScopeMap::const_iterator iter = scope->children.begin();
|
||||||
ScopeMap::const_iterator enditer = scope->children.end();
|
ScopeMap::const_iterator enditer = scope->children.end();
|
||||||
while(iter != enditer) {
|
while(iter != enditer) {
|
||||||
clearResolveRecursive((*iter).second);
|
clearReferences((*iter).second);
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
idmap.erase(scope->uniqueId);
|
||||||
clearResolve(scope);
|
clearResolve(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2833,6 +2816,18 @@ void Database::fillResolve(Scope *scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialize a new symbol table, with no initial scopes or symbols.
|
||||||
|
/// \param g is the Architecture that owns the symbol table
|
||||||
|
/// \param isByName is \b true if scope ids are calculated as a hash of the scope name.
|
||||||
|
Database::Database(Architecture *g,bool idByName)
|
||||||
|
|
||||||
|
{
|
||||||
|
glb=g;
|
||||||
|
globalscope=(Scope *)0;
|
||||||
|
flagbase.defaultValue()=0;
|
||||||
|
idByNameHash=idByName;
|
||||||
|
}
|
||||||
|
|
||||||
Database::~Database(void)
|
Database::~Database(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -2854,27 +2849,47 @@ void Database::attachScope(Scope *newscope,Scope *parent)
|
||||||
throw LowlevelError("Multiple global scopes");
|
throw LowlevelError("Multiple global scopes");
|
||||||
if (newscope->name.size() != 0)
|
if (newscope->name.size() != 0)
|
||||||
throw LowlevelError("Global scope does not have empty name");
|
throw LowlevelError("Global scope does not have empty name");
|
||||||
newscope->assignId(0);
|
|
||||||
globalscope = newscope;
|
globalscope = newscope;
|
||||||
|
idmap[globalscope->uniqueId] = globalscope;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
newscope->assignId(nextScopeId);
|
if (newscope->name.size()==0)
|
||||||
nextScopeId += 1;
|
throw LowlevelError("Non-global scope has empty name");
|
||||||
|
pair<uint8,Scope *> value(newscope->uniqueId,newscope);
|
||||||
|
pair<ScopeMap::iterator,bool> res;
|
||||||
|
res = idmap.insert(value);
|
||||||
|
if (res.second==false) {
|
||||||
|
ostringstream s;
|
||||||
|
s << "Duplicate scope id: ";
|
||||||
|
s << newscope->getFullName();
|
||||||
|
delete newscope;
|
||||||
|
throw RecovError(s.str());
|
||||||
|
}
|
||||||
parent->attachScope(newscope);
|
parent->attachScope(newscope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Give \b this database the chance to inform existing scopes of any change to the
|
||||||
|
/// configuration, which may have changed since the initial scopes were created.
|
||||||
|
void Database::adjustCaches(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
ScopeMap::iterator iter;
|
||||||
|
for(iter=idmap.begin();iter!=idmap.end();++iter) {
|
||||||
|
(*iter).second->adjustCaches();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// \param scope is the given Scope
|
/// \param scope is the given Scope
|
||||||
void Database::deleteScope(Scope *scope)
|
void Database::deleteScope(Scope *scope)
|
||||||
|
|
||||||
{
|
{
|
||||||
clearResolveRecursive(scope);
|
clearReferences(scope);
|
||||||
if (globalscope == scope) {
|
if (globalscope == scope) {
|
||||||
globalscope = (Scope *)0;
|
globalscope = (Scope *)0;
|
||||||
delete scope;
|
delete scope;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ScopeKey key(scope->name,scope->uniqueId);
|
ScopeMap::iterator iter = scope->parent->children.find(scope->uniqueId);
|
||||||
ScopeMap::iterator iter = scope->parent->children.find(key);
|
|
||||||
if (iter == scope->parent->children.end())
|
if (iter == scope->parent->children.end())
|
||||||
throw LowlevelError("Could not remove parent reference to: "+scope->name);
|
throw LowlevelError("Could not remove parent reference to: "+scope->name);
|
||||||
scope->parent->detachScope(iter);
|
scope->parent->detachScope(iter);
|
||||||
|
@ -2892,7 +2907,7 @@ void Database::deleteSubScopes(Scope *scope)
|
||||||
while(iter != enditer) {
|
while(iter != enditer) {
|
||||||
curiter = iter;
|
curiter = iter;
|
||||||
++iter;
|
++iter;
|
||||||
clearResolveRecursive((*curiter).second);
|
clearReferences((*curiter).second);
|
||||||
scope->detachScope(curiter);
|
scope->detachScope(curiter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2952,42 +2967,33 @@ void Database::removeRange(Scope *scope,AddrSpace *spc,uintb first,uintb last)
|
||||||
fillResolve(scope);
|
fillResolve(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look for an immediate child scope by name in a given parent. If does not exist,
|
/// Look for a Scope by id. If it does not exist, create a new scope
|
||||||
/// create a new scope with the name and attach it to the parent.
|
/// with the given name and parent scope.
|
||||||
/// \param nm is the base name of the desired subscope
|
/// \param id is the global id of the Scope
|
||||||
|
/// \param nm is the given name of the Scope
|
||||||
/// \param parent is the given parent scope to search
|
/// \param parent is the given parent scope to search
|
||||||
/// \return the subscope object either found or created
|
/// \return the subscope object either found or created
|
||||||
Scope *Database::findCreateSubscope(const string &nm,Scope *parent)
|
Scope *Database::findCreateScope(uint8 id,const string &nm,Scope *parent)
|
||||||
|
|
||||||
{
|
{
|
||||||
Scope *res = parent->resolveScope(nm);
|
Scope *res = resolveScope(id);
|
||||||
if (res != (Scope *)0)
|
if (res != (Scope *)0)
|
||||||
return res;
|
return res;
|
||||||
res = globalscope->buildSubScope(nm);
|
res = globalscope->buildSubScope(id,nm);
|
||||||
attachScope(res, parent);
|
attachScope(res, parent);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An \e absolute \e path of Scope names must be provided, from the global
|
/// Find a Scope object, given its global id. Return null if id is not mapped to a Scope.
|
||||||
/// Scope down to the desired Scope. If the first path name is blank (""), it
|
/// \param id is the global id
|
||||||
/// matches the global Scope. If the first path name is not blank, the
|
/// \return the matching Scope or null
|
||||||
/// global Scope is assumed, and the name is assumed to refer to a child.
|
Scope *Database::resolveScope(uint8 id) const
|
||||||
/// \param subnames is the \e path of names
|
|
||||||
/// \return the desired Scope or NULL if a matching name isn't found
|
|
||||||
Scope *Database::resolveScope(const vector<string> &subnames) const
|
|
||||||
|
|
||||||
{
|
{
|
||||||
if (subnames.size()==0) return (Scope *)0;
|
ScopeMap::const_iterator iter = idmap.find(id);
|
||||||
Scope *curScope = globalscope;
|
if (iter != idmap.end())
|
||||||
int4 i=0;
|
return (*iter).second;
|
||||||
if (subnames[0].size()==0) // blank name matches global scope
|
return (Scope *)0;
|
||||||
i += 1;
|
|
||||||
for(;i<subnames.size();++i) {
|
|
||||||
if (curScope == (Scope *)0)
|
|
||||||
break;
|
|
||||||
curScope = curScope->resolveScope(subnames[i]);
|
|
||||||
}
|
|
||||||
return curScope;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Get the Scope (and base name) associated with a qualified Symbol name
|
/// \brief Get the Scope (and base name) associated with a qualified Symbol name
|
||||||
|
@ -3014,7 +3020,7 @@ Scope *Database::resolveScopeFromSymbolName(const string &fullname,const string
|
||||||
endmark = fullname.find(delim,mark);
|
endmark = fullname.find(delim,mark);
|
||||||
if (endmark == string::npos) break;
|
if (endmark == string::npos) break;
|
||||||
string scopename = fullname.substr(mark,endmark-mark);
|
string scopename = fullname.substr(mark,endmark-mark);
|
||||||
start = start->resolveScope(scopename);
|
start = start->resolveScope(scopename,idByNameHash);
|
||||||
if (start == (Scope *)0) // Was the scope name bad
|
if (start == (Scope *)0) // Was the scope name bad
|
||||||
return start;
|
return start;
|
||||||
mark = endmark + delim.size();
|
mark = endmark + delim.size();
|
||||||
|
@ -3038,6 +3044,8 @@ Scope *Database::resolveScopeFromSymbolName(const string &fullname,const string
|
||||||
Scope *Database::findCreateScopeFromSymbolName(const string &fullname,const string &delim,string &basename,
|
Scope *Database::findCreateScopeFromSymbolName(const string &fullname,const string &delim,string &basename,
|
||||||
Scope *start)
|
Scope *start)
|
||||||
{
|
{
|
||||||
|
if (!idByNameHash)
|
||||||
|
throw LowlevelError("Scope name hashes not allowed");
|
||||||
if (start == (Scope *)0)
|
if (start == (Scope *)0)
|
||||||
start = globalscope;
|
start = globalscope;
|
||||||
|
|
||||||
|
@ -3047,7 +3055,8 @@ Scope *Database::findCreateScopeFromSymbolName(const string &fullname,const stri
|
||||||
endmark = fullname.find(delim,mark);
|
endmark = fullname.find(delim,mark);
|
||||||
if (endmark == string::npos) break;
|
if (endmark == string::npos) break;
|
||||||
string scopename = fullname.substr(mark,endmark-mark);
|
string scopename = fullname.substr(mark,endmark-mark);
|
||||||
start = findCreateSubscope(scopename, start);
|
uint8 nameId = Scope::hashScopeName(start->uniqueId, scopename);
|
||||||
|
start = findCreateScope(nameId, scopename, start);
|
||||||
mark = endmark + delim.size();
|
mark = endmark + delim.size();
|
||||||
}
|
}
|
||||||
basename = fullname.substr(mark,endmark);
|
basename = fullname.substr(mark,endmark);
|
||||||
|
@ -3130,7 +3139,10 @@ void Database::saveXml(ostream &s) const
|
||||||
{
|
{
|
||||||
partmap<Address,uint4>::const_iterator piter,penditer;
|
partmap<Address,uint4>::const_iterator piter,penditer;
|
||||||
|
|
||||||
s << "<db>\n";
|
s << "<db";
|
||||||
|
if (idByNameHash)
|
||||||
|
a_v_b(s, "scopeidbyname", true);
|
||||||
|
s << ">\n";
|
||||||
// Save the property change points
|
// Save the property change points
|
||||||
piter = flagbase.begin();
|
piter = flagbase.begin();
|
||||||
penditer = flagbase.end();
|
penditer = flagbase.end();
|
||||||
|
@ -3148,34 +3160,22 @@ void Database::saveXml(ostream &s) const
|
||||||
s << "</db>\n";
|
s << "</db>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Read an XML \<parent> tag for a Scope path
|
/// Parse the given element for the scope id of the parent.
|
||||||
///
|
/// Look up the parent scope and return it.
|
||||||
/// The \<parent> tag is assumed to either be the first child of
|
/// Throw an error if there is no matching scope
|
||||||
/// the given element, or the first child of the first child.
|
/// \param el is the given element
|
||||||
/// From the \<parent>, the \e name attribute is passed back and
|
/// \return the matching scope
|
||||||
/// a Scope path is parsed from sub-tags.
|
Scope *Database::parseParentTag(const Element *el)
|
||||||
/// \param el is the given element (with \<parent> as a child)
|
|
||||||
/// \param name will hold the \e name attribute
|
|
||||||
/// \param parnames will hold the Scope path
|
|
||||||
void Database::parseParentTag(const Element *el,string &name,vector<string> &parnames)
|
|
||||||
|
|
||||||
{
|
{
|
||||||
const List &list1(el->getChildren());
|
istringstream s(el->getAttributeValue("id"));
|
||||||
|
uint8 id = -1;
|
||||||
const Element *subel1 = *list1.begin();
|
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||||
if (subel1->getName() == "parent") {
|
s >> id;
|
||||||
name = el->getAttributeValue("name");
|
Scope *res = resolveScope(id);
|
||||||
ScopeInternal::restorePathXml(parnames,subel1);
|
if (res == (Scope *)0)
|
||||||
return;
|
throw LowlevelError("Could not find scope matching id");
|
||||||
}
|
return res;
|
||||||
|
|
||||||
const List &list2(subel1->getChildren());
|
|
||||||
const Element *subel2 = *list2.begin();
|
|
||||||
if (subel2->getName() != "parent")
|
|
||||||
throw LowlevelError("Could not find scopes <parent> tag");
|
|
||||||
|
|
||||||
name = subel1->getAttributeValue("name");
|
|
||||||
ScopeInternal::restorePathXml(parnames,subel2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The children of a \<db> tag are examined to recover Scope and Symbol objects.
|
/// The children of a \<db> tag are examined to recover Scope and Symbol objects.
|
||||||
|
@ -3183,6 +3183,11 @@ void Database::parseParentTag(const Element *el,string &name,vector<string> &par
|
||||||
void Database::restoreXml(const Element *el)
|
void Database::restoreXml(const Element *el)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
idByNameHash = false; // Default
|
||||||
|
for(int4 i=0;i<el->getNumAttributes();++i) {
|
||||||
|
if (el->getAttributeName(i) == "scopeidbyname")
|
||||||
|
idByNameHash = xml_readbool(el->getAttributeValue(i));
|
||||||
|
}
|
||||||
const List &list(el->getChildren());
|
const List &list(el->getChildren());
|
||||||
List::const_iterator iter;
|
List::const_iterator iter;
|
||||||
|
|
||||||
|
@ -3202,31 +3207,40 @@ void Database::restoreXml(const Element *el)
|
||||||
|
|
||||||
for(;iter!=list.end();++iter) {
|
for(;iter!=list.end();++iter) {
|
||||||
const Element *subel = *iter;
|
const Element *subel = *iter;
|
||||||
string name;
|
string name = subel->getAttributeValue("name");
|
||||||
vector<string> parnames;
|
istringstream s(subel->getAttributeValue("id"));
|
||||||
parseParentTag(subel,name,parnames);
|
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||||
parnames.push_back(name);
|
uint8 id;
|
||||||
Scope *new_scope = globalscope;
|
s >> id;
|
||||||
for(int4 i=1;i<parnames.size();++i)
|
const List &sublist(subel->getChildren());
|
||||||
new_scope = findCreateSubscope(parnames[i], new_scope);
|
Scope *parentScope = (Scope *)0;
|
||||||
new_scope->restoreXml(subel);
|
if (!sublist.empty()) {
|
||||||
|
const Element *parTag = sublist.front();
|
||||||
|
if (parTag->getName() == "parent")
|
||||||
|
parentScope = parseParentTag(parTag);
|
||||||
|
}
|
||||||
|
Scope *newScope = findCreateScope(id, name, parentScope);
|
||||||
|
newScope->restoreXml(subel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This allows incremental building of the Database from multiple XML sources.
|
/// This allows incremental building of the Database from multiple XML sources.
|
||||||
/// An empty Scope must already be allocated. It is registered with \b this Database,
|
/// An empty Scope must already be allocated. It is registered with \b this Database,
|
||||||
/// and then populated with Symbol objects based as the content of a given \<scope> tag.
|
/// and then populated with Symbol objects based as the content of a given XML tag.
|
||||||
|
/// The tag can either be a \<scope> itself, or another tag that wraps a \<scope> tag
|
||||||
|
/// as its first child.
|
||||||
/// \param el is the given \<scope> element
|
/// \param el is the given \<scope> element
|
||||||
/// \param new_scope is the empty Scope
|
/// \param newScope is the empty Scope
|
||||||
void Database::restoreXmlScope(const Element *el,Scope *new_scope)
|
void Database::restoreXmlScope(const Element *el,Scope *newScope)
|
||||||
|
|
||||||
{
|
{
|
||||||
Scope *par_scope;
|
const List &list(el->getChildren());
|
||||||
vector<string> parnames;
|
const Element *parTag = list.front();
|
||||||
parseParentTag(el,new_scope->name,parnames); // Shove recovered basename straight into new_scope
|
if (el->getName() != "scope") {
|
||||||
par_scope = resolveScope(parnames);
|
const List &sublist(parTag->getChildren());
|
||||||
if (par_scope == (Scope *)0)
|
parTag = sublist.front();
|
||||||
throw LowlevelError("Bad parent scope");
|
}
|
||||||
attachScope(new_scope,par_scope);
|
Scope *parentScope = parseParentTag(parTag);
|
||||||
new_scope->restoreXml(el);
|
attachScope(newScope,parentScope);
|
||||||
|
newScope->restoreXml(el);
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,18 +377,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief A key for looking up child symbol scopes within a parent, based on name
|
typedef map<uint8,Scope *> ScopeMap; ///< A map from id to Scope
|
||||||
///
|
|
||||||
/// A key for mapping from name to Scope. The class includes a deduplication component
|
|
||||||
/// if Scopes with the same name are allowed.
|
|
||||||
class ScopeKey {
|
|
||||||
string name; ///< The name of the Scope
|
|
||||||
uintb dedupId; ///< A duplication id for the Scope
|
|
||||||
public:
|
|
||||||
ScopeKey(const string &nm,uint4 id) { name = nm; dedupId = id; } ///< Construct given a name and id
|
|
||||||
bool operator<(const ScopeKey &op2) const; ///< Comparison operator
|
|
||||||
};
|
|
||||||
typedef map<ScopeKey,Scope *> ScopeMap; ///< A map from ScopeKey to Scope
|
|
||||||
|
|
||||||
/// \brief A collection of Symbol objects within a single (namespace or functional) scope
|
/// \brief A collection of Symbol objects within a single (namespace or functional) scope
|
||||||
///
|
///
|
||||||
|
@ -420,12 +409,12 @@ class Scope {
|
||||||
ScopeMap children; ///< Sorted list of child scopes
|
ScopeMap children; ///< Sorted list of child scopes
|
||||||
void attachScope(Scope *child); ///< Attach a new child Scope to \b this
|
void attachScope(Scope *child); ///< Attach a new child Scope to \b this
|
||||||
void detachScope(ScopeMap::iterator iter); ///< Detach a child Scope from \b this
|
void detachScope(ScopeMap::iterator iter); ///< Detach a child Scope from \b this
|
||||||
void assignId(uint4 val) { uniqueId = val; } ///< Let the database assign a unique id to \b this scope
|
static uint8 hashScopeName(uint8 baseId,const string &nm);
|
||||||
protected:
|
protected:
|
||||||
Architecture *glb; ///< Architecture of \b this scope
|
Architecture *glb; ///< Architecture of \b this scope
|
||||||
string name; ///< Name of \b this scope
|
string name; ///< Name of \b this scope
|
||||||
Funcdata *fd; ///< (If non-null) the function which \b this is the local Scope for
|
Funcdata *fd; ///< (If non-null) the function which \b this is the local Scope for
|
||||||
uint4 uniqueId; ///< Unique id for the scope, for deduping scope names, assigning symbol ids
|
uint8 uniqueId; ///< Unique id for the scope, for deduping scope names, assigning symbol ids
|
||||||
static const Scope *stackAddr(const Scope *scope1,
|
static const Scope *stackAddr(const Scope *scope1,
|
||||||
const Scope *scope2,
|
const Scope *scope2,
|
||||||
const Address &addr,
|
const Address &addr,
|
||||||
|
@ -460,9 +449,10 @@ protected:
|
||||||
///
|
///
|
||||||
/// This is a Scope object \e factory, intended to be called off of the global scope for building
|
/// This is a Scope object \e factory, intended to be called off of the global scope for building
|
||||||
/// global namespace scopes. Function scopes are handled differently.
|
/// global namespace scopes. Function scopes are handled differently.
|
||||||
|
/// \param id is the globally unique id associated with the scope
|
||||||
/// \param nm is the name of the new scope
|
/// \param nm is the name of the new scope
|
||||||
/// \return the new Scope object
|
/// \return the new Scope object
|
||||||
virtual Scope *buildSubScope(const string &nm)=0;
|
virtual Scope *buildSubScope(uint8 id,const string &nm)=0;
|
||||||
|
|
||||||
virtual void restrictScope(Funcdata *f); ///< Convert \b this to a local Scope
|
virtual void restrictScope(Funcdata *f); ///< Convert \b this to a local Scope
|
||||||
|
|
||||||
|
@ -512,8 +502,8 @@ public:
|
||||||
void turnOffDebug(void) const { debugon = false; }
|
void turnOffDebug(void) const { debugon = false; }
|
||||||
#endif
|
#endif
|
||||||
/// \brief Construct an empty scope, given a name and Architecture
|
/// \brief Construct an empty scope, given a name and Architecture
|
||||||
Scope(const string &nm,Architecture *g,Scope *own) {
|
Scope(uint8 id,const string &nm,Architecture *g,Scope *own) {
|
||||||
name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; uniqueId = 0; owner=own;
|
uniqueId = id; name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; owner=own;
|
||||||
#ifdef OPACTION_DEBUG
|
#ifdef OPACTION_DEBUG
|
||||||
debugon = false;
|
debugon = false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -530,6 +520,11 @@ public:
|
||||||
virtual void clearUnlocked(void)=0; ///< Clear all unlocked symbols from \b this scope
|
virtual void clearUnlocked(void)=0; ///< Clear all unlocked symbols from \b this scope
|
||||||
virtual void clearUnlockedCategory(int4 cat)=0; ///< Clear unlocked symbols of the given category from \b this scope
|
virtual void clearUnlockedCategory(int4 cat)=0; ///< Clear unlocked symbols of the given category from \b this scope
|
||||||
|
|
||||||
|
/// \brief Let scopes internally adjust any caches
|
||||||
|
///
|
||||||
|
/// This is called once after Architecture configuration is complete.
|
||||||
|
virtual void adjustCaches(void)=0;
|
||||||
|
|
||||||
/// \brief Query if the given range is owned by \b this Scope
|
/// \brief Query if the given range is owned by \b this Scope
|
||||||
///
|
///
|
||||||
/// All bytes in the range must be owned, and ownership can be informed by
|
/// All bytes in the range must be owned, and ownership can be informed by
|
||||||
|
@ -680,6 +675,7 @@ public:
|
||||||
const Address &addr,const Address &usepoint);
|
const Address &addr,const Address &usepoint);
|
||||||
|
|
||||||
const string &getName(void) const { return name; } ///< Get the name of the Scope
|
const string &getName(void) const { return name; } ///< Get the name of the Scope
|
||||||
|
uint8 getId(void) const { return uniqueId; } ///< Get the globally unique id
|
||||||
bool isGlobal(void) const { return (fd == (Funcdata *)0); } ///< Return \b true if \b this scope is global
|
bool isGlobal(void) const { return (fd == (Funcdata *)0); } ///< Return \b true if \b this scope is global
|
||||||
|
|
||||||
// The main global querying routines
|
// The main global querying routines
|
||||||
|
@ -695,7 +691,7 @@ public:
|
||||||
Funcdata *queryExternalRefFunction(const Address &addr) const; ///< Look-up a function thru an \e external \e reference
|
Funcdata *queryExternalRefFunction(const Address &addr) const; ///< Look-up a function thru an \e external \e reference
|
||||||
LabSymbol *queryCodeLabel(const Address &addr) const; ///< Look-up a code label by address
|
LabSymbol *queryCodeLabel(const Address &addr) const; ///< Look-up a code label by address
|
||||||
|
|
||||||
Scope *resolveScope(const string &name) const; ///< Find a child Scope of \b this
|
Scope *resolveScope(const string &name, bool strategy) const; ///< Find a child Scope of \b this
|
||||||
Scope *discoverScope(const Address &addr,int4 sz,const Address &usepoint); ///< Find the owning Scope of a given memory range
|
Scope *discoverScope(const Address &addr,int4 sz,const Address &usepoint); ///< Find the owning Scope of a given memory range
|
||||||
ScopeMap::const_iterator childrenBegin() const { return children.begin(); } ///< Beginning iterator of child scopes
|
ScopeMap::const_iterator childrenBegin() const { return children.begin(); } ///< Beginning iterator of child scopes
|
||||||
ScopeMap::const_iterator childrenEnd() const { return children.end(); } ///< Ending iterator of child scopes
|
ScopeMap::const_iterator childrenEnd() const { return children.end(); } ///< Ending iterator of child scopes
|
||||||
|
@ -705,7 +701,6 @@ public:
|
||||||
void setThisPointer(Symbol *sym,bool val) { sym->setThisPointer(val); } ///< Toggle the given Symbol as the "this" pointer
|
void setThisPointer(Symbol *sym,bool val) { sym->setThisPointer(val); } ///< Toggle the given Symbol as the "this" pointer
|
||||||
bool isSubScope(const Scope *scp) const; ///< Is this a sub-scope of the given Scope
|
bool isSubScope(const Scope *scp) const; ///< Is this a sub-scope of the given Scope
|
||||||
string getFullName(void) const; ///< Get the full name of \b this Scope
|
string getFullName(void) const; ///< Get the full name of \b this Scope
|
||||||
void getNameSegments(vector<string> &vec) const; ///< Get the fullname of \b this in segments
|
|
||||||
void getScopePath(vector<const Scope *> &vec) const; ///< Get the ordered list of scopes up to \b this
|
void getScopePath(vector<const Scope *> &vec) const; ///< Get the ordered list of scopes up to \b this
|
||||||
const Scope *findDistinguishingScope(const Scope *op2) const; ///< Find first ancestor of \b this not shared by given scope
|
const Scope *findDistinguishingScope(const Scope *op2) const; ///< Find first ancestor of \b this not shared by given scope
|
||||||
Architecture *getArch(void) const { return glb; } ///< Get the Architecture associated with \b this
|
Architecture *getArch(void) const { return glb; } ///< Get the Architecture associated with \b this
|
||||||
|
@ -735,7 +730,7 @@ class ScopeInternal : public Scope {
|
||||||
void insertNameTree(Symbol *sym);
|
void insertNameTree(Symbol *sym);
|
||||||
SymbolNameTree::const_iterator findFirstByName(const string &name) const;
|
SymbolNameTree::const_iterator findFirstByName(const string &name) const;
|
||||||
protected:
|
protected:
|
||||||
virtual Scope *buildSubScope(const string &nm); ///< Build an unattached Scope to be associated as a sub-scope of \b this
|
virtual Scope *buildSubScope(uint8 id,const string &nm); ///< Build an unattached Scope to be associated as a sub-scope of \b this
|
||||||
virtual void addSymbolInternal(Symbol *sym);
|
virtual void addSymbolInternal(Symbol *sym);
|
||||||
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,const RangeList &uselim);
|
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,const RangeList &uselim);
|
||||||
virtual SymbolEntry *addDynamicMapInternal(Symbol *sym,uint4 exfl,uint8 hash,int4 off,int4 sz,
|
virtual SymbolEntry *addDynamicMapInternal(Symbol *sym,uint4 exfl,uint8 hash,int4 off,int4 sz,
|
||||||
|
@ -747,13 +742,14 @@ protected:
|
||||||
SymbolNameTree multiEntrySet; ///< Set of symbols with multiple entries
|
SymbolNameTree multiEntrySet; ///< Set of symbols with multiple entries
|
||||||
uint8 nextUniqueId; ///< Next available symbol id
|
uint8 nextUniqueId; ///< Next available symbol id
|
||||||
public:
|
public:
|
||||||
ScopeInternal(const string &nm,Architecture *g); ///< Construct the Scope
|
ScopeInternal(uint8 id,const string &nm,Architecture *g); ///< Construct the Scope
|
||||||
ScopeInternal(const string &nm,Architecture *g, Scope *own); ///< Construct as a cache
|
ScopeInternal(uint8 id,const string &nm,Architecture *g, Scope *own); ///< Construct as a cache
|
||||||
virtual void clear(void);
|
virtual void clear(void);
|
||||||
virtual void categorySanity(void); ///< Make sure Symbol categories are sane
|
virtual void categorySanity(void); ///< Make sure Symbol categories are sane
|
||||||
virtual void clearCategory(int4 cat);
|
virtual void clearCategory(int4 cat);
|
||||||
virtual void clearUnlocked(void);
|
virtual void clearUnlocked(void);
|
||||||
virtual void clearUnlockedCategory(int4 cat);
|
virtual void clearUnlockedCategory(int4 cat);
|
||||||
|
virtual void adjustCaches(void);
|
||||||
virtual ~ScopeInternal(void);
|
virtual ~ScopeInternal(void);
|
||||||
virtual MapIterator begin(void) const;
|
virtual MapIterator begin(void) const;
|
||||||
virtual MapIterator end(void) const;
|
virtual MapIterator end(void) const;
|
||||||
|
@ -797,8 +793,6 @@ public:
|
||||||
void assignDefaultNames(int4 &base); ///< Assign a default name (via buildVariableName) to any unnamed symbol
|
void assignDefaultNames(int4 &base); ///< Assign a default name (via buildVariableName) to any unnamed symbol
|
||||||
set<Symbol *>::const_iterator beginMultiEntry(void) const { return multiEntrySet.begin(); } ///< Start of symbols with more than one entry
|
set<Symbol *>::const_iterator beginMultiEntry(void) const { return multiEntrySet.begin(); } ///< Start of symbols with more than one entry
|
||||||
set<Symbol *>::const_iterator endMultiEntry(void) const { return multiEntrySet.end(); } ///< End of symbols with more than one entry
|
set<Symbol *>::const_iterator endMultiEntry(void) const { return multiEntrySet.end(); } ///< End of symbols with more than one entry
|
||||||
static void savePathXml(ostream &s,const vector<string> &vec); ///< Save a path with \<val> tags
|
|
||||||
static void restorePathXml(vector<string> &vec,const Element *el); ///< Restore path from \<val> tags
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief An Address range associated with the symbol Scope that owns it
|
/// \brief An Address range associated with the symbol Scope that owns it
|
||||||
|
@ -850,19 +844,21 @@ typedef rangemap<ScopeMapper> ScopeResolve; ///< A map from address to the owni
|
||||||
/// memory ranges. This allows important properties like \e read-only and \e volatile to
|
/// memory ranges. This allows important properties like \e read-only and \e volatile to
|
||||||
/// be put down even if the Symbols aren't yet known.
|
/// be put down even if the Symbols aren't yet known.
|
||||||
class Database {
|
class Database {
|
||||||
Architecture *glb; ///< The Architecture to which this symbol table is attached
|
Architecture *glb; ///< Architecture to which this symbol table is attached
|
||||||
Scope *globalscope; ///< A quick reference to the \e global Scope
|
Scope *globalscope; ///< Quick reference to the \e global Scope
|
||||||
ScopeResolve resolvemap; ///< The Address to \e namespace map
|
ScopeResolve resolvemap; ///< Address to \e namespace map
|
||||||
|
ScopeMap idmap; ///< Map from id to Scope
|
||||||
partmap<Address,uint4> flagbase; ///< Map of global properties
|
partmap<Address,uint4> flagbase; ///< Map of global properties
|
||||||
uint4 nextScopeId; ///< Id for next attached scope (0 reserved for global scope)
|
bool idByNameHash; ///< True if scope ids are built from hash of name
|
||||||
void clearResolve(Scope *scope); ///< Clear the \e ownership ranges associated with the given Scope
|
void clearResolve(Scope *scope); ///< Clear the \e ownership ranges associated with the given Scope
|
||||||
void clearResolveRecursive(Scope *scope); ///< Clear the \e ownership ranges of a given Scope and its children
|
void clearReferences(Scope *scope); ///< Clear any map references to the given Scope and its children
|
||||||
void fillResolve(Scope *scope); ///< Add the \e ownership ranges of the given Scope to the map
|
void fillResolve(Scope *scope); ///< Add the \e ownership ranges of the given Scope to the map
|
||||||
static void parseParentTag(const Element *el,string &name,vector<string> &parnames);
|
Scope *parseParentTag(const Element *el); ///< Figure out parent scope given \<parent> tag.
|
||||||
public:
|
public:
|
||||||
Database(Architecture *g) { glb=g; globalscope=(Scope *)0; flagbase.defaultValue()=0; nextScopeId=1; } ///< Constructor
|
Database(Architecture *g,bool idByName); ///< Constructor
|
||||||
~Database(void); ///< Destructor
|
~Database(void); ///< Destructor
|
||||||
Architecture *getArch(void) const { return glb; } ///< Get the Architecture associate with \b this
|
Architecture *getArch(void) const { return glb; } ///< Get the Architecture associate with \b this
|
||||||
|
void adjustCaches(void); ///< Let scopes adjust after configuration is finished
|
||||||
void attachScope(Scope *newscope,Scope *parent); ///< Register a new Scope
|
void attachScope(Scope *newscope,Scope *parent); ///< Register a new Scope
|
||||||
void deleteScope(Scope *scope); ///< Delete the given Scope and all its sub-scopes
|
void deleteScope(Scope *scope); ///< Delete the given Scope and all its sub-scopes
|
||||||
void deleteSubScopes(Scope *scope); ///< Delete all sub-scopes of the given Scope
|
void deleteSubScopes(Scope *scope); ///< Delete all sub-scopes of the given Scope
|
||||||
|
@ -871,9 +867,9 @@ public:
|
||||||
void addRange(Scope *scope,AddrSpace *spc,uintb first,uintb last); ///< Add an address range to the \e ownership of a Scope
|
void addRange(Scope *scope,AddrSpace *spc,uintb first,uintb last); ///< Add an address range to the \e ownership of a Scope
|
||||||
void removeRange(Scope *scope,AddrSpace *spc,uintb first,uintb last); ///< Remove an address range from \e ownership of a Scope
|
void removeRange(Scope *scope,AddrSpace *spc,uintb first,uintb last); ///< Remove an address range from \e ownership of a Scope
|
||||||
Scope *getGlobalScope(void) const { return globalscope; } ///< Get the global Scope
|
Scope *getGlobalScope(void) const { return globalscope; } ///< Get the global Scope
|
||||||
Scope *resolveScope(const vector<string> &subnames) const; ///< Look-up a Scope by name
|
Scope *resolveScope(uint8 id) const; ///< Look-up a Scope by id
|
||||||
Scope *resolveScopeFromSymbolName(const string &fullname,const string &delim,string &basename,Scope *start) const;
|
Scope *resolveScopeFromSymbolName(const string &fullname,const string &delim,string &basename,Scope *start) const;
|
||||||
Scope *findCreateSubscope(const string &nm,Scope *parent); /// Find (and if not found create) a specific subscope
|
Scope *findCreateScope(uint8,const string &nm,Scope *parent); /// Find (and if not found create) a specific subscope
|
||||||
Scope *findCreateScopeFromSymbolName(const string &fullname,const string &delim,string &basename,Scope *start);
|
Scope *findCreateScopeFromSymbolName(const string &fullname,const string &delim,string &basename,Scope *start);
|
||||||
const Scope *mapScope(const Scope *qpoint,const Address &addr,const Address &usepoint) const;
|
const Scope *mapScope(const Scope *qpoint,const Address &addr,const Address &usepoint) const;
|
||||||
Scope *mapScope(Scope *qpoint,const Address &addr,const Address &usepoint);
|
Scope *mapScope(Scope *qpoint,const Address &addr,const Address &usepoint);
|
||||||
|
@ -883,7 +879,7 @@ public:
|
||||||
const partmap<Address,uint4> &getProperties(void) const { return flagbase; } ///< Get the entire property map
|
const partmap<Address,uint4> &getProperties(void) const { return flagbase; } ///< Get the entire property map
|
||||||
void saveXml(ostream &s) const; ///< Save the whole Database to an XML stream
|
void saveXml(ostream &s) const; ///< Save the whole Database to an XML stream
|
||||||
void restoreXml(const Element *el); ///< Recover the whole database from XML
|
void restoreXml(const Element *el); ///< Recover the whole database from XML
|
||||||
void restoreXmlScope(const Element *el,Scope *new_scope); ///< Register and fill out a single Scope from XML
|
void restoreXmlScope(const Element *el,Scope *newScope); ///< Register and fill out a single Scope from an XML \<scope> tag
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \param sc is the scope containing the new symbol
|
/// \param sc is the scope containing the new symbol
|
||||||
|
|
|
@ -16,18 +16,19 @@
|
||||||
#include "database_ghidra.hh"
|
#include "database_ghidra.hh"
|
||||||
#include "funcdata.hh"
|
#include "funcdata.hh"
|
||||||
|
|
||||||
Scope *ScopeGhidra::buildSubScope(const string &nm)
|
Scope *ScopeGhidra::buildSubScope(uint8 id,const string &nm)
|
||||||
|
|
||||||
{
|
{
|
||||||
return new ScopeGhidraNamespace(nm,ghidra);
|
return new ScopeGhidraNamespace(id,nm,ghidra);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \param g is the Architecture and connection to the Ghidra client
|
/// \param g is the Architecture and connection to the Ghidra client
|
||||||
|
///
|
||||||
ScopeGhidra::ScopeGhidra(ArchitectureGhidra *g)
|
ScopeGhidra::ScopeGhidra(ArchitectureGhidra *g)
|
||||||
: Scope("",g,this)
|
: Scope(0,"",g,this)
|
||||||
{
|
{
|
||||||
ghidra = g;
|
ghidra = g;
|
||||||
cache = new ScopeInternal("",g,this);
|
cache = new ScopeInternal(0,"",g,this);
|
||||||
cacheDirty = false;
|
cacheDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ ScopeGhidra::~ScopeGhidra(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Ghidra client reports a \e namespace id associated with
|
/// The Ghidra client reports a \e namespace id associated with
|
||||||
/// Symbol. Determine if a matching \e namespac Scope already exists in the cache and build
|
/// Symbol. Determine if a matching \e namespace Scope already exists in the cache and build
|
||||||
/// it if it isn't. This may mean creating a new \e namespace Scope.
|
/// it if it isn't. This may mean creating a new \e namespace Scope.
|
||||||
/// \param id is the ID associated with the Ghidra namespace
|
/// \param id is the ID associated with the Ghidra namespace
|
||||||
/// \return the Scope matching the id.
|
/// \return the Scope matching the id.
|
||||||
|
@ -46,15 +47,16 @@ Scope *ScopeGhidra::reresolveScope(uint8 id) const
|
||||||
|
|
||||||
{
|
{
|
||||||
if (id == 0) return cache;
|
if (id == 0) return cache;
|
||||||
map<uint8,Scope *>::const_iterator miter = namespaceMap.find(id);
|
Database *symboltab = ghidra->symboltab;
|
||||||
if (miter != namespaceMap.end())
|
Scope *cacheScope = symboltab->resolveScope(id);
|
||||||
return (*miter).second; // Scope was previously cached
|
if (cacheScope != (Scope *)0)
|
||||||
|
return cacheScope; // Scope was previously cached
|
||||||
|
|
||||||
Document *doc = ghidra->getNamespacePath(id);
|
Document *doc = ghidra->getNamespacePath(id);
|
||||||
if (doc == (Document *)0)
|
if (doc == (Document *)0)
|
||||||
throw LowlevelError("Could not get namespace info");
|
throw LowlevelError("Could not get namespace info");
|
||||||
|
|
||||||
Scope *curscope = glb->symboltab->getGlobalScope(); // Get pointer to ourselves (which is not const)
|
Scope *curscope = symboltab->getGlobalScope(); // Get pointer to ourselves (which is not const)
|
||||||
try {
|
try {
|
||||||
const List &list(doc->getRoot()->getChildren());
|
const List &list(doc->getRoot()->getChildren());
|
||||||
List::const_iterator iter = list.begin();
|
List::const_iterator iter = list.begin();
|
||||||
|
@ -66,16 +68,7 @@ Scope *ScopeGhidra::reresolveScope(uint8 id) const
|
||||||
istringstream s(el->getAttributeValue("id"));
|
istringstream s(el->getAttributeValue("id"));
|
||||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
s.unsetf(ios::dec | ios::hex | ios::oct);
|
||||||
s >> scopeId;
|
s >> scopeId;
|
||||||
miter = namespaceMap.find(scopeId);
|
curscope = symboltab->findCreateScope(scopeId, el->getContent(), curscope);
|
||||||
if (miter == namespaceMap.end()) {
|
|
||||||
curscope = glb->symboltab->findCreateSubscope(el->getContent(), curscope);
|
|
||||||
ScopeGhidraNamespace *ghidraScope = (ScopeGhidraNamespace *)curscope;
|
|
||||||
if (ghidraScope->getClientId() == 0)
|
|
||||||
ghidraScope->setClientId(scopeId);
|
|
||||||
namespaceMap[scopeId] = curscope;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
curscope = (*miter).second;
|
|
||||||
}
|
}
|
||||||
delete doc;
|
delete doc;
|
||||||
}
|
}
|
||||||
|
@ -260,7 +253,6 @@ void ScopeGhidra::clear(void)
|
||||||
{
|
{
|
||||||
cache->clear();
|
cache->clear();
|
||||||
holes.clear();
|
holes.clear();
|
||||||
namespaceMap.clear();
|
|
||||||
if (cacheDirty) {
|
if (cacheDirty) {
|
||||||
ghidra->symboltab->setProperties(flagbaseDefault); // Restore database properties to defaults
|
ghidra->symboltab->setProperties(flagbaseDefault); // Restore database properties to defaults
|
||||||
cacheDirty = false;
|
cacheDirty = false;
|
||||||
|
@ -415,6 +407,6 @@ bool ScopeGhidraNamespace::isNameUsed(const string &nm,const Scope *op2) const
|
||||||
if (ArchitectureGhidra::isDynamicSymbolName(nm))
|
if (ArchitectureGhidra::isDynamicSymbolName(nm))
|
||||||
return false; // Just assume default FUN_ and DAT_ names don't collide
|
return false; // Just assume default FUN_ and DAT_ names don't collide
|
||||||
const ScopeGhidraNamespace *otherScope = dynamic_cast<const ScopeGhidraNamespace *>(op2);
|
const ScopeGhidraNamespace *otherScope = dynamic_cast<const ScopeGhidraNamespace *>(op2);
|
||||||
uint8 otherId = (otherScope != (const ScopeGhidraNamespace *)0) ? otherScope->getClientId() : 0;
|
uint8 otherId = (otherScope != (const ScopeGhidraNamespace *)0) ? otherScope->getId() : 0;
|
||||||
return ghidra->isNameUsed(nm, scopeId, otherId);
|
return ghidra->isNameUsed(nm, uniqueId, otherId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ class ScopeGhidra : public Scope {
|
||||||
ArchitectureGhidra *ghidra; ///< Architecture and connection to the Ghidra client
|
ArchitectureGhidra *ghidra; ///< Architecture and connection to the Ghidra client
|
||||||
mutable ScopeInternal *cache; ///< An internal cache of previously fetched Symbol objects
|
mutable ScopeInternal *cache; ///< An internal cache of previously fetched Symbol objects
|
||||||
mutable RangeList holes; ///< List of (queried) memory ranges with no Symbol in them
|
mutable RangeList holes; ///< List of (queried) memory ranges with no Symbol in them
|
||||||
mutable map<uint8,Scope *> namespaceMap; ///< Map from id to formal global namespace objects
|
|
||||||
vector<int4> spacerange; ///< List of address spaces that are in the global range
|
vector<int4> spacerange; ///< List of address spaces that are in the global range
|
||||||
partmap<Address,uint4> flagbaseDefault; ///< Default boolean properties on memory
|
partmap<Address,uint4> flagbaseDefault; ///< Default boolean properties on memory
|
||||||
mutable bool cacheDirty; ///< Is flagbaseDefault different from cache
|
mutable bool cacheDirty; ///< Is flagbaseDefault different from cache
|
||||||
|
@ -48,7 +47,7 @@ class ScopeGhidra : public Scope {
|
||||||
virtual void removeRange(AddrSpace *spc,uintb first,uintb last) {
|
virtual void removeRange(AddrSpace *spc,uintb first,uintb last) {
|
||||||
throw LowlevelError("remove_range should not be performed on ghidra scope");
|
throw LowlevelError("remove_range should not be performed on ghidra scope");
|
||||||
}
|
}
|
||||||
virtual Scope *buildSubScope(const string &nm);
|
virtual Scope *buildSubScope(uint8 id,const string &nm);
|
||||||
virtual void addSymbolInternal(Symbol *sym) { throw LowlevelError("add_symbol_internal unimplemented"); }
|
virtual void addSymbolInternal(Symbol *sym) { throw LowlevelError("add_symbol_internal unimplemented"); }
|
||||||
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,
|
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,
|
||||||
const RangeList &uselim) { throw LowlevelError("addMap unimplemented"); }
|
const RangeList &uselim) { throw LowlevelError("addMap unimplemented"); }
|
||||||
|
@ -77,6 +76,7 @@ public:
|
||||||
virtual void clearAttribute(Symbol *sym,uint4 attr) { cache->clearAttribute(sym,attr); }
|
virtual void clearAttribute(Symbol *sym,uint4 attr) { cache->clearAttribute(sym,attr); }
|
||||||
virtual void setDisplayFormat(Symbol *sym,uint4 attr) { cache->setDisplayFormat(sym,attr); }
|
virtual void setDisplayFormat(Symbol *sym,uint4 attr) { cache->setDisplayFormat(sym,attr); }
|
||||||
|
|
||||||
|
virtual void adjustCaches(void) { cache->adjustCaches(); }
|
||||||
virtual SymbolEntry *findAddr(const Address &addr,const Address &usepoint) const;
|
virtual SymbolEntry *findAddr(const Address &addr,const Address &usepoint) const;
|
||||||
virtual SymbolEntry *findContainer(const Address &addr,int4 size,
|
virtual SymbolEntry *findContainer(const Address &addr,int4 size,
|
||||||
const Address &usepoint) const;
|
const Address &usepoint) const;
|
||||||
|
@ -127,16 +127,13 @@ public:
|
||||||
class ScopeGhidraNamespace : public ScopeInternal {
|
class ScopeGhidraNamespace : public ScopeInternal {
|
||||||
friend class ScopeGhidra;
|
friend class ScopeGhidra;
|
||||||
ArchitectureGhidra *ghidra; ///< Connection to the Ghidra client
|
ArchitectureGhidra *ghidra; ///< Connection to the Ghidra client
|
||||||
uint8 scopeId; ///< Internal id allowing Ghidra client to reference formal namespaces
|
|
||||||
void setClientId(uint8 id) { scopeId = id; }
|
|
||||||
protected:
|
protected:
|
||||||
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,
|
virtual SymbolEntry *addMapInternal(Symbol *sym,uint4 exfl,const Address &addr,int4 off,int4 sz,
|
||||||
const RangeList &uselim);
|
const RangeList &uselim);
|
||||||
public:
|
public:
|
||||||
ScopeGhidraNamespace(const string &nm,ArchitectureGhidra *g)
|
ScopeGhidraNamespace(uint8 id,const string &nm,ArchitectureGhidra *g)
|
||||||
: ScopeInternal(nm,g) { ghidra = g; scopeId = 0; } ///< Constructor
|
: ScopeInternal(id,nm,g) { ghidra = g; } ///< Constructor
|
||||||
|
|
||||||
uint8 getClientId(void) const { return scopeId; } ///< Get the Ghidra specific id
|
|
||||||
virtual bool isNameUsed(const string &nm,const Scope *op2) const;
|
virtual bool isNameUsed(const string &nm,const Scope *op2) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,15 @@ Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,FunctionSym
|
||||||
if (nm.size()==0)
|
if (nm.size()==0)
|
||||||
localmap = (ScopeLocal *)0; // Filled in by restoreXml
|
localmap = (ScopeLocal *)0; // Filled in by restoreXml
|
||||||
else {
|
else {
|
||||||
ScopeLocal *newMap = new ScopeLocal(stackid,this,glb);
|
uint8 id;
|
||||||
|
if (sym != (FunctionSymbol *)0)
|
||||||
|
id = sym->getId();
|
||||||
|
else {
|
||||||
|
// Missing a symbol, build unique id based on address
|
||||||
|
id = 0x57AB12CD;
|
||||||
|
id = (id << 32) | (addr.getOffset() & 0xffffffff);
|
||||||
|
}
|
||||||
|
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb);
|
||||||
glb->symboltab->attachScope(newMap,scope); // This may throw and delete newMap
|
glb->symboltab->attachScope(newMap,scope); // This may throw and delete newMap
|
||||||
localmap = newMap;
|
localmap = newMap;
|
||||||
funcp.setScope(localmap,baseaddr+ -1);
|
funcp.setScope(localmap,baseaddr+ -1);
|
||||||
|
@ -735,7 +743,7 @@ uint8 Funcdata::restoreXml(const Element *el)
|
||||||
if ((*iter)->getName() == "localdb") {
|
if ((*iter)->getName() == "localdb") {
|
||||||
if (localmap != (ScopeLocal *)0)
|
if (localmap != (ScopeLocal *)0)
|
||||||
throw LowlevelError("Pre-existing local scope when restoring: "+name);
|
throw LowlevelError("Pre-existing local scope when restoring: "+name);
|
||||||
ScopeLocal *newMap = new ScopeLocal(stackid,this,glb);
|
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb);
|
||||||
glb->symboltab->restoreXmlScope(*iter,newMap); // May delete newMap and throw
|
glb->symboltab->restoreXmlScope(*iter,newMap); // May delete newMap and throw
|
||||||
localmap = newMap;
|
localmap = newMap;
|
||||||
}
|
}
|
||||||
|
@ -750,7 +758,7 @@ uint8 Funcdata::restoreXml(const Element *el)
|
||||||
else if ((*iter)->getName() == "prototype") {
|
else if ((*iter)->getName() == "prototype") {
|
||||||
if (localmap == (ScopeLocal *)0) {
|
if (localmap == (ScopeLocal *)0) {
|
||||||
// If we haven't seen a <localdb> tag yet, assume we have a default local scope
|
// If we haven't seen a <localdb> tag yet, assume we have a default local scope
|
||||||
ScopeLocal *newMap = new ScopeLocal(stackid,this,glb);
|
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb);
|
||||||
Scope *scope = glb->symboltab->getGlobalScope();
|
Scope *scope = glb->symboltab->getGlobalScope();
|
||||||
glb->symboltab->attachScope(newMap,scope); // May delete newMap and throw
|
glb->symboltab->attachScope(newMap,scope); // May delete newMap and throw
|
||||||
localmap = newMap;
|
localmap = newMap;
|
||||||
|
@ -763,7 +771,7 @@ uint8 Funcdata::restoreXml(const Element *el)
|
||||||
}
|
}
|
||||||
if (localmap == (ScopeLocal *)0) { // Seen neither <localdb> or <prototype>
|
if (localmap == (ScopeLocal *)0) { // Seen neither <localdb> or <prototype>
|
||||||
// This is a function shell, so we provide default locals
|
// This is a function shell, so we provide default locals
|
||||||
ScopeLocal *newMap = new ScopeLocal(stackid,this,glb);
|
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb);
|
||||||
Scope *scope = glb->symboltab->getGlobalScope();
|
Scope *scope = glb->symboltab->getGlobalScope();
|
||||||
glb->symboltab->attachScope(newMap,scope); // May delete newMap and throw
|
glb->symboltab->attachScope(newMap,scope); // May delete newMap and throw
|
||||||
localmap = newMap;
|
localmap = newMap;
|
||||||
|
|
|
@ -923,7 +923,7 @@ void Funcdata::overrideFlow(const Address &addr,uint4 type)
|
||||||
else if (type == Override::CALL)
|
else if (type == Override::CALL)
|
||||||
op = findPrimaryBranch(iter,enditer,true,false,true);
|
op = findPrimaryBranch(iter,enditer,true,false,true);
|
||||||
else if (type == Override::CALL_RETURN)
|
else if (type == Override::CALL_RETURN)
|
||||||
op = findPrimaryBranch(iter,enditer,true,false,true);
|
op = findPrimaryBranch(iter,enditer,true,true,true);
|
||||||
else if (type == Override::RETURN)
|
else if (type == Override::RETURN)
|
||||||
op = findPrimaryBranch(iter,enditer,true,true,false);
|
op = findPrimaryBranch(iter,enditer,true,true,false);
|
||||||
|
|
||||||
|
|
|
@ -325,14 +325,12 @@ Translate *ArchitectureGhidra::buildTranslator(DocumentStorage &store)
|
||||||
return new GhidraTranslate(this);
|
return new GhidraTranslate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope *ArchitectureGhidra::buildGlobalScope(void)
|
Scope *ArchitectureGhidra::buildDatabase(DocumentStorage &store)
|
||||||
|
|
||||||
{
|
{
|
||||||
Scope *globalscope = symboltab->getGlobalScope();
|
symboltab = new Database(this,false);
|
||||||
if (globalscope == (Scope *)0) { // Make sure global scope exists
|
Scope *globalscope = new ScopeGhidra(this);
|
||||||
globalscope = new ScopeGhidra(this);
|
|
||||||
symboltab->attachScope(globalscope,(Scope *)0);
|
symboltab->attachScope(globalscope,(Scope *)0);
|
||||||
}
|
|
||||||
return globalscope;
|
return globalscope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ class ArchitectureGhidra : public Architecture {
|
||||||
bool sendsyntaxtree; ///< True if the syntax tree should be sent with function output
|
bool sendsyntaxtree; ///< True if the syntax tree should be sent with function output
|
||||||
bool sendCcode; ///< True if C code should be sent with function output
|
bool sendCcode; ///< True if C code should be sent with function output
|
||||||
bool sendParamMeasures; ///< True if measurements for argument and return parameters should be sent
|
bool sendParamMeasures; ///< True if measurements for argument and return parameters should be sent
|
||||||
virtual Scope *buildGlobalScope(void);
|
virtual Scope *buildDatabase(DocumentStorage &store);
|
||||||
virtual Translate *buildTranslator(DocumentStorage &store);
|
virtual Translate *buildTranslator(DocumentStorage &store);
|
||||||
virtual void buildLoader(DocumentStorage &store);
|
virtual void buildLoader(DocumentStorage &store);
|
||||||
virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void);
|
virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void);
|
||||||
|
|
|
@ -343,16 +343,8 @@ static bool maxmatch(string &res,const string &op1,const string &op2)
|
||||||
{ // Set res to maximum characters in common
|
{ // Set res to maximum characters in common
|
||||||
// at the beginning of op1 and op2
|
// at the beginning of op1 and op2
|
||||||
int4 len;
|
int4 len;
|
||||||
bool equal;
|
|
||||||
|
|
||||||
if (op1.size() == op2.size()) {
|
|
||||||
len = op1.size();
|
|
||||||
equal = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
equal = false;
|
|
||||||
len = ( op1.size() < op2.size() ) ? op1.size() : op2.size();
|
len = ( op1.size() < op2.size() ) ? op1.size() : op2.size();
|
||||||
}
|
|
||||||
|
|
||||||
res.erase();
|
res.erase();
|
||||||
for(int4 i=0;i<len;++i) {
|
for(int4 i=0;i<len;++i) {
|
||||||
|
@ -361,7 +353,7 @@ static bool maxmatch(string &res,const string &op1,const string &op2)
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return equal;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int4 IfaceStatus::expandCom(vector<string> &expand,istream &s,
|
int4 IfaceStatus::expandCom(vector<string> &expand,istream &s,
|
||||||
|
|
|
@ -1670,21 +1670,7 @@ void PrintC::pushAnnotation(const Varnode *vn,const PcodeOp *op)
|
||||||
void PrintC::pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op)
|
void PrintC::pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op)
|
||||||
|
|
||||||
{
|
{
|
||||||
Datatype *ct = sym->getType();
|
|
||||||
EmitXml::syntax_highlight tokenColor;
|
EmitXml::syntax_highlight tokenColor;
|
||||||
if (((sym->getFlags()&Varnode::readonly)!=0)&&(ct->getMetatype()==TYPE_ARRAY)) {
|
|
||||||
Datatype *subct = ((TypeArray *)ct)->getBase();
|
|
||||||
if (subct->isCharPrint()) {
|
|
||||||
SymbolEntry *entry = sym->getFirstWholeMap();
|
|
||||||
if (entry != (SymbolEntry *)0) {
|
|
||||||
ostringstream s;
|
|
||||||
if (printCharacterConstant(s,entry->getAddr(),subct)) {
|
|
||||||
pushAtom(Atom(s.str(),vartoken,EmitXml::const_color,op,vn));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sym->getScope()->isGlobal())
|
if (sym->getScope()->isGlobal())
|
||||||
tokenColor = EmitXml::global_color;
|
tokenColor = EmitXml::global_color;
|
||||||
else if (sym->getCategory() == 0)
|
else if (sym->getCategory() == 0)
|
||||||
|
|
|
@ -5627,6 +5627,9 @@ AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
|
||||||
ptrsize = ptr->getSize();
|
ptrsize = ptr->getSize();
|
||||||
ptrmask = calc_mask(ptrsize);
|
ptrmask = calc_mask(ptrsize);
|
||||||
baseType = ct->getPtrTo();
|
baseType = ct->getPtrTo();
|
||||||
|
if (baseType->isVariableLength())
|
||||||
|
size = 0; // Open-ended size being pointed to, there will be no "multiples" component
|
||||||
|
else
|
||||||
size = AddrSpace::byteToAddressInt(baseType->getSize(),ct->getWordSize());
|
size = AddrSpace::byteToAddressInt(baseType->getSize(),ct->getWordSize());
|
||||||
multsum = 0; // Sums start out as zero
|
multsum = 0; // Sums start out as zero
|
||||||
nonmultsum = 0;
|
nonmultsum = 0;
|
||||||
|
|
|
@ -46,7 +46,7 @@ class AddTreeState {
|
||||||
const TypePointer *ct; ///< The pointer data-type
|
const TypePointer *ct; ///< The pointer data-type
|
||||||
const Datatype *baseType; ///< The base data-type being pointed at
|
const Datatype *baseType; ///< The base data-type being pointed at
|
||||||
int4 ptrsize; ///< Size of the pointer
|
int4 ptrsize; ///< Size of the pointer
|
||||||
int4 size; ///< Size of data-type being pointed to (in address units)
|
int4 size; ///< Size of data-type being pointed to (in address units) or 0 for open ended pointer
|
||||||
uintb ptrmask; ///< Mask for modulo calculations in ptr space
|
uintb ptrmask; ///< Mask for modulo calculations in ptr space
|
||||||
uintb offset; ///< Number of bytes we dig into the base data-type
|
uintb offset; ///< Number of bytes we dig into the base data-type
|
||||||
uintb correct; ///< Number of bytes being double counted
|
uintb correct; ///< Number of bytes being double counted
|
||||||
|
|
|
@ -1092,15 +1092,18 @@ void TypeStruct::restoreXml(const Element *el,TypeFactory &typegrp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turn on the data-type's function prototype
|
/// Turn on the data-type's function prototype
|
||||||
|
/// \param tfact is the factory that owns \b this
|
||||||
/// \param model is the prototype model
|
/// \param model is the prototype model
|
||||||
/// \param outtype is the return type of the prototype
|
/// \param outtype is the return type of the prototype
|
||||||
/// \param intypes is the list of input parameters
|
/// \param intypes is the list of input parameters
|
||||||
/// \param dotdotdot is true if the prototype takes variable arguments
|
/// \param dotdotdot is true if the prototype takes variable arguments
|
||||||
/// \param voidtype is the reference "void" data-type
|
/// \param voidtype is the reference "void" data-type
|
||||||
void TypeCode::set(ProtoModel *model,
|
void TypeCode::set(TypeFactory *tfact,ProtoModel *model,
|
||||||
Datatype *outtype,const vector<Datatype *> &intypes,
|
Datatype *outtype,const vector<Datatype *> &intypes,
|
||||||
bool dotdotdot,Datatype *voidtype)
|
bool dotdotdot,Datatype *voidtype)
|
||||||
{
|
{
|
||||||
|
factory = tfact;
|
||||||
|
flags |= variable_length;
|
||||||
if (proto != (FuncProto *)0)
|
if (proto != (FuncProto *)0)
|
||||||
delete proto;
|
delete proto;
|
||||||
proto = new FuncProto();
|
proto = new FuncProto();
|
||||||
|
@ -1123,6 +1126,7 @@ TypeCode::TypeCode(const TypeCode &op) : Datatype(op)
|
||||||
|
|
||||||
{
|
{
|
||||||
proto = (FuncProto *)0;
|
proto = (FuncProto *)0;
|
||||||
|
factory = op.factory;
|
||||||
if (op.proto != (FuncProto *)0) {
|
if (op.proto != (FuncProto *)0) {
|
||||||
proto = new FuncProto();
|
proto = new FuncProto();
|
||||||
proto->copy(*op.proto);
|
proto->copy(*op.proto);
|
||||||
|
@ -1133,6 +1137,7 @@ TypeCode::TypeCode(const string &nm) : Datatype(1,TYPE_CODE,nm)
|
||||||
|
|
||||||
{
|
{
|
||||||
proto = (FuncProto *)0;
|
proto = (FuncProto *)0;
|
||||||
|
factory = (TypeFactory *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeCode::~TypeCode(void)
|
TypeCode::~TypeCode(void)
|
||||||
|
@ -1204,6 +1209,14 @@ int4 TypeCode::compareBasic(const TypeCode *op) const
|
||||||
return 2; // Carry on with comparison of parameters
|
return 2; // Carry on with comparison of parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Datatype *TypeCode::getSubType(uintb off,uintb *newoff) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if (factory == (TypeFactory *)0) return (Datatype *)0;
|
||||||
|
*newoff = 0;
|
||||||
|
return factory->getBase(1, TYPE_CODE); // Return code byte unattached to function prototype
|
||||||
|
}
|
||||||
|
|
||||||
int4 TypeCode::compare(const Datatype &op,int4 level) const
|
int4 TypeCode::compare(const Datatype &op,int4 level) const
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1284,6 +1297,8 @@ void TypeCode::restoreXml(const Element *el,TypeFactory &typegrp)
|
||||||
iter = list.begin();
|
iter = list.begin();
|
||||||
if (iter == list.end()) return; // No underlying prototype
|
if (iter == list.end()) return; // No underlying prototype
|
||||||
Architecture *glb = typegrp.getArch();
|
Architecture *glb = typegrp.getArch();
|
||||||
|
factory = &typegrp;
|
||||||
|
flags |= variable_length;
|
||||||
proto = new FuncProto();
|
proto = new FuncProto();
|
||||||
proto->setInternal( glb->defaultfp, typegrp.getTypeVoid() );
|
proto->setInternal( glb->defaultfp, typegrp.getTypeVoid() );
|
||||||
proto->restoreXml(*iter,glb);
|
proto->restoreXml(*iter,glb);
|
||||||
|
@ -2107,7 +2122,7 @@ TypeCode *TypeFactory::getTypeCode(ProtoModel *model,Datatype *outtype,
|
||||||
bool dotdotdot)
|
bool dotdotdot)
|
||||||
{
|
{
|
||||||
TypeCode tc(""); // getFuncdata type with no name
|
TypeCode tc(""); // getFuncdata type with no name
|
||||||
tc.set(model,outtype,intypes,dotdotdot,getTypeVoid());
|
tc.set(this,model,outtype,intypes,dotdotdot,getTypeVoid());
|
||||||
return (TypeCode *) findAdd(tc);
|
return (TypeCode *) findAdd(tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -342,7 +342,8 @@ class TypeCode : public Datatype {
|
||||||
protected:
|
protected:
|
||||||
friend class TypeFactory;
|
friend class TypeFactory;
|
||||||
FuncProto *proto; ///< If non-null, this describes the prototype of the underlying function
|
FuncProto *proto; ///< If non-null, this describes the prototype of the underlying function
|
||||||
void set(ProtoModel *model,
|
TypeFactory *factory; ///< Factory owning \b this
|
||||||
|
void set(TypeFactory *tfact,ProtoModel *model,
|
||||||
Datatype *outtype,const vector<Datatype *> &intypes,
|
Datatype *outtype,const vector<Datatype *> &intypes,
|
||||||
bool dotdotdot,Datatype *voidtype); ///< Establish a function pointer
|
bool dotdotdot,Datatype *voidtype); ///< Establish a function pointer
|
||||||
virtual void restoreXml(const Element *el,TypeFactory &typegrp);
|
virtual void restoreXml(const Element *el,TypeFactory &typegrp);
|
||||||
|
@ -354,6 +355,7 @@ public:
|
||||||
void setProperties(bool isConstructor,bool isDestructor); ///< Set additional function properties
|
void setProperties(bool isConstructor,bool isDestructor); ///< Set additional function properties
|
||||||
virtual ~TypeCode(void);
|
virtual ~TypeCode(void);
|
||||||
virtual void printRaw(ostream &s) const;
|
virtual void printRaw(ostream &s) const;
|
||||||
|
virtual Datatype *getSubType(uintb off,uintb *newoff) const;
|
||||||
virtual int4 compare(const Datatype &op,int4 level) const;
|
virtual int4 compare(const Datatype &op,int4 level) const;
|
||||||
virtual int4 compareDependency(const Datatype &op) const;
|
virtual int4 compareDependency(const Datatype &op) const;
|
||||||
virtual Datatype *clone(void) const { return new TypeCode(*this); }
|
virtual Datatype *clone(void) const { return new TypeCode(*this); }
|
||||||
|
|
|
@ -262,10 +262,11 @@ int4 RangeHint::compare(const RangeHint &op2) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \param id is the globally unique id associated with the function scope
|
||||||
/// \param spc is the (stack) address space associated with this function's local variables
|
/// \param spc is the (stack) address space associated with this function's local variables
|
||||||
/// \param fd is the function associated with these local variables
|
/// \param fd is the function associated with these local variables
|
||||||
/// \param g is the Architecture
|
/// \param g is the Architecture
|
||||||
ScopeLocal::ScopeLocal(AddrSpace *spc,Funcdata *fd,Architecture *g) : ScopeInternal(fd->getName(),g)
|
ScopeLocal::ScopeLocal(uint8 id,AddrSpace *spc,Funcdata *fd,Architecture *g) : ScopeInternal(id,fd->getName(),g)
|
||||||
|
|
||||||
{
|
{
|
||||||
space = spc;
|
space = spc;
|
||||||
|
|
|
@ -209,7 +209,7 @@ class ScopeLocal : public ScopeInternal {
|
||||||
void addRecommendName(Symbol *sym); ///< Convert the given symbol to a name recommendation
|
void addRecommendName(Symbol *sym); ///< Convert the given symbol to a name recommendation
|
||||||
void collectNameRecs(void); ///< Collect names of unlocked Symbols on the stack
|
void collectNameRecs(void); ///< Collect names of unlocked Symbols on the stack
|
||||||
public:
|
public:
|
||||||
ScopeLocal(AddrSpace *spc,Funcdata *fd,Architecture *g); ///< Constructor
|
ScopeLocal(uint8 id,AddrSpace *spc,Funcdata *fd,Architecture *g); ///< Constructor
|
||||||
virtual ~ScopeLocal(void) {} ///< Destructor
|
virtual ~ScopeLocal(void) {} ///< Destructor
|
||||||
|
|
||||||
AddrSpace *getSpaceId(void) const { return space; } ///< Get the associated (stack) address space
|
AddrSpace *getSpaceId(void) const { return space; } ///< Get the associated (stack) address space
|
||||||
|
|
|
@ -500,7 +500,7 @@ public class DecompileCallback {
|
||||||
}
|
}
|
||||||
String res = getSymbolName(sym);
|
String res = getSymbolName(sym);
|
||||||
if (debug != null) {
|
if (debug != null) {
|
||||||
debug.getSymbol(addr, res);
|
debug.getCodeSymbol(addr, sym.getID(), res, sym.getParentNamespace());
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -563,7 +563,7 @@ public class DecompileCallback {
|
||||||
int pathSize = 0;
|
int pathSize = 0;
|
||||||
Namespace curspace = namespace;
|
Namespace curspace = namespace;
|
||||||
long curId = namespace.getID();
|
long curId = namespace.getID();
|
||||||
while (curId != stopId && curId != 0 && !(curspace instanceof Library)) {
|
while (curId != stopId && curId != 0 && !HighFunction.collapseToGlobal(curspace)) {
|
||||||
pathSize += 1;
|
pathSize += 1;
|
||||||
curspace = curspace.getParentNamespace();
|
curspace = curspace.getParentNamespace();
|
||||||
curId = curspace.getID();
|
curId = curspace.getID();
|
||||||
|
@ -610,7 +610,10 @@ public class DecompileCallback {
|
||||||
public String getNamespacePath(long id) {
|
public String getNamespacePath(long id) {
|
||||||
Namespace namespace = getNameSpaceByID(id);
|
Namespace namespace = getNameSpaceByID(id);
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
HighFunction.createNamespaceTag(buf, namespace, true);
|
HighFunction.createNamespaceTag(buf, namespace);
|
||||||
|
if (debug != null) {
|
||||||
|
debug.getNamespacePath(namespace);
|
||||||
|
}
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.app.decompiler;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import ghidra.app.decompiler.DecompileCallback.StringData;
|
import ghidra.app.decompiler.DecompileCallback.StringData;
|
||||||
import ghidra.app.plugin.processors.sleigh.ContextCache;
|
import ghidra.app.plugin.processors.sleigh.ContextCache;
|
||||||
|
@ -49,7 +50,6 @@ public class DecompileDebug {
|
||||||
private ArrayList<Namespace> dbscope; // Symbol query: scope
|
private ArrayList<Namespace> dbscope; // Symbol query: scope
|
||||||
private ArrayList<String> database; // description of the symbol
|
private ArrayList<String> database; // description of the symbol
|
||||||
private ArrayList<DataType> dtypes; // Data-types queried
|
private ArrayList<DataType> dtypes; // Data-types queried
|
||||||
private ArrayList<String> symbol; // Names of code labels
|
|
||||||
private ArrayList<String> context; // Tracked register values associated with an address
|
private ArrayList<String> context; // Tracked register values associated with an address
|
||||||
private ArrayList<String> cpool; // Constant pool results
|
private ArrayList<String> cpool; // Constant pool results
|
||||||
private ArrayList<String> flowoverride; // Flow overrides associated with an address
|
private ArrayList<String> flowoverride; // Flow overrides associated with an address
|
||||||
|
@ -111,7 +111,6 @@ public class DecompileDebug {
|
||||||
dbscope = new ArrayList<Namespace>();
|
dbscope = new ArrayList<Namespace>();
|
||||||
database = new ArrayList<String>();
|
database = new ArrayList<String>();
|
||||||
dtypes = new ArrayList<DataType>();
|
dtypes = new ArrayList<DataType>();
|
||||||
symbol = new ArrayList<String>();
|
|
||||||
context = new ArrayList<String>();
|
context = new ArrayList<String>();
|
||||||
cpool = new ArrayList<String>();
|
cpool = new ArrayList<String>();
|
||||||
byteset = new TreeSet<ByteChunk>();
|
byteset = new TreeSet<ByteChunk>();
|
||||||
|
@ -192,9 +191,6 @@ public class DecompileDebug {
|
||||||
binimage += "\">\n";
|
binimage += "\">\n";
|
||||||
debugStream.write(binimage.getBytes());
|
debugStream.write(binimage.getBytes());
|
||||||
dumpBytes(debugStream);
|
dumpBytes(debugStream);
|
||||||
for (String element : symbol) {
|
|
||||||
debugStream.write((element).getBytes());
|
|
||||||
}
|
|
||||||
debugStream.write("</binaryimage>\n".getBytes());
|
debugStream.write("</binaryimage>\n".getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,50 +507,87 @@ public class DecompileDebug {
|
||||||
debugStream.write("</injectdebug>\n".getBytes());
|
debugStream.write("</injectdebug>\n".getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dumpDatabases(OutputStream debugStream) throws IOException {
|
private ArrayList<Namespace> orderNamespaces() {
|
||||||
Namespace scopename = null;
|
TreeMap<Long, Namespace> namespaceMap = new TreeMap<Long, Namespace>();
|
||||||
debugStream.write("<db>\n".getBytes());
|
for (Namespace namespace : dbscope) {
|
||||||
for (int i = 0; i < database.size(); ++i) {
|
namespaceMap.put(namespace.getID(), namespace);
|
||||||
scopename = dbscope.get(i);
|
}
|
||||||
if (scopename != null) {
|
ArrayList<Namespace> res = new ArrayList<Namespace>();
|
||||||
|
while (!namespaceMap.isEmpty()) {
|
||||||
|
Entry<Long, Namespace> entry = namespaceMap.firstEntry();
|
||||||
|
Long curKey = entry.getKey();
|
||||||
|
Namespace curSpace = entry.getValue();
|
||||||
|
for (;;) {
|
||||||
|
Long key;
|
||||||
|
Namespace parent = curSpace.getParentNamespace();
|
||||||
|
if (parent == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (HighFunction.collapseToGlobal(parent)) {
|
||||||
|
key = Long.valueOf(Namespace.GLOBAL_NAMESPACE_ID);
|
||||||
}
|
}
|
||||||
while (scopename != null) {
|
else {
|
||||||
|
key = Long.valueOf(parent.getID());
|
||||||
|
}
|
||||||
|
parent = namespaceMap.get(key);
|
||||||
|
if (parent == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
curKey = key;
|
||||||
|
curSpace = parent;
|
||||||
|
}
|
||||||
|
res.add(curSpace);
|
||||||
|
namespaceMap.remove(curKey);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dumpDatabases(OutputStream debugStream) throws IOException {
|
||||||
|
Namespace scopename = null;
|
||||||
|
ArrayList<Namespace> spaceList = orderNamespaces();
|
||||||
|
debugStream.write("<db scodeidbyname=\"false\">\n".getBytes());
|
||||||
|
for (Namespace element : spaceList) {
|
||||||
|
scopename = element;
|
||||||
StringBuilder datahead = new StringBuilder();
|
StringBuilder datahead = new StringBuilder();
|
||||||
Namespace parentNamespace;
|
Namespace parentNamespace;
|
||||||
datahead.append("<scope");
|
datahead.append("<scope");
|
||||||
// Force globalnamespace to have blank name
|
// Force globalnamespace to have blank name
|
||||||
if (scopename != globalnamespace && !(scopename instanceof Library)) {
|
if (scopename != globalnamespace) {
|
||||||
SpecXmlUtils.xmlEscapeAttribute(datahead, "name", scopename.getName());
|
SpecXmlUtils.xmlEscapeAttribute(datahead, "name", scopename.getName());
|
||||||
parentNamespace = scopename.getParentNamespace();
|
parentNamespace = scopename.getParentNamespace();
|
||||||
|
SpecXmlUtils.encodeUnsignedIntegerAttribute(datahead, "id", scopename.getID());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SpecXmlUtils.encodeStringAttribute(datahead, "name", "");
|
SpecXmlUtils.encodeStringAttribute(datahead, "name", "");
|
||||||
|
SpecXmlUtils.encodeUnsignedIntegerAttribute(datahead, "id",
|
||||||
|
Namespace.GLOBAL_NAMESPACE_ID);
|
||||||
parentNamespace = null;
|
parentNamespace = null;
|
||||||
}
|
}
|
||||||
datahead.append(">\n");
|
datahead.append(">\n");
|
||||||
HighFunction.createNamespaceTag(datahead, parentNamespace, false);
|
if (parentNamespace != null) {
|
||||||
|
long parentId =
|
||||||
|
HighFunction.collapseToGlobal(parentNamespace) ? Namespace.GLOBAL_NAMESPACE_ID
|
||||||
|
: parentNamespace.getID();
|
||||||
|
datahead.append("<parent");
|
||||||
|
SpecXmlUtils.encodeUnsignedIntegerAttribute(datahead, "id", parentId);
|
||||||
|
datahead.append("/>\n");
|
||||||
|
}
|
||||||
if (scopename != globalnamespace) {
|
if (scopename != globalnamespace) {
|
||||||
datahead.append("<rangeequalssymbols/>\n");
|
datahead.append("<rangeequalssymbols/>\n");
|
||||||
}
|
}
|
||||||
datahead.append("<symbollist>\n");
|
datahead.append("<symbollist>\n");
|
||||||
debugStream.write(datahead.toString().getBytes());
|
debugStream.write(datahead.toString().getBytes());
|
||||||
for (int i = 0; i < database.size(); ++i) {
|
for (int j = 0; j < database.size(); ++j) {
|
||||||
Namespace namespc = dbscope.get(i);
|
Namespace namespc = dbscope.get(j);
|
||||||
if (namespc == scopename) {
|
if (namespc == scopename) {
|
||||||
debugStream.write((database.get(i)).getBytes());
|
String entry = database.get(j);
|
||||||
dbscope.set(i, null);
|
if (entry == null) {
|
||||||
|
continue; // String may be null
|
||||||
|
}
|
||||||
|
debugStream.write(entry.getBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debugStream.write("</symbollist>\n</scope>\n".getBytes());
|
debugStream.write("</symbollist>\n</scope>\n".getBytes());
|
||||||
scopename = null;
|
|
||||||
for (Namespace element : dbscope) {
|
|
||||||
scopename = element;
|
|
||||||
if (scopename != null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
debugStream.write("</db>\n".getBytes());
|
debugStream.write("</db>\n".getBytes());
|
||||||
}
|
}
|
||||||
|
@ -627,19 +660,34 @@ public class DecompileDebug {
|
||||||
comments = comm; // Already in XML form
|
comments = comm; // Already in XML form
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getSymbol(Address addr, String name) {
|
public void getCodeSymbol(Address addr, long id, String name, Namespace namespace) {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
buf.append("<symbol");
|
buf.append("<mapsym>\n");
|
||||||
AddressSpace space = addr.getAddressSpace();
|
buf.append(" <labelsym");
|
||||||
SpecXmlUtils.encodeStringAttribute(buf, "space", space.getPhysicalSpace().getName());
|
|
||||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "offset", addr.getOffset());
|
|
||||||
SpecXmlUtils.xmlEscapeAttribute(buf, "name", name);
|
SpecXmlUtils.xmlEscapeAttribute(buf, "name", name);
|
||||||
|
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", id);
|
||||||
buf.append("/>\n");
|
buf.append("/>\n");
|
||||||
symbol.add(buf.toString());
|
buf.append(" <addr");
|
||||||
|
Varnode.appendSpaceOffset(buf, addr);
|
||||||
|
buf.append("/>\n");
|
||||||
|
buf.append(" <rangelist/>\n");
|
||||||
|
buf.append("</mapsym>\n");
|
||||||
|
getMapped(namespace, buf.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getNamespacePath(Namespace namespace) {
|
||||||
|
while (namespace != null) {
|
||||||
|
if (HighFunction.collapseToGlobal(namespace)) {
|
||||||
|
break; // Treat library namespace as root
|
||||||
|
}
|
||||||
|
dbscope.add(namespace); // Add namespace to guarantee <scope> tag
|
||||||
|
database.add(null); // Even if there isn't necessarily any symbols
|
||||||
|
namespace = namespace.getParentNamespace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getMapped(Namespace namespc, String res) {
|
public void getMapped(Namespace namespc, String res) {
|
||||||
if (namespc == null) {
|
if (namespc == null || HighFunction.collapseToGlobal(namespc)) {
|
||||||
dbscope.add(globalnamespace);
|
dbscope.add(globalnamespace);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -183,9 +183,7 @@ abstract class CoreGTreeNode implements Cloneable {
|
||||||
* @param node the node to add as a child to this node
|
* @param node the node to add as a child to this node
|
||||||
*/
|
*/
|
||||||
protected synchronized void doAddNode(GTreeNode node) {
|
protected synchronized void doAddNode(GTreeNode node) {
|
||||||
children().add(node);
|
doAddNode(children().size(), node);
|
||||||
node.setParent((GTreeNode) this);
|
|
||||||
doFireNodeAdded(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,6 +194,9 @@ abstract class CoreGTreeNode implements Cloneable {
|
||||||
*/
|
*/
|
||||||
protected synchronized void doAddNode(int index, GTreeNode node) {
|
protected synchronized void doAddNode(int index, GTreeNode node) {
|
||||||
List<GTreeNode> kids = children();
|
List<GTreeNode> kids = children();
|
||||||
|
if (kids.contains(node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int insertIndex = Math.min(kids.size(), index);
|
int insertIndex = Math.min(kids.size(), index);
|
||||||
kids.add(insertIndex, node);
|
kids.add(insertIndex, node);
|
||||||
node.setParent((GTreeNode) this);
|
node.setParent((GTreeNode) this);
|
||||||
|
|
|
@ -456,6 +456,24 @@ public class GTreeNodeTest {
|
||||||
assertNotEquals(nodeA.hashCode(), nodeB.hashCode());
|
assertNotEquals(nodeA.hashCode(), nodeB.hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCantAddNodeTwice() {
|
||||||
|
node0 = new TestNode("No Dups");
|
||||||
|
|
||||||
|
int childCount = root.getChildCount();
|
||||||
|
root.addNode(node0);
|
||||||
|
assertEquals(childCount + 1, root.getChildCount());
|
||||||
|
|
||||||
|
// now make sure the count doesn't grow again
|
||||||
|
root.addNode(node0);
|
||||||
|
assertEquals(childCount + 1, root.getChildCount());
|
||||||
|
|
||||||
|
// try adding it with an index, still shouldn't get added
|
||||||
|
root.addNode(0, node0);
|
||||||
|
assertEquals(childCount + 1, root.getChildCount());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCloneEquals() throws CloneNotSupportedException {
|
public void testCloneEquals() throws CloneNotSupportedException {
|
||||||
GTreeNode nodeA = new TestNode("AAA");
|
GTreeNode nodeA = new TestNode("AAA");
|
||||||
|
|
|
@ -615,22 +615,33 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decompiler treats some namespaces as equivalent to the "global" namespace.
|
||||||
|
* Return true if the given namespace is treated as equivalent.
|
||||||
|
* @param namespace is the namespace
|
||||||
|
* @return true if equivalent
|
||||||
|
*/
|
||||||
|
static final public boolean collapseToGlobal(Namespace namespace) {
|
||||||
|
if (namespace instanceof Library) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append an XML <parent> tag to the buffer describing the formal path elements
|
* Append an XML <parent> tag to the buffer describing the formal path elements
|
||||||
* from the root (global) namespace up to the given namespace
|
* from the root (global) namespace up to the given namespace
|
||||||
* @param buf is the buffer to write to
|
* @param buf is the buffer to write to
|
||||||
* @param namespace is the namespace being described
|
* @param namespace is the namespace being described
|
||||||
* @param includeId is true if the XML tag should include namespace ids
|
|
||||||
*/
|
*/
|
||||||
static public void createNamespaceTag(StringBuilder buf, Namespace namespace,
|
static public void createNamespaceTag(StringBuilder buf, Namespace namespace) {
|
||||||
boolean includeId) {
|
|
||||||
buf.append("<parent>\n");
|
buf.append("<parent>\n");
|
||||||
if (namespace != null) {
|
if (namespace != null) {
|
||||||
ArrayList<Namespace> arr = new ArrayList<Namespace>();
|
ArrayList<Namespace> arr = new ArrayList<Namespace>();
|
||||||
Namespace curspc = namespace;
|
Namespace curspc = namespace;
|
||||||
while (curspc != null) {
|
while (curspc != null) {
|
||||||
arr.add(0, curspc);
|
arr.add(0, curspc);
|
||||||
if (curspc instanceof Library) {
|
if (collapseToGlobal(curspc)) {
|
||||||
break; // Treat library namespace as root
|
break; // Treat library namespace as root
|
||||||
}
|
}
|
||||||
curspc = curspc.getParentNamespace();
|
curspc = curspc.getParentNamespace();
|
||||||
|
@ -639,9 +650,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
for (int i = 1; i < arr.size(); ++i) {
|
for (int i = 1; i < arr.size(); ++i) {
|
||||||
Namespace curScope = arr.get(i);
|
Namespace curScope = arr.get(i);
|
||||||
buf.append("<val");
|
buf.append("<val");
|
||||||
if (includeId) {
|
|
||||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", curScope.getID());
|
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", curScope.getID());
|
||||||
}
|
|
||||||
buf.append('>');
|
buf.append('>');
|
||||||
SpecXmlUtils.xmlEscape(buf, curScope.getName());
|
SpecXmlUtils.xmlEscape(buf, curScope.getName());
|
||||||
buf.append("</val>\n");
|
buf.append("</val>\n");
|
||||||
|
|
|
@ -338,7 +338,13 @@ public class LocalSymbolMap {
|
||||||
resBuf.append("<scope");
|
resBuf.append("<scope");
|
||||||
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name", func.getFunction().getName());
|
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name", func.getFunction().getName());
|
||||||
resBuf.append(">\n");
|
resBuf.append(">\n");
|
||||||
HighFunction.createNamespaceTag(resBuf, namespace, false);
|
resBuf.append("<parent");
|
||||||
|
long parentid = Namespace.GLOBAL_NAMESPACE_ID;
|
||||||
|
if (!HighFunction.collapseToGlobal(namespace)) {
|
||||||
|
parentid = namespace.getID();
|
||||||
|
}
|
||||||
|
SpecXmlUtils.encodeUnsignedIntegerAttribute(resBuf, "id", parentid);
|
||||||
|
resBuf.append("/>\n");
|
||||||
resBuf.append("<rangelist/>\n"); // Empty address range
|
resBuf.append("<rangelist/>\n"); // Empty address range
|
||||||
resBuf.append("<symbollist>\n");
|
resBuf.append("<symbollist>\n");
|
||||||
Iterator<HighSymbol> iter = symbolMap.values().iterator();
|
Iterator<HighSymbol> iter = symbolMap.values().iterator();
|
||||||
|
|
|
@ -2488,7 +2488,8 @@ buildVldmDdList: Dreg,buildVldmDdList is Dreg & buildVldmDdList [ counter=counte
|
||||||
build buildVldmDdList;
|
build buildVldmDdList;
|
||||||
}
|
}
|
||||||
|
|
||||||
vldmDdList: "{"^buildVldmDdList^"}" is D22 & c1215 & c0007 & buildVldmDdList [ regNum=(D22<<4)+c1215 - 1; counter=c0007>>1; ] { }
|
vldmDdList: "{"^buildVldmDdList^"}" is TMode=0 & D22 & c1215 & c0007 & buildVldmDdList [ regNum=(D22<<4)+c1215 - 1; counter=c0007>>1; ] { }
|
||||||
|
vldmDdList: "{"^buildVldmDdList^"}" is TMode=1 & thv_D22 & thv_c1215 & thv_c0007 & buildVldmDdList [ regNum=(thv_D22<<4)+thv_c1215 - 1; counter=thv_c0007>>1; ] { }
|
||||||
|
|
||||||
:vldmia^COND vldmRn,vldmDdList is ( ($(AMODE) & COND & c2327=0x19 & c2121 & c2020=1 & c0811=11 & c0000=0) |
|
:vldmia^COND vldmRn,vldmDdList is ( ($(AMODE) & COND & c2327=0x19 & c2121 & c2020=1 & c0811=11 & c0000=0) |
|
||||||
($(TMODE_E) & thv_c2327=0x19 & thv_c2121 & thv_c2020=1 & thv_c0811=11 & thv_c0000=0) ) & vldmRn & vldmDdList & vldmOffset & vldmUpdate
|
($(TMODE_E) & thv_c2327=0x19 & thv_c2121 & thv_c2020=1 & thv_c0811=11 & thv_c0000=0) ) & vldmRn & vldmDdList & vldmOffset & vldmUpdate
|
||||||
|
@ -4540,7 +4541,8 @@ buildVstmDdList: Dreg,buildVstmDdList is Dreg & buildVstmDdList [ counter=counte
|
||||||
build buildVstmDdList;
|
build buildVstmDdList;
|
||||||
}
|
}
|
||||||
|
|
||||||
vstmDdList: "{"^buildVstmDdList^"}" is D22 & c1215 & c0007 & buildVstmDdList [ regNum=(D22<<4)+c1215-1; counter=c0007>>1; ] { }
|
vstmDdList: "{"^buildVstmDdList^"}" is TMode=0 & D22 & c1215 & c0007 & buildVstmDdList [ regNum=(D22<<4)+c1215-1; counter=c0007>>1; ] { }
|
||||||
|
vstmDdList: "{"^buildVstmDdList^"}" is TMode=1 & thv_D22 & thv_c1215 & thv_c0007 & buildVstmDdList [ regNum=(thv_D22<<4)+thv_c1215-1; counter=thv_c0007>>1; ] { }
|
||||||
|
|
||||||
:vstmia^COND vldmRn,vstmDdList is ( ($(AMODE) & COND & c2327=0x19 & c2121 & c2020=0 & c0811=11 & c0000=0) |
|
:vstmia^COND vldmRn,vstmDdList is ( ($(AMODE) & COND & c2327=0x19 & c2121 & c2020=0 & c0811=11 & c0000=0) |
|
||||||
($(TMODE_E) & thv_c2327=0x19 & thv_c2121 & thv_c2020=0 & thv_c0811=11 & thv_c0000=0) ) & vldmRn & vstmDdList & vldmOffset & vldmUpdate
|
($(TMODE_E) & thv_c2327=0x19 & thv_c2121 & thv_c2020=0 & thv_c0811=11 & thv_c0000=0) ) & vldmRn & vstmDdList & vldmOffset & vldmUpdate
|
||||||
|
|
|
@ -8,3 +8,4 @@ data/languages/superh.cspec||GHIDRA||||END|
|
||||||
data/languages/superh.ldefs||GHIDRA||||END|
|
data/languages/superh.ldefs||GHIDRA||||END|
|
||||||
data/languages/superh.pspec||GHIDRA||||END|
|
data/languages/superh.pspec||GHIDRA||||END|
|
||||||
data/languages/superh.sinc||GHIDRA||||END|
|
data/languages/superh.sinc||GHIDRA||||END|
|
||||||
|
data/languages/superh2a.cspec||GHIDRA||||END|
|
||||||
|
|
|
@ -29,19 +29,6 @@
|
||||||
<default_proto>
|
<default_proto>
|
||||||
<prototype name="__stdcall" extrapop="0" stackshift="0">
|
<prototype name="__stdcall" extrapop="0" stackshift="0">
|
||||||
<input>
|
<input>
|
||||||
<pentry minsize="4" maxsize="4" metatype="float">
|
|
||||||
<register name="fr4"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="4" maxsize="4" metatype="float">
|
|
||||||
<register name="fr5"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="4" maxsize="4" metatype="float">
|
|
||||||
<register name="fr6"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="4" maxsize="4" metatype="float">
|
|
||||||
<register name="fr7"/>
|
|
||||||
</pentry>
|
|
||||||
|
|
||||||
<pentry minsize="1" maxsize="4" extension="inttype">
|
<pentry minsize="1" maxsize="4" extension="inttype">
|
||||||
<register name="r4"/>
|
<register name="r4"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
@ -59,9 +46,6 @@
|
||||||
</pentry>
|
</pentry>
|
||||||
</input>
|
</input>
|
||||||
<output killedbycall="true">
|
<output killedbycall="true">
|
||||||
<pentry minsize="4" maxsize="4" metatype="float">
|
|
||||||
<register name="fr0"/>
|
|
||||||
</pentry>
|
|
||||||
<pentry minsize="1" maxsize="4" extension="inttype">
|
<pentry minsize="1" maxsize="4" extension="inttype">
|
||||||
<register name="r0"/>
|
<register name="r0"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
processorspec="superh.pspec"
|
processorspec="superh.pspec"
|
||||||
id="SuperH:BE:32:SH-2A">
|
id="SuperH:BE:32:SH-2A">
|
||||||
<description>SuperH SH-2A processor 32-bit big-endian</description>
|
<description>SuperH SH-2A processor 32-bit big-endian</description>
|
||||||
<compiler name="default" spec="superh.cspec" id="default"/>
|
<compiler name="default" spec="superh2a.cspec" id="default"/>
|
||||||
</language>
|
</language>
|
||||||
<language processor="SuperH"
|
<language processor="SuperH"
|
||||||
endian="big"
|
endian="big"
|
||||||
|
|
88
Ghidra/Processors/SuperH/data/languages/superh2a.cspec
Normal file
88
Ghidra/Processors/SuperH/data/languages/superh2a.cspec
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<compiler_spec>
|
||||||
|
<data_organization> <!-- These tags were taken from https://gcc-renesas.com/manuals/SH-ABI-Specification.html-->
|
||||||
|
<absolute_max_alignment value="0" />
|
||||||
|
<machine_alignment value="2" />
|
||||||
|
<default_alignment value="1" />
|
||||||
|
<default_pointer_alignment value="4" />
|
||||||
|
<pointer_size value="4" />
|
||||||
|
<wchar_size value="2" />
|
||||||
|
<short_size value="2" />
|
||||||
|
<integer_size value="4" />
|
||||||
|
<long_size value="4" />
|
||||||
|
<long_long_size value="8" />
|
||||||
|
<float_size value="4" />
|
||||||
|
<double_size value="8" />
|
||||||
|
<long_double_size value="8" />
|
||||||
|
<size_alignment_map>
|
||||||
|
<entry size="1" alignment="1" />
|
||||||
|
<entry size="2" alignment="2" />
|
||||||
|
<entry size="4" alignment="4" />
|
||||||
|
<entry size="8" alignment="4" />
|
||||||
|
</size_alignment_map>
|
||||||
|
</data_organization>
|
||||||
|
<global>
|
||||||
|
<range space="ram"/>
|
||||||
|
</global>
|
||||||
|
<stackpointer register="r15" space="ram"/>
|
||||||
|
<default_proto>
|
||||||
|
<prototype name="__stdcall" extrapop="0" stackshift="0">
|
||||||
|
<input>
|
||||||
|
<pentry minsize="4" maxsize="4" metatype="float">
|
||||||
|
<register name="fr4"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="4" maxsize="4" metatype="float">
|
||||||
|
<register name="fr5"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="4" maxsize="4" metatype="float">
|
||||||
|
<register name="fr6"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="4" maxsize="4" metatype="float">
|
||||||
|
<register name="fr7"/>
|
||||||
|
</pentry>
|
||||||
|
|
||||||
|
<pentry minsize="1" maxsize="4" extension="inttype">
|
||||||
|
<register name="r4"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4" extension="inttype">
|
||||||
|
<register name="r5"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4" extension="inttype">
|
||||||
|
<register name="r6"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4" extension="inttype">
|
||||||
|
<register name="r7"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="500" align="4">
|
||||||
|
<addr offset="0" space="stack"/>
|
||||||
|
</pentry>
|
||||||
|
</input>
|
||||||
|
<output killedbycall="true">
|
||||||
|
<pentry minsize="4" maxsize="4" metatype="float">
|
||||||
|
<register name="fr0"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="4" extension="inttype">
|
||||||
|
<register name="r0"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="5" maxsize="8">
|
||||||
|
<addr space="join" piece1="r1" piece2="r0"/>
|
||||||
|
</pentry>
|
||||||
|
</output>
|
||||||
|
<unaffected>
|
||||||
|
<register name="r8"/>
|
||||||
|
<register name="r9"/>
|
||||||
|
<register name="r10"/>
|
||||||
|
<register name="r11"/>
|
||||||
|
<register name="r12"/>
|
||||||
|
<register name="r13"/>
|
||||||
|
<register name="r14"/>
|
||||||
|
<register name="r15"/>
|
||||||
|
</unaffected>
|
||||||
|
<killedbycall>
|
||||||
|
<register name="r2"/>
|
||||||
|
<register name="r3"/>
|
||||||
|
</killedbycall>
|
||||||
|
</prototype>
|
||||||
|
</default_proto>
|
||||||
|
</compiler_spec>
|
Loading…
Add table
Add a link
Reference in a new issue