mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge branch 'master' of https://github.com/NationalSecurityAgency/ghidra into DocFix
This commit is contained in:
commit
8c35703cc4
77 changed files with 4546 additions and 2442 deletions
|
@ -6,6 +6,24 @@
|
|||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
<H1 align="center">Ghidra 9.1.2 Change History (February 2020)</H1>
|
||||
<blockquote><p><u>Bugs</u></p>
|
||||
<ul>
|
||||
<li><I>Data Types</I>. Improved PDB composite reconstruction to attempt <code>pack(1)</code> alignment if default alignment fails. (GT-3401)</li>
|
||||
<li><I>Data Types</I>. Added missing support for multi-user merge of unions and structures containing bitfields or a trailing flexible array member. (GT-3479)</li>
|
||||
<li><I>Data Types</I>. Corrected structure editor save button enablement issue when editing bitfields within an unaligned structure. (GT-3519, Issue #1297)</li>
|
||||
<li><I>Disassembly</I>. Corrected potential infinite loop with disassembler caused by branch to self with invalid delay slot instruction. (GT-3511, Issue #1486)</li>
|
||||
<li><I>GUI</I>. Corrected processor manual display for Microsoft Windows users, which was not displaying processor manual and was, instead, rendering a blank page in web browser. (GT-3444)</li>
|
||||
<li><I>GUI:Bitfield Editor</I>. Added field comment support to composite bitfield editor. (GT-3410)</li>
|
||||
<li><I>Importer:MachO</I>. A MachO loader regression, in Ghidra 9.1.1, when laying down symbols at the correct location, has been fixed. (GT-3487, Issue #1446)</li>
|
||||
<li><I>Languages</I>. Corrected mnemonic for ARM thumb <code>RSB.w</code> instruction. (GT-3420, Issue #1365)</li>
|
||||
<li><I>Languages</I>. Corrected issue in M68000 with some move instructions not creating correct array assignments. (GT-3429, Issue #1394)</li>
|
||||
<li><I>Languages</I>. Updated x86 processor manual index file with latest Intel and AMD manuals. (GT-3489, Issue #1078)</li>
|
||||
<li><I>Multi-User:Ghidra Server</I>. Corrected Ghidra Server remote interface errors that occur when running with Java 11.0.6 (and later) release, which would throw RemoteException <code>"Method is not Remote"</code> errors. (GT-3521, Issue #1440)</li>
|
||||
<li><I>PDB</I>. Corrected PDB XML generation for zero-length classes and structures and resolved various datatype dependency issues encountered during PDB Analysis. Changed line numbers from hex to decimal. (GT-3462, Issue #1410)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<H1 align="center">Ghidra 9.1.1 Change History (December 2019)</H1>
|
||||
<blockquote><p><u>Improvements</u></p>
|
||||
<ul>
|
||||
|
|
|
@ -314,7 +314,7 @@ public class SampleGraphProvider extends ComponentProviderAdapter {
|
|||
return mainPanel;
|
||||
}
|
||||
|
||||
private void showFitlerPanel(boolean selected) {
|
||||
private void showFilterPanel(boolean selected) {
|
||||
if (selected) {
|
||||
mainPanel.add(filterPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ public class SampleGraphProvider extends ComponentProviderAdapter {
|
|||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
showFitlerPanel(isSelected());
|
||||
showFilterPanel(isSelected());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,6 +24,8 @@ import java.util.*;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.widgets.fieldpanel.field.FieldElement;
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import docking.widgets.fieldpanel.support.Highlight;
|
||||
|
@ -450,16 +452,14 @@ public class ListingHighlightProvider
|
|||
text = StringUtilities.findWord(text, pos, UNDERSCORE_AND_PERIOD_OK);
|
||||
}
|
||||
|
||||
if (text != null) {
|
||||
text = text.trim();
|
||||
if (text.length() == 0) {
|
||||
text = null;
|
||||
}
|
||||
if (StringUtils.isBlank(text)) {
|
||||
text = null;
|
||||
}
|
||||
|
||||
if (text != null) {
|
||||
else {
|
||||
text = text.trim();
|
||||
currentHighlightPattern = Pattern.compile(text, Pattern.LITERAL);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
|
|
@ -162,8 +162,7 @@ public abstract class CompositeEditorPanel extends JPanel
|
|||
|
||||
BitFieldEditorDialog dlg = new BitFieldEditorDialog(model.viewComposite,
|
||||
provider.dtmService, editingRow, ordinal -> {
|
||||
model.fireTableDataChanged();
|
||||
model.compositeInfoChanged();
|
||||
model.notifyCompositeChanged();
|
||||
});
|
||||
Component c = provider.getComponent();
|
||||
Window w = SwingUtilities.windowForComponent(c);
|
||||
|
|
|
@ -60,7 +60,8 @@ public class FavoritesAction extends CompositeEditorTableAction {
|
|||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
// Do nothing since we always want it enabled so the user gets a "doesn't fit" message.
|
||||
// we always want it enabled so the user gets a "doesn't fit" message.
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,6 +76,6 @@ public class FavoritesAction extends CompositeEditorTableAction {
|
|||
|
||||
@Override
|
||||
public boolean isAddToPopup(ActionContext context) {
|
||||
return super.isEnabledForContext(context);
|
||||
return isEnabledForContext(context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,10 +42,6 @@ public abstract class AbstractConvertAction extends ListingContextAction {
|
|||
this.isSigned = isSigned;
|
||||
setPopupMenuData(new MenuData(new String[] { "Convert", "" }, "Convert"));
|
||||
setEnabled(true);
|
||||
JMenuItem item = new JMenuItem();
|
||||
Font font = item.getFont();
|
||||
metrics = plugin.getTool().getActiveWindow().getFontMetrics(font);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -132,14 +128,28 @@ public abstract class AbstractConvertAction extends ListingContextAction {
|
|||
return isSigned;
|
||||
}
|
||||
|
||||
private int stringWidth(String s) {
|
||||
if (metrics == null) {
|
||||
JMenuItem item = new JMenuItem();
|
||||
Font font = item.getFont();
|
||||
metrics = plugin.getTool().getActiveWindow().getFontMetrics(font);
|
||||
}
|
||||
int w = metrics.stringWidth(s);
|
||||
if (w == 0) {
|
||||
// use default computation if metrics report 0
|
||||
return 10 * s.length();
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
String getStandardLengthString(String baseString) {
|
||||
int baseWidth = metrics.stringWidth(baseString);
|
||||
int spaceWidth = metrics.stringWidth(" ");
|
||||
int baseWidth = stringWidth(baseString);
|
||||
int spaceWidth = stringWidth(" ");
|
||||
int paddingSize = (140 - baseWidth) / spaceWidth;
|
||||
if (paddingSize <= 0) {
|
||||
return baseString;
|
||||
}
|
||||
StringBuffer buf = new StringBuffer(baseString);
|
||||
StringBuilder buf = new StringBuilder(baseString);
|
||||
for (int i = 0; i < paddingSize; i++) {
|
||||
buf.append(" ");
|
||||
}
|
||||
|
|
|
@ -116,6 +116,10 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa
|
|||
addCancelButton();
|
||||
setHelpLocation(new HelpLocation("ExporterPlugin", "Exporter_Dialog"));
|
||||
|
||||
// This dialog is temporary and will be closed when the task is finished. Mark
|
||||
// it transient so no other windows will be parented to this dialog.
|
||||
setTransient(true);
|
||||
|
||||
// need to initialize a few things
|
||||
selectedFormatChanged();
|
||||
validate();
|
||||
|
@ -503,7 +507,7 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa
|
|||
|
||||
Object tmpConsumer = new Object();
|
||||
obj.addConsumer(tmpConsumer);
|
||||
SystemUtilities.runSwingLater(() -> {
|
||||
Swing.runLater(() -> {
|
||||
try {
|
||||
AboutDomainObjectUtils.displayInformation(tool, obj.getDomainFile(),
|
||||
obj.getMetadata(), "Export Results Summary", resultsBuffer.toString(),
|
||||
|
@ -516,9 +520,10 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa
|
|||
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Methods for testing
|
||||
**************************************************/
|
||||
//==================================================================================================
|
||||
// Methods for Testing
|
||||
//==================================================================================================
|
||||
|
||||
JCheckBox getSelectionCheckBox() {
|
||||
return selectionCheckBox;
|
||||
}
|
||||
|
|
|
@ -125,7 +125,8 @@ public class LocationReferencesPlugin extends Plugin
|
|||
private void displayProviderForLocation(ProgramLocation location, Navigatable navigatable) {
|
||||
LocationDescriptor locationDescriptor = getLocationDescriptor(location);
|
||||
if (locationDescriptor == null) {
|
||||
throw new IllegalArgumentException("Unable to display provider - unknown location");
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to display provider - unknown location: " + location);
|
||||
}
|
||||
|
||||
LocationReferencesProvider provider = findProvider(locationDescriptor, navigatable);
|
||||
|
|
|
@ -398,12 +398,7 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
|||
|
||||
@Override
|
||||
public ActionContext getActionContext(MouseEvent event) {
|
||||
if (event != null) {
|
||||
if (referencesPanel.selectRow(event)) {
|
||||
return new ActionContext(this, referencesPanel.getTable());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return new ActionContext(this, referencesPanel.getTable());
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
|
|
@ -711,16 +711,9 @@ public final class ReferenceUtils {
|
|||
return null;
|
||||
}
|
||||
|
||||
List<Object> objects = variableOffset.getObjects();
|
||||
Object object = objects.get((int) variableOffset.getOffset());
|
||||
if (!(object instanceof LabelString)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Variable variable = variableOffset.getVariable();
|
||||
DataType type = variable.getDataType();
|
||||
LabelString label = (LabelString) object;
|
||||
String string = label.toString();
|
||||
String string = variableOffset.getDataTypeDisplayText();
|
||||
GenericDataTypeLocationDescriptor descriptor =
|
||||
createGenericDataTypeLocationDescriptor(program, type, string);
|
||||
return descriptor;
|
||||
|
|
|
@ -537,7 +537,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
|||
public ColumnConstraintFilterMode getColumnConstraintFilterMode() {
|
||||
// not sure about this: it could be USE_COLUMN_CONSTRAINTS_ONLY, but then the text
|
||||
// filter would not match the formatted date. This allows for both.
|
||||
return ColumnConstraintFilterMode.USE_BOTH_COLUMN_RENDERER_FITLER_STRING_AND_CONSTRAINTS;
|
||||
return ColumnConstraintFilterMode.ALLOW_ALL_FILTERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -633,17 +633,18 @@ class StackEditorModel extends CompositeEditorModel {
|
|||
newLength = compDt.getLength();
|
||||
}
|
||||
int offset = comp.getOffset();
|
||||
if (((StackFrameDataType) viewComposite).growsNegative()) {
|
||||
if (offset >= 0 && offset < getParameterOffset()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (offset < 0 && offset > getParameterOffset()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
// TODO: not sure we need to prevent creating local variables in 'save' area,
|
||||
// since doing so just leads to confusion when using stack frame editor
|
||||
// if (((StackFrameDataType) viewComposite).growsNegative()) {
|
||||
// if (offset >= 0 && offset < getParameterOffset()) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// if (offset < 0 && offset > getParameterOffset()) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
int maxBytes = ((StackFrameDataType) viewComposite).getMaxLength(offset);
|
||||
if (newLength > maxBytes) {
|
||||
return false;
|
||||
|
|
|
@ -16,16 +16,16 @@
|
|||
package ghidra.app.util.exporter;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class Compare {
|
||||
public static void compare(ArrayList<String> expectedList, File actualFile) throws Exception {
|
||||
public class StringComparer {
|
||||
public static void compareLines(List<String> expectedList, File actualFile) throws Exception {
|
||||
int index = 0;
|
||||
|
||||
|
||||
boolean hasFailure = false;
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(actualFile))) {
|
||||
|
@ -35,7 +35,7 @@ public class Compare {
|
|||
if (actualLine == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (index >= expectedList.size()) {
|
||||
++excess;
|
||||
continue;
|
||||
|
@ -46,26 +46,26 @@ public class Compare {
|
|||
expectedLine = expectedLine.trim();
|
||||
|
||||
boolean match =
|
||||
expectedLine.equals(actualLine) || actualLine.startsWith(expectedLine);
|
||||
expectedLine.equals(actualLine) || actualLine.startsWith(expectedLine);
|
||||
|
||||
hasFailure |= !match;
|
||||
|
||||
if (!match) {
|
||||
Msg.debug(Compare.class, "Expected line does not match actual line (" + index +
|
||||
Msg.debug(StringComparer.class, "Expected line does not match actual line (" + index +
|
||||
"): \nExpected: " + expectedLine + "\nActual: " + actualLine);
|
||||
}
|
||||
}
|
||||
|
||||
if (excess > 0) {
|
||||
String message = "Actual file contains " + excess + " more lines than expected";
|
||||
Msg.debug(Compare.class, message);
|
||||
Msg.debug(StringComparer.class, message);
|
||||
Assert.fail(message);
|
||||
}
|
||||
else if (!hasFailure && index < expectedList.size()) {
|
||||
int fewer = expectedList.size() - index;
|
||||
String message = "Actual file contains " + fewer +
|
||||
" fewer lines than expected";
|
||||
Msg.debug(Compare.class, message);
|
||||
" fewer lines than expected";
|
||||
Msg.debug(StringComparer.class, message);
|
||||
Assert.fail(message);
|
||||
}
|
||||
|
|
@ -37,16 +37,18 @@ public class LcsHintLoadSpecChooser implements LoadSpecChooser {
|
|||
* {@link CompilerSpec}.
|
||||
*
|
||||
* @param language The {@link Language} to use (should not be null)
|
||||
* @param compilerSpec The {@link CompilerSpec} to use (should not be null)
|
||||
* @param compilerSpec The {@link CompilerSpec} to use (f null default compiler spec will be used)
|
||||
*/
|
||||
public LcsHintLoadSpecChooser(Language language, CompilerSpec compilerSpec) {
|
||||
this.languageID = language.getLanguageID();
|
||||
this.compilerSpecID = compilerSpec.getCompilerSpecID();
|
||||
this.compilerSpecID =
|
||||
(compilerSpec == null) ? language.getDefaultCompilerSpec().getCompilerSpecID()
|
||||
: compilerSpec.getCompilerSpecID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadSpec choose(LoaderMap loaderMap) {
|
||||
|
||||
|
||||
// Use the highest priority loader (it will be the first one)
|
||||
Loader loader = loaderMap.keySet().stream().findFirst().orElse(null);
|
||||
if (loader == null) {
|
||||
|
|
|
@ -802,7 +802,7 @@ public class CodeUnitFormat {
|
|||
long originalValue = (addr.isStackAddress() &&
|
||||
originalScalar.bitLength() == addr.getAddressSpace().getSize())
|
||||
? originalScalar.getSignedValue()
|
||||
: originalScalar.getValue();
|
||||
: originalScalar.getUnsignedValue();
|
||||
long addrOffset;
|
||||
if (addr instanceof SegmentedAddress) {
|
||||
addrOffset = ((SegmentedAddress) addr).getSegmentOffset();
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.junit.*;
|
|||
|
||||
import docking.widgets.table.model.TestDataModel;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
|
||||
public class GTableTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
@ -44,6 +45,9 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
frame.getContentPane().add(new JScrollPane(table));
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
|
||||
// showing the table will trigger a call to sort; wait for sorting to finish
|
||||
waitForSort();
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -59,26 +63,31 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
setSelectedRow(table, 0);
|
||||
|
||||
triggerText(table, "a");
|
||||
assertEquals(11, table.getSelectedRow());
|
||||
assertSelectedRow(11, "a");
|
||||
|
||||
triggerText(table, "c");
|
||||
assertEquals(12, table.getSelectedRow());
|
||||
assertSelectedRow(12, "c");
|
||||
timeout();
|
||||
|
||||
triggerText(table, "ad");
|
||||
assertEquals(24, table.getSelectedRow());
|
||||
assertSelectedRow(24, "ad");
|
||||
timeout();
|
||||
|
||||
triggerText(table, "av");
|
||||
assertEquals(70, table.getSelectedRow());
|
||||
assertSelectedRow(70, "av");
|
||||
timeout();
|
||||
|
||||
triggerText(table, "x");
|
||||
assertEquals(1920, table.getSelectedRow());
|
||||
assertSelectedRow(1920, "x");
|
||||
timeout();
|
||||
|
||||
triggerText(table, "a");
|
||||
assertEquals(11, table.getSelectedRow());
|
||||
assertSelectedRow(11, "a");
|
||||
|
||||
// test the case where no match is found
|
||||
table.setAutoLookupTimeout(1000); // longer timeout needed for multiple keys
|
||||
triggerText(table, "zed");
|
||||
assertEquals(11, table.getSelectedRow()); // no change
|
||||
assertSelectedRow(11, "zed"); // no change
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -92,31 +101,31 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
setSelectedRow(table, 0);
|
||||
|
||||
triggerText(table, "a");
|
||||
assertEquals(1846, table.getSelectedRow());
|
||||
assertSelectedRow(1846, "a");
|
||||
|
||||
triggerText(table, "c");
|
||||
assertEquals(1902, table.getSelectedRow());
|
||||
assertSelectedRow(1902, "c");
|
||||
|
||||
timeout();
|
||||
triggerText(table, "ad");
|
||||
assertEquals(1885, table.getSelectedRow());
|
||||
assertSelectedRow(1885, "ad");
|
||||
|
||||
timeout();
|
||||
triggerText(table, "av");
|
||||
assertEquals(1848, table.getSelectedRow());
|
||||
assertSelectedRow(1848, "av");
|
||||
|
||||
timeout();
|
||||
triggerText(table, "x");
|
||||
assertEquals(0, table.getSelectedRow());
|
||||
assertSelectedRow(0, "x");
|
||||
|
||||
timeout();
|
||||
triggerText(table, "a");
|
||||
assertEquals(1846, table.getSelectedRow());
|
||||
assertSelectedRow(1846, "a");
|
||||
|
||||
// test the case where no match is found
|
||||
table.setAutoLookupTimeout(1000); // longer timeout needed for multiple keys
|
||||
triggerText(table, "zed");
|
||||
assertEquals(1846, table.getSelectedRow()); // no change
|
||||
assertSelectedRow(1846, "zed"); // no change
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -132,26 +141,31 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
// note: the order checked here is the same as the sorted order, since we did not move
|
||||
// any rows after disabling the sort
|
||||
triggerText(table, "a");
|
||||
assertEquals(11, table.getSelectedRow());
|
||||
assertSelectedRow(11, "a");
|
||||
|
||||
triggerText(table, "c");
|
||||
assertEquals(12, table.getSelectedRow());
|
||||
assertSelectedRow(12, "c");
|
||||
timeout();
|
||||
|
||||
triggerText(table, "ad");
|
||||
assertEquals(24, table.getSelectedRow());
|
||||
assertSelectedRow(24, "ad");
|
||||
timeout();
|
||||
|
||||
triggerText(table, "av");
|
||||
assertEquals(70, table.getSelectedRow());
|
||||
assertSelectedRow(70, "av");
|
||||
timeout();
|
||||
|
||||
triggerText(table, "x");
|
||||
assertEquals(1920, table.getSelectedRow());
|
||||
assertSelectedRow(1920, "x");
|
||||
timeout();
|
||||
|
||||
triggerText(table, "a");
|
||||
assertEquals(11, table.getSelectedRow());
|
||||
assertSelectedRow(11, "a");
|
||||
|
||||
// test the case where no match is found
|
||||
table.setAutoLookupTimeout(1000); // longer timeout needed for multiple keys
|
||||
triggerText(table, "zed");
|
||||
assertEquals(11, table.getSelectedRow()); // no change
|
||||
assertSelectedRow(11, "zed"); // no change
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -192,9 +206,31 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals("Auto-lookup failed to change the table row", 11, table.getSelectedRow());
|
||||
}
|
||||
|
||||
private void assertSelectedRow(int row, String lookupText) {
|
||||
|
||||
int actual = runSwing(() -> table.getSelectedRow());
|
||||
if (row != actual) {
|
||||
|
||||
int col = 4; // String 'Name' column
|
||||
String expectedString = (String) table.getValueAt(row, col);
|
||||
String actualString = (String) table.getValueAt(actual, col);
|
||||
String message = "Auto-lookup row not selected for '" + lookupText + "'.\n\t" +
|
||||
"Expected text: '" + expectedString + "'; Actual text: '" + actualString + "'";
|
||||
Msg.out(message);
|
||||
assertEquals(message, row, actual);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeSortColumn(int column) {
|
||||
waitForSwing();
|
||||
runSwing(() -> TableUtils.columnAlternativelySelected(table, column));
|
||||
waitForSort();
|
||||
}
|
||||
|
||||
private void waitForSort() {
|
||||
// the call to sort may be run in an invokeLater()
|
||||
waitForSwing();
|
||||
waitForCondition(() -> !model.isSortPending());
|
||||
waitForSwing();
|
||||
}
|
||||
|
||||
|
@ -202,7 +238,7 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
TableSortState descendingSortState = TableSortState.createDefaultSortState(column, false);
|
||||
runSwing(() -> model.setTableSortState(descendingSortState));
|
||||
waitForSwing();
|
||||
waitForSort();
|
||||
}
|
||||
|
||||
private void timeout() {
|
||||
|
|
|
@ -17,6 +17,8 @@ package ghidra.app.merge.datatypes;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -35,38 +37,48 @@ import ghidra.util.task.TaskMonitorAdapter;
|
|||
public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
||||
|
||||
@Test
|
||||
public void testCategoryAddRemoveDTAdd() throws Exception {
|
||||
public void testCategoryAddRemoveDTAdd() throws Exception {
|
||||
|
||||
TypeDef td = new TypedefDataType("BF", IntegerDataType.dataType);
|
||||
|
||||
AtomicReference<Structure> structRef = new AtomicReference<>();
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// Make no changes to Latest.
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2"));
|
||||
try {
|
||||
c.removeCategory("Category5", TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
Category c5 = c.createCategory("Category5");
|
||||
Structure dt = new StructureDataType("Test", 0);
|
||||
dt.add(new ByteDataType());
|
||||
dt.add(new WordDataType());
|
||||
|
||||
dt = (Structure) c5.addDataType(dt, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
dt.add(new QWordDataType());
|
||||
Structure struct =
|
||||
new StructureDataType("Test", 0, program.getDataTypeManager());
|
||||
struct.add(new ByteDataType());
|
||||
struct.add(new WordDataType());
|
||||
struct.insertBitFieldAt(3, 2, 6, td, 2, "bf1", null);
|
||||
struct.insertBitFieldAt(3, 2, 4, td, 2, "bf2", null);
|
||||
struct.add(new QWordDataType());
|
||||
|
||||
struct.setFlexibleArrayComponent(td, "flex", "my flex");
|
||||
|
||||
structRef.set(struct);
|
||||
|
||||
c.removeCategory("Category5", TaskMonitorAdapter.DUMMY);
|
||||
Category c5 = c.createCategory("Category5");
|
||||
c5.addDataType(struct, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
commit = true;
|
||||
}
|
||||
catch (InvalidNameException e) {
|
||||
Assert.fail("got InvalidNameException!");
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.toString());
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
|
@ -79,19 +91,19 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category5"));
|
||||
assertNotNull(c);
|
||||
assertNotNull(c.getDataType("Test"));
|
||||
DataType dt = c.getDataType("Test");
|
||||
assertNotNull(dt);
|
||||
assertTrue(structRef.get().isEquivalent(dt));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeAddedInMy() throws Exception {
|
||||
public void testDataTypeAddedInMy() throws Exception {
|
||||
|
||||
// A category was added to Category5 in the latest;
|
||||
// in My program, rename Category5 to "My Category5" and add a new data type
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -111,9 +123,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -157,20 +166,19 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeAddedInMy2() throws Exception {
|
||||
public void testDataTypeAddedInMy2() throws Exception {
|
||||
|
||||
TypeDef td = new TypedefDataType("BF", IntegerDataType.dataType);
|
||||
|
||||
AtomicReference<Structure> structRef = new AtomicReference<>();
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// Make no changes to Latest.
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -179,15 +187,24 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3"));
|
||||
try {
|
||||
Structure s = (Structure) c.getDataType("IntStruct");
|
||||
c.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0);
|
||||
s.add(new QWordDataType());
|
||||
c.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0, dtm);
|
||||
s.add(new QWordDataType(), "f1", "my f1");
|
||||
s.add(new FloatDataType());
|
||||
s.add(new ByteDataType());
|
||||
s.insertBitFieldAt(16, 2, 6, td, 2, "bf1", "my bf1");
|
||||
s.insertBitFieldAt(16, 2, 4, td, 2, "bf2", "my bf2");
|
||||
s.add(new WordDataType());
|
||||
|
||||
structRef.set(s);
|
||||
|
||||
c.addDataType(s, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
commit = true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.toString());
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
|
@ -199,30 +216,25 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3"));
|
||||
DataType dt = c.getDataType("IntStruct");
|
||||
assertNotNull(dt);
|
||||
assertTrue(dt instanceof Structure);
|
||||
Structure s = (Structure) dt;
|
||||
assertTrue(new QWordDataType().isEquivalent(s.getComponent(0).getDataType()));
|
||||
assertTrue(new FloatDataType().isEquivalent(s.getComponent(1).getDataType()));
|
||||
assertTrue(new ByteDataType().isEquivalent(s.getComponent(2).getDataType()));
|
||||
assertTrue(new WordDataType().isEquivalent(s.getComponent(3).getDataType()));
|
||||
assertTrue(structRef.get().isEquivalent(dt));
|
||||
|
||||
Structure s = (Structure) dt;
|
||||
assertEquals("my f1", s.getComponent(0).getComment());
|
||||
DataTypeComponent dtc = s.getComponentAt(17);
|
||||
assertEquals(7, dtc.getOrdinal());
|
||||
assertEquals("my bf1", dtc.getComment());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeAddedInMy3() throws Exception {
|
||||
public void testDataTypeAddedInMy3() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// Make no changes to Latest.
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -231,7 +243,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3"));
|
||||
try {
|
||||
Structure s = (Structure) c.getDataType("IntStruct");
|
||||
c.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
c.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0);
|
||||
s.add(new QWordDataType());
|
||||
s.add(new FloatDataType());
|
||||
|
@ -270,15 +282,13 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeAddedInLatest() throws Exception {
|
||||
public void testDataTypeAddedInLatest() throws Exception {
|
||||
|
||||
// Add A category to Category5 in the latest, add
|
||||
// add a new data type;
|
||||
// in My program, rename Category5 to "My Category5"
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -303,9 +313,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -341,14 +348,12 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeAddedInLatest2() throws Exception {
|
||||
public void testDataTypeAddedInLatest2() throws Exception {
|
||||
|
||||
// A category was added to Category5 in the latest;
|
||||
// in My program, rename Category5 to "My Category5" and add a new data type
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -372,9 +377,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -418,20 +420,15 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeDeletedInMy() throws Exception {
|
||||
public void testDataTypeDeletedInMy() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// Make no changes to Latest.
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -443,7 +440,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
"IntStruct");
|
||||
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -461,20 +458,15 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeAddedDeletedInMy() throws Exception {
|
||||
public void testDataTypeAddedDeletedInMy() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// Make no changes to Latest.
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -487,7 +479,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
DataType dt = dtm.addDataType(s, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -505,12 +497,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeDeletedChanged() throws Exception {
|
||||
public void testDataTypeDeletedChanged() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -529,9 +519,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -543,7 +530,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
"IntStruct");
|
||||
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -561,12 +548,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeDeletedChanged2() throws Exception {
|
||||
public void testDataTypeDeletedChanged2() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -585,9 +570,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -599,7 +581,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
"FloatStruct");
|
||||
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -616,12 +598,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeDeletedChanged3() throws Exception {
|
||||
public void testDataTypeDeletedChanged3() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -631,7 +611,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
"IntStruct");
|
||||
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -639,9 +619,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -669,12 +646,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeDeletedInLatest() throws Exception {
|
||||
public void testDataTypeDeletedInLatest() throws Exception {
|
||||
|
||||
mtf.initialize("notepad2", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -684,7 +659,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -692,9 +667,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -728,12 +700,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeDeletedInBoth() throws Exception {
|
||||
public void testDataTypeDeletedInBoth() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -745,7 +715,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
"IntStruct");
|
||||
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -753,9 +723,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -767,7 +734,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
"IntStruct");
|
||||
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -785,20 +752,15 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeRenamedInMy() throws Exception {
|
||||
public void testDataTypeRenamedInMy() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// Make no changes to Latest.
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -834,12 +796,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testRenamedBoth() throws Exception {
|
||||
public void testRenamedBoth() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -865,9 +825,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -902,12 +859,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testRenamedBoth2() throws Exception {
|
||||
public void testRenamedBoth2() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -933,9 +888,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -971,12 +923,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDeletedInMyRenamedInLatest() throws Exception {
|
||||
public void testDeletedInMyRenamedInLatest() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1002,9 +952,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1016,7 +963,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
"IntStruct");
|
||||
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1032,12 +979,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDeletedInLatestRenamedInMy() throws Exception {
|
||||
public void testDeletedInLatestRenamedInMy() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1047,7 +992,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
"IntStruct");
|
||||
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1055,9 +1000,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1090,12 +1032,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDeletedInLatestChangedInMy() throws Exception {
|
||||
public void testDeletedInLatestChangedInMy() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1110,7 +1050,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
Structure s = (Structure) dt;
|
||||
s.add(new ByteDataType());
|
||||
Category parent = dtm.getCategory(new CategoryPath("/Category1/Category2"));
|
||||
parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1118,9 +1058,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1161,12 +1098,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDeletedInLatestAddedInMy() throws Exception {
|
||||
public void testDeletedInLatestAddedInMy() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1181,7 +1116,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
Structure s = (Structure) dt;
|
||||
s.add(new ByteDataType());
|
||||
Category parent = dtm.getCategory(new CategoryPath("/Category1/Category2"));
|
||||
parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1189,9 +1124,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1230,12 +1162,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCompositeCommentChanged() throws Exception {
|
||||
public void testCompositeCommentChanged() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
@ -1258,9 +1188,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
|
|
|
@ -21,11 +21,11 @@ import org.junit.Assert;
|
|||
import org.junit.Test;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.ProgramModifierListener;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
/**
|
||||
|
@ -47,7 +47,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
// 2 components should get removed from CoolUnion
|
||||
commit = true;
|
||||
}
|
||||
|
@ -77,10 +77,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2"));
|
||||
Union union = (Union) c.getDataType("CoolUnion");
|
||||
|
||||
// choose MY
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);// DLL_Table from MY
|
||||
|
@ -90,6 +86,11 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2"));
|
||||
Union union = (Union) c.getDataType("CoolUnion");
|
||||
|
||||
// DLL_Table should have a Word data type as the last component
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
DataTypeComponent dtc = s.getComponent(s.getNumComponents() - 1);
|
||||
|
@ -119,7 +120,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
// 2 components should get removed from CoolUnion
|
||||
commit = true;
|
||||
}
|
||||
|
@ -154,7 +155,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// choose DLL_Table from LATEST which means delete it
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST);
|
||||
|
@ -164,6 +164,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2"));
|
||||
Union union = (Union) c.getDataType("CoolUnion");
|
||||
|
||||
|
@ -191,7 +193,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
// 2 components should get removed from CoolUnion
|
||||
commit = true;
|
||||
}
|
||||
|
@ -226,7 +228,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// choose DLL_Table from ORIGINAL
|
||||
|
||||
|
@ -234,6 +235,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2"));
|
||||
Union union = (Union) c.getDataType("CoolUnion");
|
||||
|
||||
|
@ -296,10 +299,11 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
setErrorsExpected(true);
|
||||
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
executeMerge(true);
|
||||
|
||||
waitForCompletion();
|
||||
setErrorsExpected(false);
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
checkConflictCount(0);
|
||||
|
||||
|
@ -372,13 +376,17 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
|
||||
executeMerge();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST);// LATEST CoolUnion
|
||||
|
||||
setErrorsExpected(true);
|
||||
|
||||
executeMerge();
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST);// LATEST CoolUnion
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);// MY Foo
|
||||
waitForCompletion();
|
||||
|
||||
setErrorsExpected(false);
|
||||
|
||||
checkConflictCount(0);
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
@ -452,10 +460,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
|
||||
setErrorsExpected(true);
|
||||
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);// MY CoolUnion
|
||||
|
||||
|
@ -463,6 +468,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
Union union =
|
||||
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
|
||||
|
@ -523,10 +530,12 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
|
||||
executeMerge();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST);// Latest CoolUnion
|
||||
|
||||
setErrorsExpected(true);
|
||||
|
||||
executeMerge();
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST);// Latest CoolUnion
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);// My Bar
|
||||
|
||||
//
|
||||
|
@ -534,6 +543,9 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
//
|
||||
OptionDialog errorDialog =
|
||||
waitForDialogComponent(null, OptionDialog.class, DEFAULT_WINDOW_TIMEOUT);
|
||||
|
||||
setErrorsExpected(false);
|
||||
|
||||
assertNotNull(errorDialog);
|
||||
errorDialog.close();
|
||||
window.setVisible(false);
|
||||
|
@ -573,7 +585,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
DataType dt =
|
||||
dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -603,17 +615,20 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
|
||||
setErrorsExpected(true);
|
||||
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
//
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);// choose My Bar
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);
|
||||
// choose Structure_1 from ORIGINAL
|
||||
setErrorsExpected(true);
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL); // choose Structure_1 from ORIGINAL
|
||||
|
||||
setErrorsExpected(false);
|
||||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// Bar should contain original Structure_1
|
||||
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
|
||||
DataTypeComponent[] dtcs = bar.getDefinedComponents();
|
||||
|
@ -646,7 +661,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
DataType dt =
|
||||
dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
// causes Bar to be marked as changed
|
||||
commit = true;
|
||||
}
|
||||
|
@ -677,14 +692,15 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
//
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// choose original Bar
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);
|
||||
// choose Structure_1 from MY
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL); // choose original Bar
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY); // choose Structure_1 from MY
|
||||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// Bar should contain original Structure_1
|
||||
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
|
||||
assertEquals(6, bar.getLength());
|
||||
|
@ -720,7 +736,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
DataType dt =
|
||||
dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
// causes Bar to be marked as changed
|
||||
commit = true;
|
||||
}
|
||||
|
@ -751,14 +767,15 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
//
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);// choose my Bar
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST);// delele Structure_1
|
||||
// choose Structure_1 from MY
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST);// delele Structure_1 (choose Structure_1 from MY)
|
||||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// Bar should contain undefined to replace Structure_1
|
||||
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
|
||||
assertEquals(7, bar.getLength());
|
||||
|
@ -796,7 +813,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
Structure ms = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"),
|
||||
"MyStruct");
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
Structure s1 = new StructureDataType(
|
||||
new CategoryPath("/Category1/Category2/Category5"), "s1", 0);
|
||||
s1.add(ms);
|
||||
|
@ -849,7 +866,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// conflict on ArrayStruct (6)
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// use ORIGINAL ArrayStruct
|
||||
|
@ -860,6 +876,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
// conflict on FloatStruct (2)
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST);// delete FloatStruct
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
assertNull(
|
||||
dtm.getDataType(new CategoryPath("/Category1/Category2/Category5"), "FloatStruct"));
|
||||
|
||||
|
@ -884,6 +902,198 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
assertEquals(3, dtcs.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConflictUpdate5() throws Exception {
|
||||
|
||||
TypeDef td = new TypedefDataType(new CategoryPath("/Category1/Category2"), "BF",
|
||||
IntegerDataType.dataType);
|
||||
|
||||
mtf.initialize("notepad2", new OriginalProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyOriginal(ProgramDB program) throws Exception {
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
dtm.addDataType(td, null);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "BF");
|
||||
try {
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
Structure s1 = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"),
|
||||
"Structure_1");
|
||||
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
try {
|
||||
s1.insertBitFieldAt(3, 2, 6, td, 2, "bf1", "my bf1");
|
||||
s1.insertBitFieldAt(3, 2, 4, td, 2, "bf2", "my bf2");
|
||||
foo.add(new FloatDataType());
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.toString());
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// bitfield silently transitions to int since typedef BF was removed
|
||||
|
||||
executeMerge(true);
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
Structure s1 =
|
||||
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
|
||||
assertNotNull(s1);
|
||||
DataTypeComponent[] dtcs = s1.getComponents();
|
||||
assertEquals(7, dtcs.length);
|
||||
|
||||
assertEquals(4, dtcs[3].getOffset()); // base on original 2-byte length 1st byte remains undefined
|
||||
assertEquals("bf1", dtcs[3].getFieldName());
|
||||
assertEquals("my bf1", dtcs[3].getComment());
|
||||
|
||||
DataType dt = dtcs[3].getDataType();
|
||||
assertTrue(dt instanceof BitFieldDataType);
|
||||
BitFieldDataType bfDt = (BitFieldDataType) dt;
|
||||
assertTrue(bfDt.getBaseDataType() instanceof IntegerDataType);
|
||||
assertEquals(2, bfDt.getDeclaredBitSize());
|
||||
assertEquals(6, bfDt.getBitOffset());
|
||||
|
||||
assertEquals(4, dtcs[4].getOffset()); // base on original 2-byte length 1st byte remains undefined
|
||||
assertEquals("bf2", dtcs[4].getFieldName());
|
||||
assertEquals("my bf2", dtcs[4].getComment());
|
||||
|
||||
dt = dtcs[4].getDataType();
|
||||
assertTrue(dt instanceof BitFieldDataType);
|
||||
bfDt = (BitFieldDataType) dt;
|
||||
assertTrue(bfDt.getBaseDataType() instanceof IntegerDataType);
|
||||
assertEquals(2, bfDt.getDeclaredBitSize());
|
||||
assertEquals(4, bfDt.getBitOffset());
|
||||
|
||||
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
// Structure_1 should contain MY Foo
|
||||
assertEquals(foo, dtcs[5].getDataType());
|
||||
|
||||
dtcs = foo.getComponents();
|
||||
assertEquals(5, dtcs.length);
|
||||
assertTrue(dtcs[4].getDataType().isEquivalent(new FloatDataType()));
|
||||
checkConflictCount(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConflictUpdate6() throws Exception {
|
||||
|
||||
TypeDef td = new TypedefDataType(new CategoryPath("/Category1/Category2"), "BF",
|
||||
IntegerDataType.dataType);
|
||||
|
||||
mtf.initialize("notepad2", new ProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
// add new BF not compatible with BitFields
|
||||
dtm.addDataType(
|
||||
new StructureDataType(new CategoryPath("/Category1/Category2"), "BF", 0),
|
||||
null);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
Structure s1 = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"),
|
||||
"Structure_1");
|
||||
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
try {
|
||||
s1.insertBitFieldAt(3, 2, 6, td, 2, "bf1", "my bf1");
|
||||
s1.insertBitFieldAt(3, 2, 4, td, 2, "bf2", "my bf2");
|
||||
foo.add(new FloatDataType());
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.toString());
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// bitfield silently transitions to BF.conflict since two different BF types were added
|
||||
|
||||
executeMerge(true);
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
Structure s1 =
|
||||
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
|
||||
assertNotNull(s1);
|
||||
DataTypeComponent[] dtcs = s1.getComponents();
|
||||
assertEquals(7, dtcs.length);
|
||||
|
||||
assertEquals(4, dtcs[3].getOffset()); // base on original 2-byte length 1st byte remains undefined
|
||||
assertEquals("bf1", dtcs[3].getFieldName());
|
||||
assertEquals("my bf1", dtcs[3].getComment());
|
||||
|
||||
DataType dt = dtcs[3].getDataType();
|
||||
assertTrue(dt instanceof BitFieldDataType);
|
||||
BitFieldDataType bfDt = (BitFieldDataType) dt;
|
||||
DataType bdt = bfDt.getBaseDataType();
|
||||
assertEquals("/Category1/Category2/BF.conflict", bdt.getPathName());
|
||||
assertTrue(bdt.isEquivalent(td));
|
||||
assertEquals(2, bfDt.getDeclaredBitSize());
|
||||
assertEquals(6, bfDt.getBitOffset());
|
||||
|
||||
assertEquals(4, dtcs[4].getOffset()); // base on original 2-byte length 1st byte remains undefined
|
||||
assertEquals("bf2", dtcs[4].getFieldName());
|
||||
assertEquals("my bf2", dtcs[4].getComment());
|
||||
|
||||
dt = dtcs[4].getDataType();
|
||||
assertTrue(dt instanceof BitFieldDataType);
|
||||
bfDt = (BitFieldDataType) dt;
|
||||
bdt = bfDt.getBaseDataType();
|
||||
assertEquals("/Category1/Category2/BF.conflict", bdt.getPathName());
|
||||
assertTrue(bdt.isEquivalent(td));
|
||||
assertEquals(2, bfDt.getDeclaredBitSize());
|
||||
assertEquals(4, bfDt.getBitOffset());
|
||||
|
||||
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
// Structure_1 should contain MY Foo
|
||||
assertEquals(foo, dtcs[5].getDataType());
|
||||
|
||||
dtcs = foo.getComponents();
|
||||
assertEquals(5, dtcs.length);
|
||||
assertTrue(dtcs[4].getDataType().isEquivalent(new FloatDataType()));
|
||||
checkConflictCount(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditUnions() throws Exception {
|
||||
|
||||
|
@ -896,7 +1106,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
// 2 components should get removed from CoolUnion
|
||||
commit = true;
|
||||
}
|
||||
|
@ -940,7 +1150,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// choose DLL_Table from ORIGINAL
|
||||
|
||||
|
@ -948,6 +1157,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// DLL_Table should exist
|
||||
|
||||
Structure dll = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
|
@ -988,7 +1199,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
// 2 components should get removed from CoolUnion
|
||||
commit = true;
|
||||
}
|
||||
|
@ -1029,7 +1240,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST);// delete DLL_Table
|
||||
|
||||
|
@ -1037,6 +1247,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// DLL_Table should not exist
|
||||
|
||||
Structure dll = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
|
@ -1070,10 +1282,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
DataType dt =
|
||||
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1119,7 +1331,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// original DLL_Table
|
||||
|
||||
|
@ -1127,6 +1338,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// CoolUnion should not be null
|
||||
Union union =
|
||||
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
|
@ -1157,10 +1370,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
DataType dt =
|
||||
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1206,7 +1419,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST);// delete DLL_Table
|
||||
|
||||
|
@ -1214,6 +1426,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// CoolUnion should not be null
|
||||
Union union =
|
||||
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
|
@ -1245,10 +1459,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
DataType dt =
|
||||
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1294,7 +1508,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);// my DLL_Table
|
||||
|
||||
|
@ -1302,6 +1515,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// CoolUnion should be null
|
||||
Union union =
|
||||
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
|
@ -1332,10 +1547,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
DataType dt =
|
||||
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1383,7 +1598,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// original DLL_Table
|
||||
|
||||
|
@ -1391,6 +1605,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// CoolUnion should not be null
|
||||
Union union =
|
||||
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
|
@ -1425,10 +1641,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
DataType dt =
|
||||
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1479,7 +1695,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// original DLL_Table
|
||||
|
||||
|
@ -1487,6 +1702,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// CoolUnion should not be null
|
||||
Union union =
|
||||
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
|
@ -1526,10 +1743,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
try {
|
||||
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(s, TaskMonitorAdapter.DUMMY);
|
||||
DataType dt =
|
||||
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -1584,7 +1801,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
}
|
||||
});
|
||||
executeMerge();
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// original DLL_Table
|
||||
|
||||
|
@ -1592,6 +1808,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// CoolUnion should not be null
|
||||
Union union =
|
||||
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
|
@ -1624,4 +1842,110 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
|
|||
checkConflictCount(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditUnions9() throws Exception {
|
||||
|
||||
mtf.initialize("notepad", new OriginalProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyOriginal(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
|
||||
try {
|
||||
Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "XYZ", 1);
|
||||
enumm.add("one", 1);
|
||||
enumm.add("two", 2);
|
||||
enumm.add("three", 3);
|
||||
dtm.addDataType(
|
||||
new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnum", enumm),
|
||||
null);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
|
||||
try {
|
||||
DataType enumm = dtm.getDataType(new CategoryPath("/Category1"), "XYZ");
|
||||
dtm.remove(enumm, TaskMonitor.DUMMY);
|
||||
|
||||
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"),
|
||||
"CoolUnion");
|
||||
// NOTE: bit field component byte sizing is currently auto-sized and packed within unions
|
||||
union.insertBitField(1, IntegerDataType.dataType, 4, "bf1", "latest bf1");
|
||||
union.insertBitField(2, IntegerDataType.dataType, 2, "bf2", "latest bf2");
|
||||
commit = true;
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
|
||||
try {
|
||||
DataType enumm = dtm.getDataType(new CategoryPath("/Category1"), "XYZ");
|
||||
assertTrue(enumm instanceof Enum);
|
||||
|
||||
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"),
|
||||
"CoolUnion");
|
||||
// NOTE: bit field component byte sizing is currently auto-sized and packed within unions
|
||||
union.insertBitField(1, enumm, 4, "BF1", "my bf1");
|
||||
union.insertBitField(2, enumm, 2, "BF2", "my bf2");
|
||||
|
||||
commit = true;
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
});
|
||||
executeMerge();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY);// MY bitfields w/ enum
|
||||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
|
||||
// primitive type of byte used in absence of enum
|
||||
Union union =
|
||||
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
|
||||
//@formatter:off
|
||||
assertEquals("/Category1/Category2/CoolUnion\n" +
|
||||
"Unaligned\n" +
|
||||
"Union CoolUnion {\n" +
|
||||
" 0 qword 8 null \"\"\n" +
|
||||
" 0 byte:4(4) 1 BF1 \"my bf1\"\n" +
|
||||
" 0 byte:2(6) 1 BF2 \"my bf2\"\n" +
|
||||
" 0 word 2 null \"\"\n" +
|
||||
" 0 undefined * * * * * 4 null \"\"\n" +
|
||||
" 0 DLL_Table 96 null \"\"\n" +
|
||||
" 0 DLL_Table * 4 null \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 96 Actual Alignment = 1\n", union.toString());
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.merge.datatypes;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
|
||||
|
@ -37,7 +36,7 @@ import ghidra.util.task.TaskMonitorAdapter;
|
|||
public class DataTypeMerge8Test extends AbstractDataTypeMergeTest {
|
||||
|
||||
@Test
|
||||
public void testConflictFixUpForNonFittingStruct() throws Exception {
|
||||
public void testConflictFixUpForNonFittingStruct() throws Exception {
|
||||
|
||||
final CategoryPath miscPath = new CategoryPath("/MISC");
|
||||
final CategoryPath rootPath = new CategoryPath("/");
|
||||
|
@ -163,7 +162,7 @@ public class DataTypeMerge8Test extends AbstractDataTypeMergeTest {
|
|||
JLabel label = (JLabel) TestUtils.getInstanceField("label", logPanel);
|
||||
String statusText = label.getText();
|
||||
String expectedText =
|
||||
"Merging Data Types: Not enough undefined bytes to fit /XYZ in structure " +
|
||||
"Structure Merge: Not enough undefined bytes to fit /XYZ in structure " +
|
||||
"/MISC/ABC at offset 0x4.\nIt needs 3 more byte(s) to be able to fit.";
|
||||
assertTrue(statusText.contains(expectedText));
|
||||
}
|
||||
|
|
|
@ -485,9 +485,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest {
|
|||
try {
|
||||
Listing listing = program.getListing();
|
||||
Address startAddr = addr(program, "0x1002d20");
|
||||
program.getMemory()
|
||||
.setBytes(startAddr, new byte[] { (byte) 0x8d, (byte) 0x04, (byte) 0x8d,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0 }); //LEA EAX,[0x0 + ECX*0x4]
|
||||
program.getMemory().setBytes(startAddr, new byte[] { (byte) 0x8d, (byte) 0x04,
|
||||
(byte) 0x8d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0 }); //LEA EAX,[0x0 + ECX*0x4]
|
||||
createInstruction(program, startAddr);
|
||||
Instruction instruction = listing.getInstructionAt(startAddr);
|
||||
Assert.assertTrue(instruction != null);
|
||||
|
@ -579,8 +578,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest {
|
|||
setupAddNameDiffOnSubOperand();
|
||||
|
||||
executeMerge(ASK_USER);
|
||||
chooseEquate("0x1002d20", 1, KEEP_MY); // 0x4 Order seems to have been switched
|
||||
chooseEquate("0x1002d20", 1, KEEP_MY); // 0x0
|
||||
chooseEquate("0x1002d20", 1, KEEP_MY); // 0x4
|
||||
waitForMergeCompletion();
|
||||
|
||||
EquateTable equateTab = resultProgram.getEquateTable();
|
||||
|
@ -602,31 +601,6 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest {
|
|||
// MY 0x0=ZERO 0x4=QUAD
|
||||
setupAddNameDiffOnSubOperand();
|
||||
|
||||
executeMerge(ASK_USER);
|
||||
chooseEquate("0x1002d20", 1, KEEP_LATEST); // 0x4
|
||||
chooseEquate("0x1002d20", 1, KEEP_MY); // 0x0
|
||||
waitForMergeCompletion();
|
||||
|
||||
EquateTable equateTab = resultProgram.getEquateTable();
|
||||
List<Equate> equates = equateTab.getEquates(addr("0x1002d20"), 1);
|
||||
assertEquals(2, equates.size());
|
||||
Equate eq;
|
||||
eq = equates.get(0);
|
||||
assertEquals("FOUR", eq.getName());
|
||||
assertEquals(4L, eq.getValue());
|
||||
eq = equates.get(1);
|
||||
assertEquals("ZERO", eq.getName());
|
||||
assertEquals(0L, eq.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNameDiffOnSubOperandPickMyLatest() throws Exception {
|
||||
// 0x1002d20 LEA EAX,[0x0 + ECX*0x4]
|
||||
//
|
||||
// LATEST 0x0=NADA 0x4=FOUR
|
||||
// MY 0x0=ZERO 0x4=QUAD
|
||||
setupAddNameDiffOnSubOperand();
|
||||
|
||||
executeMerge(ASK_USER);
|
||||
chooseEquate("0x1002d20", 1, KEEP_MY); // 0x4
|
||||
chooseEquate("0x1002d20", 1, KEEP_LATEST); // 0x0
|
||||
|
@ -644,6 +618,31 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest {
|
|||
assertEquals(4L, eq.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNameDiffOnSubOperandPickMyLatest() throws Exception {
|
||||
// 0x1002d20 LEA EAX,[0x0 + ECX*0x4]
|
||||
//
|
||||
// LATEST 0x0=NADA 0x4=FOUR
|
||||
// MY 0x0=ZERO 0x4=QUAD
|
||||
setupAddNameDiffOnSubOperand();
|
||||
|
||||
executeMerge(ASK_USER);
|
||||
chooseEquate("0x1002d20", 1, KEEP_LATEST); // 0x4
|
||||
chooseEquate("0x1002d20", 1, KEEP_MY); // 0x0
|
||||
waitForMergeCompletion();
|
||||
|
||||
EquateTable equateTab = resultProgram.getEquateTable();
|
||||
List<Equate> equates = equateTab.getEquates(addr("0x1002d20"), 1);
|
||||
assertEquals(2, equates.size());
|
||||
Equate eq;
|
||||
eq = equates.get(0);
|
||||
assertEquals("FOUR", eq.getName());
|
||||
assertEquals(4L, eq.getValue());
|
||||
eq = equates.get(1);
|
||||
assertEquals("ZERO", eq.getName());
|
||||
assertEquals(0L, eq.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddSameNameDiffValue() throws Exception {
|
||||
mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() {
|
||||
|
|
|
@ -477,12 +477,8 @@ public class BookmarkPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
waitForTable();
|
||||
|
||||
selectAllTableRows();
|
||||
|
||||
runSwing(() -> provider.delete());
|
||||
|
||||
waitForTable();
|
||||
|
||||
assertEquals(0, table.getRowCount());
|
||||
waitForCondition(() -> table.getRowCount() == 0, "Bookmarks not deleted");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -315,7 +315,7 @@ public class StackEditorActions4Test extends AbstractStackEditorTest {
|
|||
assertEquals(0xa, getOffset(model.getNumComponents() - 1));
|
||||
|
||||
FavoritesAction fav = getFavorite("word");
|
||||
assertTrue(fav.isEnabled());
|
||||
assertTrue(fav.isEnabledForContext(null)); // context not utilized
|
||||
assertEquals("", model.getStatus());
|
||||
invoke(fav);
|
||||
assertEquals("", model.getStatus());
|
||||
|
|
|
@ -575,6 +575,37 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(comps.length - 1, newDt.getDefinedComponents().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeConflictHandling() throws Exception {
|
||||
Category sub1 = root.createCategory("Cat1");
|
||||
DataType dt1 = new StructureDataType("DT", 1);
|
||||
DataType dt2 = new StructureDataType("DT", 2);
|
||||
DataType added1 = sub1.addDataType(dt1, null);
|
||||
DataType added2 = sub1.addDataType(dt2, null);
|
||||
assertEquals("DT", added1.getName());
|
||||
assertEquals("DT.conflict", added2.getName());
|
||||
|
||||
List<DataType> list = sub1.getDataTypesByBaseName("DT");
|
||||
assertEquals(2, list.size());
|
||||
assertEquals(added1, list.get(0));
|
||||
assertEquals(added2, list.get(1));
|
||||
|
||||
list = sub1.getDataTypesByBaseName("DT.conflict");
|
||||
assertEquals(2, list.size());
|
||||
assertEquals(added1, list.get(0));
|
||||
assertEquals(added2, list.get(1));
|
||||
|
||||
sub1.remove(added2, TaskMonitor.DUMMY);
|
||||
list = sub1.getDataTypesByBaseName("DT");
|
||||
assertEquals(1, list.size());
|
||||
assertEquals(added1, list.get(0));
|
||||
|
||||
list = sub1.getDataTypesByBaseName("DT.conflict");
|
||||
assertEquals(1, list.size());
|
||||
assertEquals(added1, list.get(0));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDataTypeManager() throws Exception {
|
||||
Category sub1 = root.createCategory("SubCat-A");
|
||||
|
@ -772,10 +803,7 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
clearEvents();
|
||||
|
||||
struct2 = (Structure) newDt.insert(3, struct2).getDataType();
|
||||
int eventCount = getEventCount();
|
||||
if (4 != eventCount) {
|
||||
System.err.println("halt!");
|
||||
}
|
||||
|
||||
assertEquals(5, getEventCount());
|
||||
Event ev = getEvent(4);
|
||||
assertEquals("DT Changed", ev.evName);
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.functioncompare;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
@ -57,7 +56,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
private Function five;
|
||||
private FunctionComparisonPlugin plugin;
|
||||
private FunctionComparisonProvider provider;
|
||||
private FunctionComparisonProvider provider0;
|
||||
private FunctionComparisonProvider provider2;
|
||||
private FunctionComparisonModel model;
|
||||
|
||||
@Before
|
||||
|
@ -70,23 +69,17 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
model = createTestModel();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Tests for {@link FunctionComparisonService#compareFunctions(Set)}
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testSetNoFunctions() throws Exception {
|
||||
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet();
|
||||
FunctionComparisonProvider provider = plugin.compareFunctions(functions);
|
||||
provider = compare(functions);
|
||||
assertNull(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetOneFunction() throws Exception {
|
||||
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo);
|
||||
provider = plugin.compareFunctions(functions);
|
||||
provider = compare(functions);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo);
|
||||
}
|
||||
|
@ -94,23 +87,23 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testSetDuplicateFunctionDifferentProviders() throws Exception {
|
||||
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo);
|
||||
provider = plugin.compareFunctions(functions);
|
||||
provider = compare(functions);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo);
|
||||
|
||||
provider0 = plugin.compareFunctions(functions);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider0, foo);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, foo, foo);
|
||||
provider2 = compare(functions);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider2, foo);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, foo, foo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDuplicateFunctionSameProvider() throws Exception {
|
||||
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo);
|
||||
provider = plugin.compareFunctions(functions);
|
||||
provider = compare(functions);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo);
|
||||
|
||||
plugin.compareFunctions(functions, provider);
|
||||
compare(functions, provider);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo);
|
||||
}
|
||||
|
@ -118,7 +111,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testSetMultipleFunctions() throws Exception {
|
||||
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, junk, stuff);
|
||||
provider = plugin.compareFunctions(functions);
|
||||
provider = compare(functions);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, junk, stuff);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, junk, stuff);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, junk, foo, junk, stuff);
|
||||
|
@ -130,16 +123,16 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
Set<Function> functions1 = CompareFunctionsTestUtility.getFunctionsAsSet(one, two);
|
||||
Set<Function> functions2 = CompareFunctionsTestUtility.getFunctionsAsSet(three, four, five);
|
||||
|
||||
provider = plugin.compareFunctions(functions1);
|
||||
provider0 = plugin.compareFunctions(functions2);
|
||||
provider = compare(functions1);
|
||||
provider2 = compare(functions2);
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, one, two);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, one, one, two);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, two, one, two);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider0, three, four, five);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, three, three, four, five);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, four, three, four, five);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, five, three, four, five);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider2, three, four, five);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, three, three, four, five);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, four, three, four, five);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, five, three, four, five);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -147,8 +140,8 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
Set<Function> functions1 = CompareFunctionsTestUtility.getFunctionsAsSet(foo, two);
|
||||
Set<Function> functions2 = CompareFunctionsTestUtility.getFunctionsAsSet(bar, three, four);
|
||||
|
||||
provider = plugin.compareFunctions(functions1);
|
||||
plugin.compareFunctions(functions2, provider);
|
||||
provider = compare(functions1);
|
||||
compare(functions2, provider);
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, two, bar, three, four);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, two, bar, three, four);
|
||||
|
@ -160,47 +153,35 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
four);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Tests for {@link FunctionComparisonService#compareFunctions(Set, FunctionComparisonProvider)}
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testSetAddToSpecificProvider() throws Exception {
|
||||
Set<Function> functions1 = CompareFunctionsTestUtility.getFunctionsAsSet(foo, two);
|
||||
Set<Function> functions2 = CompareFunctionsTestUtility.getFunctionsAsSet(bar, three);
|
||||
Set<Function> functions3 = CompareFunctionsTestUtility.getFunctionsAsSet(four);
|
||||
provider = plugin.compareFunctions(functions1);
|
||||
provider0 = plugin.compareFunctions(functions2);
|
||||
provider = compare(functions1);
|
||||
provider2 = compare(functions2);
|
||||
|
||||
plugin.compareFunctions(functions3, provider0);
|
||||
compare(functions3, provider2);
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, two);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider0, bar, three, four);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider2, bar, three, four);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, two);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, two, foo, two);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, bar, bar, three, four);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, three, bar, three, four);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, four, bar, three, four);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, bar, bar, three, four);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, three, bar, three, four);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, four, bar, three, four);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Tests for {@link FunctionComparisonService#removeFunction(Function)}
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testRemoveFunction() throws Exception {
|
||||
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
|
||||
provider = plugin.compareFunctions(functions);
|
||||
provider = compare(functions);
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar);
|
||||
|
||||
plugin.removeFunction(foo);
|
||||
remove(foo);
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, bar);
|
||||
|
@ -209,15 +190,17 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testRemoveFunctionTargetOnly() throws Exception {
|
||||
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
|
||||
provider = plugin.compareFunctions(functions);
|
||||
plugin.compareFunctions(foo, two, provider); // add a target to foo, which is not also a source
|
||||
provider = compare(functions);
|
||||
|
||||
// add a target to foo, which is not also a source
|
||||
runSwing(() -> plugin.compareFunctions(foo, two, provider));
|
||||
|
||||
// Verify the structure with the new target
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar, two);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar);
|
||||
|
||||
plugin.removeFunction(two);
|
||||
remove(two);
|
||||
|
||||
// Verify the new target is gone
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar);
|
||||
|
@ -228,85 +211,67 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testRemoveFunctionMultipleProviders() throws Exception {
|
||||
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
|
||||
provider = plugin.compareFunctions(functions);
|
||||
provider0 = plugin.compareFunctions(functions);
|
||||
provider = compare(functions);
|
||||
provider2 = compare(functions);
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider0, foo, bar);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider2, foo, bar);
|
||||
|
||||
plugin.removeFunction(foo);
|
||||
remove(foo);
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, bar);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider0, bar);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider2, bar);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveNonexistentFunction() throws Exception {
|
||||
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
|
||||
provider = plugin.compareFunctions(functions);
|
||||
provider = compare(functions);
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar);
|
||||
|
||||
plugin.removeFunction(two); // nothing should happen
|
||||
remove(two); // nothing should happen
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Tests for {@link FunctionComparisonService#removeFunction(Function, FunctionComparisonProvider)}
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testRemoveFunctionFromSpecificProvider() throws Exception {
|
||||
Set<Function> functions1 = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
|
||||
provider = plugin.compareFunctions(functions1);
|
||||
provider0 = plugin.compareFunctions(functions1);
|
||||
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
|
||||
provider = compare(functions);
|
||||
provider2 = compare(functions);
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider0, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, foo, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, bar, foo, bar);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider2, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, foo, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, bar, foo, bar);
|
||||
|
||||
plugin.removeFunction(foo, provider);
|
||||
remove(foo, provider);
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, bar);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider0, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, foo, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider0, bar, foo, bar);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider2, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, foo, foo, bar);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider2, bar, foo, bar);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Tests for {@link FunctionComparisonService#compareFunctions(Function, Function)}
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testDualCompare() {
|
||||
provider = plugin.compareFunctions(foo, bar);
|
||||
provider = compare(foo, bar);
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, bar);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Tests for {@link FunctionComparisonService#compareFunctions(Function, Function, FunctionComparisonProvider)}
|
||||
*
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testDualCompareAddToExisting() {
|
||||
provider = plugin.compareFunctions(foo, bar);
|
||||
plugin.compareFunctions(foo, two, provider);
|
||||
provider = compare(foo, bar);
|
||||
runSwing(() -> plugin.compareFunctions(foo, two, provider));
|
||||
|
||||
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo);
|
||||
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, bar, two);
|
||||
|
@ -321,7 +286,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testGetTargets() {
|
||||
Set<Function> targets = model.getTargetFunctions();
|
||||
assertTrue(targets.size() == 6);
|
||||
assertEquals(6, targets.size());
|
||||
assertTrue(targets.contains(bar));
|
||||
assertTrue(targets.contains(two));
|
||||
assertTrue(targets.contains(three));
|
||||
|
@ -333,7 +298,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testGetTargetsForSource() {
|
||||
Set<Function> targets = model.getTargetFunctions(bar);
|
||||
assertTrue(targets.size() == 3);
|
||||
assertEquals(3, targets.size());
|
||||
assertTrue(targets.contains(three));
|
||||
assertTrue(targets.contains(four));
|
||||
assertTrue(targets.contains(five));
|
||||
|
@ -342,7 +307,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void getSources() {
|
||||
Set<Function> sources = model.getSourceFunctions();
|
||||
assertTrue(sources.size() == 3);
|
||||
assertEquals(3, sources.size());
|
||||
assertTrue(sources.contains(foo));
|
||||
assertTrue(sources.contains(bar));
|
||||
assertTrue(sources.contains(junk));
|
||||
|
@ -353,19 +318,39 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
model.removeFunction(bar);
|
||||
|
||||
Set<Function> sources = model.getSourceFunctions();
|
||||
assertTrue(sources.size() == 2);
|
||||
assertEquals(2, sources.size());
|
||||
assertTrue(sources.contains(foo));
|
||||
assertTrue(sources.contains(junk));
|
||||
|
||||
Set<Function> targets = model.getTargetFunctions(foo);
|
||||
assertTrue(targets.size() == 1);
|
||||
assertEquals(1, targets.size());
|
||||
assertTrue(targets.contains(two));
|
||||
|
||||
targets = model.getTargetFunctions(junk);
|
||||
assertTrue(targets.size() == 1);
|
||||
assertEquals(1, targets.size());
|
||||
assertTrue(targets.contains(stuff));
|
||||
}
|
||||
|
||||
private void remove(Function f) {
|
||||
runSwing(() -> plugin.removeFunction(f));
|
||||
}
|
||||
|
||||
private void remove(Function f, FunctionComparisonProvider fp) {
|
||||
runSwing(() -> plugin.removeFunction(f, fp));
|
||||
}
|
||||
|
||||
private void compare(Set<Function> functions, FunctionComparisonProvider fp) {
|
||||
runSwing(() -> plugin.compareFunctions(functions, fp));
|
||||
}
|
||||
|
||||
private FunctionComparisonProvider compare(Set<Function> functions) {
|
||||
return runSwing(() -> plugin.compareFunctions(functions));
|
||||
}
|
||||
|
||||
private FunctionComparisonProvider compare(Function f1, Function f2) {
|
||||
return runSwing(() -> plugin.compareFunctions(f1, f2));
|
||||
}
|
||||
|
||||
private ProgramBuilder buildTestProgram1() throws Exception {
|
||||
ProgramBuilder builder = new ProgramBuilder("TestPgm1", ProgramBuilder._TOY_BE);
|
||||
builder.createMemory(".text", "0x1001000", 0x6600);
|
||||
|
@ -404,26 +389,26 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
}
|
||||
|
||||
private FunctionComparisonModel createTestModel() {
|
||||
FunctionComparisonModel model = new FunctionComparisonModel();
|
||||
FunctionComparisonModel newModel = new FunctionComparisonModel();
|
||||
|
||||
FunctionComparison c1 = new FunctionComparison();
|
||||
c1.setSource(foo);
|
||||
c1.addTarget(bar);
|
||||
c1.addTarget(two);
|
||||
model.addComparison(c1);
|
||||
newModel.addComparison(c1);
|
||||
|
||||
FunctionComparison c2 = new FunctionComparison();
|
||||
c2.setSource(bar);
|
||||
c2.addTarget(three);
|
||||
c2.addTarget(four);
|
||||
c2.addTarget(five);
|
||||
model.addComparison(c2);
|
||||
newModel.addComparison(c2);
|
||||
|
||||
FunctionComparison c3 = new FunctionComparison();
|
||||
c3.setSource(junk);
|
||||
c3.addTarget(stuff);
|
||||
model.addComparison(c3);
|
||||
newModel.addComparison(c3);
|
||||
|
||||
return model;
|
||||
return newModel;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,6 +228,18 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
|||
"The Listing is not at the expected address");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertCurrentAddress(Address expected) {
|
||||
codeBrowser.updateNow();
|
||||
waitForSwing();
|
||||
|
||||
waitForCondition(() -> {
|
||||
ProgramLocation loc = codeBrowser.getCurrentLocation();
|
||||
Address actual = loc.getAddress();
|
||||
return expected.equals(actual);
|
||||
}, "Listing is not at the expected address");
|
||||
}
|
||||
|
||||
private void assertExternalNavigationPerformed() {
|
||||
// going to the 'external linkage' means we went to the thunk function and not the
|
||||
// external program
|
||||
|
|
|
@ -63,6 +63,16 @@ public abstract class DecompilerVariable {
|
|||
return dataType;
|
||||
}
|
||||
|
||||
// The parent variable declaration node has the type
|
||||
ClangNode parent = variable.Parent();
|
||||
if (parent instanceof ClangVariableDecl) {
|
||||
ClangVariableDecl decl = (ClangVariableDecl) parent;
|
||||
dataType = decl.getDataType();
|
||||
if (dataType != null) {
|
||||
return dataType;
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer the type of the first input varnode, unless that type is a 'void *'.
|
||||
// Usually, in that special case, the output varnode has the correct type information.
|
||||
PcodeOp op = variable.getPcodeOp();
|
||||
|
|
|
@ -328,7 +328,7 @@ class VTFunctionAssociationTableModel extends AddressBasedTableModel<VTFunctionR
|
|||
}
|
||||
|
||||
private boolean hasNoFilter() {
|
||||
return filterSettings == FilterSettings.SHOW_ALL && !hasFitler();
|
||||
return filterSettings == FilterSettings.SHOW_ALL && !hasFilter();
|
||||
}
|
||||
|
||||
private boolean passesUnmatchedFunctionFilter(FunctionAssociationInfo info) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.feature.vt.gui.provider.matchtable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import ghidra.feature.vt.api.main.VTMatch;
|
||||
import ghidra.feature.vt.gui.filters.*;
|
||||
import ghidra.feature.vt.gui.plugin.VTController;
|
||||
|
@ -23,8 +24,6 @@ import ghidra.util.HelpLocation;
|
|||
import ghidra.util.layout.VariableRowHeightGridLayout;
|
||||
import ghidra.util.layout.VerticalLayout;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class MatchesFilterDialogComponentProvider extends
|
||||
AncillaryFilterDialogComponentProvider<VTMatch> {
|
||||
|
||||
|
@ -58,9 +57,9 @@ public class MatchesFilterDialogComponentProvider extends
|
|||
|
||||
// Row 1 - Right Component
|
||||
// association status filter
|
||||
AssociationStatusFilter associationStatusFitler = new AssociationStatusFilter();
|
||||
addFilter(associationStatusFitler);
|
||||
rowOnePanel.add(associationStatusFitler.getComponent());
|
||||
AssociationStatusFilter associationStatusFilter = new AssociationStatusFilter();
|
||||
addFilter(associationStatusFilter);
|
||||
rowOnePanel.add(associationStatusFilter.getComponent());
|
||||
|
||||
// Row 2 - Left Component
|
||||
// symbol type filter
|
||||
|
|
|
@ -15,12 +15,77 @@
|
|||
*/
|
||||
package db.buffers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.server.RemoteObjectInvocationHandler;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* <code>RemoteBufferFileHandle</code> facilitates access to a remote BufferFile
|
||||
* via RMI.
|
||||
* <p>
|
||||
* Methods from {@link BufferFileHandle} <b>must</b> be re-declared here
|
||||
* so they may be properly marshalled for remote invocation via RMI.
|
||||
* This became neccessary with an OpenJDK 11.0.6 change made to
|
||||
* {@link RemoteObjectInvocationHandler}.
|
||||
*/
|
||||
public interface RemoteBufferFileHandle extends BufferFileHandle, Remote {
|
||||
// provides combined interface
|
||||
@Override
|
||||
public boolean isReadOnly() throws IOException;
|
||||
|
||||
@Override
|
||||
public boolean setReadOnly() throws IOException;
|
||||
|
||||
@Override
|
||||
public int getParameter(String name) throws NoSuchElementException, IOException;
|
||||
|
||||
@Override
|
||||
public void setParameter(String name, int value) throws IOException;
|
||||
|
||||
@Override
|
||||
public void clearParameters() throws IOException;
|
||||
|
||||
@Override
|
||||
public String[] getParameterNames() throws IOException;
|
||||
|
||||
@Override
|
||||
public int getBufferSize() throws IOException;
|
||||
|
||||
@Override
|
||||
public int getIndexCount() throws IOException;
|
||||
|
||||
@Override
|
||||
public int[] getFreeIndexes() throws IOException;
|
||||
|
||||
@Override
|
||||
public void setFreeIndexes(int[] indexes) throws IOException;
|
||||
|
||||
@Override
|
||||
public void close() throws IOException;
|
||||
|
||||
@Override
|
||||
public boolean delete() throws IOException;
|
||||
|
||||
@Override
|
||||
public DataBuffer get(int index) throws IOException;
|
||||
|
||||
@Override
|
||||
public void put(DataBuffer buf, int index) throws IOException;
|
||||
|
||||
@Override
|
||||
public void dispose() throws IOException;
|
||||
|
||||
@Override
|
||||
public InputBlockStream getInputBlockStream() throws IOException;
|
||||
|
||||
@Override
|
||||
public OutputBlockStream getOutputBlockStream(int blockCount) throws IOException;
|
||||
|
||||
@Override
|
||||
public BlockStreamHandle<InputBlockStream> getInputBlockStreamHandle() throws IOException;
|
||||
|
||||
@Override
|
||||
public BlockStreamHandle<OutputBlockStream> getOutputBlockStreamHandle(int blockCount)
|
||||
throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -15,12 +15,116 @@
|
|||
*/
|
||||
package db.buffers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.server.RemoteObjectInvocationHandler;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* <code>RemoteManagedBufferFileHandle</code> facilitates access to a ManagedBufferFile
|
||||
* via RMI.
|
||||
* <p>
|
||||
* Methods from {@link BufferFileHandle} and {@link ManagedBufferFile} <b>must</b>
|
||||
* be re-declared here so they may be properly marshalled for remote invocation via RMI.
|
||||
* This became neccessary with an OpenJDK 11.0.6 change made to
|
||||
* {@link RemoteObjectInvocationHandler}.
|
||||
*/
|
||||
public interface RemoteManagedBufferFileHandle extends ManagedBufferFileHandle, Remote {
|
||||
// provides combined interface
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// BufferFileHandle methods
|
||||
//--------------------------------------------------------------------------
|
||||
@Override
|
||||
public boolean isReadOnly() throws IOException;
|
||||
|
||||
@Override
|
||||
public boolean setReadOnly() throws IOException;
|
||||
|
||||
@Override
|
||||
public int getParameter(String name) throws NoSuchElementException, IOException;
|
||||
|
||||
@Override
|
||||
public void setParameter(String name, int value) throws IOException;
|
||||
|
||||
@Override
|
||||
public void clearParameters() throws IOException;
|
||||
|
||||
@Override
|
||||
public String[] getParameterNames() throws IOException;
|
||||
|
||||
@Override
|
||||
public int getBufferSize() throws IOException;
|
||||
|
||||
@Override
|
||||
public int getIndexCount() throws IOException;
|
||||
|
||||
@Override
|
||||
public int[] getFreeIndexes() throws IOException;
|
||||
|
||||
@Override
|
||||
public void setFreeIndexes(int[] indexes) throws IOException;
|
||||
|
||||
@Override
|
||||
public void close() throws IOException;
|
||||
|
||||
@Override
|
||||
public boolean delete() throws IOException;
|
||||
|
||||
@Override
|
||||
public DataBuffer get(int index) throws IOException;
|
||||
|
||||
@Override
|
||||
public void put(DataBuffer buf, int index) throws IOException;
|
||||
|
||||
@Override
|
||||
public void dispose() throws IOException;
|
||||
|
||||
@Override
|
||||
public InputBlockStream getInputBlockStream() throws IOException;
|
||||
|
||||
@Override
|
||||
public OutputBlockStream getOutputBlockStream(int blockCount) throws IOException;
|
||||
|
||||
@Override
|
||||
public BlockStreamHandle<InputBlockStream> getInputBlockStreamHandle() throws IOException;
|
||||
|
||||
@Override
|
||||
public BlockStreamHandle<OutputBlockStream> getOutputBlockStreamHandle(int blockCount)
|
||||
throws IOException;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// ManagedBufferFileHandle methods
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ManagedBufferFileHandle getSaveFile() throws IOException;
|
||||
|
||||
@Override
|
||||
public void saveCompleted(boolean commit) throws IOException;
|
||||
|
||||
@Override
|
||||
public boolean canSave() throws IOException;
|
||||
|
||||
@Override
|
||||
public void setVersionComment(String comment) throws IOException;
|
||||
|
||||
@Override
|
||||
public BufferFileHandle getNextChangeDataFile(boolean getFirst) throws IOException;
|
||||
|
||||
@Override
|
||||
public BufferFileHandle getSaveChangeDataFile() throws IOException;
|
||||
|
||||
@Override
|
||||
public long getCheckinID() throws IOException;
|
||||
|
||||
@Override
|
||||
public byte[] getForwardModMapData(int oldVersion) throws IOException;
|
||||
|
||||
@Override
|
||||
public InputBlockStream getInputBlockStream(byte[] changeMapData) throws IOException;
|
||||
|
||||
@Override
|
||||
public BlockStreamHandle<InputBlockStream> getInputBlockStreamHandle(byte[] changeMapData)
|
||||
throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -1854,20 +1854,16 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
// as message dialogs will too be closed
|
||||
DockingDialog d = (DockingDialog) activeWindow;
|
||||
Window ancestor = SwingUtilities.getWindowAncestor(d);
|
||||
if (!d.isShowing()) {
|
||||
if (!ancestor.isShowing()) {
|
||||
return null;
|
||||
}
|
||||
if (d.isShowing() && isNonTransientWindow(d)) {
|
||||
return d;
|
||||
}
|
||||
|
||||
// The active window is not a suitable parent; try its parent
|
||||
if (ancestor.isShowing() && isNonTransientWindow(ancestor)) {
|
||||
return ancestor;
|
||||
}
|
||||
|
||||
DialogComponentProvider provider = d.getComponent();
|
||||
if (provider.isTransient()) {
|
||||
return ancestor;
|
||||
}
|
||||
|
||||
return d;
|
||||
return null;
|
||||
}
|
||||
|
||||
public ComponentProvider getActiveComponentProvider() {
|
||||
|
|
|
@ -41,8 +41,15 @@ import resources.ResourceManager;
|
|||
*
|
||||
* @param <T> The type of DockingAction to build
|
||||
* @param <B> the Type of action builder
|
||||
* @param <C> The type of ActionContext. By default, the ActionContext type always starts as
|
||||
* the base ActionContext class. If the client calls the {@link #withContext(Class)} method on
|
||||
* the builder, then that class (which must be a subclass of ActionContext) becomes the ActionContext
|
||||
* type that will be used for future calls to the builder methods that take predicates with
|
||||
* ActionContext (i.e. {@link #enabledWhen(Predicate)} and {@link #validContextWhen(Predicate)}.
|
||||
* This works by substituting a builder with a different ActionContext type when chaining after
|
||||
* the {@link #withContext(Class)} call.
|
||||
*/
|
||||
public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends AbstractActionBuilder<T, B>> {
|
||||
public abstract class AbstractActionBuilder<T extends DockingActionIf, C extends ActionContext, B extends AbstractActionBuilder<T, C, B>> {
|
||||
|
||||
/**
|
||||
* Name for the {@code DockingAction}
|
||||
|
@ -54,6 +61,11 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
*/
|
||||
protected String owner;
|
||||
|
||||
/**
|
||||
* Specifies the type of ActionContext that the built action works on.
|
||||
*/
|
||||
protected Class<? extends ActionContext> actionContextClass;
|
||||
|
||||
/**
|
||||
* The {@code KeyBindingType} for this {@code DockingAction}
|
||||
*/
|
||||
|
@ -62,7 +74,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
/**
|
||||
* The callback to perform when the action is invoked
|
||||
*/
|
||||
protected Consumer<ActionContext> actionCallback;
|
||||
protected Consumer<C> actionCallback;
|
||||
|
||||
/**
|
||||
* Description for the {@code DockingAction}. (optional)
|
||||
|
@ -147,17 +159,17 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
/**
|
||||
* Predicate for determining if an action is enabled for a given context
|
||||
*/
|
||||
private Predicate<ActionContext> enabledPredicate;
|
||||
private Predicate<C> enabledPredicate;
|
||||
|
||||
/**
|
||||
* Predicate for determining if an action should be included on the pop-up menu
|
||||
*/
|
||||
private Predicate<ActionContext> popupPredicate;
|
||||
private Predicate<C> popupPredicate;
|
||||
|
||||
/**
|
||||
* Predicate for determining if an action is applicable for a given context
|
||||
*/
|
||||
private Predicate<ActionContext> validContextPredicate;
|
||||
private Predicate<C> validContextPredicate;
|
||||
|
||||
/**
|
||||
* Builder constructor
|
||||
|
@ -167,6 +179,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
public AbstractActionBuilder(String name, String owner) {
|
||||
this.name = name;
|
||||
this.owner = owner;
|
||||
this.actionContextClass = ActionContext.class;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -370,7 +383,8 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
* @see #popupMenuGroup(String)
|
||||
*/
|
||||
public B popupMenuGroup(String group, String subGroup) {
|
||||
popupSubGroup = group;
|
||||
popupGroup = group;
|
||||
popupSubGroup = subGroup;
|
||||
return self();
|
||||
}
|
||||
|
||||
|
@ -446,7 +460,8 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
* @see #toolBarGroup(String)
|
||||
*/
|
||||
public B toolBarGroup(String group, String subGroup) {
|
||||
toolBarSubGroup = group;
|
||||
toolBarGroup = group;
|
||||
toolBarSubGroup = subGroup;
|
||||
return self();
|
||||
}
|
||||
|
||||
|
@ -484,7 +499,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
* @param action the callback to execute when the action is invoked
|
||||
* @return this builder (for chaining)
|
||||
*/
|
||||
public B onAction(Consumer<ActionContext> action) {
|
||||
public B onAction(Consumer<C> action) {
|
||||
actionCallback = action;
|
||||
return self();
|
||||
}
|
||||
|
@ -501,7 +516,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
* enabled state
|
||||
* @return this builder (for chaining)
|
||||
*/
|
||||
public B enabledWhen(Predicate<ActionContext> predicate) {
|
||||
public B enabledWhen(Predicate<C> predicate) {
|
||||
enabledPredicate = predicate;
|
||||
return self();
|
||||
}
|
||||
|
@ -524,7 +539,7 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
* @return this builder (for chaining)
|
||||
* @see #popupMenuPath(String...)
|
||||
*/
|
||||
public B popupWhen(Predicate<ActionContext> predicate) {
|
||||
public B popupWhen(Predicate<C> predicate) {
|
||||
popupPredicate = predicate;
|
||||
return self();
|
||||
}
|
||||
|
@ -540,11 +555,68 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
* validity for a given {@link ActionContext}
|
||||
* @return this builder (for chaining)
|
||||
*/
|
||||
public B validContextWhen(Predicate<ActionContext> predicate) {
|
||||
public B validContextWhen(Predicate<C> predicate) {
|
||||
validContextPredicate = predicate;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specific ActionContext type to use for the various predicate calls
|
||||
* ({@link #validContextWhen(Predicate)}, {@link #enabledWhen(Predicate)}, and
|
||||
* {@link #popupWhen(Predicate)}).
|
||||
* <P>
|
||||
* In other words, this allows the client to specify the type of ActionContext that is valid for
|
||||
* the action being built.
|
||||
* <P>
|
||||
* To be effective, this method must be called <b>before</b> setting any of the predicates
|
||||
* such as the {@link #enabledWhen(Predicate)}. Once this method is called you can define your
|
||||
* predicates using the more specific ActionContext and be assured your predicates will only
|
||||
* be called when the current action context is the type (or sub-type) of the context you have
|
||||
* specified here.
|
||||
* <P>
|
||||
* For example, assume you have an action that is only enabled when the context is of type
|
||||
* FooActionContext. If you don't call this method to set the ActionContext type, you would have
|
||||
* to write your predicate something like this:
|
||||
* <pre>
|
||||
* builder.enabledWhen(context -> {
|
||||
* if (!(context instanceof FooContext)) {
|
||||
* return false;
|
||||
* }
|
||||
* return ((FooContext) context).isAwesome();
|
||||
* });
|
||||
* </pre>
|
||||
* But by first calling the builder method <CODE>withContext(FooContext.class)</CODE>, you can
|
||||
* simply write:
|
||||
*
|
||||
* <pre>
|
||||
* builder.enabledWhen(context -> return context.isAwesome() }
|
||||
* </pre>
|
||||
*
|
||||
* @param newActionContextClass the more specific ActionContext type.
|
||||
* @param <AC2> The new ActionContext type (as determined by the newActionContextClass) that
|
||||
* the returned builder will have.
|
||||
* @param <B2> the new builder type.
|
||||
* @return an ActionBuilder whose generic types have been modified to match the new ActionContext.
|
||||
* It still contains all the configuration that has been applied so far.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <AC2 extends ActionContext, B2 extends AbstractActionBuilder<T, AC2, B2>> B2 withContext(
|
||||
Class<AC2> newActionContextClass) {
|
||||
|
||||
// To make this work, we need to return a builder whose ActionContext is AC2 and not AC
|
||||
// (which is what this builder is now)
|
||||
//
|
||||
// Since we "know" that the only thing that matters regarding the ActionContext type is that
|
||||
// the template type (AC) must match the type of actionContextClass instance variable, we
|
||||
// can get away with returning this same builder and casting it to be a builder with type
|
||||
// AC2 instead of AC. We can do this since we set the actionContextClass below
|
||||
|
||||
actionContextClass = newActionContextClass;
|
||||
|
||||
B2 newSelf = (B2) self();
|
||||
return newSelf;
|
||||
}
|
||||
|
||||
protected void validate() {
|
||||
if (actionCallback == null) {
|
||||
throw new IllegalStateException(
|
||||
|
@ -566,16 +638,36 @@ public abstract class AbstractActionBuilder<T extends DockingActionIf, B extends
|
|||
}
|
||||
|
||||
if (enabledPredicate != null) {
|
||||
action.enabledWhen(enabledPredicate);
|
||||
action.enabledWhen(adaptPredicate(enabledPredicate));
|
||||
}
|
||||
if (validContextPredicate != null) {
|
||||
action.validContextWhen(validContextPredicate);
|
||||
action.validContextWhen(adaptPredicate(validContextPredicate));
|
||||
}
|
||||
if (popupPredicate != null) {
|
||||
action.popupWhen(enabledPredicate);
|
||||
action.popupWhen(adaptPredicate(popupPredicate));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Since the built action will need a predicate that handles any action type, this method
|
||||
* creates a predicate that adapts a user supplied predicate for a more specific ActionContext
|
||||
* to a general predicate that can accept any ActionContext.
|
||||
* @param predicate the client supplied predicate that expects a more specific ActionContext
|
||||
* @return a predicate that can handle any ActionContext
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Predicate<ActionContext> adaptPredicate(Predicate<C> predicate) {
|
||||
if (actionContextClass == ActionContext.class) {
|
||||
// don't wrap the predicate if it doesn't need it
|
||||
return (Predicate<ActionContext>) predicate;
|
||||
}
|
||||
// Convert a sub-classed ActionContext predicate to a plain ActionContext predicate
|
||||
Predicate<ActionContext> predicateAdapter = (ac) -> {
|
||||
return actionContextClass.isInstance(ac) && predicate.test((C) ac);
|
||||
};
|
||||
return predicateAdapter;
|
||||
}
|
||||
|
||||
protected boolean isPopupAction() {
|
||||
return popupPath != null;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import docking.action.DockingAction;
|
|||
* Builder for {@link DockingAction}s
|
||||
*/
|
||||
public class ActionBuilder
|
||||
extends AbstractActionBuilder<DockingAction, ActionBuilder> {
|
||||
extends AbstractActionBuilder<DockingAction, ActionContext, ActionBuilder> {
|
||||
|
||||
/**
|
||||
* Builder constructor
|
||||
|
|
|
@ -26,7 +26,7 @@ import docking.menu.MultiActionDockingAction;
|
|||
* Builder for {@link MultiActionDockingAction}
|
||||
*/
|
||||
public class MultiActionBuilder
|
||||
extends AbstractActionBuilder<MultiActionDockingAction, MultiActionBuilder> {
|
||||
extends AbstractActionBuilder<MultiActionDockingAction, ActionContext, MultiActionBuilder> {
|
||||
/**
|
||||
* List of actions for the the MultActionDockingAction
|
||||
*/
|
||||
|
|
|
@ -27,7 +27,7 @@ import docking.widgets.EventTrigger;
|
|||
* @param <T> The action state type
|
||||
*/
|
||||
public class MultiStateActionBuilder<T> extends
|
||||
AbstractActionBuilder<MultiStateDockingAction<T>, MultiStateActionBuilder<T>> {
|
||||
AbstractActionBuilder<MultiStateDockingAction<T>, ActionContext, MultiStateActionBuilder<T>> {
|
||||
|
||||
private BiConsumer<ActionState<T>, EventTrigger> actionStateChangedCallback;
|
||||
private boolean performActionOnButtonClick;
|
||||
|
@ -77,7 +77,7 @@ public class MultiStateActionBuilder<T> extends
|
|||
public MultiStateDockingAction<T> build() {
|
||||
validate();
|
||||
MultiStateDockingAction<T> action =
|
||||
new MultiStateDockingAction<T>(name, owner, isToolbarAction()) {
|
||||
new MultiStateDockingAction<>(name, owner, isToolbarAction()) {
|
||||
|
||||
@Override
|
||||
public void actionStateChanged(ActionState<T> newActionState,
|
||||
|
|
|
@ -21,7 +21,7 @@ import docking.action.ToggleDockingAction;
|
|||
* Builder for {@link ToggleDockingAction}s
|
||||
*/
|
||||
public class ToggleActionBuilder extends
|
||||
AbstractActionBuilder<ToggleDockingAction, ToggleActionBuilder> {
|
||||
AbstractActionBuilder<ToggleDockingAction, ActionContext, ToggleActionBuilder> {
|
||||
|
||||
/**
|
||||
* The initial toggle state for the action
|
||||
|
|
|
@ -190,10 +190,23 @@ public abstract class AbstractSortedTableModel<T> extends AbstractGTableModel<T>
|
|||
return pendingSortState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is a pending change to the current sort state
|
||||
* (this includes a sort state that signals no sort will be applied)
|
||||
*
|
||||
* @return true if there is a pending change to the current sort state
|
||||
*/
|
||||
public boolean isSortPending() {
|
||||
return isSortPending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this model has been sorted and does not have a new pending sort that will
|
||||
* be applied
|
||||
*
|
||||
* @return true if sorted
|
||||
* @see #isSortPending()
|
||||
*/
|
||||
public boolean isSorted() {
|
||||
return !isSortPending && !sortState.isUnsorted();
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ public class DefaultRowFilterTransformer<ROW_OBJECT> implements RowFilterTransfo
|
|||
}
|
||||
|
||||
ColumnConstraintFilterMode mode = renderer.getColumnConstraintFilterMode();
|
||||
return mode == ColumnConstraintFilterMode.USE_COLUMN_CONSTRAINTS_ONLY;
|
||||
return mode == ColumnConstraintFilterMode.ALLOW_CONSTRAINTS_FILTER_ONLY;
|
||||
}
|
||||
|
||||
private String getRenderedColumnValue(Object columnValue, int columnIndex) {
|
||||
|
|
|
@ -196,7 +196,7 @@ public class GTableHeader extends JTableHeader {
|
|||
|
||||
int realIndex = gTable.convertColumnIndexToModel(columnIndex);
|
||||
|
||||
String columnFilterToolTip = getColumnFilterToolTip(model, columnIndex);
|
||||
String columnFilterToolTip = getColumnFilterToolTip(model, realIndex);
|
||||
VariableColumnTableModel variableModel = VariableColumnTableModel.from(model);
|
||||
if (variableModel != null) {
|
||||
String description = variableModel.getColumnDescription(realIndex);
|
||||
|
|
|
@ -22,11 +22,11 @@ import ghidra.util.SystemUtilities;
|
|||
/**
|
||||
* Class that maps one type of column constraint into another. Typically, these are created
|
||||
* automatically based on {@link ColumnTypeMapper} that are discovered by the system. For example,
|
||||
*{@literal if you have a column type of "Foo", and you create a ColumnTypeMapper<Foo, String>, then all the}
|
||||
* string constraints would now be available that column.
|
||||
* {@literal if you have a column type of "Foo", and you create a ColumnTypeMapper<Foo, String>,
|
||||
* then all the} string constraints would now be available that column.
|
||||
*
|
||||
* @param <T> The column type.
|
||||
* @param <M> the converted (mapped) type.
|
||||
* @param <T> The column type
|
||||
* @param <M> the converted (mapped) type
|
||||
*/
|
||||
public class MappedColumnConstraint<T, M> implements ColumnConstraint<T> {
|
||||
|
||||
|
|
|
@ -27,10 +27,14 @@ import ghidra.util.table.column.GColumnRenderer;
|
|||
import ghidra.util.table.column.GColumnRenderer.ColumnConstraintFilterMode;
|
||||
|
||||
/**
|
||||
* Class for maintaining information about a table's column for the purpose of configuring filters
|
||||
* based on that columns values. These are generated by examining a table's column types and finding
|
||||
* out if there are any ColumnConstraints that support that type. If so, a ColumnFilterData is
|
||||
* created for that column which then allows filtering on that columns data.
|
||||
* This class provides all known {@link ColumnConstraint}s for a given table column.
|
||||
*
|
||||
* <P>Class for maintaining information about a particular table's column for the purpose of
|
||||
* configuring filters based on that column's values. Instances of this class are generated
|
||||
* by examining a table's column types and finding any {@link ColumnConstraint}s that support
|
||||
* that type. If column constraints are found, a {@link ColumnFilterData} is created for that column
|
||||
* which then allows filtering on that columns data via the column constraints mechanism (which
|
||||
* is different than the traditional text filter).
|
||||
*
|
||||
* @param <T> the column type.
|
||||
*/
|
||||
|
@ -61,12 +65,20 @@ public class ColumnFilterData<T> implements Comparable<ColumnFilterData<T>> {
|
|||
private List<ColumnConstraint<T>> initializeConstraints(RowObjectFilterModel<?> model,
|
||||
Class<T> columnClass) {
|
||||
|
||||
//
|
||||
// Case 1: the column is not dynamic and thus has no way of overriding the column
|
||||
// constraint filtering mechanism.
|
||||
//
|
||||
Collection<ColumnConstraint<T>> defaultConstraints =
|
||||
DiscoverableTableUtils.getColumnConstraints(columnClass);
|
||||
if (!(model instanceof DynamicColumnTableModel)) {
|
||||
return new ArrayList<>(defaultConstraints);
|
||||
}
|
||||
|
||||
//
|
||||
// Case 2: the column is dynamic, but does not supply a specialized column renderer,
|
||||
// which is the means for overriding the column constraint filtering mechanism.
|
||||
//
|
||||
DynamicColumnTableModel<?> columnBasedModel = (DynamicColumnTableModel<?>) model;
|
||||
DynamicTableColumn<?, ?, ?> column = columnBasedModel.getColumn(modelIndex);
|
||||
GColumnRenderer<?> columnRenderer = column.getColumnRenderer();
|
||||
|
@ -74,24 +86,36 @@ public class ColumnFilterData<T> implements Comparable<ColumnFilterData<T>> {
|
|||
return new ArrayList<>(defaultConstraints);
|
||||
}
|
||||
|
||||
//
|
||||
// Case 3: the column renderer has signaled that it uses only column constraint filtering
|
||||
// and does not support the traditional text based filtering.
|
||||
//
|
||||
ColumnConstraintFilterMode mode = columnRenderer.getColumnConstraintFilterMode();
|
||||
if (mode == ColumnConstraintFilterMode.USE_COLUMN_CONSTRAINTS_ONLY) {
|
||||
if (mode == ColumnConstraintFilterMode.ALLOW_CONSTRAINTS_FILTER_ONLY) {
|
||||
return new ArrayList<>(defaultConstraints);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
//
|
||||
// Case 4: the column supports text filtering. Find any column constraints for the
|
||||
// column's type. Then, create string-based constraints that will filter on
|
||||
// the column's conversion from its type to a string (via
|
||||
// GColumnRenderer.getFilterString()).
|
||||
//
|
||||
@SuppressWarnings("unchecked") // See type note on the class below
|
||||
GColumnRenderer<T> asT = (GColumnRenderer<T>) columnRenderer;
|
||||
ColumnRendererMapper mapper = new ColumnRendererMapper(asT, columnBasedModel, modelIndex);
|
||||
Collection<ColumnConstraint<T>> rendererStringConstraints =
|
||||
DiscoverableTableUtils.getColumnConstraints(mapper);
|
||||
|
||||
List<ColumnConstraint<T>> results = new ArrayList<>(rendererStringConstraints);
|
||||
|
||||
if (mode == ColumnConstraintFilterMode.USE_BOTH_COLUMN_RENDERER_FITLER_STRING_AND_CONSTRAINTS) {
|
||||
// also use the normal constraints with the renderer constraints
|
||||
results.addAll(defaultConstraints);
|
||||
if (mode == ColumnConstraintFilterMode.ALLOW_RENDERER_STRING_FILTER_ONLY) {
|
||||
return new ArrayList<>(rendererStringConstraints);
|
||||
}
|
||||
|
||||
//
|
||||
// Case 5: the renderer supports both text filtering and column constraint filtering.
|
||||
//
|
||||
// assume: mode == ColumnConstraintFilterMode.ALLOW_ALL_FILTERS
|
||||
List<ColumnConstraint<T>> results = new ArrayList<>(rendererStringConstraints);
|
||||
results.addAll(defaultConstraints);
|
||||
return results;
|
||||
}
|
||||
|
||||
|
@ -213,6 +237,13 @@ public class ColumnFilterData<T> implements Comparable<ColumnFilterData<T>> {
|
|||
* This class allows us to turn client columns of type <code>T</code> to a String. We use
|
||||
* the renderer provided at construction time to generate a filter string when
|
||||
* {@link #convert(Object)} is called.
|
||||
*
|
||||
* <P>Implementation Note: the type 'T' here is used to satisfy the external client's
|
||||
* expected list of constraints. We will not be able to identify 'T' at runtime. Rather,
|
||||
* our parent's {@link #getSourceType()} will simply be {@link Object}. This is fine, as
|
||||
* this particular class will not have {@link #getSourceType()} called, due to how we
|
||||
* are using it. (Normally, the source type is used to find compatible constraints; we
|
||||
* are not using the discovery mechanism with this private class.)
|
||||
*/
|
||||
private class ColumnRendererMapper extends ColumnTypeMapper<T, String> {
|
||||
|
||||
|
@ -229,14 +260,13 @@ public class ColumnFilterData<T> implements Comparable<ColumnFilterData<T>> {
|
|||
|
||||
@Override
|
||||
public String convert(T value) {
|
||||
Settings settings = model.getColumnSettings(columnModelIndex);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
Settings settings = model.getColumnSettings(columnModelIndex);
|
||||
String s = renderer.getFilterString(value, settings);
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -102,9 +102,9 @@ public class ColumnFilterDialogModel<R> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a new filter fow (a new major row in the dialog filter panel)
|
||||
* @param logicOperation the logical operation for how this row interacts with the rows before it
|
||||
* @return the new filter row that represents a major row in the dialog filter panel.
|
||||
* Creates a new filter row (a new major row in the dialog filter panel)
|
||||
* @param logicOperation the logical operation for how this row interacts with preceding rows
|
||||
* @return the new filter row that represents a major row in the dialog filter panel
|
||||
*/
|
||||
public DialogFilterRow createFilterRow(LogicOperation logicOperation) {
|
||||
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
*/
|
||||
package docking.widgets.table.sort;
|
||||
|
||||
import static ghidra.util.table.column.GColumnRenderer.ColumnConstraintFilterMode.*;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import docking.widgets.table.*;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.util.table.column.GColumnRenderer;
|
||||
import ghidra.util.table.column.GColumnRenderer.ColumnConstraintFilterMode;
|
||||
|
||||
/**
|
||||
* A special version of the backup comparator that uses the column's rendered value for
|
||||
|
@ -47,7 +48,7 @@ public class ColumnRenderedValueBackupComparator<T> implements Comparator<Object
|
|||
@SuppressWarnings("unchecked")
|
||||
GColumnRenderer<Object> renderer = (GColumnRenderer<Object>) column.getColumnRenderer();
|
||||
if (renderer != null) {
|
||||
if (renderer.getColumnConstraintFilterMode() == ColumnConstraintFilterMode.USE_COLUMN_CONSTRAINTS_ONLY) {
|
||||
if (renderer.getColumnConstraintFilterMode() == ALLOW_CONSTRAINTS_FILTER_ONLY) {
|
||||
// this implies that the column has signaled that it does not support
|
||||
// filtering/sorting using its rendered value
|
||||
supportsColumnSorting = false;
|
||||
|
|
|
@ -74,9 +74,9 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
|
|||
* This variable can be in one of three states:
|
||||
* <ul>
|
||||
* <li>null - signals that there is no filter change taking place</li>
|
||||
* <li>An instance of <code>NullTableFitler</code> - the client has removed the current
|
||||
* <li>An instance of <code>NullTableFilter</code> - the client has removed the current
|
||||
* filter by calling {@link #setTableFilter(TableFilter)} with a null value</li>
|
||||
* <li>An instance of a custom <code>TableFitler</code> - the client has changed the
|
||||
* <li>An instance of a custom <code>TableFilter</code> - the client has changed the
|
||||
* filter to a non-null value by calling {@link #setTableFilter(TableFilter)}</li>
|
||||
* </ul>
|
||||
*/
|
||||
|
@ -399,7 +399,7 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
|
|||
*
|
||||
* @return true if there is a table filter set.
|
||||
*/
|
||||
public boolean hasFitler() {
|
||||
public boolean hasFilter() {
|
||||
TableFilter<ROW_OBJECT> currentFilter = getTableFilter();
|
||||
return !currentFilter.isEmpty();
|
||||
}
|
||||
|
@ -429,7 +429,7 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
|
|||
return data;
|
||||
}
|
||||
|
||||
if (!hasFitler()) {
|
||||
if (!hasFilter()) {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -463,14 +463,14 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the given <code>TableFitler</code> on this model. This table filter will then be used
|
||||
* Sets the given <code>TableFilter</code> on this model. This table filter will then be used
|
||||
* by this model in the default {@link #doFilter(List, TableSortingContext, TaskMonitor)}
|
||||
* method.
|
||||
* @param tableFitler The filter to use for table filtering.
|
||||
* @param tableFilter The filter to use for table filtering.
|
||||
*/
|
||||
@Override
|
||||
public void setTableFilter(TableFilter<ROW_OBJECT> tableFitler) {
|
||||
this.pendingTableFilter = tableFitler;
|
||||
public void setTableFilter(TableFilter<ROW_OBJECT> tableFilter) {
|
||||
this.pendingTableFilter = tableFilter;
|
||||
if (pendingTableFilter == null) {
|
||||
// Don't allow the pending filter to be null in this case. The client has changed
|
||||
// the filter. If we use null, then we don't know the difference between a client
|
||||
|
@ -480,8 +480,8 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
|
|||
reFilter();
|
||||
}
|
||||
|
||||
private void setAppliedTableFitler(TableFilter<ROW_OBJECT> tableFitler) {
|
||||
if (tableFitler == null) {
|
||||
private void setAppliedTableFilter(TableFilter<ROW_OBJECT> tableFilter) {
|
||||
if (tableFilter == null) {
|
||||
// null means there was no change to the text filter--so don't set it (see the
|
||||
// javadoc for the filter variables)
|
||||
return;
|
||||
|
@ -532,7 +532,7 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
|
|||
this.allData = allData;
|
||||
this.filteredData = filteredData;
|
||||
|
||||
setAppliedTableFitler(pendingTableFilter);
|
||||
setAppliedTableFilter(pendingTableFilter);
|
||||
pendingSortContext = null;
|
||||
|
||||
TableSortingContext<ROW_OBJECT> newSortingContext = filteredData.getSortContext();
|
||||
|
|
|
@ -36,7 +36,7 @@ public interface AbstractWrapperTypeColumnRenderer<T> extends GColumnRenderer<T>
|
|||
// Overridden to only allow the constraint filtering mechanism.
|
||||
@Override
|
||||
public default ColumnConstraintFilterMode getColumnConstraintFilterMode() {
|
||||
return ColumnConstraintFilterMode.USE_COLUMN_CONSTRAINTS_ONLY;
|
||||
return ColumnConstraintFilterMode.ALLOW_CONSTRAINTS_FILTER_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,12 +36,12 @@ import ghidra.util.exception.AssertException;
|
|||
* columns. The specifics of how the text filter works are defined by the
|
||||
* {@link RowFilterTransformer}, which is controlled by the user via the button at the right
|
||||
* of the filter field. (In the absence of this button, filters are typically a 'contains'
|
||||
* filter.
|
||||
* filter.)
|
||||
*
|
||||
* <P>The default transformer turns items to strings by, in order,:
|
||||
* <OL>
|
||||
* <LI>checking the the renderer's {@link #getFilterString(Object, Settings)},
|
||||
* if a renderer is installed
|
||||
* <LI>checking the the <b>column</b> renderer's
|
||||
* {@link #getFilterString(Object, Settings)},if a column renderer is installed
|
||||
* </LI>
|
||||
* <LI>checking to see if the column value is an instance of {@link DisplayStringProvider}
|
||||
* </LI>
|
||||
|
@ -68,6 +68,10 @@ import ghidra.util.exception.AssertException;
|
|||
* </LI>
|
||||
* </OL>
|
||||
*
|
||||
* <P><B>Note: The default filtering behavior of this class is to only filter on the aforementioned
|
||||
* filter text field. That is, column constraints will not be enabled by default. To
|
||||
* change this, change the value returned by {@link #getColumnConstraintFilterMode()}.</B>
|
||||
*
|
||||
* @param <T> the column type
|
||||
*/
|
||||
public interface GColumnRenderer<T> extends TableCellRenderer {
|
||||
|
@ -79,21 +83,14 @@ public interface GColumnRenderer<T> extends TableCellRenderer {
|
|||
public enum ColumnConstraintFilterMode {
|
||||
//@formatter:off
|
||||
|
||||
/**
|
||||
* Signals that the programmer didn't make a decision about how filtering for this
|
||||
* column should work. This currently will treat all filtering as if
|
||||
* {@link #USE_COLUMN_RENDERER_FITLER_STRING_ONLY} was chosen.
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/** Use only {@link GColumnRenderer#getFilterString(Object, Settings)} value; no constraints */
|
||||
USE_COLUMN_RENDERER_FITLER_STRING_ONLY,
|
||||
ALLOW_RENDERER_STRING_FILTER_ONLY,
|
||||
|
||||
/** Use only column constraints when filtering */
|
||||
USE_COLUMN_CONSTRAINTS_ONLY,
|
||||
ALLOW_CONSTRAINTS_FILTER_ONLY,
|
||||
|
||||
/** Use both the rendered filter String and any found column constraints */
|
||||
USE_BOTH_COLUMN_RENDERER_FITLER_STRING_AND_CONSTRAINTS,
|
||||
ALLOW_ALL_FILTERS,
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
|
@ -107,7 +104,7 @@ public interface GColumnRenderer<T> extends TableCellRenderer {
|
|||
* @return the mode
|
||||
*/
|
||||
public default ColumnConstraintFilterMode getColumnConstraintFilterMode() {
|
||||
return ColumnConstraintFilterMode.DEFAULT;
|
||||
return ColumnConstraintFilterMode.ALLOW_RENDERER_STRING_FILTER_ONLY;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1747,14 +1747,23 @@ public class GhidraFileChooserTest extends AbstractDockingTest {
|
|||
public void testHistoryRestoresSelectedFiles() throws Exception {
|
||||
|
||||
File startDir = createTempDir();
|
||||
setDir(startDir);
|
||||
createFileSubFile(startDir, 3);
|
||||
File subDir = createFileSubFile(startDir, 3);
|
||||
setDir(subDir);
|
||||
|
||||
// // debug
|
||||
// DirectoryList list = getListView();
|
||||
// ListSelectionModel sm = list.getSelectionModel();
|
||||
// sm.addListSelectionListener(e -> {
|
||||
// Msg.debug(this, "selection changed: " + e);
|
||||
// });
|
||||
|
||||
pressUp();
|
||||
selectFile(getListView(), 1);
|
||||
assertSelectedIndex(getListView(), 1);
|
||||
|
||||
pressUp();
|
||||
selectFile(getListView(), 2);
|
||||
assertSelectedIndex(getListView(), 2);
|
||||
|
||||
pressBack();
|
||||
assertSelectedIndex(getListView(), 1);
|
||||
|
@ -1914,7 +1923,12 @@ public class GhidraFileChooserTest extends AbstractDockingTest {
|
|||
|
||||
private void assertSelectedIndex(DirectoryList list, int expected) {
|
||||
int actual = runSwing(() -> list.getSelectedIndex());
|
||||
assertEquals("Wrong list index selected", expected, actual);
|
||||
|
||||
// debug code
|
||||
if (expected != actual) {
|
||||
waitForCondition(() -> expected == actual,
|
||||
"Wrong list index selected ");
|
||||
}
|
||||
}
|
||||
|
||||
private void assertSelectedIndex(GTable table, int expected) {
|
||||
|
@ -1923,6 +1937,11 @@ public class GhidraFileChooserTest extends AbstractDockingTest {
|
|||
}
|
||||
|
||||
private File selectFile(DirectoryList list, int index) {
|
||||
|
||||
// TODO debug - remove when all tests passing on server
|
||||
int size = list.getModel().getSize();
|
||||
Msg.debug(this, "selectFile() - new index: " + index + "; list size: " + size);
|
||||
|
||||
runSwing(() -> list.setSelectedIndex(index));
|
||||
return runSwing(() -> list.getSelectedFile());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
/* ###
|
||||
* 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 docking.action;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import resources.Icons;
|
||||
|
||||
public class ActionBuilderTest {
|
||||
private int actionCount = 0;
|
||||
|
||||
|
||||
@Test
|
||||
public void testDescription() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.description("foo")
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
assertEquals("foo", action.getDescription());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMenuPath() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.menuPath("foo", "bar")
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
MenuData data = action.getMenuBarData();
|
||||
assertEquals("foo->bar", data.getMenuPathAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMenuGroup() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.menuPath("foo", "bar")
|
||||
.menuGroup("A", "B")
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
MenuData data = action.getMenuBarData();
|
||||
assertEquals("A", data.getMenuGroup());
|
||||
assertEquals("B", data.getMenuSubGroup());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMenuIcon() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.menuPath("foo", "bar")
|
||||
.menuIcon(Icons.ADD_ICON)
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
MenuData data = action.getMenuBarData();
|
||||
assertEquals(Icons.ADD_ICON, data.getMenuIcon());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMenuMnemonic() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.menuPath("foo", "bar")
|
||||
.menuMnemonic(5)
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
MenuData data = action.getMenuBarData();
|
||||
assertEquals(5, data.getMnemonic());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopupPath() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.popupMenuPath("foo", "bar")
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
MenuData data = action.getPopupMenuData();
|
||||
assertEquals("foo->bar", data.getMenuPathAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopupGroup() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.popupMenuPath("foo", "bar")
|
||||
.popupMenuGroup("A", "B")
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
MenuData data = action.getPopupMenuData();
|
||||
assertEquals("A", data.getMenuGroup());
|
||||
assertEquals("B", data.getMenuSubGroup());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopupIcon() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.popupMenuPath("foo", "bar")
|
||||
.popupMenuIcon(Icons.ADD_ICON)
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
MenuData data = action.getPopupMenuData();
|
||||
assertEquals(Icons.ADD_ICON, data.getMenuIcon());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToolbarIcon() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.toolBarIcon(Icons.ADD_ICON)
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
ToolBarData data = action.getToolBarData();
|
||||
assertEquals(Icons.ADD_ICON, data.getIcon());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToolbarGroup() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.toolBarIcon(Icons.ADD_ICON)
|
||||
.toolBarGroup("A", "B")
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
ToolBarData data = action.getToolBarData();
|
||||
assertEquals("A", data.getToolBarGroup());
|
||||
assertEquals("B", data.getToolBarSubGroup());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyBindingKeyStroke() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.keyBinding(KeyStroke.getKeyStroke("A"))
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
assertEquals(KeyStroke.getKeyStroke("A"), action.getKeyBinding());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyBindingKeyString() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.keyBinding("ALT A")
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
assertEquals(KeyStroke.getKeyStroke("ALT A"), action.getKeyBinding());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnAction() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.onAction(e -> actionCount = 6)
|
||||
.build();
|
||||
|
||||
assertEquals(0, actionCount);
|
||||
action.actionPerformed(new ActionContext());
|
||||
assertEquals(6, actionCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnabled() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.enabled(true)
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
assertTrue(action.isEnabled());
|
||||
|
||||
action = new ActionBuilder("Test", "Test")
|
||||
.enabled(false)
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
assertFalse(action.isEnabled());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnabledWhen() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.enabledWhen(c -> c.getContextObject() == this)
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
assertTrue(action.isEnabledForContext(new ActionContext(null, this, null)));
|
||||
assertFalse(action.isEnabledForContext(new ActionContext()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidContextWhen() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.validContextWhen(c -> c.getContextObject() == this)
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
assertTrue(action.isValidContext(new ActionContext(null, this, null)));
|
||||
assertFalse(action.isValidContext(new ActionContext()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPopupWhen() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.popupWhen(c -> c.getContextObject() == this)
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
assertTrue(action.isAddToPopup(new ActionContext(null, this, null)));
|
||||
assertFalse(action.isAddToPopup(new ActionContext()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithContext() {
|
||||
DockingAction action = new ActionBuilder("Test", "Test")
|
||||
.withContext(FooActionContext.class)
|
||||
.enabledWhen(c -> c.foo())
|
||||
.onAction(e -> actionCount++)
|
||||
.build();
|
||||
|
||||
assertFalse(action.isEnabledForContext(new ActionContext()));
|
||||
assertTrue(action.isEnabledForContext(new FooActionContext()));
|
||||
}
|
||||
|
||||
static class FooActionContext extends ActionContext {
|
||||
public boolean foo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -15,11 +15,121 @@
|
|||
*/
|
||||
package ghidra.framework.remote;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.server.RemoteObjectInvocationHandler;
|
||||
|
||||
import db.buffers.ManagedBufferFileHandle;
|
||||
import ghidra.framework.store.*;
|
||||
import ghidra.util.InvalidNameException;
|
||||
|
||||
/**
|
||||
* <code>RepositoryHandle</code> provides access to a remote repository via RMI.
|
||||
* <p>
|
||||
* Methods from {@link RepositoryHandle} <b>must</b> be re-declared here
|
||||
* so they may be properly marshalled for remote invocation via RMI.
|
||||
* This became neccessary with an OpenJDK 11.0.6 change made to
|
||||
* {@link RemoteObjectInvocationHandler}.
|
||||
*/
|
||||
public interface RemoteRepositoryHandle extends RepositoryHandle, Remote {
|
||||
@Override
|
||||
String getName() throws IOException;
|
||||
|
||||
@Override
|
||||
User getUser() throws IOException;
|
||||
|
||||
@Override
|
||||
User[] getUserList() throws IOException;
|
||||
|
||||
@Override
|
||||
boolean anonymousAccessAllowed() throws IOException;
|
||||
|
||||
@Override
|
||||
String[] getServerUserList() throws IOException;
|
||||
|
||||
@Override
|
||||
void setUserList(User[] users, boolean anonymousAccessAllowed) throws IOException;
|
||||
|
||||
@Override
|
||||
String[] getSubfolderList(String folderPath) throws IOException;
|
||||
|
||||
@Override
|
||||
int getItemCount() throws IOException;
|
||||
|
||||
@Override
|
||||
RepositoryItem[] getItemList(String folderPath) throws IOException;
|
||||
|
||||
@Override
|
||||
RepositoryItem getItem(String parentPath, String name) throws IOException;
|
||||
|
||||
@Override
|
||||
RepositoryItem getItem(String fileID) throws IOException;
|
||||
|
||||
@Override
|
||||
ManagedBufferFileHandle createDatabase(String parentPath, String itemName, String fileID,
|
||||
int bufferSize, String contentType, String projectPath)
|
||||
throws IOException, InvalidNameException;
|
||||
|
||||
@Override
|
||||
ManagedBufferFileHandle openDatabase(String parentPath, String itemName, int version,
|
||||
int minChangeDataVer) throws IOException;
|
||||
|
||||
@Override
|
||||
ManagedBufferFileHandle openDatabase(String parentPath, String itemName, long checkoutId)
|
||||
throws IOException;
|
||||
|
||||
@Override
|
||||
Version[] getVersions(String parentPath, String itemName) throws IOException;
|
||||
|
||||
@Override
|
||||
void deleteItem(String parentPath, String itemName, int version) throws IOException;
|
||||
|
||||
@Override
|
||||
void moveFolder(String oldParentPath, String newParentPath, String oldFolderName,
|
||||
String newFolderName) throws InvalidNameException, IOException;
|
||||
|
||||
@Override
|
||||
void moveItem(String oldParentPath, String newParentPath, String oldItemName,
|
||||
String newItemName) throws InvalidNameException, IOException;
|
||||
|
||||
@Override
|
||||
ItemCheckoutStatus checkout(String parentPath, String itemName, CheckoutType checkoutType,
|
||||
String projectPath) throws IOException;
|
||||
|
||||
@Override
|
||||
void terminateCheckout(String parentPath, String itemName, long checkoutId, boolean notify)
|
||||
throws IOException;
|
||||
|
||||
@Override
|
||||
ItemCheckoutStatus getCheckout(String parentPath, String itemName, long checkoutId)
|
||||
throws IOException;
|
||||
|
||||
@Override
|
||||
ItemCheckoutStatus[] getCheckouts(String parentPath, String itemName) throws IOException;
|
||||
|
||||
@Override
|
||||
boolean folderExists(String folderPath) throws IOException;
|
||||
|
||||
@Override
|
||||
boolean fileExists(String parentPath, String itemName) throws IOException;
|
||||
|
||||
@Override
|
||||
long getLength(String parentPath, String itemName) throws IOException;
|
||||
|
||||
@Override
|
||||
boolean hasCheckouts(String parentPath, String itemName) throws IOException;
|
||||
|
||||
@Override
|
||||
boolean isCheckinActive(String parentPath, String itemName) throws IOException;
|
||||
|
||||
@Override
|
||||
void updateCheckoutVersion(String parentPath, String itemName, long checkoutId,
|
||||
int checkoutVersion) throws IOException;
|
||||
|
||||
@Override
|
||||
RepositoryChangeEvent[] getEvents() throws IOException;
|
||||
|
||||
@Override
|
||||
void close() throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -15,11 +15,54 @@
|
|||
*/
|
||||
package ghidra.framework.remote;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.server.RemoteObjectInvocationHandler;
|
||||
|
||||
/**
|
||||
* <code>RepositoryServerHandle</code> provides access to a remote repository server via RMI.
|
||||
* <p>
|
||||
* Methods from {@link RepositoryServerHandle} <b>must</b> be re-declared here
|
||||
* so they may be properly marshalled for remote invocation via RMI.
|
||||
* This became neccessary with an OpenJDK 11.0.6 change made to
|
||||
* {@link RemoteObjectInvocationHandler}.
|
||||
*/
|
||||
public interface RemoteRepositoryServerHandle extends RepositoryServerHandle, Remote {
|
||||
|
||||
@Override
|
||||
boolean anonymousAccessAllowed() throws IOException;
|
||||
|
||||
@Override
|
||||
boolean isReadOnly() throws IOException;
|
||||
|
||||
@Override
|
||||
RepositoryHandle createRepository(String name) throws IOException;
|
||||
|
||||
@Override
|
||||
RepositoryHandle getRepository(String name) throws IOException;
|
||||
|
||||
@Override
|
||||
void deleteRepository(String name) throws IOException;
|
||||
|
||||
@Override
|
||||
String[] getRepositoryNames() throws IOException;
|
||||
|
||||
@Override
|
||||
String getUser() throws IOException;
|
||||
|
||||
@Override
|
||||
String[] getAllUsers() throws IOException;
|
||||
|
||||
@Override
|
||||
boolean canSetPassword() throws IOException;
|
||||
|
||||
@Override
|
||||
long getPasswordExpiration() throws IOException;
|
||||
|
||||
@Override
|
||||
boolean setPassword(char[] saltedSHA256PasswordHash) throws IOException;
|
||||
|
||||
@Override
|
||||
void connected() throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -158,12 +158,18 @@ public class TextLayoutGraphics extends Graphics2D {
|
|||
//Insert spaces to account for distance past last field in row
|
||||
FontMetrics metrics = COMPONENT.getFontMetrics(sortedTextInfo.font);
|
||||
int spaceWidth = metrics.charWidth(' ');
|
||||
if (spaceWidth == 0) {
|
||||
// some environments report 0 for some fonts
|
||||
spaceWidth = 4;
|
||||
}
|
||||
|
||||
int fillSpaces =
|
||||
Math.round((float) (sortedTextInfo.point.x - lastXPos) / (float) spaceWidth);
|
||||
//Account for the case where there's a very small amount of space between fields
|
||||
if (fillSpaces == 0 && sortedTextInfo.point.x > lastXPos) {
|
||||
fillSpaces = 1;
|
||||
}
|
||||
|
||||
for (int j = 0; j < fillSpaces; j++) {
|
||||
buffer.append(' ');
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package utilities.util.reflection;
|
|||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
@ -153,6 +154,84 @@ public class ReflectionUtilitiesTest {
|
|||
babyTypeArguments.get(1));
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void testRuntimeTypeDiscovery_Null() {
|
||||
ReflectionUtilities.getTypeArguments(List.class, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRumtimeTypeDiscovery_AnonymousClass() {
|
||||
|
||||
List<String> myList = new ArrayList<String>() {
|
||||
// stub
|
||||
};
|
||||
List<Class<?>> types = ReflectionUtilities.getTypeArguments(List.class, myList.getClass());
|
||||
assertEquals(1, types.size());
|
||||
assertEquals(String.class, types.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRumtimeTypeDiscovery_LocalVariable() {
|
||||
|
||||
List<String> myList = new ArrayList<String>();
|
||||
List<Class<?>> types = ReflectionUtilities.getTypeArguments(List.class, myList.getClass());
|
||||
assertEquals(1, types.size());
|
||||
assertNull(types.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRuntimeTypeDiscovery_MixedHierarchy_AbstractClassAndInterfaceBothDefineValues() {
|
||||
|
||||
//
|
||||
// Test to make sure that we get not only a directly hierarchy, but the lateral one
|
||||
// as well, where we pursue interfaces that may have defined some types.
|
||||
//
|
||||
|
||||
List<Class<?>> types = ReflectionUtilities.getTypeArguments(RuntimeBaseInterface.class,
|
||||
ChildExtendingPartiallyDefinedTypes.class);
|
||||
assertEquals(2, types.size());
|
||||
assertEquals(String.class, types.get(0));
|
||||
assertEquals(Double.class, types.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRuntimeTypeDiscovery_SubInterfaceDefinesValues() {
|
||||
|
||||
//
|
||||
// Test to make sure that we get not only a directly hierarchy, but the lateral one
|
||||
// as well, where we pursue interfaces that may have defined some types.
|
||||
//
|
||||
|
||||
List<Class<?>> types = ReflectionUtilities.getTypeArguments(RuntimeBaseInterface.class,
|
||||
ChildExtendingWhollyDefinedTypes.class);
|
||||
assertEquals(2, types.size());
|
||||
assertEquals(String.class, types.get(0));
|
||||
assertEquals(Double.class, types.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRuntimeTypeDiscovery_MixedHierarchy_UnrelatedParents() {
|
||||
|
||||
//
|
||||
// Test to make sure that we get not only a directly hierarchy, but the lateral one
|
||||
// as well, where we pursue interfaces that may have defined some types.
|
||||
//
|
||||
// This test also verifies that in a mixed type hierarchy, we can correctly locate types
|
||||
// depending upon the parent type we pass in.
|
||||
//
|
||||
|
||||
List<Class<?>> types = ReflectionUtilities.getTypeArguments(RuntimeBaseInterface.class,
|
||||
ChildWithMixedParentTypes.class);
|
||||
assertEquals(2, types.size());
|
||||
assertEquals(String.class, types.get(0));
|
||||
assertEquals(Double.class, types.get(1));
|
||||
|
||||
types = ReflectionUtilities.getTypeArguments(List.class,
|
||||
ChildWithMixedParentTypes.class);
|
||||
assertEquals(1, types.size());
|
||||
assertEquals(Integer.class, types.get(0));
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
@ -179,6 +258,39 @@ public class ReflectionUtilitiesTest {
|
|||
}
|
||||
}
|
||||
|
||||
private interface RuntimeBaseInterface<T, J> {
|
||||
// stub
|
||||
}
|
||||
|
||||
private interface PartiallyDefinedInterface<J> extends RuntimeBaseInterface<String, J> {
|
||||
// stub
|
||||
}
|
||||
|
||||
private interface WhollyDefinedInterface extends RuntimeBaseInterface<String, Double> {
|
||||
// stub
|
||||
}
|
||||
|
||||
private class AbstractPartiallyDefinedClass<I> implements RuntimeBaseInterface<I, Double> {
|
||||
// stub
|
||||
}
|
||||
|
||||
private class ChildExtendingPartiallyDefinedTypes
|
||||
extends AbstractPartiallyDefinedClass<String>
|
||||
implements PartiallyDefinedInterface<Double> {
|
||||
// stub
|
||||
}
|
||||
|
||||
private class ChildExtendingWhollyDefinedTypes
|
||||
implements WhollyDefinedInterface {
|
||||
// stub
|
||||
}
|
||||
|
||||
private class ChildWithMixedParentTypes
|
||||
extends ArrayList<Integer>
|
||||
implements WhollyDefinedInterface {
|
||||
// stub
|
||||
}
|
||||
|
||||
private class RuntimeBaseType<T, J> {
|
||||
// stub
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ public abstract class VisualGraphComponentProvider<V extends VisualVertex,
|
|||
Undo/redo for graph operations (delete; group/ungroup; move)
|
||||
-rapid pressing will shortcut items
|
||||
-undo/redo allows us to prune nodes
|
||||
--how to maintain old nodes/edges? (FitleringVisualGraph)
|
||||
--how to maintain old nodes/edges? (FilteringVisualGraph)
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.graph.job;
|
||||
|
||||
import static util.CollectionUtils.asSet;
|
||||
import static util.CollectionUtils.asStream;
|
||||
import static util.CollectionUtils.*;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
@ -108,7 +107,7 @@ public class FilterVerticesJob<V extends VisualVertex, E extends VisualEdge<V>>
|
|||
passedVertices = matching;
|
||||
|
||||
// 2)
|
||||
failedVertices = findCurrentVerticesFailingTheFitler(matching);
|
||||
failedVertices = findCurrentVerticesFailingTheFilter(matching);
|
||||
failedEdges = filterGraph.getAllEdges(failedVertices);
|
||||
|
||||
Set<E> allRelatedEdges = filterGraph.getAllEdges(passedVertices);
|
||||
|
@ -119,7 +118,7 @@ public class FilterVerticesJob<V extends VisualVertex, E extends VisualEdge<V>>
|
|||
filterGraph.unfilterVertices(passedVertices);
|
||||
}
|
||||
|
||||
private Set<V> findCurrentVerticesFailingTheFitler(Set<V> validVertices) {
|
||||
private Set<V> findCurrentVerticesFailingTheFilter(Set<V> validVertices) {
|
||||
|
||||
UnmodifiableIterator<V> nonMatchingIterator =
|
||||
Iterators.filter(filterGraph.getUnfilteredVertices(), v -> !validVertices.contains(v));
|
||||
|
|
|
@ -580,7 +580,7 @@ public class GhidraFileData {
|
|||
boolean isVersioned() {
|
||||
synchronized (fileSystem) {
|
||||
if (versionedFolderItem == null) {
|
||||
return false;
|
||||
return isCheckedOut();
|
||||
}
|
||||
return !isHijacked();
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ public class AssemblySentential<NT extends AssemblyNonTerminal> extends
|
|||
return Collections.singleton(new WhiteSpaceParseToken(grammar, this, ""));
|
||||
}
|
||||
if (Character.isLetterOrDigit(buffer.charAt(b)) &&
|
||||
Character.isLetterOrDigit(buffer.charAt(b - 1))) {
|
||||
(b == 0 || Character.isLetterOrDigit(buffer.charAt(b - 1)))) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -282,7 +282,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
if (monitor == null) {
|
||||
monitor = TaskMonitorAdapter.DUMMY;
|
||||
}
|
||||
|
||||
|
||||
boolean success = false;
|
||||
try {
|
||||
int id = startTransaction("create program");
|
||||
|
@ -2141,8 +2141,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
* Translate language
|
||||
* @param translator language translator, if null only re-disassembly will occur.
|
||||
* @param newCompilerSpecID new compiler specification which corresponds to new language, may be null.
|
||||
* @param monitor
|
||||
* @throws LockException
|
||||
* @param forceRedisassembly if true a redisassembly will be forced even if not required
|
||||
* @param monitor task monitor
|
||||
* @throws LockException if exclusive access is missing
|
||||
*/
|
||||
public void setLanguage(LanguageTranslator translator, CompilerSpecID newCompilerSpecID,
|
||||
boolean forceRedisassembly, TaskMonitor monitor) throws LockException {
|
||||
|
@ -2153,7 +2154,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
try {
|
||||
setEventsEnabled(false);
|
||||
try {
|
||||
boolean notifyCodeManager = true;
|
||||
boolean redisassemblyRequired = true;
|
||||
int oldLanguageVersion = languageVersion;
|
||||
int oldLanguageMinorVersion = languageMinorVersion;
|
||||
if (translator != null) {
|
||||
|
@ -2168,7 +2169,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
}
|
||||
else if (!forceRedisassembly && language.getVersion() == languageVersion &&
|
||||
language.getMinorVersion() == languageMinorVersion) {
|
||||
notifyCodeManager = false; // compiler spec change only
|
||||
redisassemblyRequired = false; // compiler spec change only
|
||||
Msg.info(this, "Setting compiler spec for Program " + getName() + ": " +
|
||||
compilerSpecID + " -> " + newCompilerSpecID);
|
||||
}
|
||||
|
@ -2207,15 +2208,14 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
monitor.setProgress(0);
|
||||
ProgramRegisterContextDB contextMgr =
|
||||
(ProgramRegisterContextDB) getProgramContext();
|
||||
if (translator != null) {
|
||||
if (redisassemblyRequired) {
|
||||
contextMgr.setLanguage(translator, compilerSpec, memoryManager, monitor);
|
||||
}
|
||||
else {
|
||||
// force re-initialization
|
||||
contextMgr.initializeDefaultValues(language, compilerSpec);
|
||||
}
|
||||
|
||||
if (notifyCodeManager) {
|
||||
if (redisassemblyRequired) {
|
||||
Disassembler.clearUnimplementedPcodeWarnings(this, null, monitor);
|
||||
repairContext(oldLanguageVersion, oldLanguageMinorVersion, translator, monitor);
|
||||
monitor.setMessage("Updating instructions...");
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
package ghidra.program.database.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import db.Record;
|
||||
|
@ -26,6 +25,7 @@ import ghidra.program.database.DatabaseObject;
|
|||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.DataTypeConflictHandler.ConflictResult;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -41,6 +41,7 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
|
||||
private LazyLoadingCachingMap<String, CategoryDB> subcategoryMap;
|
||||
private LazyLoadingCachingMap<String, DataType> dataTypeMap;
|
||||
private ConflictMap conflictMap;
|
||||
|
||||
/**
|
||||
* Category Constructor
|
||||
|
@ -57,19 +58,19 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
this.name = name;
|
||||
this.parent = parent;
|
||||
|
||||
subcategoryMap = new LazyLoadingCachingMap<>(mgr.lock, CategoryDB.class) {
|
||||
subcategoryMap = new LazyLoadingCachingMap<>(mgr.lock) {
|
||||
@Override
|
||||
public Map<String, CategoryDB> loadMap() {
|
||||
return buildSubcategoryMap();
|
||||
}
|
||||
};
|
||||
dataTypeMap = new LazyLoadingCachingMap<>(mgr.lock, DataType.class) {
|
||||
dataTypeMap = new LazyLoadingCachingMap<>(mgr.lock) {
|
||||
@Override
|
||||
public Map<String, DataType> loadMap() {
|
||||
return createDataTypeMap();
|
||||
}
|
||||
};
|
||||
|
||||
conflictMap = new ConflictMap(mgr.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,6 +103,7 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
protected boolean refresh(Record rec) {
|
||||
subcategoryMap.clear();
|
||||
dataTypeMap.clear();
|
||||
conflictMap.clear();
|
||||
|
||||
if (isRoot()) {
|
||||
return true;
|
||||
|
@ -210,13 +212,26 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
return map;
|
||||
}
|
||||
|
||||
private String getBaseName(String dataTypeName) {
|
||||
int indexOf = dataTypeName.indexOf(DataType.CONFLICT_SUFFIX);
|
||||
if (indexOf <= 0) {
|
||||
return dataTypeName;
|
||||
}
|
||||
return dataTypeName.substring(0, indexOf);
|
||||
}
|
||||
|
||||
private boolean isConflictName(String dataTypeName) {
|
||||
return dataTypeName.contains(DataType.CONFLICT_SUFFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Category#getCategories()
|
||||
*/
|
||||
@Override
|
||||
public Category[] getCategories() {
|
||||
validate(mgr.lock);
|
||||
return subcategoryMap.valuesToArray();
|
||||
Collection<CategoryDB> categories = subcategoryMap.values();
|
||||
return categories.toArray(new Category[categories.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -225,7 +240,8 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
@Override
|
||||
public DataType[] getDataTypes() {
|
||||
validate(mgr.lock);
|
||||
return dataTypeMap.valuesToArray();
|
||||
Collection<DataType> dataTypes = dataTypeMap.values();
|
||||
return dataTypes.toArray(new DataType[dataTypes.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -587,19 +603,144 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
}
|
||||
|
||||
void dataTypeRenamed(DataType childDataType, String oldName) {
|
||||
dataTypeMap.remove(oldName);
|
||||
dataTypeMap.put(childDataType.getName(), childDataType);
|
||||
dataTypeRemoved(oldName);
|
||||
dataTypeAdded(childDataType);
|
||||
}
|
||||
|
||||
void dataTypeAdded(DataType childDataType) {
|
||||
dataTypeMap.put(childDataType.getName(), childDataType);
|
||||
void dataTypeAdded(DataType dataType) {
|
||||
String dtName = dataType.getName();
|
||||
dataTypeMap.put(dtName, dataType);
|
||||
if (isConflictName(dtName)) {
|
||||
conflictMap.addDataType(dataType);
|
||||
}
|
||||
}
|
||||
|
||||
void dataTypeRemoved(String dataTypeName) {
|
||||
dataTypeMap.remove(dataTypeName);
|
||||
if (isConflictName(dataTypeName)) {
|
||||
conflictMap.removeDataTypeName(dataTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
void categoryAdded(CategoryDB cat) {
|
||||
subcategoryMap.put(cat.getName(), cat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DataType> getDataTypesByBaseName(String dataTypeName) {
|
||||
List<DataType> list = new ArrayList<>();
|
||||
String baseName = getBaseName(dataTypeName);
|
||||
|
||||
DataType baseType = dataTypeMap.get(baseName);
|
||||
if (baseType != null) {
|
||||
list.add(baseType);
|
||||
}
|
||||
|
||||
List<DataType> relatedNameDataTypes = conflictMap.getDataTypesByBaseName(baseName);
|
||||
list.addAll(relatedNameDataTypes);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to handle the complexities of having a map as the value in a LazyLoadingCachingMap
|
||||
* This map uses the data type's base name as the key (i.e. all .conflict suffixes stripped off.)
|
||||
* The value is another map that maps the actual data type's name to the data type. This map
|
||||
* effectively provides an efficient way to get all data types in a category that have the
|
||||
* same name, but possibly have had their name modified (by appending .conflict) to get around
|
||||
* the requirement that names have to be unique in the same category.
|
||||
*/
|
||||
private class ConflictMap extends LazyLoadingCachingMap<String, Map<String, DataType>> {
|
||||
|
||||
ConflictMap(Lock lock) {
|
||||
super(lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a map of all data types whose name has a .conflict suffix where the key
|
||||
* is the base name and {@link LazyLoadingCachingMap} the value is a map of actual name
|
||||
* to data type. This mapping is
|
||||
* maintained as a lazy cache map. This is only called by the super class when the
|
||||
* cached needs to be populated and we are depending on it to acquire the necessary
|
||||
* database lock. (See {@link LazyLoadingCachingMap#loadMap()}
|
||||
* @return the loaded map
|
||||
*/
|
||||
@Override
|
||||
protected Map<String, Map<String, DataType>> loadMap() {
|
||||
Map<String, Map<String, DataType>> map = new HashMap<>();
|
||||
Collection<DataType> values = dataTypeMap.values();
|
||||
for (DataType dataType : values) {
|
||||
String dataTypeName = dataType.getName();
|
||||
if (isConflictName(dataTypeName)) {
|
||||
String baseName = getBaseName(dataTypeName);
|
||||
Map<String, DataType> innerMap =
|
||||
map.computeIfAbsent(baseName, b -> new HashMap<>());
|
||||
innerMap.put(dataTypeName, dataType);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the data type to the conflict mapping structure. If the mapping is currently not
|
||||
* loaded then this method can safely do nothing. This method is synchronized to provide
|
||||
* thread safe access/manipulation of the map.
|
||||
* @param dataType the data type to add to the mapping if the mapping is already loaded
|
||||
*/
|
||||
synchronized void addDataType(DataType dataType) {
|
||||
// if the cache is not currently populated, don't need to do anything
|
||||
Map<String, Map<String, DataType>> map = getMap();
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String dataTypeName = dataType.getName();
|
||||
String baseName = getBaseName(dataTypeName);
|
||||
Map<String, DataType> innerMap = map.computeIfAbsent(baseName, b -> new HashMap<>());
|
||||
innerMap.put(dataTypeName, dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the data type with the given name from the conflict mapping structure. If the
|
||||
* mapping is currently not loaded then this method can safely do nothing. This method is
|
||||
* synchronized to provide thread safe access/manipulate of the map.
|
||||
* @param dataTypeName the name of the data type to remove from this mapping
|
||||
*/
|
||||
synchronized void removeDataTypeName(String dataTypeName) {
|
||||
Map<String, Map<String, DataType>> map = getMap();
|
||||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
String baseName = getBaseName(dataTypeName);
|
||||
Map<String, DataType> innerMap = map.get(baseName);
|
||||
if (innerMap == null) {
|
||||
return;
|
||||
}
|
||||
innerMap.remove(dataTypeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all data types that have conflict names for the given base name
|
||||
* @param baseName the data type base name to search for (i.e. the .conflict suffix removed)
|
||||
* @return a list of all conflict named data types that would have the given base name if
|
||||
* no conflicts existed
|
||||
*/
|
||||
List<DataType> getDataTypesByBaseName(String baseName) {
|
||||
|
||||
// Note that the following call to get MUST NOT be in a synchronized block because
|
||||
// it may trigger a loading of the cache which requires a database lock and you
|
||||
// can't be synchronized on this class when acquiring a database lock or else a
|
||||
// deadlock will occur.
|
||||
Map<String, DataType> map = get(baseName);
|
||||
if (map == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// the following must be synchronized so that the implied iterator can complete without
|
||||
// another thread changing the map's values.
|
||||
synchronized (this) {
|
||||
return new ArrayList<>(map.values());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataType getParent() {
|
||||
public Composite getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
|
|
@ -774,7 +774,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
private DataType resolveBitFieldDataType(BitFieldDataType bitFieldDataType,
|
||||
DataTypeConflictHandler handler) {
|
||||
|
||||
// NOTE: When a bit-field is getting adding added it will get resolved more than once.
|
||||
// NOTE: When a bit-field is getting added it will get resolved more than once.
|
||||
// The first time we will ensure that the base data type, which may be a TypeDef, gets
|
||||
// resolved. If the bit-offset is too large it will be set to 0
|
||||
// with the expectation that it will get corrected during subsequent packing.
|
||||
|
@ -788,7 +788,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
int storageSizeBits = 8 * storageSize;
|
||||
if ((bitOffset + bitSize) > storageSizeBits) {
|
||||
// should get recomputed during packing when used within aligned structure
|
||||
bitOffset = getDataOrganization().isBigEndian() ? baseLengthBits - bitSize : 0;
|
||||
int effectiveBitSize = Math.min(bitSize, baseLengthBits);
|
||||
bitOffset = getDataOrganization().isBigEndian() ? baseLengthBits - effectiveBitSize : 0;
|
||||
storageSize = baseLength;
|
||||
}
|
||||
try {
|
||||
|
@ -933,14 +934,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
if (category == null) {
|
||||
return null;
|
||||
}
|
||||
String namePrefix = dtName + DataType.CONFLICT_SUFFIX;
|
||||
DataType[] dataTypes = category.getDataTypes();
|
||||
for (DataType candidate : dataTypes) {
|
||||
List<DataType> relatedByName = category.getDataTypesByBaseName(dtName);
|
||||
|
||||
for (DataType candidate : relatedByName) {
|
||||
String candidateName = candidate.getName();
|
||||
if (candidateName.startsWith(namePrefix)) {
|
||||
if (!candidateName.equals(excludedName) && candidate.isEquivalent(dataType)) {
|
||||
return candidate;
|
||||
}
|
||||
if (!candidateName.equals(excludedName) && candidate.isEquivalent(dataType)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -3207,13 +3206,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
lock.acquire();
|
||||
try {
|
||||
long[] ids = parentChildAdapter.getParentIds(childID);
|
||||
// TODO: consider deduping ids using Set
|
||||
List<DataType> dts = new ArrayList<>();
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
DataType dt = getDataType(ids[i]);
|
||||
for (long id : ids) {
|
||||
DataType dt = getDataType(id);
|
||||
if (dt == null) {
|
||||
// cleanup invalid records for missing parent
|
||||
attemptRecordRemovalForParent(ids[i]);
|
||||
attemptRecordRemovalForParent(id);
|
||||
}
|
||||
else {
|
||||
dts.add(dt);
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
package ghidra.program.database.data;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.util.Lock;
|
||||
|
||||
|
@ -39,15 +38,14 @@ public abstract class LazyLoadingCachingMap<K, V> {
|
|||
|
||||
private Lock lock;
|
||||
private SoftReference<Map<K, V>> softRef;
|
||||
private Class<V> valueClass;
|
||||
|
||||
protected LazyLoadingCachingMap(Lock lock, Class<V> valueClass) {
|
||||
protected LazyLoadingCachingMap(Lock lock) {
|
||||
this.lock = lock;
|
||||
this.valueClass = valueClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will reload the map data from scratch.
|
||||
* This method will reload the map data from scratch. Subclass may assume that the database
|
||||
* lock has been acquired.
|
||||
* @return a map containing all current key, value pairs.
|
||||
*/
|
||||
protected abstract Map<K, V> loadMap();
|
||||
|
@ -96,13 +94,13 @@ public abstract class LazyLoadingCachingMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
public V[] valuesToArray() {
|
||||
/**
|
||||
* Returns an unmodifiable view of the values in this map.
|
||||
* @return an unmodifiable view of the values in this map.
|
||||
*/
|
||||
public Collection<V> values() {
|
||||
Map<K, V> map = getOrLoadMap();
|
||||
synchronized (this) {
|
||||
@SuppressWarnings("unchecked")
|
||||
V[] array = (V[]) Array.newInstance(valueClass, map.size());
|
||||
return map.values().toArray(array);
|
||||
}
|
||||
return Collections.unmodifiableCollection(map.values());
|
||||
}
|
||||
|
||||
private Map<K, V> getOrLoadMap() {
|
||||
|
@ -113,6 +111,15 @@ public abstract class LazyLoadingCachingMap<K, V> {
|
|||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
// We must get the database lock before calling loadMap(). Also, we can't get the
|
||||
// database lock while having the synchronization lock for this class or a deadlock can
|
||||
// occur, since the other methods may be called while the client has the db lock.
|
||||
// Note: all other places where the map is being used or manipulated, it must be done
|
||||
// while having the class's synchronization lock since the map itself is not thread safe.
|
||||
// It should be safe here since it creates a new map and then in one operation it sets it
|
||||
// as the map to be used elsewhere.
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
map = getMap();
|
||||
|
@ -132,11 +139,12 @@ public abstract class LazyLoadingCachingMap<K, V> {
|
|||
* "lock".
|
||||
* @return the underlying map of key,value pairs or null if it is currently not loaded.
|
||||
*/
|
||||
private Map<K, V> getMap() {
|
||||
protected Map<K, V> getMap() {
|
||||
if (softRef == null) {
|
||||
return null;
|
||||
}
|
||||
return softRef.get();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import ghidra.program.model.data.*;
|
|||
import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
|
@ -640,6 +641,13 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create copy of structure for target dtm (source archive information is discarded).
|
||||
* WARNING! copying unaligned structures which contain bitfields can produce
|
||||
* invalid results when switching endianess due to the differences in packing order.
|
||||
* @param dtm target data type manager
|
||||
* @return cloned structure
|
||||
*/
|
||||
@Override
|
||||
public DataType copy(DataTypeManager dtm) {
|
||||
StructureDataType struct =
|
||||
|
@ -649,6 +657,13 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
return struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create cloned structure for target dtm preserving source archive information.
|
||||
* WARNING! cloning unaligned structures which contain bitfields can produce
|
||||
* invalid results when switching endianess due to the differences in packing order.
|
||||
* @param dtm target data type manager
|
||||
* @return cloned structure
|
||||
*/
|
||||
@Override
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
StructureDataType struct =
|
||||
|
@ -891,12 +906,28 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
@Override
|
||||
public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length, String name,
|
||||
String comment) {
|
||||
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Offset cannot be negative.");
|
||||
}
|
||||
|
||||
if (dataType instanceof BitFieldDataType) {
|
||||
BitFieldDataType bfDt = (BitFieldDataType) dataType;
|
||||
if (length <= 0) {
|
||||
length = dataType.getLength();
|
||||
}
|
||||
try {
|
||||
return insertBitFieldAt(offset, length, bfDt.getBitOffset(), bfDt.getBaseDataType(),
|
||||
bfDt.getDeclaredBitSize(), name, comment);
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
}
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Offset cannot be negative.");
|
||||
}
|
||||
validateDataType(dataType);
|
||||
|
||||
dataType = resolve(dataType);
|
||||
|
@ -966,6 +997,7 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
if (ordinal < 0 || ordinal >= numComponents) {
|
||||
throw new ArrayIndexOutOfBoundsException(ordinal);
|
||||
}
|
||||
|
||||
validateDataType(dataType);
|
||||
|
||||
DataTypeComponent origDtc = getComponent(ordinal);
|
||||
|
@ -1009,9 +1041,7 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
throw new IllegalArgumentException(
|
||||
"Offset " + offset + " is beyond end of structure (" + structLength + ").");
|
||||
}
|
||||
if (dataType instanceof BitFieldDataType) {
|
||||
throw new IllegalArgumentException("Components may not be replaced with a bit-field");
|
||||
}
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
@ -1085,19 +1115,14 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
componentAdapter.removeRecord(dtc.getKey());
|
||||
}
|
||||
components.clear();
|
||||
numComponents = 0;
|
||||
structLength = 0;
|
||||
|
||||
if (flexibleArrayComponent != null) {
|
||||
flexibleArrayComponent.getDataType().removeParent(this);
|
||||
componentAdapter.removeRecord(flexibleArrayComponent.getKey());
|
||||
flexibleArrayComponent = null;
|
||||
}
|
||||
if (struct.isNotYetDefined()) {
|
||||
numComponents = 0;
|
||||
structLength = 0;
|
||||
}
|
||||
else {
|
||||
structLength = struct.getLength();
|
||||
numComponents = isInternallyAligned() ? 0 : structLength;
|
||||
}
|
||||
|
||||
setAlignment(struct, false);
|
||||
|
||||
|
@ -1154,14 +1179,17 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
|
||||
private void doReplaceWithUnaligned(Structure struct) throws IOException {
|
||||
// assumes components is clear and that alignment characteristics have been set.
|
||||
if (struct.isNotYetDefined()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: unaligned bitfields should remain unchanged when
|
||||
// transitioning endianess even though it makes little sense.
|
||||
// Unaligned structures are not intended to be portable!
|
||||
structLength = struct.getLength();
|
||||
numComponents = structLength;
|
||||
|
||||
DataTypeComponent[] otherComponents = struct.getDefinedComponents();
|
||||
for (int i = 0; i < otherComponents.length; i++) {
|
||||
DataTypeComponent dtc = otherComponents[i];
|
||||
|
||||
DataType dt = resolve(dtc.getDataType());
|
||||
checkAncestry(dt);
|
||||
|
||||
|
|
|
@ -72,12 +72,12 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
|
|||
}
|
||||
|
||||
if (openMode == DBConstants.UPGRADE && oldContextDataExists) {
|
||||
// TODO: Make sure upgrade is working correctly before uncommenting
|
||||
// try {
|
||||
// OldProgramContextDB.removeOldContextData(dbHandle);
|
||||
// } catch (IOException e) {
|
||||
// errorHandler.dbError(e);
|
||||
// }
|
||||
try {
|
||||
OldProgramContextDB.removeOldContextData(dbHandle);
|
||||
}
|
||||
catch (IOException e) {
|
||||
errorHandler.dbError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,6 +161,12 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Intialize context with default values defined by pspec and cspec.
|
||||
* NOTE: cspec values take precedence
|
||||
* @param lang processor language
|
||||
* @param compilerSpec compiler specification
|
||||
*/
|
||||
public void initializeDefaultValues(Language lang, CompilerSpec compilerSpec) {
|
||||
defaultRegisterValueMap.clear();
|
||||
lang.applyContextSettings(this);
|
||||
|
@ -288,9 +294,31 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform context upgrade due to a language change
|
||||
* @param translator language translator required by major upgrades (may be null)
|
||||
* @param newCompilerSpec new compiler specification
|
||||
* @param programMemory program memory
|
||||
* @param monitor task monitor
|
||||
* @throws CancelledException thrown if monitor cancelled
|
||||
*/
|
||||
public void setLanguage(LanguageTranslator translator, CompilerSpec newCompilerSpec,
|
||||
AddressSetView programMemory, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
if (translator == null) {
|
||||
Language lang = program.getLanguage();
|
||||
boolean clearContext = Boolean.valueOf(
|
||||
lang.getProperty(GhidraLanguagePropertyKeys.RESET_CONTEXT_ON_UPGRADE));
|
||||
if (clearContext) {
|
||||
RegisterValueStore store = registerValueMap.get(baseContextRegister);
|
||||
if (store != null) {
|
||||
store.clearAll();
|
||||
}
|
||||
}
|
||||
initializeDefaultValues(lang, newCompilerSpec);
|
||||
return;
|
||||
}
|
||||
|
||||
Language newLanguage = translator.getNewLanguage();
|
||||
|
||||
// Sort the registers by size so that largest come first.
|
||||
|
@ -309,8 +337,11 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
|
|||
continue;
|
||||
}
|
||||
|
||||
boolean clearContext = register.isProcessorContext() && Boolean.valueOf(
|
||||
newLanguage.getProperty(GhidraLanguagePropertyKeys.RESET_CONTEXT_ON_UPGRADE));
|
||||
|
||||
// Update storage range map
|
||||
if (!store.setLanguage(translator, monitor)) {
|
||||
if (clearContext || !store.setLanguage(translator, monitor)) {
|
||||
// Clear and remove old register value store
|
||||
Msg.warn(this,
|
||||
"WARNING! Discarding all context for register " + register.getName());
|
||||
|
|
|
@ -1150,12 +1150,12 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||
throws InsufficientBytesException, UnknownInstructionException,
|
||||
AddressOverflowException, NestedDelaySlotException {
|
||||
|
||||
List<PseudoInstruction> delaySlotList = parseDelaySlots(inst, blockMemBuffer, block);
|
||||
|
||||
if (followFlow) {
|
||||
processInstructionFlows(inst, block);
|
||||
}
|
||||
|
||||
List<PseudoInstruction> delaySlotList = parseDelaySlots(inst, blockMemBuffer, block);
|
||||
|
||||
block.addInstruction(inst);
|
||||
|
||||
if (delaySlotList != null) {
|
||||
|
|
|
@ -174,9 +174,6 @@ class DisassemblerQueue {
|
|||
branchFlow = currentBranchQueue.first();
|
||||
currentBranchQueue.remove(branchFlow);
|
||||
}
|
||||
if (processedBranchFlows.contains(branchFlow)) {
|
||||
continue;
|
||||
}
|
||||
processedBranchFlows.add(branchFlow);
|
||||
|
||||
Address blockAddr = branchFlow.getDestinationAddress();
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -48,6 +50,19 @@ public interface Category extends Comparable<Category> {
|
|||
*/
|
||||
public abstract DataType[] getDataTypes();
|
||||
|
||||
/**
|
||||
* Get all data types in this category whose base name matches the base name of the given name.
|
||||
* The base name of a name is the first part of the string up to where the first ".conflict"
|
||||
* occurs. In other words, finds all data types whose name matches the given name once
|
||||
* any conflict suffixes have been removed from both the given name and the data types
|
||||
* that are being scanned.
|
||||
* @param name the name for which to get conflict related data types in this category. Note: the
|
||||
* name that is passed in will be normalized to its base name, so you may pass in names with .conflict
|
||||
* appended as a convenience.
|
||||
* @return a list of data types that have the same base name as the base name of the given name
|
||||
*/
|
||||
public abstract List<DataType> getDataTypesByBaseName(String name);
|
||||
|
||||
/**
|
||||
* Adds the given datatype to this category.
|
||||
* @param dt the datatype to add to this category.
|
||||
|
|
|
@ -196,9 +196,8 @@ public interface Structure extends Composite {
|
|||
public void deleteAtOffset(int offset);
|
||||
|
||||
/**
|
||||
* Remove all components from this structure, effectively setting the
|
||||
* length to zero.
|
||||
*
|
||||
* Remove all components from this structure (including flex-array),
|
||||
* effectively setting the length to zero.
|
||||
*/
|
||||
public void deleteAll();
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult;
|
|||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
|
@ -297,9 +298,25 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
@Override
|
||||
public DataTypeComponentImpl insertAtOffset(int offset, DataType dataType, int length,
|
||||
String componentName, String comment) {
|
||||
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Offset cannot be negative.");
|
||||
}
|
||||
|
||||
if (dataType instanceof BitFieldDataType) {
|
||||
BitFieldDataType bfDt = (BitFieldDataType) dataType;
|
||||
if (length <= 0) {
|
||||
length = dataType.getLength();
|
||||
}
|
||||
try {
|
||||
return insertBitFieldAt(offset, length, bfDt.getBitOffset(), bfDt.getBaseDataType(),
|
||||
bfDt.getDeclaredBitSize(), componentName, comment);
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
}
|
||||
|
||||
validateDataType(dataType);
|
||||
|
||||
dataType = dataType.clone(dataMgr);
|
||||
|
@ -524,7 +541,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent insertBitFieldAt(int byteOffset, int byteWidth, int bitOffset,
|
||||
public DataTypeComponentImpl insertBitFieldAt(int byteOffset, int byteWidth, int bitOffset,
|
||||
DataType baseDataType, int bitSize, String componentName, String comment)
|
||||
throws InvalidDataTypeException {
|
||||
|
||||
|
@ -847,6 +864,13 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
return available;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create copy of structure for target dtm (source archive information is discarded).
|
||||
* WARNING! copying unaligned structures which contain bitfields can produce
|
||||
* invalid results when switching endianess due to the differences in packing order.
|
||||
* @param dtm target data type manager
|
||||
* @return cloned structure
|
||||
*/
|
||||
@Override
|
||||
public DataType copy(DataTypeManager dtm) {
|
||||
StructureDataType struct = new StructureDataType(categoryPath, getName(), getLength(), dtm);
|
||||
|
@ -855,6 +879,13 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
return struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create cloned structure for target dtm preserving source archive information.
|
||||
* WARNING! cloning unaligned structures which contain bitfields can produce
|
||||
* invalid results when switching endianess due to the differences in packing order.
|
||||
* @param dtm target data type manager
|
||||
* @return cloned structure
|
||||
*/
|
||||
@Override
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
if (dataMgr == dtm) {
|
||||
|
@ -907,15 +938,9 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
int oldLength = structLength;
|
||||
|
||||
components.clear();
|
||||
structLength = 0;
|
||||
numComponents = 0;
|
||||
flexibleArrayComponent = null;
|
||||
if (struct.isNotYetDefined()) {
|
||||
structLength = 0;
|
||||
numComponents = 0;
|
||||
}
|
||||
else {
|
||||
structLength = struct.getLength();
|
||||
numComponents = isInternallyAligned() ? 0 : structLength;
|
||||
}
|
||||
|
||||
setAlignment(struct);
|
||||
|
||||
|
@ -950,14 +975,17 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
|
||||
private void doReplaceWithUnaligned(Structure struct) {
|
||||
// assumes components is clear and that alignment characteristics have been set.
|
||||
if (struct.isNotYetDefined()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: unaligned bitfields should remain unchanged when
|
||||
// transitioning endianess even though it makes little sense.
|
||||
// Unaligned structures are not intended to be portable!
|
||||
structLength = struct.getLength();
|
||||
numComponents = structLength;
|
||||
|
||||
DataTypeComponent[] otherComponents = struct.getDefinedComponents();
|
||||
for (int i = 0; i < otherComponents.length; i++) {
|
||||
DataTypeComponent dtc = otherComponents[i];
|
||||
|
||||
DataType dt = dtc.getDataType().clone(dataMgr);
|
||||
checkAncestry(dt);
|
||||
|
||||
|
@ -1126,9 +1154,6 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
if (index < 0 || index >= numComponents) {
|
||||
throw new ArrayIndexOutOfBoundsException(index);
|
||||
}
|
||||
if (dataType instanceof BitFieldDataType) {
|
||||
throw new IllegalArgumentException("Components may not be replaced with a bit-field");
|
||||
}
|
||||
|
||||
validateDataType(dataType);
|
||||
|
||||
|
@ -1168,9 +1193,6 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
throw new IllegalArgumentException(
|
||||
"Offset " + offset + " is beyond end of structure (" + structLength + ").");
|
||||
}
|
||||
if (dataType instanceof BitFieldDataType) {
|
||||
throw new IllegalArgumentException("Components may not be replaced with a bit-field");
|
||||
}
|
||||
|
||||
validateDataType(dataType);
|
||||
|
||||
|
|
|
@ -112,4 +112,11 @@ public final class GhidraLanguagePropertyKeys {
|
|||
* following the call. Non-returning functions can be detected in many cases.
|
||||
*/
|
||||
public static final String ENABLE_NO_RETURN_ANALYSIS = "enableNoReturnAnalysis";
|
||||
|
||||
/**
|
||||
* Property to indicate that all stored instruction context should be cleared
|
||||
* during a language upgrade operation which requires redisassembly.
|
||||
* NOTE: This is an experimental concept which may be removed in the future
|
||||
*/
|
||||
public static final String RESET_CONTEXT_ON_UPGRADE = "resetContextOnUpgrade";
|
||||
}
|
||||
|
|
|
@ -120,16 +120,22 @@ public class VariableOffset {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get list of markup objects
|
||||
* @return list of markup objects
|
||||
* Returns the data type access portion of this variable offset as a string
|
||||
* @return the text
|
||||
*/
|
||||
public List<Object> getObjects() {
|
||||
public String getDataTypeDisplayText() {
|
||||
List<Object> objects = getObjects(false);
|
||||
LabelString labelString = (LabelString) objects.get(0);
|
||||
return labelString.toString();
|
||||
}
|
||||
|
||||
private List<Object> getObjects(boolean showScalarAdjustment) {
|
||||
|
||||
DataType dt = variable.getDataType();
|
||||
StringBuffer name = new StringBuffer(variable.getName());
|
||||
|
||||
long scalarAdjustment = 0;
|
||||
if (includeScalarAdjustment && (replacedElement instanceof Scalar)) {
|
||||
if (showScalarAdjustment && (replacedElement instanceof Scalar)) {
|
||||
Scalar s = (Scalar) replacedElement;
|
||||
scalarAdjustment = variable.isStackVariable() ? s.getSignedValue() : s.getValue();
|
||||
scalarAdjustment -= offset;
|
||||
|
@ -214,6 +220,14 @@ public class VariableOffset {
|
|||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of markup objects
|
||||
* @return list of markup objects
|
||||
*/
|
||||
public List<Object> getObjects() {
|
||||
return getObjects(includeScalarAdjustment);
|
||||
}
|
||||
|
||||
public Variable getVariable() {
|
||||
return variable;
|
||||
}
|
||||
|
|
|
@ -560,15 +560,46 @@ public class ReflectionUtilities {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type arguments for the given base class and extension.
|
||||
*
|
||||
* <p>Caveat: this lookup will only work if the given child class is a concrete class that
|
||||
* has its type arguments specified. For example, these cases will work:
|
||||
* <pre>
|
||||
* // anonymous class definition
|
||||
* List<String> myList = new ArrayList<String>() {
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* // class definition
|
||||
* public class MyList implements List<String> {
|
||||
* </pre>
|
||||
*
|
||||
* Whereas this case will not work:
|
||||
* <pre>
|
||||
* // local variable with the type specified
|
||||
* List<String> myList = new ArrayList<String>();
|
||||
* </pre>
|
||||
*
|
||||
* <p>Note: a null entry in the result list will exist for any type that was unrecoverable
|
||||
*
|
||||
*
|
||||
* @param <T> the type of the base and child class
|
||||
* @param baseClass the base class
|
||||
* @param childClass the child class
|
||||
* @return the type arguments
|
||||
*/
|
||||
public static <T> List<Class<?>> getTypeArguments(Class<T> baseClass,
|
||||
Class<? extends T> childClass) {
|
||||
Map<Type, Type> resolvedTypesDictionary = new HashMap<>();
|
||||
|
||||
Objects.requireNonNull(baseClass);
|
||||
Objects.requireNonNull(childClass);
|
||||
|
||||
Map<Type, Type> resolvedTypesDictionary = new HashMap<>();
|
||||
Type baseClassAsType =
|
||||
walkClassHierarchyAndResolveTypes(baseClass, resolvedTypesDictionary, childClass);
|
||||
|
||||
// now see if we can resolve the type arguments defined by 'baseClass' to the raw runtime
|
||||
// class that is in use
|
||||
// try to resolve type arguments defined by 'baseClass' to the raw runtime class
|
||||
Type[] baseClassDeclaredTypeArguments = getDeclaredTypeArguments(baseClassAsType);
|
||||
return resolveBaseClassTypeArguments(resolvedTypesDictionary,
|
||||
baseClassDeclaredTypeArguments);
|
||||
|
@ -577,29 +608,69 @@ public class ReflectionUtilities {
|
|||
private static <T> Type walkClassHierarchyAndResolveTypes(Class<T> baseClass,
|
||||
Map<Type, Type> resolvedTypes, Type type) {
|
||||
|
||||
while (!getClass(type).equals(baseClass)) {
|
||||
if (type instanceof Class) {
|
||||
type = ((Class<?>) type).getGenericSuperclass();
|
||||
}
|
||||
else {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
|
||||
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
|
||||
TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
|
||||
for (int i = 0; i < actualTypeArguments.length; i++) {
|
||||
resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
|
||||
}
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!rawType.equals(baseClass)) {
|
||||
type = rawType.getGenericSuperclass();
|
||||
if (equals(type, baseClass)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
if (type instanceof Class) {
|
||||
|
||||
Class<?> clazz = (Class<?>) type;
|
||||
Type[] interfaceTypes = clazz.getGenericInterfaces();
|
||||
Set<Type> toCheck = new HashSet<>();
|
||||
toCheck.addAll(Arrays.asList(interfaceTypes));
|
||||
|
||||
Type parentType = clazz.getGenericSuperclass();
|
||||
toCheck.add(parentType);
|
||||
|
||||
for (Type t : toCheck) {
|
||||
Type result = walkClassHierarchyAndResolveTypes(baseClass, resolvedTypes, t);
|
||||
if (equals(result, baseClass)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
return type;
|
||||
return parentType;
|
||||
}
|
||||
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
|
||||
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
|
||||
TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
|
||||
for (int i = 0; i < actualTypeArguments.length; i++) {
|
||||
resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
|
||||
}
|
||||
|
||||
if (rawType.equals(baseClass)) {
|
||||
return rawType;
|
||||
}
|
||||
|
||||
Type[] interfaceTypes = rawType.getGenericInterfaces();
|
||||
Set<Type> toCheck = new HashSet<>();
|
||||
toCheck.addAll(Arrays.asList(interfaceTypes));
|
||||
|
||||
Type parentType = rawType.getGenericSuperclass();
|
||||
toCheck.add(parentType);
|
||||
|
||||
for (Type t : toCheck) {
|
||||
Type result = walkClassHierarchyAndResolveTypes(baseClass, resolvedTypes, t);
|
||||
if (equals(result, baseClass)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
|
||||
return parentType;
|
||||
}
|
||||
|
||||
private static boolean equals(Type type, Class<?> c) {
|
||||
Class<?> typeClass = getClass(type);
|
||||
if (typeClass == null) {
|
||||
return false;
|
||||
}
|
||||
return typeClass.equals(c);
|
||||
}
|
||||
|
||||
private static Class<?> getClass(Type type) {
|
||||
|
@ -637,7 +708,6 @@ public class ReflectionUtilities {
|
|||
return typeArgumentsAsClasses;
|
||||
}
|
||||
|
||||
// we checked
|
||||
private static Type[] getDeclaredTypeArguments(Type type) {
|
||||
if (type instanceof Class) {
|
||||
return ((Class<?>) type).getTypeParameters();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</global>
|
||||
<stackpointer register="SP" space="RAM" growth="negative"/>
|
||||
<default_proto>
|
||||
<prototype name="__stdcall" extrapop="-2" stackshift="-2">
|
||||
<prototype name="__stdcall" extrapop="2" stackshift="2">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="1">
|
||||
<register name="A"/>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</global>
|
||||
<stackpointer register="SP" space="ram" growth="negative"/>
|
||||
<default_proto>
|
||||
<prototype name="__stdcall" extrapop="-2" stackshift="-2">
|
||||
<prototype name="__stdcall" extrapop="2" stackshift="2">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="1">
|
||||
<register name="A"/>
|
||||
|
|
|
@ -76,7 +76,6 @@
|
|||
<symbol name="USART3_UDRE" address="code:0x006E" entry="true"/>
|
||||
<symbol name="USART3_TX" address="code:0x0070" entry="true"/>
|
||||
|
||||
<!-- See /usr/lib/avr/include/avr/iom64.h -->
|
||||
<symbol name="PINA" address="mem:0x20"/>
|
||||
<symbol name="DDRA" address="mem:0x21"/>
|
||||
<symbol name="PORTA" address="mem:0x22"/>
|
||||
|
@ -134,14 +133,19 @@
|
|||
|
||||
<symbol name="SPMCSR" address="mem:0x57"/>
|
||||
|
||||
<symbol name="RAMPZ" address="mem:0x5b"/>
|
||||
<symbol name="EIND" address="mem:0x5c"/>
|
||||
<symbol name="_SPL" address="mem:0x5d"/>
|
||||
<symbol name="_SPH" address="mem:0x5e"/>
|
||||
<symbol name="SREG" address="mem:0x5f"/>
|
||||
<symbol name="WDTCSR" address="mem:0x60"/>
|
||||
<symbol name="CLKPR" address="mem:0x61"/>
|
||||
|
||||
<symbol name="PRR2" address="mem:0x63"/>
|
||||
<symbol name="PRR0" address="mem:0x64"/>
|
||||
<symbol name="PRR1" address="mem:0x65"/>
|
||||
<symbol name="OSCCAL" address="mem:0x66"/>
|
||||
|
||||
<symbol name="BGCR" address="mem:0x67"/>
|
||||
<symbol name="PCICR" address="mem:0x68"/>
|
||||
<symbol name="EICRA" address="mem:0x69"/>
|
||||
<symbol name="EICRB" address="mem:0x6a"/>
|
||||
|
@ -154,9 +158,10 @@
|
|||
<symbol name="TIMSK3" address="mem:0x71"/>
|
||||
<symbol name="TIMSK4" address="mem:0x72"/>
|
||||
<symbol name="TIMSK5" address="mem:0x73"/>
|
||||
<symbol name="XMCRA" address="mem:0x74"/>
|
||||
<symbol name="XMCRB" address="mem:0x75"/>
|
||||
|
||||
<symbol name="NEMCR" address="mem:0x75"/>
|
||||
|
||||
<symbol name="ADCSRC" address="mem:0x77"/>
|
||||
<symbol name="ADCL" address="mem:0x78"/>
|
||||
<symbol name="ADCH" address="mem:0x79"/>
|
||||
<symbol name="ADCSRA" address="mem:0x7a"/>
|
||||
|
@ -224,7 +229,8 @@
|
|||
<symbol name="TWDR" address="mem:0xbb"/>
|
||||
<symbol name="TWCR" address="mem:0xbc"/>
|
||||
<symbol name="TWAMR" address="mem:0xbd"/>
|
||||
|
||||
<symbol name="IRQ_MASK1" address="mem:0xbe"/>
|
||||
<symbol name="IRQ_STATUS1" address="mem:0xbf"/>
|
||||
<symbol name="UCSR0A" address="mem:0xc0"/>
|
||||
<symbol name="UCSR0B" address="mem:0xc1"/>
|
||||
<symbol name="UCSR0C" address="mem:0xc2"/>
|
||||
|
@ -245,22 +251,63 @@
|
|||
<symbol name="UCSR2B" address="mem:0xd1"/>
|
||||
<symbol name="UCSR2C" address="mem:0xd2"/>
|
||||
|
||||
<symbol name="UBRR2L" address="mem:0xd4"/>
|
||||
<symbol name="UBRR2H" address="mem:0xd5"/>
|
||||
<symbol name="UDR2" address="mem:0xd6"/>
|
||||
<symbol name="SCRSTRLL" address="mem:0xd7"/>
|
||||
<symbol name="SCRSTRLH " address="mem:0xd8"/>
|
||||
<symbol name="SCRSTRHL" address="mem:0xd9"/>
|
||||
<symbol name="SCRSTRHH" address="mem:0xda"/>
|
||||
<symbol name="SCCSR" address="mem:0xdb"/>
|
||||
<symbol name="SCCR0 " address="mem:0xdc"/>
|
||||
<symbol name="SCCR1" address="mem:0xdd"/>
|
||||
<symbol name="SCSR" address="mem:0xde"/>
|
||||
<symbol name="SCIRQM" address="mem:0xdf"/>
|
||||
<symbol name="SCIRQS" address="mem:0xe0"/>
|
||||
<symbol name="SCCNTLL " address="mem:0xe1"/>
|
||||
<symbol name="SCCNTLH" address="mem:0xe2"/>
|
||||
<symbol name="SCCNTHL" address="mem:0xe3"/>
|
||||
<symbol name="SCCNTHH" address="mem:0xe4"/>
|
||||
<symbol name="SCBTSRLL " address="mem:0xe5"/>
|
||||
<symbol name="SCBTSRLH" address="mem:0xe6"/>
|
||||
<symbol name="SCBTSRHL" address="mem:0xe7"/>
|
||||
<symbol name="SCBTSRHH" address="mem:0xe8"/>
|
||||
<symbol name="SCTSRLL" address="mem:0xe9"/>
|
||||
<symbol name="SCTSRLH" address="mem:0xea"/>
|
||||
<symbol name="SCTSRHL" address="mem:0xeb"/>
|
||||
<symbol name="SCTSRHH" address="mem:0xec"/>
|
||||
<symbol name="SCOCR3LL" address="mem:0xed"/>
|
||||
<symbol name="SCOCR3LH" address="mem:0xee"/>
|
||||
<symbol name="SCOCR3HL" address="mem:0xef"/>
|
||||
<symbol name="SCOCR3HH" address="mem:0xf0"/>
|
||||
<symbol name="SCOCR2LL " address="mem:0xf1"/>
|
||||
<symbol name="SCOCR2LH" address="mem:0xf2"/>
|
||||
<symbol name="SCOCR2HL" address="mem:0xf3"/>
|
||||
<symbol name="SCOCR2HH" address="mem:0xf4"/>
|
||||
<symbol name="SCOCR1LL " address="mem:0xf5"/>
|
||||
<symbol name="SCOCR1LH" address="mem:0xf6"/>
|
||||
<symbol name="SCOCR1HL" address="mem:0xf7"/>
|
||||
<symbol name="SCOCR1HH" address="mem:0xf8"/>
|
||||
<symbol name="SCTSTRLL" address="mem:0xf9"/>
|
||||
<symbol name="SCTSTRLH" address="mem:0xfa"/>
|
||||
<symbol name="SCTSTRHL" address="mem:0xfb"/>
|
||||
<symbol name="SCTSTRHH" address="mem:0xfc"/>
|
||||
|
||||
<symbol name="PINH" address="mem:0x100"/>
|
||||
<symbol name="DDRH" address="mem:0x101"/>
|
||||
<symbol name="PORTH" address="mem:0x102"/>
|
||||
<symbol name="PINJ" address="mem:0x103"/>
|
||||
<symbol name="DDRJ" address="mem:0x104"/>
|
||||
<symbol name="PORTJ" address="mem:0x105"/>
|
||||
<symbol name="PINK" address="mem:0x106"/>
|
||||
<symbol name="DDRK" address="mem:0x107"/>
|
||||
<symbol name="PORK" address="mem:0x108"/>
|
||||
<symbol name="PINL" address="mem:0x109"/>
|
||||
<symbol name="DDRL" address="mem:0x10a"/>
|
||||
<symbol name="PORTL" address="mem:0x10b"/>
|
||||
<symbol name="MAFCR0" address="mem:0x100c"/>
|
||||
<symbol name="MAFCR1" address="mem:0x10d"/>
|
||||
<symbol name="MAFSA0L" address="mem:0x10e"/>
|
||||
<symbol name="MAFSA0H" address="mem:0x10f"/>
|
||||
<symbol name="MAFPA0L" address="mem:0x110"/>
|
||||
<symbol name="MAFPA0H" address="mem:0x111"/>
|
||||
<symbol name="MAFSA1L" address="mem:0x112"/>
|
||||
<symbol name="MAFSA1H" address="mem:0x113"/>
|
||||
<symbol name="MAFPA1L" address="mem:0x114"/>
|
||||
<symbol name="MAFPA1H" address="mem:0x115"/>
|
||||
<symbol name="MAFSA2L" address="mem:0x116"/>
|
||||
<symbol name="MAFSA2H" address="mem:0x117"/>
|
||||
<symbol name="MAFPA2L" address="mem:0x1018"/>
|
||||
<symbol name="MAFPA2H" address="mem:0x119"/>
|
||||
<symbol name="MAFSA3L" address="mem:0x11a"/>
|
||||
<symbol name="MAFSA3H" address="mem:0x11b"/>
|
||||
<symbol name="MAFPA3L" address="mem:0x11c"/>
|
||||
<symbol name="MAFPA3H" address="mem:0x11d"/>
|
||||
|
||||
<symbol name="TCCR5A" address="mem:0x120"/>
|
||||
<symbol name="TCCR5B" address="mem:0x121"/>
|
||||
|
@ -277,21 +324,87 @@
|
|||
<symbol name="OCR5CL" address="mem:0x12c"/>
|
||||
<symbol name="OCR5CH" address="mem:0x12d"/>
|
||||
|
||||
<symbol name="UCSR3A" address="mem:0x130"/>
|
||||
<symbol name="UCSR3B" address="mem:0x131"/>
|
||||
<symbol name="UCSR3C" address="mem:0x132"/>
|
||||
|
||||
<symbol name="UBRR3L" address="mem:0x134"/>
|
||||
<symbol name="UBRR3H" address="mem:0x135"/>
|
||||
<symbol name="UDR3" address="mem:0x136"/>
|
||||
<symbol name="LLCR" address="mem:0x12f"/>
|
||||
<symbol name="LLDRL" address="mem:0x130"/>
|
||||
<symbol name="LLDRH" address="mem:0x131"/>
|
||||
<symbol name="DRTRAM3" address="mem:0x132"/>
|
||||
<symbol name="DRTRAM2" address="mem:0x133"/>
|
||||
<symbol name="DRTRAM1" address="mem:0x134"/>
|
||||
<symbol name="DRTRAM0" address="mem:0x135"/>
|
||||
<symbol name="DPDS0" address="mem:0x136"/>
|
||||
<symbol name="DPDS1" address="mem:0x137"/>
|
||||
<symbol name="PARCR" address="mem:0x138"/>
|
||||
<symbol name="TRXPR" address="mem:0x139"/>
|
||||
|
||||
<symbol name="AES_CTRL" address="mem:0x13c"/>
|
||||
<symbol name="AES_STATUS" address="mem:0x13d"/>
|
||||
<symbol name="AES_STATE" address="mem:0x13e"/>
|
||||
<symbol name="AES_KEY" address="mem:0x13f"/>
|
||||
|
||||
<symbol name="TRX_STATUS" address="mem:0x141"/>
|
||||
<symbol name="TRX_STATE" address="mem:0x142"/>
|
||||
<symbol name="TRX_CTRL_0" address="mem:0x143"/>
|
||||
<symbol name="TRX_CTRL_1" address="mem:0x144"/>
|
||||
<symbol name="PHY_TX_PWR" address="mem:0x145"/>
|
||||
<symbol name="PHY_RSSI" address="mem:0x146"/>
|
||||
<symbol name="PHY_ED_LEVEL" address="mem:0x147"/>
|
||||
<symbol name="PHY_CC_CCA" address="mem:0x148"/>
|
||||
<symbol name="CCA_THRES" address="mem:0x149"/>
|
||||
<symbol name="RX_CTRL" address="mem:0x14a"/>
|
||||
<symbol name="SFD_VALUE" address="mem:0x14b"/>
|
||||
<symbol name="TRX_CTRL_2" address="mem:0x14c"/>
|
||||
<symbol name="ANT_DIV" address="mem:0x14d"/>
|
||||
<symbol name="IRQ_MASK" address="mem:0x14e"/>
|
||||
<symbol name="IRQ_STATUS" address="mem:0x14f"/>
|
||||
<symbol name="VREG_CTRL" address="mem:0x150"/>
|
||||
<symbol name="BATMON" address="mem:0x151"/>
|
||||
<symbol name="XOSC_CTRL" address="mem:0x152"/>
|
||||
<symbol name="CC_CTRL_0" address="mem:0x153"/>
|
||||
<symbol name="CC_CTRL_1" address="mem:0x154"/>
|
||||
<symbol name="RX_SYN" address="mem:0x155"/>
|
||||
<symbol name="TRX_RPC" address="mem:0x156"/>
|
||||
<symbol name="XAH_CTRL_1" address="mem:0x157"/>
|
||||
<symbol name="FTN_CTRL" address="mem:0x158"/>
|
||||
|
||||
<symbol name="PLL_CF" address="mem:0x15a"/>
|
||||
<symbol name="PLL_DCU" address="mem:0x15b"/>
|
||||
<symbol name="PART_NUM" address="mem:0x15c"/>
|
||||
<symbol name="VERSION_NUM " address="mem:0x15d"/>
|
||||
<symbol name="MAN_ID_0" address="mem:0x15e"/>
|
||||
<symbol name="MAN_ID_1" address="mem:0x15f"/>
|
||||
<symbol name="SHORT_ADDR_0" address="mem:0x160"/>
|
||||
<symbol name="SHORT_ADDR_1" address="mem:0x161"/>
|
||||
<symbol name="PAN_ID_0" address="mem:0x162"/>
|
||||
<symbol name="PAN_ID_1" address="mem:0x163"/>
|
||||
<symbol name="IEEE_ADDR_0" address="mem:0x164"/>
|
||||
<symbol name="IEEE_ADDR_1" address="mem:0x165"/>
|
||||
<symbol name="IEEE_ADDR_2" address="mem:0x166"/>
|
||||
<symbol name="IEEE_ADDR_3" address="mem:0x167"/>
|
||||
<symbol name="IEEE_ADDR_4" address="mem:0x168"/>
|
||||
<symbol name="IEEE_ADDR_5" address="mem:0x169"/>
|
||||
<symbol name="IEEE_ADDR_6" address="mem:0x16a"/>
|
||||
<symbol name="IEEE_ADDR_7" address="mem:0x16b"/>
|
||||
<symbol name="XAH_CTRL_0" address="mem:0x16c"/>
|
||||
<symbol name="CSMA_SEED_0" address="mem:0x16d"/>
|
||||
<symbol name="CSMA_SEED_1" address="mem:0x16e"/>
|
||||
<symbol name="CSMA_BE" address="mem:0x16f"/>
|
||||
|
||||
<symbol name="TST_CTRL_DIGI" address="mem:0x176"/>
|
||||
|
||||
<symbol name="TST_RX_LENGTH" address="mem:0x17b"/>
|
||||
<symbol name="TST_AGC" address="mem:0x17c"/>
|
||||
<symbol name="TST_SDM" address="mem:0x17d"/>
|
||||
|
||||
<symbol name="TRXFBST" address="mem:0x180"/>
|
||||
|
||||
<symbol name="TRXFBEND" address="mem:0x1ff"/>
|
||||
|
||||
</default_symbols>
|
||||
|
||||
<default_memory_blocks>
|
||||
<memory_block name="regalias" start_address="mem:0x00" length="0x20" initialized="false"/>
|
||||
<memory_block name="iospace" start_address="mem:0x20" length="0xd0" initialized="false"/>
|
||||
<memory_block name="mem" start_address="mem:0x200" length="0xf00" initialized="false"/>
|
||||
<memory_block name="iospace" start_address="mem:0x20" length="0x1e0" initialized="false"/>
|
||||
<memory_block name="data" start_address="mem:0x200" length="0x2000" initialized="false"/>
|
||||
</default_memory_blocks>
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</global>
|
||||
<stackpointer register="sp" space="ram" growth="positive"/>
|
||||
<default_proto>
|
||||
<prototype name="__stdcall" extrapop="unknown" stackshift="4">
|
||||
<prototype name="__stdcall" extrapop="unknown" stackshift="-4">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="4">
|
||||
<register name="r12"/>
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue