Merge branch 'NationalSecurityAgency:master' into master

This commit is contained in:
20Enderdude20 2024-04-15 10:03:48 -07:00 committed by GitHub
commit dc2e1c537e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 1329 additions and 415 deletions

View File

@ -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)");
});
};

View File

@ -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());

View File

@ -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) {

View File

@ -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(

View File

@ -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) {

View File

@ -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);

View File

@ -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));

View File

@ -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) {

View File

@ -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) {

View File

@ -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 " +

View File

@ -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;
}

View File

@ -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);
}
}
}

View File

@ -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() {

View File

@ -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.
*/

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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"

View File

@ -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|

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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
{

View File

@ -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

View File

@ -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.

View File

@ -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

View 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

View File

@ -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

View File

@ -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;

View File

@ -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 {

View File

@ -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,

View File

@ -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

View File

@ -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?

View 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>

View File

@ -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);

View File

@ -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");

View File

@ -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

View File

@ -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);

View File

@ -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";
}
}

View File

@ -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";
}
}

View File

@ -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);

View File

@ -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.
*

View File

@ -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));

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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