mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-09-20 09:31:47 +00:00
Merge branch 'NationalSecurityAgency:master' into master
This commit is contained in:
commit
dc2e1c537e
|
@ -27,12 +27,10 @@ import ghidra.base.help.GhidraHelpService;
|
|||
import ghidra.framework.Application;
|
||||
import ghidra.framework.GhidraApplicationConfiguration;
|
||||
import ghidra.framework.client.RepositoryAdapter;
|
||||
import ghidra.framework.data.DomainObjectAdapter;
|
||||
import ghidra.framework.main.FrontEndTool;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.project.DefaultProjectManager;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.UsrException;
|
||||
import ghidra.util.extensions.ExtensionUtils;
|
||||
|
@ -90,6 +88,9 @@ public class GhidraRun implements GhidraLaunchable {
|
|||
SystemUtilities.runSwingLater(() -> {
|
||||
String projectPath = processArguments(args);
|
||||
openProject(projectPath);
|
||||
|
||||
log.info("Ghidra starup complete (" + GhidraLauncher.getMillisecondsFromLaunch() +
|
||||
" ms)");
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -86,8 +86,8 @@ public class DataTypeSettingsDialog extends AbstractSettingsDialog {
|
|||
nameBuf.append("Default ");
|
||||
}
|
||||
String name = dataType.getDisplayName();
|
||||
// default array settings defer to base type
|
||||
if (dtc == null) {
|
||||
// default array settings defer to base type
|
||||
name = getSettingsBaseType(dataType).getDisplayName();
|
||||
}
|
||||
nameBuf.append(name);
|
||||
|
@ -147,6 +147,7 @@ public class DataTypeSettingsDialog extends AbstractSettingsDialog {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applySettings() {
|
||||
DataTypeManager dtm = dataType.getDataTypeManager();
|
||||
int txId = dtm.startTransaction(getTitle());
|
||||
|
|
|
@ -201,6 +201,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
MemoryBlockType.BIT_MAPPED, MemoryBlockType.BYTE_MAPPED };
|
||||
|
||||
comboBox = new GhidraComboBox<>(items);
|
||||
comboBox.getAccessibleContext().setAccessibleName("Block Type");
|
||||
comboBox.addItemListener(e -> blockTypeSelected());
|
||||
panel.add(comboBox);
|
||||
return panel;
|
||||
|
@ -265,6 +266,9 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
initialValueLabel = new GDLabel("Initial Value");
|
||||
initialValueField = new RegisterField(8, null, false);
|
||||
initialValueField.setName("Initial Value");
|
||||
initialValueField.getAccessibleContext().setAccessibleName("Initialized Block Value");
|
||||
initialValueField.getAccessibleContext()
|
||||
.setAccessibleDescription("Enter the initial value for every byte in this block");
|
||||
|
||||
initialValueField.setChangeListener(e -> initialValueChanged());
|
||||
|
||||
|
@ -299,6 +303,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
return preferredSize;
|
||||
}
|
||||
};
|
||||
fileBytesComboBox.getAccessibleContext().setAccessibleName("Byte Source");
|
||||
fileBytesComboBox.addItemListener(e -> fileBytesChanged());
|
||||
if (!allFileBytes.isEmpty()) {
|
||||
model.setFileBytes(allFileBytes.get(0));
|
||||
|
@ -477,6 +482,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
baseAddrField.setAddressFactory(addrFactory);
|
||||
baseAddrField.setName("Source Addr");
|
||||
baseAddrField.addChangeListener(ev -> baseAddressChanged());
|
||||
baseAddrField.setAccessibleName("Source Address");
|
||||
|
||||
JPanel schemePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||
|
||||
|
@ -485,12 +491,14 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
schemeDestByteCountField.setAllowsHexPrefix(false);
|
||||
schemeDestByteCountField.setDecimalMode();
|
||||
schemeDestByteCountField.addChangeListener(ev -> schemeDestByteCountChanged());
|
||||
schemeDestByteCountField.setAccessibleName("Mapping Ratio: Destination Size");
|
||||
|
||||
schemeSrcByteCountField = new IntegerTextField(4, 1);
|
||||
schemeSrcByteCountField.setAllowNegativeValues(false);
|
||||
schemeSrcByteCountField.setAllowsHexPrefix(false);
|
||||
schemeSrcByteCountField.setDecimalMode();
|
||||
schemeSrcByteCountField.addChangeListener(ev -> schemeSrcByteCountChanged());
|
||||
schemeSrcByteCountField.setAccessibleName("Mapping Ratio: Source Size");
|
||||
|
||||
schemePanel.add(schemeDestByteCountField.getComponent());
|
||||
schemePanel.add(new GLabel(" : "));
|
||||
|
@ -516,6 +524,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
private Component buildCommentField() {
|
||||
commentField = new JTextField();
|
||||
commentField.setName("Comment");
|
||||
commentField.getAccessibleContext().setAccessibleName("Memory Block Comment");
|
||||
commentField.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
|
@ -538,6 +547,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
private Component buildLengthField() {
|
||||
lengthField = new RegisterField(36, null, false);
|
||||
lengthField.setName("Length");
|
||||
lengthField.getAccessibleContext().setAccessibleName("Memory Block Length");
|
||||
lengthField.setChangeListener(e -> lengthChanged());
|
||||
return lengthField;
|
||||
}
|
||||
|
@ -545,6 +555,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
private Component buildFileOffsetField() {
|
||||
fileOffsetField = new RegisterField(60, null, false);
|
||||
fileOffsetField.setName("File Offset");
|
||||
fileOffsetField.getAccessibleContext().setAccessibleName("File Offset");
|
||||
fileOffsetField.setChangeListener(e -> fileOffsetChanged());
|
||||
return fileOffsetField;
|
||||
}
|
||||
|
@ -552,6 +563,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
private Component buildAddressField() {
|
||||
addrField = new AddressInput();
|
||||
addrField.setName("Start Addr");
|
||||
addrField.setAccessibleName("Memory Block Start Address");
|
||||
addrFactory = model.getProgram().getAddressFactory();
|
||||
addrField.setAddressFactory(addrFactory, AddressInput.INCLUDE_ALL_MEMORY_SPACES);
|
||||
addrField.addChangeListener(ev -> addrChanged());
|
||||
|
@ -561,6 +573,7 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
private Component buildNameField() {
|
||||
nameField = new JTextField();
|
||||
nameField.setName("Block Name");
|
||||
nameField.getAccessibleContext().setAccessibleName("Memory Block Name");
|
||||
nameField.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
|
|
|
@ -114,9 +114,13 @@ class ExpandBlockDialog extends DialogComponentProvider implements ChangeListene
|
|||
startAddressInput = new AddressInput();
|
||||
startAddressInput.setName("NewStartAddress");
|
||||
startAddressInput.setAddressFactory(addrFactory);
|
||||
startAddressInput.setAccessibleName("New Start Address");
|
||||
|
||||
endAddressInput = new AddressInput();
|
||||
endAddressInput.setName("EndAddress");
|
||||
endAddressInput.setAddressFactory(addrFactory);
|
||||
endAddressInput.setAccessibleName("New End Address");
|
||||
|
||||
Address start = block.getStart();
|
||||
Address end = block.getEnd();
|
||||
|
||||
|
@ -139,6 +143,7 @@ class ExpandBlockDialog extends DialogComponentProvider implements ChangeListene
|
|||
|
||||
lengthField = new RegisterField(32, null, false);
|
||||
lengthField.setName("BlockLength");
|
||||
lengthField.getAccessibleContext().setAccessibleName("Block Length");
|
||||
lengthField.setValue(Long.valueOf(model.getLength()));
|
||||
|
||||
panel.add(
|
||||
|
|
|
@ -67,6 +67,8 @@ class ImageBaseDialog extends DialogComponentProvider {
|
|||
JPanel panel = new JPanel(new MiddleLayout());
|
||||
textField = new JTextField(20);
|
||||
textField.setText(currentAddr.toString());
|
||||
textField.getAccessibleContext().setAccessibleName("Image Base Address");
|
||||
|
||||
textField.selectAll();
|
||||
textField.addActionListener(e -> {
|
||||
if (addr != null) {
|
||||
|
|
|
@ -94,14 +94,18 @@ class SplitBlockDialog extends DialogComponentProvider {
|
|||
panelOne.setBorder(BorderFactory.createTitledBorder("Block to Split"));
|
||||
blockOneNameField = new JTextField(10);
|
||||
blockOneNameField.setName("BlockOneName");
|
||||
blockOneNameField.getAccessibleContext().setAccessibleName("Name of Block To Split");
|
||||
blockOneStartField = new JTextField(10);
|
||||
blockOneStartField.setName("BlockOneStart");
|
||||
blockOneStartField.getAccessibleContext().setAccessibleName("Address of Block To Split");
|
||||
|
||||
blockOneEnd = new AddressInput();
|
||||
blockOneEnd.setName("BlockOneEnd");
|
||||
blockOneEnd.setAccessibleName("New Block End Adddress");
|
||||
|
||||
blockOneLengthField = new RegisterField(32, null, false);
|
||||
blockOneLengthField.setName("BlockOneLength");
|
||||
blockOneLengthField.getAccessibleContext().setAccessibleName("New Block Length");
|
||||
|
||||
panelOne.add(new GLabel("Block Name:", SwingConstants.RIGHT));
|
||||
panelOne.add(blockOneNameField);
|
||||
|
@ -116,13 +120,16 @@ class SplitBlockDialog extends DialogComponentProvider {
|
|||
panelTwo.setBorder(BorderFactory.createTitledBorder("New Block"));
|
||||
blockTwoNameField = new JTextField(10);
|
||||
blockTwoNameField.setName("BlockTwoName");
|
||||
blockTwoNameField.getAccessibleContext().setAccessibleName("Name of New Block");
|
||||
blockTwoStart = new AddressInput();
|
||||
blockTwoStart.setName("BlockTwoStart");
|
||||
blockTwoStart.setAccessibleName("New Block Start Address");
|
||||
blockTwoEndField = new JTextField(10);
|
||||
blockTwoEndField.setName("BlockTwoEnd");
|
||||
|
||||
blockTwoLengthField = new RegisterField(32, null, false);
|
||||
blockTwoLengthField.setName("BlockTwoLength");
|
||||
blockTwoLengthField.getAccessibleContext().setAccessibleName("New Block Size");
|
||||
|
||||
panelTwo.add(new GLabel("Block Name:", SwingConstants.RIGHT));
|
||||
panelTwo.add(blockTwoNameField);
|
||||
|
|
|
@ -71,6 +71,7 @@ class EditExternalReferencePanel extends EditReferencePanel {
|
|||
|
||||
topPanel.add(new GLabel("Name:", SwingConstants.RIGHT));
|
||||
extLibName = new GhidraComboBox<>();
|
||||
extLibName.getAccessibleContext().setAccessibleDescription("Choose external program name");
|
||||
extLibName.setEditable(true);
|
||||
extLibName.addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
|
@ -136,10 +137,12 @@ class EditExternalReferencePanel extends EditReferencePanel {
|
|||
|
||||
bottomPanel.add(new GLabel("Label:", SwingConstants.RIGHT));
|
||||
extLabel = new JTextField();
|
||||
extLabel.getAccessibleContext().setAccessibleName("External Label");
|
||||
bottomPanel.add(extLabel);
|
||||
|
||||
bottomPanel.add(new GLabel("Address:", SwingConstants.RIGHT));
|
||||
extAddr = new AddressInput();
|
||||
extAddr.getAccessibleContext().setAccessibleName("External Address");
|
||||
bottomPanel.add(extAddr);
|
||||
|
||||
setLayout(new VerticalLayout(5));
|
||||
|
|
|
@ -35,6 +35,7 @@ import docking.widgets.checkbox.GCheckBox;
|
|||
import docking.widgets.combobox.GhidraComboBox;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import docking.widgets.label.GLabel;
|
||||
import docking.widgets.table.GTable;
|
||||
import generic.theme.GColor;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import ghidra.app.util.AddressInput;
|
||||
|
@ -79,7 +80,7 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
private long defaultOffset;
|
||||
private JWindow historyWin;
|
||||
private HistoryTableModel model;
|
||||
private JTable displayTable;
|
||||
private GTable displayTable;
|
||||
|
||||
private boolean isValidState;
|
||||
|
||||
|
@ -98,9 +99,13 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
setLayout(new PairLayout(10, 10, 160));
|
||||
|
||||
offsetCheckbox = new GCheckBox("Offset:");
|
||||
offsetCheckbox.getAccessibleContext()
|
||||
.setAccessibleDescription(
|
||||
"Selecting this checkbox allows entering a refernce offset");
|
||||
offsetCheckbox.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
offsetCheckbox.addChangeListener(e -> enableOffsetField(offsetCheckbox.isSelected()));
|
||||
offsetField = new JTextField();
|
||||
offsetField.getAccessibleContext().setAccessibleName("Enter Offset");
|
||||
|
||||
addrLabel = new GDLabel("Base Address:");
|
||||
addrLabel.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
|
@ -108,19 +113,12 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
addrLabel.setPreferredSize(d);
|
||||
|
||||
toAddressField = new AddressInput();
|
||||
addrLabel.setLabelFor(toAddressField);
|
||||
|
||||
addrHistoryButton = new GButton(MENU_ICON);
|
||||
addrHistoryButton.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (addrHistoryButton.isEnabled()) {
|
||||
toggleAddressHistoryPopup();
|
||||
}
|
||||
}
|
||||
});
|
||||
addrHistoryButton.addActionListener(e -> toggleAddressHistoryPopup());
|
||||
addrHistoryButton.setText(null);
|
||||
addrHistoryButton.setMargin(new Insets(0, 0, 0, 0));
|
||||
addrHistoryButton.setFocusable(false);
|
||||
addrHistoryButton.setToolTipText("Address History");
|
||||
|
||||
includeOtherOverlaysCheckbox = new JCheckBox("Include OTHER overlay spaces",
|
||||
|
@ -128,6 +126,7 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
includeOtherOverlaysCheckbox.addChangeListener(e -> refreshToAddressField());
|
||||
|
||||
refTypes = new GhidraComboBox<>(MEM_REF_TYPES);
|
||||
refTypes.getAccessibleContext().setAccessibleName("Memory Ref Types");
|
||||
|
||||
JPanel addrPanel = new JPanel(new BorderLayout());
|
||||
addrPanel.add(toAddressField, BorderLayout.CENTER);
|
||||
|
@ -554,25 +553,27 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
return;
|
||||
}
|
||||
|
||||
List<Address> list = addrHistoryMap.get(fromCodeUnit.getProgram());
|
||||
Address[] addrs = new Address[list.size()];
|
||||
list.toArray(addrs);
|
||||
|
||||
JPanel panel = new JPanel(new BorderLayout(0, 0));
|
||||
|
||||
model = new HistoryTableModel(fromCodeUnit.getProgram());
|
||||
displayTable = new JTable(model);
|
||||
displayTable = new GTable(model);
|
||||
displayTable.setTableHeader(null);
|
||||
displayTable.setBorder(new LineBorder(Colors.BORDER));
|
||||
displayTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
displayTable.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
int keyCode = e.getKeyCode();
|
||||
if (keyCode == KeyEvent.VK_ENTER || keyCode == KeyEvent.VK_SPACE) {
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
displayTable.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
int row = displayTable.getSelectedRow();
|
||||
Address addr = model.getAddress(row);
|
||||
toAddressField.setAddress(addr);
|
||||
toggleAddressHistoryPopup();
|
||||
chooseEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -596,13 +597,17 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
|
||||
panel.add(displayTable, BorderLayout.CENTER);
|
||||
|
||||
// Sets the preferred size to the table inside this popup history window so that its width
|
||||
// is the same as the text field and button to make it resemble the look of a combo box.
|
||||
// We also had to add a fudge factor to the height to keep it from truncating the last
|
||||
// row in the table.
|
||||
int w = toAddressField.getWidth() + addrHistoryButton.getWidth();
|
||||
Dimension d = displayTable.getPreferredSize();
|
||||
displayTable.setPreferredSize(new Dimension(w, d.height));
|
||||
displayTable.setPreferredSize(new Dimension(w, d.height + 10));
|
||||
|
||||
Window dlgWin = findMyWindow();
|
||||
historyWin = new JWindow(dlgWin);
|
||||
historyWin.getContentPane().setLayout(new BorderLayout(0, 0));
|
||||
historyWin.getContentPane().setLayout(new BorderLayout());
|
||||
historyWin.getContentPane().add(panel, BorderLayout.CENTER);
|
||||
historyWin.pack();
|
||||
|
||||
|
@ -655,6 +660,15 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
});
|
||||
}
|
||||
|
||||
private void chooseEntry() {
|
||||
int row = displayTable.getSelectedRow();
|
||||
if (row >= 0) {
|
||||
Address addr = model.getAddress(row);
|
||||
toAddressField.setAddress(addr);
|
||||
toggleAddressHistoryPopup();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTableSelectionForEvent(MouseEvent anEvent) {
|
||||
Point location = anEvent.getPoint();
|
||||
if (displayTable == null) {
|
||||
|
|
|
@ -159,7 +159,6 @@ public class EditReferenceDialog extends ReusableDialogComponentProvider {
|
|||
|
||||
bottomPanelLayout = new CardLayout();
|
||||
bottomPanel = new JPanel(bottomPanelLayout);
|
||||
bottomPanel.setFocusCycleRoot(true);
|
||||
bottomPanel.setPreferredSize(new Dimension(PREFERRED_PANEL_WIDTH, PREFERRED_PANEL_HEIGHT));
|
||||
bottomPanel.setBorder(new EmptyBorder(0, 2, 0, 2));
|
||||
|
||||
|
@ -235,7 +234,6 @@ public class EditReferenceDialog extends ReusableDialogComponentProvider {
|
|||
activeRefPanel = extRefPanel;
|
||||
}
|
||||
bottomPanelLayout.show(bottomPanel, activeRefPanel.getName());
|
||||
activeRefPanel.requestFocus();
|
||||
}
|
||||
|
||||
public void initDialog(CodeUnit cu, int opIndex, int subIndex, Reference ref) {
|
||||
|
@ -252,7 +250,6 @@ public class EditReferenceDialog extends ReusableDialogComponentProvider {
|
|||
}
|
||||
|
||||
initializing = false;
|
||||
activeRefPanel.requestFocus();
|
||||
}
|
||||
|
||||
private void configureAddReference(int opIndex, int subIndex) {
|
||||
|
|
|
@ -56,9 +56,10 @@ class EditRegisterReferencePanel extends EditReferencePanel {
|
|||
setBorder(new EmptyBorder(0, 5, 5, 5));
|
||||
|
||||
regList = new GhidraComboBox<>();
|
||||
regList.getAccessibleContext().setAccessibleName("Registers");
|
||||
|
||||
refTypes = new GhidraComboBox<>(REGISTER_REF_TYPES);
|
||||
|
||||
refTypes.getAccessibleContext().setAccessibleName("Ref Types");
|
||||
add(new GLabel("Register:", SwingConstants.RIGHT));
|
||||
add(regList);
|
||||
add(new GLabel("Ref-Type:", SwingConstants.RIGHT));
|
||||
|
@ -180,8 +181,9 @@ class EditRegisterReferencePanel extends EditReferencePanel {
|
|||
return false;
|
||||
}
|
||||
|
||||
Function f = fromCodeUnit.getProgram().getFunctionManager().getFunctionContaining(
|
||||
fromCodeUnit.getMinAddress());
|
||||
Function f = fromCodeUnit.getProgram()
|
||||
.getFunctionManager()
|
||||
.getFunctionContaining(fromCodeUnit.getMinAddress());
|
||||
if (f == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -207,8 +209,9 @@ class EditRegisterReferencePanel extends EditReferencePanel {
|
|||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
Function f = fromCodeUnit.getProgram().getFunctionManager().getFunctionContaining(
|
||||
fromCodeUnit.getMinAddress());
|
||||
Function f = fromCodeUnit.getProgram()
|
||||
.getFunctionManager()
|
||||
.getFunctionContaining(fromCodeUnit.getMinAddress());
|
||||
if (f == null) {
|
||||
// Function no longer exists
|
||||
showInputErr("Register reference not permitted!\nAddress " +
|
||||
|
|
|
@ -58,8 +58,10 @@ class EditStackReferencePanel extends EditReferencePanel {
|
|||
setBorder(new EmptyBorder(0, 5, 5, 5));
|
||||
|
||||
stackOffset = new JTextField();
|
||||
stackOffset.getAccessibleContext().setAccessibleName("Stack Offset");
|
||||
|
||||
refTypes = new GhidraComboBox<>(STACK_REF_TYPES);
|
||||
refTypes.getAccessibleContext().setAccessibleName("Ref Types");
|
||||
|
||||
add(new GLabel("Stack Offset:", SwingConstants.RIGHT));
|
||||
add(stackOffset);
|
||||
|
@ -129,8 +131,9 @@ class EditStackReferencePanel extends EditReferencePanel {
|
|||
return false;
|
||||
}
|
||||
|
||||
Function f = fromCodeUnit.getProgram().getFunctionManager().getFunctionContaining(
|
||||
fromCodeUnit.getMinAddress());
|
||||
Function f = fromCodeUnit.getProgram()
|
||||
.getFunctionManager()
|
||||
.getFunctionContaining(fromCodeUnit.getMinAddress());
|
||||
if (f == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import docking.actions.KeyBindingUtils;
|
|||
import docking.dnd.DropTgtAdapter;
|
||||
import docking.dnd.Droppable;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import generic.theme.GColor;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import generic.theme.Gui;
|
||||
import ghidra.app.util.*;
|
||||
|
@ -44,10 +45,10 @@ import ghidra.program.model.mem.Memory;
|
|||
import ghidra.program.model.symbol.*;
|
||||
|
||||
class InstructionPanel extends JPanel implements ChangeListener {
|
||||
|
||||
private static Color FOCUS_COLOR = new GColor("color.palette.yellow");
|
||||
private static final int BORDER_SIZE = 2;
|
||||
private static final Border EMPTY_BORDER = new EmptyBorder(BORDER_SIZE,
|
||||
BORDER_SIZE, BORDER_SIZE, BORDER_SIZE);
|
||||
private static final Border EMPTY_BORDER =
|
||||
new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE);
|
||||
private static final Border ETCHED_BORDER = new EtchedBorder();
|
||||
|
||||
private final static Color NOT_IN_MEMORY_COLOR = Colors.ERROR;
|
||||
|
@ -75,79 +76,13 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
|
||||
private boolean dropSupported;
|
||||
private DropTgtAdapter dropTargetAdapter;
|
||||
private Droppable dropHandler = new Droppable() {
|
||||
|
||||
/**
|
||||
* Set drag feedback according to the ok parameter.
|
||||
* @param ok true means the drop action is OK
|
||||
* @param e event that has current state of drag and drop operation
|
||||
*/
|
||||
@Override
|
||||
public void dragUnderFeedback(boolean ok, DropTargetDragEvent e) {
|
||||
// stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if is OK to drop the transferable at the location
|
||||
* specified the event.
|
||||
* @param e event that has current state of drag and drop operation
|
||||
*/
|
||||
@Override
|
||||
public boolean isDropOk(DropTargetDragEvent e) {
|
||||
|
||||
Component targetComp = e.getDropTargetContext().getComponent();
|
||||
if (targetComp instanceof JLabel) {
|
||||
|
||||
updateLabels(getLabelIndex((JLabel) targetComp), -1);
|
||||
|
||||
try {
|
||||
Object data = e.getTransferable()
|
||||
.getTransferData(
|
||||
SelectionTransferable.localProgramSelectionFlavor);
|
||||
AddressSetView view = ((SelectionTransferData) data).getAddressSet();
|
||||
if (memory.contains(view)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (UnsupportedFlavorException e1) {
|
||||
// return false
|
||||
}
|
||||
catch (IOException e1) {
|
||||
// return false
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoDragUnderFeedback() {
|
||||
// stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the object to the droppable component. The DropTargetAdapter
|
||||
* calls this method from its drop() method.
|
||||
* @param obj Transferable object that is to be dropped; in this
|
||||
* case, it is an AddressSetView
|
||||
* @param e has current state of drop operation
|
||||
* @param f represents the opaque concept of a data format as
|
||||
* would appear on a clipboard, during drag and drop.
|
||||
*/
|
||||
@Override
|
||||
public void add(Object obj, DropTargetDropEvent e, DataFlavor f) {
|
||||
AddressSetView view = ((SelectionTransferData) obj).getAddressSet();
|
||||
if (view.getNumAddressRanges() == 0) {
|
||||
return;
|
||||
}
|
||||
listener.selectionDropped(view, currentCodeUnit, activeIndex);
|
||||
}
|
||||
|
||||
};
|
||||
private Droppable dropHandler = new InstructionPanelDroppable();
|
||||
private int nOperands;
|
||||
|
||||
InstructionPanel(int topPad, int leftPad, int bottomPad, int rightPad,
|
||||
DockingAction goHomeAction, ReferencesPlugin plugin,
|
||||
InstructionPanelListener listener) {
|
||||
super();
|
||||
super(new BorderLayout());
|
||||
this.dropSupported = listener != null ? listener.dropSupported() : false;
|
||||
this.goHomeAction = goHomeAction;
|
||||
this.symbolInspector = plugin.getSymbolInspector();
|
||||
|
@ -156,13 +91,39 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
create(topPad, leftPad, bottomPad, rightPad);
|
||||
}
|
||||
|
||||
private int getNextIndex() {
|
||||
if (operandLabels.length == 0) {
|
||||
return ReferenceManager.MNEMONIC;
|
||||
}
|
||||
if (activeIndex == ReferenceManager.MNEMONIC) {
|
||||
return 0;
|
||||
}
|
||||
if (activeIndex < nOperands - 1) {
|
||||
return activeIndex + 1;
|
||||
}
|
||||
return ReferenceManager.MNEMONIC;
|
||||
}
|
||||
|
||||
private int getPreviousIndex() {
|
||||
if (operandLabels.length == 0) {
|
||||
return ReferenceManager.MNEMONIC;
|
||||
}
|
||||
if (activeIndex == ReferenceManager.MNEMONIC) {
|
||||
return nOperands - 1;
|
||||
}
|
||||
if (activeIndex > 0) {
|
||||
return activeIndex - 1;
|
||||
}
|
||||
return ReferenceManager.MNEMONIC;
|
||||
}
|
||||
|
||||
CodeUnit getCurrentCodeUnit() {
|
||||
return currentCodeUnit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
updateLabels(activeIndex, activeSubIndex);
|
||||
updateActiveIndex(activeIndex, activeSubIndex);
|
||||
}
|
||||
|
||||
void setCodeUnitLocation(CodeUnit cu, int opIndex, int subIndex, boolean locked) {
|
||||
|
@ -180,12 +141,12 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
}
|
||||
currentCodeUnit = cu;
|
||||
activeIndex = ReferenceManager.MNEMONIC - 1; // force updateLabels to work
|
||||
updateLabels(opIndex, subIndex);
|
||||
updateActiveIndex(opIndex, subIndex);
|
||||
updateDropTargets(cu != null ? cu.getNumOperands() : -1);
|
||||
}
|
||||
|
||||
void setSelectedOpIndex(int index, int subIndex) {
|
||||
updateLabels(index, subIndex);
|
||||
updateActiveIndex(index, subIndex);
|
||||
}
|
||||
|
||||
int getSelectedOpIndex() {
|
||||
|
@ -200,9 +161,6 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
* Create the components for this panel.
|
||||
*/
|
||||
private void create(int topPad, int leftPad, int bottomPad, int rightPad) {
|
||||
setLayout(new BorderLayout());
|
||||
//setBorder(new EmptyBorder(topPad, leftPad, bottomPad, rightPad));
|
||||
|
||||
Border border = new TitledBorder(new EtchedBorder(), "Source");
|
||||
setBorder(border);
|
||||
|
||||
|
@ -226,15 +184,20 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
innerPanel = new JPanel();
|
||||
BoxLayout bl = new BoxLayout(innerPanel, BoxLayout.X_AXIS);
|
||||
innerPanel.setLayout(bl);
|
||||
setName("Instruction Panel");
|
||||
setToolTipText("This component selects which instruction piece is active for this dialog");
|
||||
innerPanel.getAccessibleContext()
|
||||
.setAccessibleDescription("Use left or right arrows to choose which mnemonic or" +
|
||||
" operand piece this dialog applies to");
|
||||
updateAccessibleInfo();
|
||||
|
||||
if (goHomeAction != null) {
|
||||
Action action = KeyBindingUtils.adaptDockingActionToNonContextAction(goHomeAction);
|
||||
JButton homeButton = new JButton(action);
|
||||
homeButton.setText(null);
|
||||
homeButton.setMargin(new Insets(0, 0, 0, 0));
|
||||
homeButton.setFocusable(false);
|
||||
innerPanel.add(Box.createHorizontalStrut(5));
|
||||
innerPanel.add(homeButton);
|
||||
add(homeButton, BorderLayout.WEST);
|
||||
}
|
||||
|
||||
innerPanel.add(Box.createHorizontalStrut(5));
|
||||
|
@ -242,6 +205,7 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
innerPanel.add(Box.createHorizontalStrut(20));
|
||||
innerPanel.add(mnemonicLabel);
|
||||
innerPanel.add(Box.createHorizontalStrut(10));
|
||||
innerPanel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
|
||||
|
||||
for (JLabel operandLabel : operandLabels) {
|
||||
innerPanel.add(operandLabel);
|
||||
|
@ -267,6 +231,35 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
}
|
||||
|
||||
}
|
||||
innerPanel.setFocusable(true);
|
||||
innerPanel.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
switch (e.getKeyCode()) {
|
||||
case KeyEvent.VK_LEFT:
|
||||
updateActiveIndex(getPreviousIndex(), -1);
|
||||
e.consume();
|
||||
break;
|
||||
case KeyEvent.VK_RIGHT:
|
||||
updateActiveIndex(getNextIndex(), -1);
|
||||
e.consume();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
innerPanel.addFocusListener(new FocusListener() {
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
innerPanel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
innerPanel.setBorder(BorderFactory.createLineBorder(FOCUS_COLOR, 1));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,10 +279,30 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
/**
|
||||
* Method updateLabels.
|
||||
*/
|
||||
private void updateLabels(int index, int subIndex) {
|
||||
private void updateActiveIndex(int index, int subIndex) {
|
||||
int prevIndex = activeIndex;
|
||||
activeIndex = index;
|
||||
activeSubIndex = subIndex;
|
||||
updateLabels();
|
||||
updateAccessibleInfo();
|
||||
if (activeIndex != prevIndex && listener != null) {
|
||||
listener.operandSelected(activeIndex, activeSubIndex);
|
||||
}
|
||||
updateAccessibleInfo();
|
||||
}
|
||||
|
||||
private void updateAccessibleInfo() {
|
||||
String accessibleName = "Instruction Reference Panel";
|
||||
if (activeIndex < 0) {
|
||||
accessibleName += ", mnemonic selected";
|
||||
}
|
||||
else {
|
||||
accessibleName += ", operand " + activeIndex + " selected";
|
||||
}
|
||||
innerPanel.getAccessibleContext().setAccessibleName(accessibleName);
|
||||
}
|
||||
|
||||
private void updateLabels() {
|
||||
for (JLabel operandLabel : operandLabels) {
|
||||
operandLabel.setText("");
|
||||
operandLabel.setBorder(EMPTY_BORDER);
|
||||
|
@ -297,7 +310,7 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
}
|
||||
if (currentCodeUnit != null) {
|
||||
|
||||
int nOperands = currentCodeUnit.getNumOperands();
|
||||
nOperands = currentCodeUnit.getNumOperands();
|
||||
for (int i = 0; i < nOperands; i++) {
|
||||
String opRep = cuFormat.getOperandRepresentationString(currentCodeUnit, i);
|
||||
if (i < nOperands - 1) {
|
||||
|
@ -315,9 +328,6 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
}
|
||||
innerPanel.invalidate();
|
||||
repaint();
|
||||
if (activeIndex != prevIndex && listener != null) {
|
||||
listener.operandSelected(activeIndex, activeSubIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -418,9 +428,75 @@ class InstructionPanel extends JPanel implements ChangeListener {
|
|||
public void mousePressed(MouseEvent e) {
|
||||
if (!locked) {
|
||||
JLabel label = (JLabel) e.getSource();
|
||||
updateLabels(getLabelIndex(label), -1);
|
||||
updateActiveIndex(getLabelIndex(label), -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class InstructionPanelDroppable implements Droppable {
|
||||
/**
|
||||
* Set drag feedback according to the ok parameter.
|
||||
* @param ok true means the drop action is OK
|
||||
* @param e event that has current state of drag and drop operation
|
||||
*/
|
||||
@Override
|
||||
public void dragUnderFeedback(boolean ok, DropTargetDragEvent e) {
|
||||
// stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if is OK to drop the transferable at the location
|
||||
* specified the event.
|
||||
* @param e event that has current state of drag and drop operation
|
||||
*/
|
||||
@Override
|
||||
public boolean isDropOk(DropTargetDragEvent e) {
|
||||
|
||||
Component targetComp = e.getDropTargetContext().getComponent();
|
||||
if (targetComp instanceof JLabel) {
|
||||
|
||||
updateActiveIndex(getLabelIndex((JLabel) targetComp), -1);
|
||||
|
||||
try {
|
||||
Object data = e.getTransferable()
|
||||
.getTransferData(SelectionTransferable.localProgramSelectionFlavor);
|
||||
AddressSetView view = ((SelectionTransferData) data).getAddressSet();
|
||||
if (memory.contains(view)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (UnsupportedFlavorException e1) {
|
||||
// return false
|
||||
}
|
||||
catch (IOException e1) {
|
||||
// return false
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoDragUnderFeedback() {
|
||||
// stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the object to the droppable component. The DropTargetAdapter
|
||||
* calls this method from its drop() method.
|
||||
* @param obj Transferable object that is to be dropped; in this
|
||||
* case, it is an AddressSetView
|
||||
* @param e has current state of drop operation
|
||||
* @param f represents the opaque concept of a data format as
|
||||
* would appear on a clipboard, during drag and drop.
|
||||
*/
|
||||
@Override
|
||||
public void add(Object obj, DropTargetDropEvent e, DataFlavor f) {
|
||||
AddressSetView view = ((SelectionTransferData) obj).getAddressSet();
|
||||
if (view.getNumAddressRanges() == 0) {
|
||||
return;
|
||||
}
|
||||
listener.selectionDropped(view, currentCodeUnit, activeIndex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,6 @@ class TipOfTheDayDialog extends ReusableDialogComponentProvider {
|
|||
Icon tipIcon = new GIcon("icon.plugin.totd.provider");
|
||||
|
||||
tipArea = new JTextArea(4, 30);
|
||||
tipArea.setEditable(false);
|
||||
tipArea.setFont(Gui.getFont(FONT_ID));
|
||||
tipArea.setWrapStyleWord(true);
|
||||
tipArea.setLineWrap(true);
|
||||
|
@ -139,6 +138,8 @@ class TipOfTheDayDialog extends ReusableDialogComponentProvider {
|
|||
}
|
||||
String tip = tips.get(tipIndex);
|
||||
tipArea.setText(tip);
|
||||
tipArea.getAccessibleContext().setAccessibleName("Ghidra Tip of The Day");
|
||||
tipArea.getAccessibleContext().setAccessibleDescription(tip);
|
||||
}
|
||||
|
||||
int getTipIndex() {
|
||||
|
|
|
@ -77,6 +77,7 @@ public class AddressInput extends JPanel implements FocusableEditor {
|
|||
textField.setName("JTextField");//for JUnits...
|
||||
combo = new GComboBox<>();
|
||||
combo.setName("JComboBox");//for JUnits...
|
||||
combo.getAccessibleContext().setAccessibleName("Address Space");
|
||||
add(textField, BorderLayout.CENTER);
|
||||
//add(combo, BorderLayout.WEST);
|
||||
comboAdded = false;
|
||||
|
@ -367,6 +368,14 @@ public class AddressInput extends JPanel implements FocusableEditor {
|
|||
combo.setEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the accessible name for this address input field.
|
||||
* @param name the accessible name for this address field
|
||||
*/
|
||||
public void setAccessibleName(String name) {
|
||||
textField.getAccessibleContext().setAccessibleName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text field to be editable according to the state param.
|
||||
*/
|
||||
|
|
|
@ -22,8 +22,7 @@ import java.net.URL;
|
|||
import java.util.*;
|
||||
|
||||
import generic.stl.Pair;
|
||||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidra.GhidraLaunchable;
|
||||
import ghidra.*;
|
||||
import ghidra.app.util.opinion.Loader;
|
||||
import ghidra.framework.*;
|
||||
import ghidra.framework.model.DomainFolder;
|
||||
|
@ -118,6 +117,9 @@ public class AnalyzeHeadless implements GhidraLaunchable {
|
|||
HeadlessOptions options = analyzer.getOptions();
|
||||
parseOptions(options, args, optionStartIndex, ghidraURL, filesToImport);
|
||||
|
||||
Msg.info(AnalyzeHeadless.class,
|
||||
"Headless startup complete (" + GhidraLauncher.getMillisecondsFromLaunch() + " ms)");
|
||||
|
||||
// Do the headless processing
|
||||
try {
|
||||
if (ghidraURL != null) {
|
||||
|
|
|
@ -112,6 +112,50 @@ public class InstanceSettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(PaddingSettingsDefinition.UNPADDED_VALUE, data.getLong("padded").longValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComponentInstanceSettings() throws Exception {
|
||||
|
||||
Structure s = new StructureDataType("struct", 0);
|
||||
s.setPackingEnabled(true);
|
||||
s.add(new ArrayDataType(ByteDataType.dataType, 4, -1));
|
||||
s = (Structure) dataMgr.resolve(s, null);
|
||||
|
||||
Data data = DataUtilities.createData(program, addr(10), s, -1, false,
|
||||
ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
|
||||
|
||||
Data component = data.getComponent(new int[] { 0, 2 });
|
||||
assertNotNull(component);
|
||||
|
||||
Settings defaultSettings = component.getDefaultSettings();
|
||||
FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.CHAR);
|
||||
EndianSettingsDefinition.DEF.setBigEndian(defaultSettings, false);
|
||||
PaddingSettingsDefinition.DEF.setPadded(defaultSettings, true);
|
||||
|
||||
assertEquals(FormatSettingsDefinition.CHAR, component.getLong("format").longValue());
|
||||
FormatSettingsDefinition.DEF.setChoice(component, FormatSettingsDefinition.DECIMAL);
|
||||
assertEquals(FormatSettingsDefinition.DECIMAL, component.getLong("format").longValue());
|
||||
|
||||
assertEquals(EndianSettingsDefinition.LITTLE, component.getLong("endian").longValue());
|
||||
EndianSettingsDefinition.DEF.setChoice(component, EndianSettingsDefinition.BIG);
|
||||
assertEquals(EndianSettingsDefinition.BIG, component.getLong("endian").longValue());
|
||||
|
||||
assertEquals(PaddingSettingsDefinition.PADDED_VALUE,
|
||||
component.getLong("padded").longValue());
|
||||
PaddingSettingsDefinition.DEF.setChoice(component,
|
||||
PaddingSettingsDefinition.UNPADDED_VALUE);
|
||||
assertEquals(PaddingSettingsDefinition.UNPADDED_VALUE,
|
||||
component.getLong("padded").longValue());
|
||||
|
||||
FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.HEX);
|
||||
EndianSettingsDefinition.DEF.clear(defaultSettings);
|
||||
PaddingSettingsDefinition.DEF.clear(defaultSettings);
|
||||
|
||||
assertEquals(FormatSettingsDefinition.DECIMAL, component.getLong("format").longValue());
|
||||
assertEquals(EndianSettingsDefinition.BIG, component.getLong("endian").longValue());
|
||||
assertEquals(PaddingSettingsDefinition.UNPADDED_VALUE,
|
||||
component.getLong("padded").longValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetInstanceNames() throws Exception {
|
||||
Data data = listing.getDataAt(addr(10));
|
||||
|
@ -259,7 +303,6 @@ public class InstanceSettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
private void addBlock() throws Exception {
|
||||
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock("test", addr(0), 100, (byte) 0,
|
||||
TaskMonitor.DUMMY, false);
|
||||
memory.createInitializedBlock("test", addr(0), 100, (byte) 0, TaskMonitor.DUMMY, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -389,6 +389,41 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(Array.class, array.getValueClass(defaultSettings));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultSettingsOnCharArrayComponent() throws Exception {
|
||||
|
||||
DataType charDT = dataMgr.resolve(new CharDataType(), null);
|
||||
SettingsDefinition[] settingsDefinitions = charDT.getSettingsDefinitions();
|
||||
|
||||
assertTrue("Expect multiple settings on char type", settingsDefinitions.length > 2); // make sure we get more than two settings
|
||||
|
||||
Array array = new ArrayDataType(charDT, 5, -1);
|
||||
assertArrayEquals(settingsDefinitions, array.getSettingsDefinitions());
|
||||
|
||||
array = (Array) dataMgr.resolve(array, null);
|
||||
assertArrayEquals(settingsDefinitions, array.getSettingsDefinitions());
|
||||
|
||||
Structure s = new StructureDataType("struct", 0);
|
||||
s.setPackingEnabled(true);
|
||||
s.add(array);
|
||||
s = (Structure) dataMgr.resolve(s, null);
|
||||
DataTypeComponent dtc = s.getComponent(0);
|
||||
|
||||
Settings defaultSettings = dtc.getDefaultSettings();
|
||||
|
||||
assertEquals(FormatSettingsDefinition.CHAR,
|
||||
FormatSettingsDefinition.DEF_CHAR.getChoice(defaultSettings));
|
||||
|
||||
assertEquals(MutabilitySettingsDefinition.NORMAL,
|
||||
MutabilitySettingsDefinition.DEF.getChoice(defaultSettings));
|
||||
|
||||
assertEquals(String.class, array.getValueClass(defaultSettings));
|
||||
|
||||
FormatSettingsDefinition.DEF_CHAR.setChoice(defaultSettings, FormatSettingsDefinition.HEX);
|
||||
|
||||
assertEquals(Array.class, array.getValueClass(defaultSettings));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultSettingsOnTypedef() throws Exception {
|
||||
DataType byteDT = dataMgr.resolve(ByteDataType.dataType, null);
|
||||
|
@ -516,7 +551,6 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
private void addBlock() throws Exception {
|
||||
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock("test", addr(0), 100, (byte) 0,
|
||||
TaskMonitor.DUMMY, false);
|
||||
memory.createInitializedBlock("test", addr(0), 100, (byte) 0, TaskMonitor.DUMMY, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ model {
|
|||
include "emulateutil.cc"
|
||||
include "flow.cc"
|
||||
include "userop.cc"
|
||||
include "multiprecision.cc"
|
||||
include "funcdata.cc"
|
||||
include "funcdata_block.cc"
|
||||
include "funcdata_varnode.cc"
|
||||
|
|
|
@ -19,6 +19,7 @@ src/decompile/datatests/convert.xml||GHIDRA||||END|
|
|||
src/decompile/datatests/deadvolatile.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/deindirect.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/displayformat.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/divopt.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/dupptr.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/elseif.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/floatprint.xml||GHIDRA||||END|
|
||||
|
|
|
@ -80,7 +80,7 @@ CORE= xml marshal space float address pcoderaw translate opcodes globalcontext
|
|||
# Additional core files for any projects that decompile
|
||||
DECCORE=capability architecture options graph cover block cast typeop database cpool \
|
||||
comment stringmanage modelrules fspec action loadimage grammar varnode op \
|
||||
type variable varmap jumptable emulate emulateutil flow userop \
|
||||
type variable varmap jumptable emulate emulateutil flow userop multiprecision \
|
||||
funcdata funcdata_block funcdata_op funcdata_varnode unionresolve pcodeinject \
|
||||
heritage prefersplit rangeutil ruleaction subflow blockaction merge double \
|
||||
transform coreaction condexe override dynamic crc32 prettyprint \
|
||||
|
|
|
@ -831,133 +831,4 @@ int4 bit_transitions(uintb val,int4 sz)
|
|||
return res;
|
||||
}
|
||||
|
||||
/// \brief Multiply 2 unsigned 64-bit values, producing a 128-bit value
|
||||
///
|
||||
/// TODO: Remove once we import a full multiprecision library.
|
||||
/// \param res points to the result array (2 uint8 pieces)
|
||||
/// \param x is the first 64-bit value
|
||||
/// \param y is the second 64-bit value
|
||||
void mult64to128(uint8 *res,uint8 x,uint8 y)
|
||||
|
||||
{
|
||||
uint8 f = x & 0xffffffff;
|
||||
uint8 e = x >> 32;
|
||||
uint8 d = y & 0xffffffff;
|
||||
uint8 c = y >> 32;
|
||||
uint8 fd = f * d;
|
||||
uint8 fc = f * c;
|
||||
uint8 ed = e * d;
|
||||
uint8 ec = e * c;
|
||||
uint8 tmp = (fd >> 32) + (fc & 0xffffffff) + (ed & 0xffffffff);
|
||||
res[1] = (tmp>>32) + (fc>>32) + (ed>>32) + ec;
|
||||
res[0] = (tmp<<32) + (fd & 0xffffffff);
|
||||
}
|
||||
|
||||
/// \brief Subtract (in-place) a 128-bit value from a base 128-value
|
||||
///
|
||||
/// The base value is altered in place.
|
||||
/// TODO: Remove once we import a full multiprecision library.
|
||||
/// \param a is the base 128-bit value being subtracted from in-place
|
||||
/// \param b is the other 128-bit value being subtracted
|
||||
void unsignedSubtract128(uint8 *a,uint8 *b)
|
||||
|
||||
{
|
||||
bool borrow = (a[0] < b[0]);
|
||||
a[0] -= b[0];
|
||||
a[1] -= b[1];
|
||||
if (borrow)
|
||||
a[1] -= 1;
|
||||
}
|
||||
|
||||
/// \brief Compare two unsigned 128-bit values
|
||||
///
|
||||
/// TODO: Remove once we import a full multiprecision library.
|
||||
/// Given a first and second value, return -1, 0, or 1 depending on whether the first value
|
||||
/// is \e less, \e equal, or \e greater than the second value.
|
||||
/// \param a is the first 128-bit value (as an array of 2 uint8 elements)
|
||||
/// \param b is the second 128-bit value
|
||||
/// \return the comparison code
|
||||
int4 unsignedCompare128(uint8 *a,uint8 *b)
|
||||
|
||||
{
|
||||
if (a[1] != b[1])
|
||||
return (a[1] < b[1]) ? -1 : 1;
|
||||
if (a[0] != b[0])
|
||||
return (a[0] < b[0]) ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Unsigned division of a power of 2 (upto 2^127) by a 64-bit divisor
|
||||
///
|
||||
/// The result must be less than 2^64. The remainder is calculated.
|
||||
/// \param n is the power of 2 for the numerand
|
||||
/// \param divisor is the 64-bit divisor
|
||||
/// \param q is the passed back 64-bit quotient
|
||||
/// \param r is the passed back 64-bit remainder
|
||||
/// \return 0 if successful, 1 if result is too big, 2 if divide by 0
|
||||
int4 power2Divide(int4 n,uint8 divisor,uint8 &q,uint8 &r)
|
||||
|
||||
{
|
||||
if (divisor == 0) return 2;
|
||||
uint8 power = 1;
|
||||
if (n < 64) {
|
||||
power <<= n;
|
||||
q = power / divisor;
|
||||
r = power % divisor;
|
||||
return 0;
|
||||
}
|
||||
// Divide numerand and divisor by 2^(n-63) to get approximation of result
|
||||
uint8 y = divisor >> (n-64); // Most of the way on divisor
|
||||
if (y == 0) return 1; // Check if result will be too big
|
||||
y >>= 1; // Divide divisor by final bit
|
||||
power <<= 63;
|
||||
uint8 max;
|
||||
if (y == 0) {
|
||||
max = 0;
|
||||
max -= 1; // Could be maximal
|
||||
// Check if divisor is a power of 2
|
||||
if ((((uint8)1) << (n-64)) == divisor)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
max = power / y + 1;
|
||||
uint8 min = power / (y+1);
|
||||
if (min != 0)
|
||||
min -= 1;
|
||||
uint8 fullpower[2];
|
||||
fullpower[1] = ((uint8)1)<<(n-64);
|
||||
fullpower[0] = 0;
|
||||
uint8 mult[2];
|
||||
mult[0] = 0;
|
||||
mult[1] = 0;
|
||||
uint8 tmpq = 0;
|
||||
while(max > min+1) {
|
||||
tmpq = max + min;
|
||||
if (tmpq < min) {
|
||||
tmpq = (tmpq>>1) + 0x8000000000000000L;
|
||||
}
|
||||
else
|
||||
tmpq >>= 1;
|
||||
mult64to128(mult,divisor,tmpq);
|
||||
if (unsignedCompare128(fullpower,mult) < 0)
|
||||
max = tmpq-1;
|
||||
else
|
||||
min = tmpq;
|
||||
}
|
||||
// min is now our putative quotient
|
||||
if (tmpq != min)
|
||||
mult64to128(mult,divisor,min);
|
||||
unsignedSubtract128(fullpower,mult); // Calculate remainder
|
||||
// min might be 1 too small
|
||||
if (fullpower[1] != 0 || fullpower[0] >= divisor) {
|
||||
q = min + 1;
|
||||
r = fullpower[0] - divisor;
|
||||
}
|
||||
else {
|
||||
q = min;
|
||||
r = fullpower[0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End namespace ghidra
|
||||
|
|
|
@ -577,10 +577,5 @@ extern int4 count_leading_zeros(uintb val); ///< Return the number of leading z
|
|||
extern uintb coveringmask(uintb val); ///< Return a mask that \e covers the given value
|
||||
extern int4 bit_transitions(uintb val,int4 sz); ///< Calculate the number of bit transitions in the sized value
|
||||
|
||||
extern void mult64to128(uint8 *res,uint8 x,uint8 y);
|
||||
extern void unsignedSubtract128(uint8 *a,uint8 *b);
|
||||
extern int4 unsignedCompare128(uint8 *a,uint8 *b);
|
||||
extern int4 power2Divide(int4 n,uint8 divisor,uint8 &q,uint8 &r);
|
||||
|
||||
} // End namespace ghidra
|
||||
#endif
|
||||
|
|
|
@ -1600,6 +1600,15 @@ void ParamListStandardOut::initialize(void)
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Find the return value storage using the older \e fallback method
|
||||
///
|
||||
/// Given the active set of trial locations that might hold (pieces of) the return value, calculate
|
||||
/// the best matching ParamEntry from \b this ParamList and mark all the trials that are contained
|
||||
/// in the ParamEntry as \e used. If \b firstOnly is \b true, the ParamList is assumed to contain
|
||||
/// partial storage locations that might get used for return values split storage. In this case,
|
||||
/// only the first ParamEntry in a storage class is allowed to match.
|
||||
/// \param active is the set of active trials
|
||||
/// \param firstOnly is \b true if only the first entry in a storage class can match
|
||||
void ParamListStandardOut::fillinMapFallback(ParamActive *active,bool firstOnly) const
|
||||
|
||||
{
|
||||
|
|
|
@ -286,6 +286,7 @@ public:
|
|||
Varnode *newUnique(int4 s,Datatype *ct=(Datatype *)0); ///< Create a new \e temporary Varnode
|
||||
Varnode *newCodeRef(const Address &m); ///< Create a code address \e annotation Varnode
|
||||
Varnode *setInputVarnode(Varnode *vn); ///< Mark a Varnode as an input to the function
|
||||
Varnode *newExtendedConstant(int4 s,uint8 *val,PcodeOp *op); ///< Create extended precision constant
|
||||
void adjustInputVarnodes(const Address &addr,int4 sz);
|
||||
void deleteVarnode(Varnode *vn) { vbank.destroy(vn); } ///< Delete the given varnode
|
||||
|
||||
|
|
|
@ -372,6 +372,36 @@ Varnode *Funcdata::setInputVarnode(Varnode *vn)
|
|||
return vn;
|
||||
}
|
||||
|
||||
/// Construct a constant Varnode up to 128 bits, using INT_ZEXT and PIECE if necessary.
|
||||
/// This method is temporary until we have full extended precision constants.
|
||||
/// \param s is the size of the Varnode in bytes
|
||||
/// \param val is the 128-bit value in 2 64-bit chunks
|
||||
/// \param op is point before which any new PcodeOp should get inserted
|
||||
/// \return the new effective constant Varnode
|
||||
Varnode *Funcdata::newExtendedConstant(int4 s,uint8 *val,PcodeOp *op)
|
||||
|
||||
{
|
||||
if (s <= 8)
|
||||
return newConstant(s, val[0]);
|
||||
Varnode *newConstVn;
|
||||
if (val[1] == 0) {
|
||||
PcodeOp *extOp = newOp(1,op->getAddr());
|
||||
opSetOpcode(extOp,CPUI_INT_ZEXT);
|
||||
newConstVn = newUniqueOut(s,extOp);
|
||||
opSetInput(extOp,newConstant(8,val[0]),0);
|
||||
opInsertBefore(extOp,op);
|
||||
}
|
||||
else {
|
||||
PcodeOp *pieceOp = newOp(2,op->getAddr());
|
||||
opSetOpcode(pieceOp,CPUI_PIECE);
|
||||
newConstVn = newUniqueOut(s,pieceOp);
|
||||
opSetInput(pieceOp,newConstant(8,val[1]),0); // Most significant piece
|
||||
opSetInput(pieceOp,newConstant(8,val[0]),1); // Least significant piece
|
||||
opInsertBefore(pieceOp,op);
|
||||
}
|
||||
return newConstVn;
|
||||
}
|
||||
|
||||
/// \brief Adjust input Varnodes contained in the given range
|
||||
///
|
||||
/// After this call, a single \e input Varnode will exist that fills the given range.
|
||||
|
|
|
@ -54,6 +54,7 @@ class PrimitiveExtractor {
|
|||
union_invalid = 16 ///< Unions are treated as an illegal element
|
||||
};
|
||||
public:
|
||||
/// \brief A primitive data-type and its offset within the containing data-type
|
||||
class Primitive {
|
||||
public:
|
||||
Datatype *dt; ///< Primitive data-type
|
||||
|
@ -71,7 +72,7 @@ public:
|
|||
PrimitiveExtractor(Datatype *dt,bool unionIllegal,int4 offset,int4 max); ///< Constructor
|
||||
int4 size(void) const { return primitives.size(); } ///< Return the number of primitives extracted
|
||||
const Primitive &get(int4 i) const { return primitives[i]; } ///< Get a particular primitive
|
||||
bool isValid(void) const { return (flags & invalid) == 0; }
|
||||
bool isValid(void) const { return (flags & invalid) == 0; } ///< Return \b true if primitives were successfully extracted
|
||||
bool containsUnknown(void) const { return (flags & unknown_element)!=0; } ///< Are there \b unknown elements
|
||||
bool isAligned(void) const { return (flags & unaligned)==0; } ///< Are all elements aligned
|
||||
bool containsHoles(void) const { return (flags & extra_space)!=0; } ///< Is there empty space that is not padding
|
||||
|
|
334
Ghidra/Features/Decompiler/src/decompile/cpp/multiprecision.cc
Normal file
334
Ghidra/Features/Decompiler/src/decompile/cpp/multiprecision.cc
Normal file
|
@ -0,0 +1,334 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
#include "multiprecision.hh"
|
||||
|
||||
namespace ghidra {
|
||||
|
||||
extern int4 count_leading_zeros(uintb val); ///< Return the number of leading zero bits in the given value
|
||||
|
||||
/// \brief Multi-precision logical left shift by a constant amount
|
||||
///
|
||||
/// \b in and \b out arrays are specified and can point to the same storage.
|
||||
/// \param num is the number 64-bit words in the extended precision integers
|
||||
/// \param in is the 128-bit value to shift
|
||||
/// \param out is the container for the 128-bit result
|
||||
/// \param sa is the number of bits to shift
|
||||
static void leftshift(int4 num,uint8 *in,uint8 *out,int4 sa)
|
||||
|
||||
{
|
||||
int4 inIndex = num - 1 - sa / 64;
|
||||
sa = sa % 64;
|
||||
int4 outIndex = num - 1;
|
||||
if (sa == 0) {
|
||||
for(;inIndex>=0;--inIndex) {
|
||||
out[outIndex--] = in[inIndex];
|
||||
}
|
||||
for(;outIndex>=0;--outIndex) {
|
||||
out[outIndex] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(;inIndex>0;--inIndex) {
|
||||
out[outIndex--] = (in[inIndex] << sa) | (in[inIndex-1] >> (64-sa));
|
||||
}
|
||||
out[outIndex--] = in[0] << sa;
|
||||
for(;outIndex>=0;--outIndex) {
|
||||
out[outIndex] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \param in is the 128-bit input (as 2 64-bit words)
|
||||
/// \param out will hold the 128-bit result
|
||||
/// \param sa is the number of bits to shift
|
||||
void leftshift128(uint8 *in,uint8 *out,int4 sa)
|
||||
|
||||
{
|
||||
leftshift(2,in,out,sa);
|
||||
}
|
||||
|
||||
/// \brief Compare two multi-precision unsigned integers
|
||||
///
|
||||
/// -1, 0, or 1 is returned depending on if the first integer is less than, equal to, or greater than
|
||||
/// the second integer.
|
||||
/// \param num is the number 64-bit words in the extended precision integers
|
||||
/// \param in1 is the first integer to compare
|
||||
/// \param in2 is the second integer to compare
|
||||
/// \return -1, 0, or 1
|
||||
static inline int4 ucompare(int4 num,uint8 *in1,uint8 *in2)
|
||||
|
||||
{
|
||||
for(int4 i=num-1;i>=0;--i) {
|
||||
if (in1[i] != in2[i])
|
||||
return (in1[i] < in2[i]) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \param in1 is the first 128-bit value (as 2 64-bit words) to compare
|
||||
/// \param in2 is the second 128-bit value
|
||||
/// \return \b true if the first value is less than the second value
|
||||
bool uless128(uint8 *in1,uint8 *in2)
|
||||
|
||||
{
|
||||
return ucompare(2,in1,in2) < 0;
|
||||
}
|
||||
|
||||
/// \param in1 is the first 128-bit value (as 2 64-bit words) to compare
|
||||
/// \param in2 is the second 128-bit value
|
||||
/// \return \b true if the first value is less than or equal to the second value
|
||||
bool ulessequal128(uint8 *in1,uint8 *in2)
|
||||
|
||||
{
|
||||
return ucompare(2,in1,in2) <= 0;
|
||||
}
|
||||
|
||||
/// \brief Multi-precision add operation
|
||||
///
|
||||
/// \param num is the number 64-bit words in the extended precision integers
|
||||
/// \param in1 is the first integer
|
||||
/// \param in2 is the integer added to the first
|
||||
/// \param out is where the add result is stored
|
||||
static inline void add(int4 num,uint8 *in1,uint8 *in2,uint8 *out)
|
||||
|
||||
{
|
||||
uint8 carry = 0;
|
||||
for(int4 i=0;i<num;++i) {
|
||||
uint8 tmp = in2[i] + carry;
|
||||
uint8 tmp2 = in1[i] + tmp;
|
||||
out[i] = tmp2;
|
||||
carry = (tmp < in2[i] || tmp2 < tmp) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// \param in1 is the first 128-bit value (as 2 64-bit words) to add
|
||||
/// \param in2 is the second 128-bit value to add
|
||||
/// \param out will hold the 128-bit result
|
||||
void add128(uint8 *in1,uint8 *in2,uint8 *out)
|
||||
|
||||
{
|
||||
add(2,in1,in2,out);
|
||||
}
|
||||
|
||||
/// \brief Multi-precision subtract operation
|
||||
///
|
||||
/// \param num is the number 64-bit words in the extended precision integers
|
||||
/// \param in1 is the first integer
|
||||
/// \param in2 is the integer subtracted from the first
|
||||
/// \param out is where the subtraction result is stored
|
||||
static inline void subtract(int4 num,uint8 *in1,uint8 *in2,uint8 *out)
|
||||
|
||||
{
|
||||
uint8 borrow = 0;
|
||||
for(int4 i=0;i<num;++i) {
|
||||
uint8 tmp = in2[i] + borrow;
|
||||
borrow = (tmp < in2[i] || in1[i] < tmp) ? 1: 0;
|
||||
out[i] = in1[i] - tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/// \param in1 is the first 128-bit value (as 2 64-bit words)
|
||||
/// \param in2 is the second 128-bit value to subtract
|
||||
/// \param out will hold the 128-bit result
|
||||
void subtract128(uint8 *in1,uint8 *in2,uint8 *out)
|
||||
|
||||
{
|
||||
subtract(2,in1,in2,out);
|
||||
}
|
||||
|
||||
/// \brief Split an array of 64-bit words into an array of 32-bit words
|
||||
///
|
||||
/// The arrays must already be allocated. The least significant half of each 64-bit word is put
|
||||
/// into the 32-bit word array first. The index of the most significant non-zero 32-bit word is
|
||||
/// calculated and returned as the \e effective size of the resulting array.
|
||||
/// \param num is the number of 64-bit words to split
|
||||
/// \param val is the array of 64-bit words
|
||||
/// \param res is the array that will hold the 32-bit words
|
||||
/// \return the effective size of the 32-bit word array
|
||||
static int4 split64_32(int4 num,uint8 *val,uint4 *res)
|
||||
|
||||
{
|
||||
int4 m = 0;
|
||||
for(int4 i=0;i<num;++i) {
|
||||
uint4 hi = val[i] >> 32;
|
||||
uint4 lo = val[i] & 0xffffffff;
|
||||
if (hi != 0)
|
||||
m = i*2 + 2;
|
||||
else if (lo != 0)
|
||||
m = i*2 + 1;
|
||||
res[i*2] = lo;
|
||||
res[i*2+1] = hi;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/// \brief Pack an array of 32-bit words into an array of 64-bit words
|
||||
///
|
||||
/// The arrays must already be allocated. The 64-bit word array is padded out with zeroes if
|
||||
/// the specified size exceeds the provided number of 32-bit words.
|
||||
/// \param num is the number of 64-bit words in the resulting array
|
||||
/// \param max is the number of 32-bit words to pack
|
||||
/// \param out is the array of 64-bit words
|
||||
/// \param in is the array of 32-bit words
|
||||
static void pack32_64(int4 num,int4 max,uint8 *out,uint4 *in)
|
||||
|
||||
{
|
||||
int4 j = num * 2 - 1;
|
||||
for(int4 i=num-1;i>=0;--i) {
|
||||
uint8 val;
|
||||
val = (j<max) ? in[j] : 0;
|
||||
val <<= 32;
|
||||
j -= 1;
|
||||
if (j < max)
|
||||
val |= in[j];
|
||||
j -= 1;
|
||||
out[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Logical shift left for an extended integer in 32-bit word arrays
|
||||
///
|
||||
/// \param arr is the array of 32-bit words
|
||||
/// \param size is the number of words in the array
|
||||
/// \param sa is the number of bits to shift
|
||||
static void shift_left(uint4 *arr,int4 size,int4 sa)
|
||||
|
||||
{
|
||||
if (sa == 0) return;
|
||||
for (int4 i = size - 1; i > 0; --i)
|
||||
arr[i] = (arr[i] << sa) | (arr[i-1] >> (32-sa));
|
||||
arr[0] = arr[0] << sa;
|
||||
}
|
||||
|
||||
/// \brief Logical shift right for an extended integer in 32-bit word arrays
|
||||
///
|
||||
/// \param arr is the array of 32-bit words
|
||||
/// \param size is the number of words in the array
|
||||
/// \param sa is the number of bits to shift
|
||||
static void shift_right(uint4 *arr,int4 size,int4 sa)
|
||||
|
||||
{
|
||||
if (sa == 0) return;
|
||||
for(int4 i=0;i<size-1;++i)
|
||||
arr[i] = (arr[i] >> sa) | (arr[i+1] << (32-sa));
|
||||
arr[size-1] = arr[size -1] >> sa;
|
||||
}
|
||||
|
||||
/// \brief Knuth's algorithm d, for integer division
|
||||
///
|
||||
/// The numerator and denominator, expressed in 32-bit \e digits, are provided.
|
||||
/// The algorithm calculates the quotient and the remainder is left in the array originally
|
||||
/// containing the numerator.
|
||||
/// \param m is the number of 32-bit digits in the numerator
|
||||
/// \param n is the number of 32-bit digits in the denominator
|
||||
/// \param u is the numerator and will hold the remainder
|
||||
/// \param v is the denominator
|
||||
/// \param q will hold the final quotient
|
||||
static void knuth_algorithm_d(int4 m,int4 n,uint4 *u,uint4 *v,uint4 *q)
|
||||
|
||||
{
|
||||
int4 s = count_leading_zeros(v[n-1]) - 8*(sizeof(uintb)-sizeof(uint4));
|
||||
shift_left(v,n,s);
|
||||
shift_left(u,m,s);
|
||||
|
||||
for(int4 j=m-n-1;j>=0;--j) {
|
||||
uint8 tmp = ((uint8)u[n+j] << 32) + u[n-1+j];
|
||||
uint8 qhat = tmp / v[n-1];
|
||||
uint8 rhat = tmp % v[n-1];
|
||||
do {
|
||||
if (qhat <= 0xffffffff && qhat * v[n-2] <= (rhat << 32) + u[n-2+j])
|
||||
break;
|
||||
qhat -= 1;
|
||||
rhat += v[n-1];
|
||||
} while(rhat <= 0xffffffff);
|
||||
|
||||
uint8 carry = 0;
|
||||
int8 t;
|
||||
for (int4 i=0;i<n;++i) {
|
||||
tmp = qhat*v[i];
|
||||
t = u[i+j] - carry - (tmp & 0xffffffff);
|
||||
u[i+j] = t;
|
||||
carry = (tmp >> 32) - (t >> 32);
|
||||
}
|
||||
t = u[j+n] - carry;
|
||||
u[j+n] = t;
|
||||
|
||||
q[j] = qhat;
|
||||
if (t < 0) {
|
||||
q[j] -= 1;
|
||||
carry = 0;
|
||||
for(int4 i=0;i<n;++i) {
|
||||
tmp = u[i+j] + (v[i] + carry);
|
||||
u[i+j] = tmp;
|
||||
carry = tmp >> 32;
|
||||
}
|
||||
u[j+n] += carry;
|
||||
}
|
||||
}
|
||||
shift_right(u,m,s);
|
||||
}
|
||||
|
||||
/// \param numer holds the 2 64-bit words of the numerator
|
||||
/// \param denom holds the 2 words of the denominator
|
||||
/// \param quotient_res will hold the 2 words of the quotient
|
||||
/// \param remainder_res will hold the 2 words of the remainder
|
||||
void udiv128(uint8 *numer,uint8 *denom,uint8 *quotient_res,uint8 *remainder_res)
|
||||
|
||||
{
|
||||
if (numer[1] == 0 && denom[1] == 0) {
|
||||
quotient_res[0] = numer[0] / denom[0];
|
||||
quotient_res[1] = 0;
|
||||
remainder_res[0] = numer[0] % denom[0];
|
||||
remainder_res[1] = 0;
|
||||
return;
|
||||
}
|
||||
uint4 v[4];
|
||||
uint4 u[5]; // Array needs one more entry for normalization overflow
|
||||
uint4 q[4];
|
||||
int4 n = split64_32(2,denom,v);
|
||||
if (n == 0) {
|
||||
throw LowlevelError("divide by 0");
|
||||
}
|
||||
int4 m = split64_32(2,numer,u);
|
||||
if ( m < n || ( (n==m) && u[n-1] < v[n-1])) {
|
||||
// denominator is smaller than the numerator, quotient is 0
|
||||
quotient_res[0] = 0;
|
||||
quotient_res[1] = 0;
|
||||
remainder_res[0] = numer[0];
|
||||
remainder_res[1] = numer[1];
|
||||
return;
|
||||
}
|
||||
u[m] = 0;
|
||||
m += 1; // Extend u array by 1 to account for normalization
|
||||
if (n == 1) {
|
||||
uint4 d = v[0];
|
||||
uint4 rem = 0;
|
||||
for(int4 i=m-1;i>=0;--i) {
|
||||
uint8 tmp = ((uint8)rem << 32) + u[i];
|
||||
q[i] = tmp / d;
|
||||
u[i] = 0;
|
||||
rem = tmp % d;
|
||||
}
|
||||
u[0] = rem; // Last carry is final remainder
|
||||
}
|
||||
else {
|
||||
knuth_algorithm_d(m,n,u,v,q);
|
||||
}
|
||||
pack32_64(2,m-n,quotient_res,q);
|
||||
pack32_64(2,m-1,remainder_res,u);
|
||||
}
|
||||
|
||||
} // End namespace ghidra
|
|
@ -0,0 +1,42 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
/// \file multiprecision.hh
|
||||
/// \brief Multi-precision integers
|
||||
#ifndef __CPUI_MULTIPRECISION__
|
||||
#define __CPUI_MULTIPRECISION__
|
||||
|
||||
#include "error.hh"
|
||||
|
||||
namespace ghidra {
|
||||
|
||||
extern void leftshift128(uint8 *in,uint8 *out,int4 sa); ///< 128-bit INT_LEFT operation with constant shift amount
|
||||
extern bool uless128(uint8 *in1,uint8 *in2); ///< 128-bit INT_LESS operation
|
||||
extern bool ulessequal128(uint8 *in1,uint8 *in2); ///< 128-bit INT_LESSEQUAL operation
|
||||
extern void udiv128(uint8 *numer,uint8 *denom,uint8 *quotient_res,uint8 *remainder_res); ///< 128-bit INT_DIV
|
||||
extern void add128(uint8 *in1,uint8 *in2,uint8 *out); ///< 128-bit INT_ADD operation
|
||||
extern void subtract128(uint8 *in1,uint8 *in2,uint8 *out); ///< 128-bit INT_SUB operation
|
||||
|
||||
/// \brief Set a 128-bit value (2 64-bit words) from a 64-bit value
|
||||
///
|
||||
/// \param res will hold the 128-bit value
|
||||
/// \param val is the 64-bit value to set from
|
||||
inline void set_u128(uint8 *res,uint8 val) {
|
||||
res[0] = val;
|
||||
res[1] = 0;
|
||||
}
|
||||
|
||||
} // End namespace ghidra
|
||||
#endif
|
|
@ -17,6 +17,7 @@
|
|||
#include "coreaction.hh"
|
||||
#include "subflow.hh"
|
||||
#include "rangeutil.hh"
|
||||
#include "multiprecision.hh"
|
||||
|
||||
namespace ghidra {
|
||||
|
||||
|
@ -1884,8 +1885,12 @@ int4 RuleDoubleShift::applyOp(PcodeOp *op,Funcdata &data)
|
|||
}
|
||||
else if (sa1 == sa2 && size <= sizeof(uintb)) { // FIXME: precision
|
||||
mask = calc_mask(size);
|
||||
if (opc1 == CPUI_INT_LEFT)
|
||||
if (opc1 == CPUI_INT_LEFT) {
|
||||
// The INT_LEFT is highly likely to be a multiply, so don't collapse to an INT_AND if there
|
||||
// are other uses of the intermediate value.
|
||||
if (secvn->loneDescend() == (PcodeOp *)0) return 0;
|
||||
mask = (mask<<sa1) & mask;
|
||||
}
|
||||
else
|
||||
mask = (mask>>sa1) & mask;
|
||||
newvn = data.newConstant(size,mask);
|
||||
|
@ -7359,16 +7364,15 @@ int4 RuleDivTermAdd::applyOp(PcodeOp *op,Funcdata &data)
|
|||
OpCode shiftopc;
|
||||
PcodeOp *subop = findSubshift(op,n,shiftopc);
|
||||
if (subop == (PcodeOp *)0) return 0;
|
||||
// TODO: Cannot currently support 128-bit arithmetic, except in special case of 2^64
|
||||
if (n > 64) return 0;
|
||||
if (n > 127) return 0; // Up to 128-bits
|
||||
|
||||
Varnode *multvn = subop->getIn(0);
|
||||
if (!multvn->isWritten()) return 0;
|
||||
PcodeOp *multop = multvn->getDef();
|
||||
if (multop->code() != CPUI_INT_MULT) return 0;
|
||||
uintb multConst;
|
||||
int4 constExtType = multop->getIn(1)->isConstantExtended(multConst);
|
||||
if (constExtType < 0) return 0;
|
||||
uint8 multConst[2];
|
||||
if (!multop->getIn(1)->isConstantExtended(multConst))
|
||||
return 0;
|
||||
|
||||
Varnode *extvn = multop->getIn(0);
|
||||
if (!extvn->isWritten()) return 0;
|
||||
|
@ -7381,20 +7385,10 @@ int4 RuleDivTermAdd::applyOp(PcodeOp *op,Funcdata &data)
|
|||
if (op->code()==CPUI_INT_RIGHT) return 0;
|
||||
}
|
||||
|
||||
uintb newc;
|
||||
if (n < 64 || (extvn->getSize() <= 8)) {
|
||||
uintb pow = 1;
|
||||
pow <<= n; // Calculate 2^n
|
||||
newc = multConst + pow;
|
||||
}
|
||||
else {
|
||||
if (constExtType != 2) return 0; // TODO: Can't currently represent
|
||||
if (!signbit_negative(multConst,8)) return 0;
|
||||
// Adding 2^64 to a sign-extended 64-bit value with its sign set, causes all the
|
||||
// set extension bits to be cancelled out, converting it into a
|
||||
// zero-extended 64-bit value.
|
||||
constExtType = 1; // Set extension of constant to INT_ZEXT
|
||||
}
|
||||
uint8 power[2];
|
||||
set_u128(power, 1);
|
||||
leftshift128(power,power,n); // power = 2^n
|
||||
add128(multConst,power,multConst); // multConst += 2^n
|
||||
Varnode *x = extop->getIn(0);
|
||||
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
|
@ -7405,17 +7399,7 @@ int4 RuleDivTermAdd::applyOp(PcodeOp *op,Funcdata &data)
|
|||
continue;
|
||||
|
||||
// Construct the new constant
|
||||
Varnode *newConstVn;
|
||||
if (constExtType == 0)
|
||||
newConstVn = data.newConstant(extvn->getSize(),newc);
|
||||
else {
|
||||
// Create new extension of the constant
|
||||
PcodeOp *newExtOp = data.newOp(1,op->getAddr());
|
||||
data.opSetOpcode(newExtOp,(constExtType==1) ? CPUI_INT_ZEXT : CPUI_INT_SEXT);
|
||||
newConstVn = data.newUniqueOut(extvn->getSize(),newExtOp);
|
||||
data.opSetInput(newExtOp,data.newConstant(8,multConst),0);
|
||||
data.opInsertBefore(newExtOp,op);
|
||||
}
|
||||
Varnode *newConstVn = data.newExtendedConstant(extvn->getSize(), multConst, op);
|
||||
|
||||
// Construct the new multiply
|
||||
PcodeOp *newmultop = data.newOp(2,op->getAddr());
|
||||
|
@ -7532,7 +7516,8 @@ int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data)
|
|||
if (!multvn->isWritten()) return 0;
|
||||
PcodeOp *multop = multvn->getDef();
|
||||
if (multop->code() != CPUI_INT_MULT) return 0;
|
||||
if (!multop->getIn(1)->isConstant()) return 0;
|
||||
uint8 multConst[2];
|
||||
if (!multop->getIn(1)->isConstantExtended(multConst)) return 0;
|
||||
Varnode *zextvn = multop->getIn(0);
|
||||
if (!zextvn->isWritten()) return 0;
|
||||
PcodeOp *zextop = zextvn->getDef();
|
||||
|
@ -7545,14 +7530,16 @@ int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data)
|
|||
if (addop->code() != CPUI_INT_ADD) continue;
|
||||
if ((addop->getIn(0)!=z)&&(addop->getIn(1)!=z)) continue;
|
||||
|
||||
uintb pow = 1;
|
||||
pow <<= n; // Calculate 2^n
|
||||
uintb newc = multop->getIn(1)->getOffset() + pow;
|
||||
uint8 pow[2];
|
||||
set_u128(pow, 1);
|
||||
leftshift128(pow,pow,n); // Calculate 2^n
|
||||
add128(multConst, pow, multConst); // multConst = multConst + 2^n
|
||||
PcodeOp *newmultop = data.newOp(2,op->getAddr());
|
||||
data.opSetOpcode(newmultop,CPUI_INT_MULT);
|
||||
Varnode *newmultvn = data.newUniqueOut(zextvn->getSize(),newmultop);
|
||||
data.opSetInput(newmultop,zextvn,0);
|
||||
data.opSetInput(newmultop,data.newConstant(zextvn->getSize(),newc),1);
|
||||
Varnode *newConstVn = data.newExtendedConstant(zextvn->getSize(), multConst, op);
|
||||
data.opSetInput(newmultop,newConstVn,1);
|
||||
data.opInsertBefore(newmultop,op);
|
||||
|
||||
PcodeOp *newshiftop = data.newOp(2,op->getAddr());
|
||||
|
@ -7591,7 +7578,7 @@ int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data)
|
|||
/// \param xsize will hold the number of (non-zero) bits in the numerand
|
||||
/// \param extopc holds whether the extension is INT_ZEXT or INT_SEXT
|
||||
/// \return the extended numerand if possible, or the unextended numerand, or NULL
|
||||
Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &extopc)
|
||||
Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uint8 *y,int4 &xsize,OpCode &extopc)
|
||||
|
||||
{
|
||||
PcodeOp *curOp = op;
|
||||
|
@ -7621,18 +7608,22 @@ Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &e
|
|||
if (curOp->code() != CPUI_INT_MULT) return (Varnode *)0; // There MUST be an INT_MULT
|
||||
Varnode *inVn = curOp->getIn(0);
|
||||
if (!inVn->isWritten()) return (Varnode *)0;
|
||||
if (inVn->isConstantExtended(y) >= 0) {
|
||||
if (inVn->isConstantExtended(y)) {
|
||||
inVn = curOp->getIn(1);
|
||||
if (!inVn->isWritten()) return (Varnode *)0;
|
||||
}
|
||||
else if (curOp->getIn(1)->isConstantExtended(y) < 0)
|
||||
else if (!curOp->getIn(1)->isConstantExtended(y))
|
||||
return (Varnode *)0; // There MUST be a constant
|
||||
|
||||
Varnode *resVn;
|
||||
PcodeOp *extOp = inVn->getDef();
|
||||
extopc = extOp->code();
|
||||
if (extopc != CPUI_INT_SEXT) {
|
||||
uintb nzMask = inVn->getNZMask();
|
||||
uintb nzMask;
|
||||
if (extopc == CPUI_INT_ZEXT)
|
||||
nzMask = extOp->getIn(0)->getNZMask();
|
||||
else
|
||||
nzMask = inVn->getNZMask();
|
||||
xsize = 8*sizeof(uintb) - count_leading_zeros(nzMask);
|
||||
if (xsize == 0) return (Varnode *)0;
|
||||
if (xsize > 4*inVn->getSize()) return (Varnode *)0;
|
||||
|
@ -7672,44 +7663,50 @@ Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &e
|
|||
/// Do some additional checks on the parameters as an optimized encoding
|
||||
/// of a divisor.
|
||||
/// \param n is the power of 2
|
||||
/// \param y is the multiplicative coefficient
|
||||
/// \param y is the (up to 128-bit) multiplicative coefficient
|
||||
/// \param xsize is the maximum power of 2
|
||||
/// \return the divisor or 0 if the checks fail
|
||||
uintb RuleDivOpt::calcDivisor(uintb n,uint8 y,int4 xsize)
|
||||
uintb RuleDivOpt::calcDivisor(uintb n,uint8 *y,int4 xsize)
|
||||
|
||||
{
|
||||
if (n > 127) return 0; // Not enough precision
|
||||
if (y <= 1) return 0; // Boundary cases are wrong form
|
||||
if (n > 127 || xsize > 64) return 0; // Not enough precision
|
||||
uint8 power[2];
|
||||
uint8 q[2];
|
||||
uint8 r[2];
|
||||
set_u128(power, 1);
|
||||
if (ulessequal128(y, power)) // Boundary cases, y <= 1, are wrong form
|
||||
return 0;
|
||||
|
||||
uint8 d,r;
|
||||
uint8 power;
|
||||
if (n < 64) {
|
||||
power = ((uint8)1) << n;
|
||||
d = power / (y-1);
|
||||
r = power % (y-1);
|
||||
subtract128(y, power, y); // y = y - 1
|
||||
leftshift128(power, power, n); // power = 2^n
|
||||
|
||||
udiv128(power, y, q, r);
|
||||
if (0 != q[1])
|
||||
return 0; // Result is bigger than 64-bits
|
||||
if (uless128(y,q)) return 0; // if y < q
|
||||
uint8 diff = 0;
|
||||
if (!uless128(r,q)) { // if r >= q
|
||||
// Its possible y is 1 too big giving us a q that is smaller by 1 than the correct value
|
||||
q[0] += 1; // Adjust to bigger q
|
||||
subtract128(r,y,r); // and remainder for the smaller y
|
||||
add128(r, q, r);
|
||||
if (!uless128(r,q)) return 0;
|
||||
diff = q[0]; // Using y that is off by one adds extra error, affecting allowable maxx
|
||||
}
|
||||
else {
|
||||
if (0 != power2Divide(n,y-1,d,r))
|
||||
return 0; // Result is bigger than 64-bits
|
||||
}
|
||||
if (d>=y) return 0;
|
||||
if (r >= d) return 0;
|
||||
// The optimization of division to multiplication
|
||||
// by the reciprocal holds true, if the maximum value
|
||||
// of x times the remainder is less than 2^n
|
||||
uint8 maxx = 1;
|
||||
maxx <<= xsize;
|
||||
// of x times q-r is less than 2^n
|
||||
uint8 maxx = (xsize == 64) ? 0 : ((uint8)1) << xsize;
|
||||
maxx -= 1; // Maximum possible x value
|
||||
uint8 tmp;
|
||||
if (n < 64)
|
||||
tmp = power / (d-r); // r < d => divisor is non-zero
|
||||
else {
|
||||
uint8 unused;
|
||||
if (0 != power2Divide(n,d-r,tmp,unused))
|
||||
return (uintb)d; // tmp is bigger than 2^64 > maxx
|
||||
}
|
||||
if (tmp<=maxx) return 0;
|
||||
return (uintb)d;
|
||||
uint8 tmp[2];
|
||||
uint8 denom[2];
|
||||
diff += q[0] - r[0];
|
||||
set_u128(denom,diff);
|
||||
udiv128(power,denom, tmp, r);
|
||||
if (0 != tmp[1])
|
||||
return (uintb)q[0]; // tmp is bigger than 2^64 > maxx
|
||||
if (tmp[0]<=maxx) return 0;
|
||||
return (uintb)q[0];
|
||||
}
|
||||
|
||||
/// \brief Replace sign-bit extractions from the first given Varnode with the second Varnode
|
||||
|
@ -7785,7 +7782,7 @@ bool RuleDivOpt::checkFormOverlap(PcodeOp *op)
|
|||
Varnode *cvn = superOp->getIn(1);
|
||||
if (!cvn->isConstant()) return true; // Might be a form where constant has propagated yet
|
||||
int4 n,xsize;
|
||||
uintb y;
|
||||
uint8 y[2];
|
||||
OpCode extopc;
|
||||
Varnode *inVn = findForm(superOp, n, y, xsize, extopc);
|
||||
if (inVn != (Varnode *)0) return true;
|
||||
|
@ -7797,8 +7794,8 @@ bool RuleDivOpt::checkFormOverlap(PcodeOp *op)
|
|||
/// \brief Convert INT_MULT and shift forms into INT_DIV or INT_SDIV
|
||||
///
|
||||
/// The unsigned and signed variants are:
|
||||
/// - `sub( (zext(V)*c)>>n, 0) => V / (2^n/(c-1))`
|
||||
/// - `sub( (sext(V)*c)s>>n, 0) => V s/ (2^n/(c-1))`
|
||||
/// - `sub( (zext(V)*c), d) >> e => V / (2^n/(c-1)) where n = d*8 + e`
|
||||
/// - `sub( (sext(V)*c), d) s>> e => V s/ (2^n/(c-1)) where n = d*8 + e`
|
||||
void RuleDivOpt::getOpList(vector<uint4> &oplist) const
|
||||
|
||||
{
|
||||
|
@ -7811,7 +7808,7 @@ int4 RuleDivOpt::applyOp(PcodeOp *op,Funcdata &data)
|
|||
|
||||
{
|
||||
int4 n,xsize;
|
||||
uintb y;
|
||||
uint8 y[2];
|
||||
OpCode extOpc;
|
||||
Varnode *inVn = findForm(op,n,y,xsize,extOpc);
|
||||
if (inVn == (Varnode *)0) return 0;
|
||||
|
|
|
@ -1264,7 +1264,7 @@ public:
|
|||
};
|
||||
|
||||
class RuleDivOpt : public Rule {
|
||||
static uintb calcDivisor(uintb n,uint8 y,int4 xsize); ///< Calculate the divisor
|
||||
static uintb calcDivisor(uintb n,uint8 *y,int4 xsize); ///< Calculate the divisor
|
||||
static void moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data);
|
||||
static bool checkFormOverlap(PcodeOp *op); ///< If form rooted at given PcodeOp is superseded by an overlapping form
|
||||
public:
|
||||
|
@ -1275,7 +1275,7 @@ public:
|
|||
}
|
||||
virtual void getOpList(vector<uint4> &oplist) const;
|
||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||
static Varnode *findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &extopc);
|
||||
static Varnode *findForm(PcodeOp *op,int4 &n,uint8 *y,int4 &xsize,OpCode &extopc);
|
||||
};
|
||||
|
||||
class RuleSignDiv2 : public Rule {
|
||||
|
|
|
@ -3706,6 +3706,7 @@ static void findSlaSpecs(vector<string> &res, const string &dir, const string &s
|
|||
/// \param enforceLocalKeyWord is \b true to force all local variable definitions to use the \b local keyword
|
||||
/// \param largeTemporaryWarning is \b true for individual warnings about temporary varnodes that are too large
|
||||
/// \param caseSensitiveRegisterNames is \b true if register names are allowed to be case sensitive
|
||||
/// \param debugOutput is \b true if the output file is written using the debug (XML) form of the .sla format
|
||||
void SleighCompile::setAllOptions(const map<string,string> &defines, bool unnecessaryPcodeWarning,
|
||||
bool lenientConflict, bool allCollisionWarning,
|
||||
bool allNopWarning,bool deadTempWarning,bool enforceLocalKeyWord,
|
||||
|
|
|
@ -780,37 +780,55 @@ void Varnode::printRawHeritage(ostream &s,int4 depth) const
|
|||
s << endl;
|
||||
}
|
||||
|
||||
/// If \b this is a constant, or is extended (INT_ZEXT,INT_SEXT) from a constant,
|
||||
/// the \e value of the constant is passed back and a non-negative integer is returned, either:
|
||||
/// - 0 for a normal constant Varnode
|
||||
/// - 1 for a zero extension (INT_ZEXT) of a normal constant
|
||||
/// - 2 for a sign extension (INT_SEXT) of a normal constant
|
||||
/// \param val is a reference to the constant value that is passed back
|
||||
/// \return the extension code (or -1 if \b this cannot be interpreted as a constant)
|
||||
int4 Varnode::isConstantExtended(uintb &val) const
|
||||
/// If \b this is a constant, or is extended (INT_ZEXT,INT_SEXT,PIECE) from a constant,
|
||||
/// the \e value of the constant (currently up to 128 bits) is passed back and \b true is returned.
|
||||
/// \param val will hold the 128-bit constant value
|
||||
/// \return \b true if a constant was recovered
|
||||
bool Varnode::isConstantExtended(uint8 *val) const
|
||||
|
||||
{
|
||||
if (isConstant()) {
|
||||
val = getOffset();
|
||||
return 0;
|
||||
val[0] = getOffset();
|
||||
val[1] = 0;
|
||||
return true;
|
||||
}
|
||||
if (!isWritten()) return -1;
|
||||
if (!isWritten() || size <= 8) return false;
|
||||
if (size > 16) return false; // Currently only up to 128-bit values
|
||||
OpCode opc = def->code();
|
||||
if (opc == CPUI_INT_ZEXT) {
|
||||
Varnode *vn0 = def->getIn(0);
|
||||
if (vn0->isConstant()) {
|
||||
val = vn0->getOffset();
|
||||
return 1;
|
||||
val[0] = vn0->getOffset();
|
||||
val[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (opc == CPUI_INT_SEXT) {
|
||||
Varnode *vn0 = def->getIn(0);
|
||||
if (vn0->isConstant()) {
|
||||
val = vn0->getOffset();
|
||||
return 2;
|
||||
val[0] = vn0->getOffset();
|
||||
if (vn0->getSize() < 8)
|
||||
val[0] = sign_extend(val[0], vn0->getSize(), size);
|
||||
val[1] = (signbit_negative(val[0], 8)) ? 0xffffffffffffffffL : 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
else if (opc == CPUI_PIECE) {
|
||||
Varnode *vnlo = def->getIn(1);
|
||||
if (vnlo->isConstant()) {
|
||||
val[0] = vnlo->getOffset();
|
||||
Varnode *vnhi = def->getIn(0);
|
||||
if (vnhi->isConstant()) {
|
||||
val[1] = vnhi->getOffset();
|
||||
if (vnlo->getSize() == 8)
|
||||
return true;
|
||||
val[0] |= val[1] << 8*vnlo->getSize();
|
||||
val[1] >>= 8*(8-vnlo->getSize());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Make an initial determination of the Datatype of this Varnode. If a Datatype is already
|
||||
|
|
|
@ -290,7 +290,7 @@ public:
|
|||
return (loc.getOffset() == val);
|
||||
}
|
||||
|
||||
int4 isConstantExtended(uintb &val) const; ///< Is \b this an (extended) constant
|
||||
bool isConstantExtended(uint8 *val) const; ///< Is \b this an (extended) constant
|
||||
/// Return \b true if this Varnode is linked into the SSA tree
|
||||
bool isHeritageKnown(void) const { return ((flags&(Varnode::insert|Varnode::constant|Varnode::annotation))!=0); }
|
||||
bool isTypeLock(void) const { return ((flags&Varnode::typelock)!=0); } ///< Does \b this have a locked Datatype?
|
||||
|
|
292
Ghidra/Features/Decompiler/src/decompile/datatests/divopt.xml
Normal file
292
Ghidra/Features/Decompiler/src/decompile/datatests/divopt.xml
Normal file
|
@ -0,0 +1,292 @@
|
|||
<decompilertest>
|
||||
<binaryimage arch="x86:LE:64:default:gcc">
|
||||
<!-- Examples of optimized division and modulo for constants
|
||||
81 89 91 93 95 97 99 101 103 107 111 112 115 119 121 123 125 -->
|
||||
<bytechunk space="ram" offset="0x100000" readonly="true">
|
||||
f30f1efa48ba53069e6ecd0f8b94488b
|
||||
0f4889c848f7e24829d148d1e94801ca
|
||||
488b4f0848c1ea064889c848891748ba
|
||||
e10217b8c0052e7048f7e24829d148d1
|
||||
e94801ca488b4f1048c1ea064889c848
|
||||
89570848ba176881166881166848f7e2
|
||||
4829d148d1e94801ca488b4f1848c1ea
|
||||
064889c84889571048ba175860810516
|
||||
586048f7e24829d148d1e94801ca488b
|
||||
4f2048c1ea064889c84889571848ba31
|
||||
d28e150823ed5848f7e24829d148d1e9
|
||||
4801ca488b4f2848c1ea064889c84889
|
||||
572048bad151812fae7ed05148f7e248
|
||||
29d148d1e94801ca488b4f3048c1ea06
|
||||
4889c84889572848ba15a8f52b056afd
|
||||
4a48f7e24829d148d1e94801ca488b4f
|
||||
3848c1ea064889c84889573048bae5ae
|
||||
9f2d56866f4448f7e24829d148d1e948
|
||||
01ca488b4f4048c1ea064889c8488957
|
||||
3848bac527904acecb223e48f7e24829
|
||||
d148d1e94801ca488b4f4848c1ea0648
|
||||
89c84889574048ba6ff60bb1a2343e32
|
||||
48f7e24829d148d1e94801ca488b4f50
|
||||
48c1ea064889c84889574848bab95073
|
||||
12880b352748f7e24829d148d1e94801
|
||||
ca48b9942449922449922448c1ea0648
|
||||
895750488b575848c1ea044889d048f7
|
||||
e1488b4f604889c84889575848ba07cf
|
||||
1128da6af01c48f7e24829d148d1e948
|
||||
01ca488b4f6848c1ea064889c8488957
|
||||
6048ba5d13815c13815c1348f7e24829
|
||||
d148d1e94801ca488b4f7048c1ea0648
|
||||
89c84889576848bae3fdc869be56cf0e
|
||||
48f7e24829d148d1e94801ca488b4f78
|
||||
48c1ea064889c84889577048ba11680a
|
||||
81a610680a48f7e24829d148d1e94801
|
||||
ca48c1ea0648895778488b8f80000000
|
||||
48ba77be9f1a2fdd24064889c848f7e2
|
||||
4829d148d1e94801ca48c1ea06488997
|
||||
80000000c30000000000000000000000
|
||||
f30f1efa48ba9581a75bf3c32265488b
|
||||
0f4889c848c1f93f48f7ea48c1fa0548
|
||||
29ca488b4f0848891748ba71810b5ce0
|
||||
0217b84889c848f7ea4801ca48c1f93f
|
||||
48c1fa064829ca488b4f104889570848
|
||||
ba032dd0022dd0022d4889c848c1f93f
|
||||
48f7ea48c1fa044829ca488b4f184889
|
||||
571048ba030b2cb0c0020b2c4889c848
|
||||
c1f93f48f7ea48c1fa044829ca488b4f
|
||||
204889571848ba1969c70a849176ac48
|
||||
89c848f7ea4801ca48c1f93f48c1fa06
|
||||
4829ca488b4f284889572048bae9a8c0
|
||||
17573fe8a84889c848f7ea4801ca48c1
|
||||
f93f48c1fa064829ca488b4f30488957
|
||||
2848ba0bd4fa9502b57ea54889c848f7
|
||||
ea4801ca48c1f93f48c1fa064829ca48
|
||||
8b4f384889573048ba73d7cf162bc337
|
||||
a24889c848f7ea4801ca48c1f93f48c1
|
||||
fa064829ca488b4f404889573848bae3
|
||||
134825e765119f4889c848f7ea4801ca
|
||||
48c1f93f48c1fa064829ca488b4f4848
|
||||
89574048ba67bf102b4ae323134889c8
|
||||
48c1f93f48f7ea48c1fa034829ca488b
|
||||
4f504889574848ba5da83909c4859a93
|
||||
4889c848f7ea4801ca48c1f93f48c1fa
|
||||
064829ca488b4f584889575048ba2549
|
||||
9224499224494889c848c1f93f48f7ea
|
||||
48c1fa054829ca488b4f604889575848
|
||||
bae13902455b0d9e234889c848c1f93f
|
||||
48f7ea48c1fa044829ca488b4f684889
|
||||
576048baaf8940ae8940ae894889c848
|
||||
f7ea4801ca48c1f93f48c1fa064829ca
|
||||
488b4f704889576848ba793f729aafd5
|
||||
b3434889c848f7ea48c1f93f48c1fa05
|
||||
4829ca488b4f784889577048ba093485
|
||||
40530834854889c848f7ea4801ca48c1
|
||||
f93f48c1fa064829ca48895778488b8f
|
||||
8000000048bacff753e3a59bc4204889
|
||||
c848c1f93f48f7ea48c1fa044829ca48
|
||||
899780000000c3000000000000000000
|
||||
f30f1efa488b0f488b775848ba53069e
|
||||
6ecd0f8b944889c848f7e24889c84829
|
||||
d048d1e84801c248c1ea06488d04d248
|
||||
bae10217b8c0052e70488d04c04829c1
|
||||
48890f488b4f084889c848f7e24889c8
|
||||
4829d048d1e84801c248c1ea06488d04
|
||||
92488d0442488d04c248ba1768811668
|
||||
8116684829c148894f08488b4f104889
|
||||
c848f7e24889c84829d048d1e84801c2
|
||||
48c1ea06486bd25b4829d148ba175860
|
||||
810516586048894f10488b4f184889c8
|
||||
48f7e24889c84829d048d1e84801c248
|
||||
c1ea06488d14524889d048c1e0054829
|
||||
d048ba31d28e150823ed584829c14889
|
||||
4f18488b4f204889c848f7e24889c848
|
||||
29d048d1e84801c248c1ea06488d0452
|
||||
48c1e0054829d048bad151812fae7ed0
|
||||
514829c148894f20488b4f284889c848
|
||||
f7e24889c84829d048d1e84801c248c1
|
||||
ea06488d045248c1e0054801c24829d1
|
||||
48ba15a8f52b056afd4a48894f28488b
|
||||
4f304889c848f7e24889c84829d048d1
|
||||
e84801c248c1ea06488d04524889c248
|
||||
c1e2054801d048bae5ae9f2d56866f44
|
||||
4829c148894f30488b4f384889c848f7
|
||||
e24889c84829d048d1e84801c248c1ea
|
||||
06488d0492488d0480488d048248bac5
|
||||
27904acecb223e4829c148894f38488b
|
||||
4f404889c848f7e24889c84829d048d1
|
||||
e84801c248c1ea06486bd2674829d148
|
||||
ba6ff60bb1a2343e3248894f40488b4f
|
||||
484889c848f7e24889c84829d048d1e8
|
||||
4801c248c1ea06486bd26b4829d148ba
|
||||
b9507312880b352748894f48488b4f50
|
||||
4889c848f7e24889c84829d048d1e848
|
||||
01c248c1ea06486bd26f4829d14889f2
|
||||
48c1ea0448894f5048b9942449922449
|
||||
92244889d048f7e1488d0cd500000000
|
||||
4829d148ba07cf1128da6af01c48c1e1
|
||||
044829ce488b4f60488977584889c848
|
||||
f7e24889c84829d048d1e84801c248c1
|
||||
ea06486bd2734829d148ba5d13815c13
|
||||
815c1348894f60488b4f684889c848f7
|
||||
e24889c84829d048d1e84801c248c1ea
|
||||
06486bd2774829d148bae3fdc869be56
|
||||
cf0e48894f68488b4f704889c848f7e2
|
||||
4889c84829d048d1e84801c248c1ea06
|
||||
4889d048c1e0044829d0488d04c248ba
|
||||
11680a81a610680a4829c148894f7048
|
||||
8b4f784889c848f7e24889c84829d048
|
||||
d1e84801c248c1ea06486bd27b4829d1
|
||||
48ba77be9f1a2fdd240648894f78488b
|
||||
8f800000004889c848f7e24889c84829
|
||||
d048d1e84801c248c1ea064889d048c1
|
||||
e0054829d0488d04824829c148898f80
|
||||
000000c3000000000000000000000000
|
||||
f30f1efa48ba9581a75bf3c32265488b
|
||||
0f4889c848f7ea4889c848c1f83f48c1
|
||||
fa054829c2488d04d248ba71810b5ce0
|
||||
0217b8488d04c04829c148890f488b4f
|
||||
084889c848f7ea4889c848c1f83f4801
|
||||
ca48c1fa064829c2488d0492488d0442
|
||||
488d04c248ba032dd0022dd0022d4829
|
||||
c148894f08488b4f104889c848f7ea48
|
||||
89c848c1f83f48c1fa044829c2486bd2
|
||||
5b4829d148ba030b2cb0c0020b2c4889
|
||||
4f10488b4f184889c848f7ea4889c848
|
||||
c1f83f48c1fa044829c2488d14524889
|
||||
d048c1e0054829d048ba1969c70a8491
|
||||
76ac4829c148894f18488b4f204889c8
|
||||
48f7ea4889c848c1f83f4801ca48c1fa
|
||||
064829c2488d045248c1e0054829d048
|
||||
bae9a8c017573fe8a84829c148894f20
|
||||
488b4f284889c848f7ea4889c848c1f8
|
||||
3f4801ca48c1fa064829c2488d045248
|
||||
c1e0054801c24829d148ba0bd4fa9502
|
||||
b57ea548894f28488b4f304889c848f7
|
||||
ea4889c848c1f83f4801ca48c1fa0648
|
||||
29c2488d04524889c248c1e2054801d0
|
||||
48ba73d7cf162bc337a24829c148894f
|
||||
30488b4f384889c848f7ea4889c848c1
|
||||
f83f4801ca48c1fa064829c2488d0492
|
||||
488d0480488d048248bae3134825e765
|
||||
119f4829c148894f38488b4f404889c8
|
||||
48f7ea4889c848c1f83f4801ca48c1fa
|
||||
064829c2486bd2674829d148ba67bf10
|
||||
2b4ae3231348894f40488b4f484889c8
|
||||
48f7ea4889c848c1f83f48c1fa034829
|
||||
c2486bd26b4829d148ba5da83909c485
|
||||
9a9348894f48488b4f504889c848f7ea
|
||||
4889c848c1f83f4801ca48c1fa064829
|
||||
c2486bd26f4829d148ba254992244992
|
||||
244948894f50488b4f584889c848f7ea
|
||||
4889c848c1f83f48c1fa054829c2488d
|
||||
04d5000000004829d048bae13902455b
|
||||
0d9e2348c1e0044829c148894f58488b
|
||||
4f604889c848f7ea4889c848c1f83f48
|
||||
c1fa044829c2486bd2734829d148baaf
|
||||
8940ae8940ae8948894f60488b4f6848
|
||||
89c848f7ea4889c848c1f83f4801ca48
|
||||
c1fa064829c2486bd2774829d148ba79
|
||||
3f729aafd5b34348894f68488b4f7048
|
||||
89c848f7ea4889c848c1fa0548c1f83f
|
||||
4829c24889d048c1e0044829d0488d04
|
||||
c248ba09348540530834854829c14889
|
||||
4f70488b4f784889c848f7ea4889c848
|
||||
c1f83f4801ca48c1fa064829c2486bd2
|
||||
7b4829d148bacff753e3a59bc4204889
|
||||
4f78488b8f800000004889c848f7ea48
|
||||
89c848c1f83f48c1fa044829c24889d0
|
||||
48c1e0054829d0488d04824829c14889
|
||||
8f80000000c3
|
||||
</bytechunk>
|
||||
<symbol space="ram" offset="0x100000" name="divoptu"/>
|
||||
<symbol space="ram" offset="0x100280" name="divopti"/>
|
||||
<symbol space="ram" offset="0x100500" name="modoptu"/>
|
||||
<symbol space="ram" offset="0x100880" name="modopti"/>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>option integerformat dec</com>
|
||||
<com>parse line extern void divoptu(uint8 *divu);</com>
|
||||
<com>lo fu divoptu</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>parse line extern void divopti(int8 *divi);</com>
|
||||
<com>lo fu divopti</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>parse line extern void modoptu(uint8 *modu);</com>
|
||||
<com>lo fu modoptu</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>parse line extern void modopti(int8 *modi);</com>
|
||||
<com>lo fu modopti</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>quit</com>
|
||||
</script>
|
||||
<stringmatch name="Unsigned Division #1" min="1" max="1">\*divu = \*divu / 81;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #2" min="1" max="1">divu\[1\] = divu\[1\] / 89;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #3" min="1" max="1">divu\[2\] = divu\[2\] / 91;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #4" min="1" max="1">divu\[3\] = divu\[3\] / 93;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #5" min="1" max="1">divu\[4\] = divu\[4\] / 95;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #6" min="1" max="1">divu\[5\] = divu\[5\] / 97;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #7" min="1" max="1">divu\[6\] = divu\[6\] / 99;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #8" min="1" max="1">divu\[7\] = divu\[7\] / 101;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #9" min="1" max="1">divu\[8\] = divu\[8\] / 103;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #10" min="1" max="1">divu\[9\] = divu\[9\] / 107;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #11" min="1" max="1">divu\[10\] = divu\[10\] / 111;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #12" min="1" max="1">divu\[11\] = divu\[11\] / 112;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #13" min="1" max="1">divu\[12\] = divu\[12\] / 115;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #14" min="1" max="1">divu\[13\] = divu\[13\] / 119;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #15" min="1" max="1">divu\[14\] = divu\[14\] / 121;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #16" min="1" max="1">divu\[15\] = divu\[15\] / 123;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #17" min="1" max="1">divu\[16\] = divu\[16\] / 125;</stringmatch>
|
||||
<stringmatch name="Signed Division #1" min="1" max="1">\*divi = \*divi / 81;</stringmatch>
|
||||
<stringmatch name="Signed Division #2" min="1" max="1">divi\[1\] = divi\[1\] / 89;</stringmatch>
|
||||
<stringmatch name="Signed Division #3" min="1" max="1">divi\[2\] = divi\[2\] / 91;</stringmatch>
|
||||
<stringmatch name="Signed Division #4" min="1" max="1">divi\[3\] = divi\[3\] / 93;</stringmatch>
|
||||
<stringmatch name="Signed Division #5" min="1" max="1">divi\[4\] = divi\[4\] / 95;</stringmatch>
|
||||
<stringmatch name="Signed Division #6" min="1" max="1">divi\[5\] = divi\[5\] / 97;</stringmatch>
|
||||
<stringmatch name="Signed Division #7" min="1" max="1">divi\[6\] = divi\[6\] / 99;</stringmatch>
|
||||
<stringmatch name="Signed Division #8" min="1" max="1">divi\[7\] = divi\[7\] / 101;</stringmatch>
|
||||
<stringmatch name="Signed Division #9" min="1" max="1">divi\[8\] = divi\[8\] / 103;</stringmatch>
|
||||
<stringmatch name="Signed Division #10" min="1" max="1">divi\[9\] = divi\[9\] / 107;</stringmatch>
|
||||
<stringmatch name="Signed Division #11" min="1" max="1">divi\[10\] = divi\[10\] / 111;</stringmatch>
|
||||
<stringmatch name="Signed Division #12" min="1" max="1">divi\[11\] = divi\[11\] / 112;</stringmatch>
|
||||
<stringmatch name="Signed Division #13" min="1" max="1">divi\[12\] = divi\[12\] / 115;</stringmatch>
|
||||
<stringmatch name="Signed Division #14" min="1" max="1">divi\[13\] = divi\[13\] / 119;</stringmatch>
|
||||
<stringmatch name="Signed Division #15" min="1" max="1">divi\[14\] = divi\[14\] / 121;</stringmatch>
|
||||
<stringmatch name="Signed Division #16" min="1" max="1">divi\[15\] = divi\[15\] / 123;</stringmatch>
|
||||
<stringmatch name="Signed Division #17" min="1" max="1">divi\[16\] = divi\[16\] / 125;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #1" min="1" max="1">\*modu = \*modu % 81;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #2" min="1" max="1">modu\[1\] = modu\[1\] % 89;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #3" min="1" max="1">modu\[2\] = modu\[2\] % 91;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #4" min="1" max="1">modu\[3\] = modu\[3\] % 93;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #5" min="1" max="1">modu\[4\] = modu\[4\] % 95;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #6" min="1" max="1">modu\[5\] = modu\[5\] % 97;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #7" min="1" max="1">modu\[6\] = modu\[6\] % 99;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #8" min="1" max="1">modu\[7\] = modu\[7\] % 101;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #9" min="1" max="1">modu\[8\] = modu\[8\] % 103;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #10" min="1" max="1">modu\[9\] = modu\[9\] % 107;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #11" min="1" max="1">modu\[10\] = modu\[10\] % 111;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #12" min="1" max="1">modu\[11\] = modu\[11\] % 112;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #13" min="1" max="1">modu\[12\] = modu\[12\] % 115;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #14" min="1" max="1">modu\[13\] = modu\[13\] % 119;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #15" min="1" max="1">modu\[14\] = modu\[14\] % 121;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #16" min="1" max="1">modu\[15\] = modu\[15\] % 123;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #17" min="1" max="1">modu\[16\] = modu\[16\] % 125;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #1" min="1" max="1">\*modi = \*modi % 81;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #2" min="1" max="1">modi\[1\] = modi\[1\] % 89;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #3" min="1" max="1">modi\[2\] = modi\[2\] % 91;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #4" min="1" max="1">modi\[3\] = modi\[3\] % 93;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #5" min="1" max="1">modi\[4\] = modi\[4\] % 95;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #6" min="1" max="1">modi\[5\] = modi\[5\] % 97;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #7" min="1" max="1">modi\[6\] = modi\[6\] % 99;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #8" min="1" max="1">modi\[7\] = modi\[7\] % 101;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #9" min="1" max="1">modi\[8\] = modi\[8\] % 103;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #10" min="1" max="1">modi\[9\] = modi\[9\] % 107;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #11" min="1" max="1">modi\[10\] = modi\[10\] % 111;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #12" min="1" max="1">modi\[11\] = modi\[11\] % 112;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #13" min="1" max="1">modi\[12\] = modi\[12\] % 115;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #14" min="1" max="1">modi\[13\] = modi\[13\] % 119;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #15" min="1" max="1">modi\[14\] = modi\[14\] % 121;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #16" min="1" max="1">modi\[15\] = modi\[15\] % 123;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #17" min="1" max="1">modi\[16\] = modi\[16\] % 125;</stringmatch>
|
||||
</decompilertest>
|
|
@ -20,43 +20,74 @@
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import db.Transaction;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.services.ProgramManager;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.pdb.pdbapplicator.DefaultPdbApplicator;
|
||||
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorOptions;
|
||||
import ghidra.features.base.values.GhidraValuesMap;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.LanguageService;
|
||||
import ghidra.program.model.lang.Processor;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.util.DefaultLanguageService;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.MessageType;
|
||||
|
||||
public class PdbDeveloperApplyDummyScript extends GhidraScript {
|
||||
|
||||
private static final String PDB_PROMPT = "Choose a PDB file";
|
||||
private static final String IMAGE_BASE_PROMPT = "Image Base";
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
File pdbFile = askFile("Choose a PDB file", "OK");
|
||||
if (pdbFile == null) {
|
||||
Msg.info(this, "Canceled execution due to no input file");
|
||||
return;
|
||||
}
|
||||
if (!pdbFile.exists()) {
|
||||
String message = pdbFile.getAbsolutePath() + " is not a valid file.";
|
||||
Msg.info(this, message);
|
||||
popup(message);
|
||||
return;
|
||||
}
|
||||
|
||||
LanguageService ls = DefaultLanguageService.getLanguageService();
|
||||
Processor processor_x86 = Processor.findOrPossiblyCreateProcessor("x86");
|
||||
Language x86 = ls.getDefaultLanguage(processor_x86);
|
||||
ProgramDB program = new ProgramDB("Test", x86, x86.getDefaultCompilerSpec(), this);
|
||||
Address imageBase =
|
||||
program.getAddressFactory().getDefaultAddressSpace().getAddress(0x400000L);
|
||||
|
||||
GhidraValuesMap values = new GhidraValuesMap();
|
||||
|
||||
values.defineFile(PDB_PROMPT, null);
|
||||
values.defineAddress(IMAGE_BASE_PROMPT, imageBase, program);
|
||||
|
||||
// Validator for values
|
||||
values.setValidator((valueMap, status) -> {
|
||||
File file = valueMap.getFile(PDB_PROMPT);
|
||||
if (file == null) {
|
||||
status.setStatusText("PDB file must be selected.", MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
if (!file.exists()) {
|
||||
status.setStatusText(file.getAbsolutePath() + " is not a valid file.",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
String fileName = file.getAbsolutePath();
|
||||
if (!fileName.endsWith(".pdb") && !fileName.endsWith(".PDB")) {
|
||||
status.setStatusText("Expected .pdb file extenstion (got '" + fileName + "').",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
// We do not need to check the existence of an image base because we provide a default
|
||||
// value
|
||||
return true;
|
||||
});
|
||||
|
||||
// asks the script to show a dialog where the user can give values for all the items
|
||||
// in the ValuesMap.
|
||||
|
||||
values = askValues("Enter Values", null, values);
|
||||
|
||||
File pdbFile = values.getFile(PDB_PROMPT);
|
||||
String pdbFileName = pdbFile.getAbsolutePath();
|
||||
if (!pdbFileName.endsWith(".pdb") && !pdbFileName.endsWith(".PDB")) {
|
||||
String message = "Aborting: Expected input file to have extension of type .pdb (got '" +
|
||||
pdbFileName + "').";
|
||||
Msg.info(this, message);
|
||||
popup(message);
|
||||
return;
|
||||
}
|
||||
imageBase = values.getAddress(IMAGE_BASE_PROMPT);
|
||||
|
||||
MessageLog log = new MessageLog();
|
||||
|
||||
|
@ -64,10 +95,9 @@ public class PdbDeveloperApplyDummyScript extends GhidraScript {
|
|||
PdbReaderOptions pdbReaderOptions = new PdbReaderOptions();
|
||||
PdbApplicatorOptions pdbApplicatorOptions = new PdbApplicatorOptions();
|
||||
|
||||
LanguageService ls = DefaultLanguageService.getLanguageService();
|
||||
Processor processor_x86 = Processor.findOrPossiblyCreateProcessor("x86");
|
||||
Language x86 = ls.getDefaultLanguage(processor_x86);
|
||||
ProgramDB program = new ProgramDB("Test", x86, x86.getDefaultCompilerSpec(), this);
|
||||
try (Transaction tx = program.openTransaction("Set Image Base")) {
|
||||
program.setImageBase(imageBase, true);
|
||||
}
|
||||
|
||||
ProgramManager programManager = state.getTool().getService(ProgramManager.class);
|
||||
programManager.openProgram(program);
|
||||
|
|
|
@ -19,39 +19,79 @@
|
|||
|
||||
import java.io.*;
|
||||
|
||||
import docking.widgets.values.GValuesMap;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.features.base.values.GhidraValuesMap;
|
||||
import ghidra.util.*;
|
||||
|
||||
public class PdbDeveloperDumpScript extends GhidraScript {
|
||||
|
||||
private static final String PDB_PROMPT = "Choose a PDB file";
|
||||
private static final String OUTPUT_PROMPT = "Choose an output file";
|
||||
|
||||
private static boolean validatePdb(GValuesMap valueMap, StatusListener status) {
|
||||
File file = valueMap.getFile(PDB_PROMPT);
|
||||
if (file == null) {
|
||||
status.setStatusText("PDB file must be selected.", MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
if (!file.exists()) {
|
||||
status.setStatusText(file.getAbsolutePath() + " is not a valid file.",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
String fileName = file.getAbsolutePath();
|
||||
if (!fileName.endsWith(".pdb") && !fileName.endsWith(".PDB")) {
|
||||
status.setStatusText("Expected .pdb file extenstion (got '" + fileName + "').",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
// We do not need to check the existence of an image base because we provide a default
|
||||
// value
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean validateOutput(GValuesMap valueMap, StatusListener status) {
|
||||
File file = valueMap.getFile(OUTPUT_PROMPT);
|
||||
// File will exist, as we supplied a default value
|
||||
String fileName = file.getAbsolutePath();
|
||||
if (fileName.endsWith(".pdb") || fileName.endsWith(".PDB")) {
|
||||
status.setStatusText("Output file may not end with .pdb (got '" + fileName + "').",
|
||||
MessageType.ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
File pdbFile = askFile("Choose a PDB file", "OK");
|
||||
if (pdbFile == null) {
|
||||
Msg.info(this, "Canceled execution due to no input file");
|
||||
return;
|
||||
}
|
||||
if (!pdbFile.exists()) {
|
||||
String message = pdbFile.getAbsolutePath() + " is not a valid file.";
|
||||
Msg.info(this, message);
|
||||
popup(message);
|
||||
return;
|
||||
}
|
||||
String pdbFileName = pdbFile.getAbsolutePath();
|
||||
if (!pdbFileName.endsWith(".pdb") && !pdbFileName.endsWith(".PDB")) {
|
||||
String message = "Aborting: Expected input file to have extension of type .pdb (got '" +
|
||||
pdbFileName + "').";
|
||||
Msg.info(this, message);
|
||||
popup(message);
|
||||
return;
|
||||
}
|
||||
|
||||
File dumpFile = askFile("Choose an output file", "OK");
|
||||
if (dumpFile == null) {
|
||||
Msg.info(this, "Canceled execution due to no output file");
|
||||
return;
|
||||
}
|
||||
GhidraValuesMap values = new GhidraValuesMap();
|
||||
|
||||
values.defineFile(PDB_PROMPT, null);
|
||||
values.setValidator((valueMap, status) -> {
|
||||
return validatePdb(valueMap, status);
|
||||
});
|
||||
values = askValues("Enter Values", null, values);
|
||||
File pdbFile = values.getFile(PDB_PROMPT);
|
||||
String pdbFileName = pdbFile.getAbsolutePath();
|
||||
|
||||
// creating a default output and asking again; PDB file should retain its current value
|
||||
// from above
|
||||
String outputFileName = pdbFileName + ".txt";
|
||||
values.defineFile(OUTPUT_PROMPT, new File(outputFileName));
|
||||
values.setValidator((valueMap, status) -> {
|
||||
if (!validatePdb(valueMap, status)) {
|
||||
return false;
|
||||
}
|
||||
return validateOutput(valueMap, status);
|
||||
});
|
||||
values = askValues("Enter Values", null, values);
|
||||
pdbFile = values.getFile(PDB_PROMPT); // might have changed
|
||||
pdbFileName = pdbFile.getAbsolutePath(); // might have changed
|
||||
File dumpFile = values.getFile(OUTPUT_PROMPT);
|
||||
|
||||
if (dumpFile.exists()) {
|
||||
if (!askYesNo("Confirm Overwrite", "Overwrite file: " + dumpFile.getName())) {
|
||||
Msg.info(this, "Operation canceled");
|
||||
|
|
|
@ -59,7 +59,7 @@ import sarif.io.SarifIO;
|
|||
packageName = MiscellaneousPluginPackage.NAME,
|
||||
category = PluginCategoryNames.ANALYSIS,
|
||||
shortDescription = "Sarif Plugin.",
|
||||
description = "From sarif parsing to DL modelling"
|
||||
description = "SARIF parsing and visualization plugin."
|
||||
)
|
||||
//@formatter:on
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ public class SarifObject implements IsfObject {
|
|||
if (SARIF) {
|
||||
message = new JsonObject();
|
||||
message.addProperty("text", key);
|
||||
kind = "INFORMATIONAL";
|
||||
level = "NONE";
|
||||
kind = "informational"; // convention specifies lower-case
|
||||
level = "none";
|
||||
ruleId = ruleKey;
|
||||
properties = new JsonObject();
|
||||
properties.add("additionalProperties", element);
|
||||
|
|
|
@ -24,7 +24,10 @@ public class SarifKindResultHandler extends SarifResultHandler {
|
|||
}
|
||||
|
||||
public String parse() {
|
||||
return result.getKind().toString();
|
||||
if (result.getKind() != null) {
|
||||
return result.getKind().toString();
|
||||
}
|
||||
return "none";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,10 @@ public class SarifLevelResultHandler extends SarifResultHandler {
|
|||
}
|
||||
|
||||
public String parse() {
|
||||
return result.getLevel().toString();
|
||||
if (result.getLevel() != null) {
|
||||
return result.getLevel().toString();
|
||||
}
|
||||
return "none";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -270,7 +270,7 @@ public class OptionDialog extends DialogComponentProvider {
|
|||
if (savedDialogChoicePanel != null) {
|
||||
panel.add(savedDialogChoicePanel, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
setAccessibleDescription(message);
|
||||
addWorkPanel(panel);
|
||||
setRememberLocation(false);
|
||||
setRememberSize(false);
|
||||
|
|
|
@ -139,6 +139,14 @@ public class IntegerTextField {
|
|||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the accessible name for the component of this input field.
|
||||
* @param name the accessible name for this field
|
||||
*/
|
||||
public void setAccessibleName(String name) {
|
||||
textField.getAccessibleContext().setAccessibleName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the changes listener.
|
||||
*
|
||||
|
|
|
@ -92,7 +92,7 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest {
|
|||
assertEquals(new RowColLocation(2, 0), field.dataToScreenLocation(2, 0));
|
||||
assertEquals(new RowColLocation(2, 4), field.dataToScreenLocation(2, 4));
|
||||
assertEquals(new RowColLocation(2, 12), field.dataToScreenLocation(2, 12));
|
||||
assertEquals(new DefaultRowColLocation(0, 0), field.dataToScreenLocation(2, 15));
|
||||
assertEquals(new RowColLocation(2, 12), field.dataToScreenLocation(2, 15));
|
||||
|
||||
assertEquals(new RowColLocation(3, 0), field.dataToScreenLocation(3, 0));
|
||||
assertEquals(new RowColLocation(3, 4), field.dataToScreenLocation(3, 4));
|
||||
|
|
|
@ -273,8 +273,8 @@ public class ClassSearcher {
|
|||
|
||||
SystemUtilities.runSwingNow(() -> fireClassListChanged());
|
||||
|
||||
t = (new Date()).getTime() - t;
|
||||
String finishedMessage = "Class search complete (" + t + " ms)";
|
||||
String finishedMessage = "Class search complete (%d ms, %d classes loaded)"
|
||||
.formatted((new Date()).getTime() - t, extensionPoints.size());
|
||||
monitor.setMessage(finishedMessage);
|
||||
log.info(finishedMessage);
|
||||
}
|
||||
|
|
|
@ -287,6 +287,10 @@ class DataComponent extends DataDB {
|
|||
if (component != null) {
|
||||
return component.getDefaultSettings();
|
||||
}
|
||||
if (parent instanceof DataComponent) {
|
||||
// Ensure we pickup default component settings for array
|
||||
return parent.getDefaultSettings();
|
||||
}
|
||||
return super.getDefaultSettings();
|
||||
}
|
||||
|
||||
|
|
|
@ -177,6 +177,15 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB implem
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeSettingsChanged(DataType dt) {
|
||||
super.dataTypeSettingsChanged(dt);
|
||||
if (!isCreatingDataType()) {
|
||||
program.dataTypeChanged(getID(dt), ProgramEvent.DATA_TYPE_SETTING_CHANGED, false, null,
|
||||
dt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dataTypeAdded(DataType newDt, DataType originalDataType) {
|
||||
super.dataTypeAdded(newDt, originalDataType);
|
||||
|
|
|
@ -101,7 +101,7 @@ public enum ProgramEvent implements EventType {
|
|||
DATA_TYPE_RENAMED, // a data type was renamed
|
||||
DATA_TYPE_MOVED, // a data type was moved
|
||||
DATA_TYPE_CHANGED, // a data type was changed
|
||||
DATA_TYPE_SETTING_CHANGED, // a data type's settings changed
|
||||
DATA_TYPE_SETTING_CHANGED, // a data type's settings changed (default or at specific address)
|
||||
DATA_TYPE_REPLACED, // a data type was replaced
|
||||
SOURCE_ARCHIVE_ADDED, // a new data type source archive was defined
|
||||
SOURCE_ARCHIVE_CHANGED, // a data type source archive was changed
|
||||
|
|
|
@ -17,6 +17,8 @@ package ghidra;
|
|||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -35,6 +37,8 @@ import utility.module.ModuleUtilities;
|
|||
*/
|
||||
public class GhidraLauncher {
|
||||
|
||||
private static Instant START_INSTANT = Instant.now();
|
||||
|
||||
/**
|
||||
* Launches the given {@link GhidraLaunchable} specified in the first command line argument
|
||||
*
|
||||
|
@ -46,7 +50,6 @@ public class GhidraLauncher {
|
|||
*/
|
||||
public static void launch(String[] args) throws Exception {
|
||||
|
||||
// Initialize the Ghidra environment
|
||||
GhidraApplicationLayout layout = initializeGhidraEnvironment();
|
||||
|
||||
// Make sure the thing to launch meets the criteria:
|
||||
|
@ -93,6 +96,13 @@ public class GhidraLauncher {
|
|||
launch(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the current number of milliseconds that have elapsed since execution began}
|
||||
*/
|
||||
public static long getMillisecondsFromLaunch() {
|
||||
return ChronoUnit.MILLIS.between(START_INSTANT, Instant.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Ghidra environment by discovering its {@link GhidraApplicationLayout layout}
|
||||
* and adding all relevant modules and libraries to the classpath
|
||||
|
|
|
@ -52,7 +52,7 @@ ldst_imm: tmp is b_30=1 & b_24=0 & b_21=0 & b_15=0 & b_14=0 & b_12=0
|
|||
|
||||
ldst_wback: "" is b_23=0 & b_1620=0b00000 { }
|
||||
ldst_wback: ", #"^ldst_imm is b_23=1 & b_1620=0b11111 & Rn_GPR64xsp & ldst_imm { Rn_GPR64xsp = tmp_ldXn; }
|
||||
ldst_wback: ", "^Rm_GPR64 is b_23=1 & Rn_GPR64xsp & Rm_GPR64 { Rn_GPR64xsp = Rm_GPR64; }
|
||||
ldst_wback: ", "^Rm_GPR64 is b_23=1 & Rn_GPR64xsp & Rm_GPR64 { Rn_GPR64xsp = Rn_GPR64xsp + Rm_GPR64; }
|
||||
|
||||
# C7.2.177 LD1 (multiple structures) page C7-2415 line 141110 MATCH x0c402000/mask=xbfff2000
|
||||
# C7.2.177 LD1 (multiple structures) page C7-2415 line 141110 MATCH x0cc02000/mask=xbfe02000
|
||||
|
|
Loading…
Reference in New Issue
Block a user