Merge remote-tracking branch 'origin/GT-3501-rev308_Scalar_table_refactor'

This commit is contained in:
ghidravore 2020-02-21 14:56:29 -05:00
commit 2803e050c5
5 changed files with 341 additions and 224 deletions

View file

@ -90,7 +90,7 @@
program. Any new code units containing scalars added to the program will
automatically appear in the table.</P>
<P>To bring the <B>Scalar Table</B>, choose <B>Window</B><IMG src="../../shared/arrow.gif" border=
<P>To bring up the <B>Scalar Table</B>, choose <B>Window</B><IMG src="../../shared/arrow.gif" border=
"0"><B>Scalar Table</B> from the tool's menu. This table can be docked in the tool
if desired.</P>
@ -99,11 +99,15 @@
<UL>
<LI><B>Location</B> - displays the address of the code unit containing the scalar.</LI>
<LI><B>Preview</B> - displays the code unit containing the scalar.</LI>
<LI><B>Hex</B> - displays the scalar as a hex number.</LI>
<LI><B>Hex</B> - displays the scalar as an unsigned hex number.</LI>
<LI><B>Decimal (Signed)</B> - displays the scalar as a decimal number.</LI>
<LI><B>Function Name</B> - displays the name of the function containing the scalar.</LI>
<LI><B>Decimal (Unsigned)</B> - displays the scalar as a decimal number (this
column is hidden by default).</LI>
<LI><B>Bits</B> - displays the number of bits required to store the scalar value (this
column is hidden by default).</LI>
<LI><B>Signedness</B> - displays whether the scalar is <I>signed</I> or <I>unsigned</I> (this
column is hidden by default).</LI>
</UL>
</BLOCKQUOTE>

View file

@ -0,0 +1,98 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.scalartable;
import java.util.*;
import docking.widgets.table.constraint.*;
import docking.widgets.table.constraint.provider.LongEditorProvider;
import docking.widgets.table.constraint.provider.LongRangeEditorProvider;
import ghidra.program.model.scalar.Scalar;
/**
* Provides Scalar-related column constraints.
*/
public class ScalarColumnConstraintProvider implements ColumnConstraintProvider {
@Override
public Collection<ColumnConstraint<?>> getColumnConstraints() {
List<ColumnConstraint<?>> list = new ArrayList<>();
/*
* Since we're converting Scalar to Long, we'll also get the extant Long constraints;
* they'll operate on the scalars value, independent of signedness.
*/
// @formatter:off
list.add(makeSignedConstraint(new AtLeastColumnConstraint<>("At Least (signed)", 0l, new LongEditorProvider(), "scalar")));
list.add(makeSignedConstraint(new AtMostColumnConstraint<>("At Most (signed)", 0l, new LongEditorProvider(), "scalar")));
list.add(makeSignedConstraint(new InRangeColumnConstraint<>("In Range (signed)", 0l, 0l, new LongRangeEditorProvider(), "scalar")));
list.add(makeSignedConstraint(new NotInRangeColumnConstraint<>("Not In Range (signed)", 0l, 0l, new LongRangeEditorProvider(), "scalar")));
list.add(makeUnsignedConstraint(new AtLeastColumnConstraint<>("At Least (unsigned)", 0l, new LongEditorProvider(), "scalar-unsigned")));
list.add(makeUnsignedConstraint(new AtMostColumnConstraint<>("At Most (unsigned)", 0l, new LongEditorProvider(), "scalar-unsigned")));
list.add(makeUnsignedConstraint(new InRangeColumnConstraint<>("In Range (unsigned)", 0l, 0l, new LongRangeEditorProvider(), "scalar-unsigned")));
list.add(makeUnsignedConstraint(new NotInRangeColumnConstraint<>("Not In Range (unsigned)", 0l, 0l, new LongRangeEditorProvider(), "scalar-unsigned")));
// @formatter:on
return list;
}
private static ColumnConstraint<?> makeSignedConstraint(ColumnConstraint<Long> delegate) {
return new ScalarMappedColumnConstraint(new ScalarToSignedLongColumnTypeMapper(), delegate);
}
private static ColumnConstraint<?> makeUnsignedConstraint(ColumnConstraint<Long> delegate) {
return new ScalarMappedColumnConstraint(new ScalarToUnsignedLongColumnTypeMapper(),
delegate);
}
/**
* Class that converts a Scalar to a signed Long value
*/
static class ScalarToSignedLongColumnTypeMapper extends ColumnTypeMapper<Scalar, Long> {
@Override
public Long convert(Scalar value) {
return value.getSignedValue();
}
}
/**
* Class that converts a Scalar to an unsigned Long value
*/
static class ScalarToUnsignedLongColumnTypeMapper extends ColumnTypeMapper<Scalar, Long> {
@Override
public Long convert(Scalar value) {
return value.getUnsignedValue();
}
}
/**
* Class to adapt Long-type constraints to Scalar-type columns.
*/
static class ScalarMappedColumnConstraint extends MappedColumnConstraint<Scalar, Long> {
public ScalarMappedColumnConstraint(ColumnTypeMapper<Scalar, Long> mapper,
ColumnConstraint<Long> delegate) {
super(mapper, delegate);
}
}
}

View file

@ -17,6 +17,7 @@ package ghidra.app.plugin.core.scalartable;
import java.awt.Component;
import java.math.BigInteger;
import java.util.Comparator;
import javax.swing.*;
import javax.swing.table.TableModel;
@ -26,7 +27,6 @@ import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.address.*;
import ghidra.program.model.data.Resource;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.Reference;
@ -51,10 +51,6 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
static final int TEMP_MAX_RESULTS = 1_000_000;
private static final int FUNCTION_COL_WIDTH = 150;
private static final int HEXADECIMAL_COL_WIDTH = 100;
private static final int DECIMAL_COL_WIDTH = 100;
private Listing listing;
private ProgramSelection currentSelection;
@ -77,12 +73,13 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
DiscoverableTableUtils.adaptColumForModel(this, new AddressTableColumn()), 1, true);
descriptor.addVisibleColumn(
DiscoverableTableUtils.adaptColumForModel(this, new PreviewTableColumn()));
descriptor.addVisibleColumn(new ScalarHexValueTableColumn());
descriptor.addVisibleColumn(new ScalarHexUnsignedValueTableColumn());
descriptor.addVisibleColumn(new ScalarSignedDecimalValueTableColumn());
descriptor.addHiddenColumn(new ScalarUnsignedDecimalValueTableColumn());
descriptor.addVisibleColumn(
DiscoverableTableUtils.adaptColumForModel(this, new ScalarFunctionNameTableColumn()));
descriptor.addHiddenColumn(new ScalarBitCountTableColumn());
descriptor.addHiddenColumn(new ScalarSignednessTableColumn());
return descriptor;
}
@ -169,7 +166,7 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
Reference[] operandReferences = instruction.getOperandReferences(opIndex);
if (operandReferences.length == 0) {
getScalarFromInstruction(instruction, opObjs, monitor);
getScalarsFromInstruction(instruction, opObjs, monitor);
}
}
}
@ -200,14 +197,18 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
}
}
private void getScalarFromInstruction(Instruction instruction, Object[] opObjs,
private void getScalarsFromInstruction(Instruction instruction, Object[] opObjs,
TaskMonitor monitor) throws CancelledException {
Scalar scalar = getScalarFromOperand(opObjs, monitor);
for (Object opObj : opObjs) {
monitor.checkCanceled();
Scalar scalar = getScalarFromOperand(opObj, monitor);
if (scalar != null) {
addMatch(new ScalarRowObject(instruction, scalar));
}
}
}
private void addMatch(ScalarRowObject rowObject) {
@ -300,25 +301,8 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
return rowObject.getAddress();
}
private Scalar getScalarFromOperand(Object[] opObjs, TaskMonitor monitor)
throws CancelledException {
if (opObjs == null) {
return null;
}
Object obj = null;
for (Object opObj : opObjs) {
monitor.checkCanceled();
if (opObj instanceof Register) {
return null;
}
if (opObj instanceof Scalar) {
obj = opObj;
}
}
return (Scalar) obj;
private Scalar getScalarFromOperand(Object opObj, TaskMonitor monitor) {
return opObj instanceof Scalar ? (Scalar) opObj : null;
}
private Scalar getScalarFromData(Data data) {
@ -340,49 +324,110 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
}
//==================================================================================================
// Columns
// Columns & Column helpers
//==================================================================================================
private class ScalarHexValueTableColumn
extends AbstractDynamicTableColumn<ScalarRowObject, Scalar, Program>
implements ProgramLocationTableColumn<ScalarRowObject, Scalar> {
private class ScalarComparator implements Comparator<Scalar> {
private GColumnRenderer<Scalar> renderer = new AbstractGColumnRenderer<Scalar>() {
@Override
public int compare(Scalar o1, Scalar o2) {
// @formatter:off
if (o1 == o2) { return 0;}
if (o1 == null) { return 1; }
if (o2 == null) { return -1; }
// @formatter:on
// sort unsigned before signed
if (o1.isSigned() != o2.isSigned()) {
return (o1.isSigned() ? 1 : -1);
}
return o1.compareTo(o2);
}
}
private abstract class AbstractScalarValueRenderer extends AbstractGColumnRenderer<Scalar> {
@Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
Scalar value = (Scalar) data.getValue();
String text = asString(value);
String text = formatScalar(value);
label.setText(text);
label.setOpaque(true);
setHorizontalAlignment(SwingConstants.RIGHT);
return label;
}
private String asString(Scalar s) {
if (s == null) {
return "";
}
return s.toString(16, false, false, "", "");
}
protected abstract String formatScalar(Scalar scalar);
@Override
protected void configureFont(JTable table, TableModel model, int column) {
setFont(getFixedWidthFont());
public ColumnConstraintFilterMode getColumnConstraintFilterMode() {
return ColumnConstraintFilterMode.USE_COLUMN_CONSTRAINTS_ONLY;
}
@Override
public String getFilterString(Scalar t, Settings settings) {
return asString(t);
return formatScalar(t);
}
}
private abstract class AbstractScalarValueTableColumn
extends AbstractDynamicTableColumn<ScalarRowObject, Scalar, Program>
implements ProgramLocationTableColumn<ScalarRowObject, Scalar> {
@Override
public Comparator<Scalar> getComparator() {
return new ScalarComparator();
}
@Override
public ProgramLocation getProgramLocation(ScalarRowObject rowObject, Settings settings,
Program p, ServiceProvider provider) {
return new ProgramLocation(p, rowObject.getAddress());
}
}
private class ScalarHexUnsignedValueTableColumn extends AbstractScalarValueTableColumn {
private static final int HEXADECIMAL_COL_WIDTH = 100;
AbstractScalarValueRenderer renderer = new AbstractScalarValueRenderer() {
private static final int RADIX = 16;
private static final boolean ZERO_PADDED = false;
private static final boolean SHOW_SIGN = false;
private static final String PREFIX = "0x";
private static final String SUFFIX = "";
@Override
protected String formatScalar(Scalar scalar) {
if (scalar == null) {
return "";
}
return scalar.toString(RADIX, ZERO_PADDED, SHOW_SIGN, PREFIX, SUFFIX);
}
@Override
protected void configureFont(JTable table, TableModel model, int column) {
setFont(fixedWidthFont);
}
@Override
public ColumnConstraintFilterMode getColumnConstraintFilterMode() {
return ColumnConstraintFilterMode.USE_BOTH_COLUMN_RENDERER_FITLER_STRING_AND_CONSTRAINTS;
}
};
@Override
public String getColumnName() {
return "Hex";
return "Hex (Unsigned)";
}
@Override
@ -390,27 +435,44 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
return HEXADECIMAL_COL_WIDTH;
}
@Override
public Scalar getValue(ScalarRowObject rowObject, Settings settings, Program p,
ServiceProvider provider) throws IllegalArgumentException {
return rowObject.getScalar();
}
@Override
public ProgramLocation getProgramLocation(ScalarRowObject rowObject, Settings settings,
Program p, ServiceProvider provider) {
return new ProgramLocation(program, rowObject.getAddress());
}
@Override
public GColumnRenderer<Scalar> getColumnRenderer() {
return renderer;
}
@Override
public Scalar getValue(ScalarRowObject rowObject, Settings settings, Program p,
ServiceProvider provider) throws IllegalArgumentException {
Scalar scalar = rowObject.getScalar();
Scalar unsigned = new Scalar(scalar.bitLength(), scalar.getUnsignedValue(), false);
return unsigned;
}
}
private class ScalarSignedDecimalValueTableColumn
extends AbstractDynamicTableColumn<ScalarRowObject, Long, Program>
implements ProgramLocationTableColumn<ScalarRowObject, Long> {
private class ScalarSignedDecimalValueTableColumn extends AbstractScalarValueTableColumn {
private static final int DECIMAL_COL_WIDTH = 100;
AbstractScalarValueRenderer renderer = new AbstractScalarValueRenderer() {
private static final int RADIX = 10;
private static final boolean ZERO_PADDED = false;
private static final boolean SHOW_SIGN = true;
private static final String PREFIX = "";
private static final String SUFFIX = "";
@Override
protected String formatScalar(Scalar scalar) {
if (scalar == null) {
return "";
}
return scalar.toString(RADIX, ZERO_PADDED, SHOW_SIGN, PREFIX, SUFFIX);
}
};
@Override
public String getColumnName() {
@ -423,22 +485,45 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
}
@Override
public Long getValue(ScalarRowObject rowObject, Settings settings, Program p,
ServiceProvider provider) throws IllegalArgumentException {
return rowObject.getScalar().getSignedValue();
public GColumnRenderer<Scalar> getColumnRenderer() {
return renderer;
}
@Override
public ProgramLocation getProgramLocation(ScalarRowObject rowObject, Settings settings,
Program p, ServiceProvider provider) {
return new ProgramLocation(program, rowObject.getAddress());
}
public Scalar getValue(ScalarRowObject rowObject, Settings settings, Program p,
ServiceProvider provider) throws IllegalArgumentException {
Scalar scalar = rowObject.getScalar();
Scalar signed = new Scalar(scalar.bitLength(), scalar.getUnsignedValue(), true);
return signed;
}
private class ScalarUnsignedDecimalValueTableColumn
extends AbstractDynamicTableColumn<ScalarRowObject, Long, Program>
implements ProgramLocationTableColumn<ScalarRowObject, Long> {
}
private class ScalarUnsignedDecimalValueTableColumn extends AbstractScalarValueTableColumn {
private static final int DECIMAL_COL_WIDTH = 100;
AbstractScalarValueRenderer renderer = new AbstractScalarValueRenderer() {
private static final int RADIX = 10;
private static final boolean ZERO_PADDED = false;
private static final boolean SHOW_SIGN = false;
private static final String PREFIX = "";
private static final String SUFFIX = "";
@Override
protected String formatScalar(Scalar scalar) {
if (scalar == null) {
return "";
}
return scalar.toString(RADIX, ZERO_PADDED, SHOW_SIGN, PREFIX, SUFFIX);
}
};
@Override
public String getColumnName() {
@ -451,10 +536,37 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
}
@Override
public Long getValue(ScalarRowObject rowObject, Settings settings, Program p,
ServiceProvider provider) throws IllegalArgumentException {
public GColumnRenderer<Scalar> getColumnRenderer() {
return renderer;
}
return rowObject.getScalar().getUnsignedValue();
@Override
public Scalar getValue(ScalarRowObject rowObject, Settings settings, Program p,
ServiceProvider provider) throws IllegalArgumentException {
Scalar scalar = rowObject.getScalar();
Scalar unsigned = new Scalar(scalar.bitLength(), scalar.getUnsignedValue(), false);
return unsigned;
}
}
private class ScalarBitCountTableColumn
extends AbstractDynamicTableColumn<ScalarRowObject, Integer, Program>
implements ProgramLocationTableColumn<ScalarRowObject, Integer> {
private static final int BIT_COUNT_COL_WIDTH = 80;
@Override
public String getColumnName() {
return "Bits";
}
@Override
public Integer getValue(ScalarRowObject rowObject, Settings settings, Program p,
ServiceProvider provider) throws IllegalArgumentException {
return rowObject.getScalar().bitLength();
}
@Override
@ -462,10 +574,53 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
Program p, ServiceProvider provider) {
return new ProgramLocation(program, rowObject.getAddress());
}
@Override
public int getColumnPreferredWidth() {
return BIT_COUNT_COL_WIDTH;
}
}
public static enum Signedness {
Signed, Unsigned
}
private class ScalarSignednessTableColumn
extends AbstractDynamicTableColumn<ScalarRowObject, Signedness, Program>
implements ProgramLocationTableColumn<ScalarRowObject, Signedness> {
private static final int SIGNEDNESS_COL_WIDTH = 100;
@Override
public String getColumnName() {
return "Signedness";
}
@Override
public Signedness getValue(ScalarRowObject rowObject, Settings settings, Program p,
ServiceProvider provider) throws IllegalArgumentException {
return rowObject.getScalar().isSigned() ? Signedness.Signed : Signedness.Unsigned;
}
@Override
public ProgramLocation getProgramLocation(ScalarRowObject rowObject, Settings settings,
Program p, ServiceProvider provider) {
return new ProgramLocation(program, rowObject.getAddress());
}
@Override
public int getColumnPreferredWidth() {
return SIGNEDNESS_COL_WIDTH;
}
}
private class ScalarFunctionNameTableColumn extends FunctionNameTableColumn {
private static final int FUNCTION_COL_WIDTH = 150;
@Override
public int getColumnPreferredWidth() {
return FUNCTION_COL_WIDTH;

View file

@ -116,7 +116,7 @@ public class Scalar implements Comparable<Scalar> {
public BigInteger getBigInteger() {
int signum = (signed && testBit(bitLength - 1)) ? -1 : 1;
// Get magnitide
// Get magnitude
int numBytes = ((bitLength - 1) / 8) + 1;
long tmpVal = getValue();
if (signed && tmpVal < 0) {

View file

@ -1,140 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.scalar;
/**
* ScalarFormat.java
*
* This class exists just to make it easy to hold onto sensible
* groupings and conventions for formatting scalars. This is
* used by Scalar in the toString(ScalarFormat) and the
* addToStringBuffer(StringBuffer, ScalarFormat) methods.
*
* @version 1999/02/04
*/
public class ScalarFormat {
private boolean zeroPadded;
private boolean signed;
private String pre;
private String post;
private int radix;
// Constructors:
/**
* <p>Create a default ScalarFormat. (hex, zeropadded, unsigned
* no pre or post strings)</p>
*/
public ScalarFormat() {
radix = 16;
zeroPadded = true;
signed = false;
pre = "";
post = "";
}
/**
* <p> Create a ScalarFormat with the given values.</p>
*
* @param radix the radix to use (only 2,8,10 and 16 are valid)..
* @param zeroPadded true if value should be 0 padded.
* @param signed true if value should be treated as signed.
* @param pre string to add after optional sign but before value.
* @param post string to add at end of the value.
* @throws IllegalArgumentException if radix is not one of (2,8,10,16).
*/
public ScalarFormat(int radix, boolean zeroPadded, boolean signed,
String pre, String post) {
switch (radix) {
case 2:
case 8:
case 10:
case 16:
break;
default:
throw new IllegalArgumentException("Invalid radix");
}
this.zeroPadded = zeroPadded;
this.signed = signed;
this.pre = pre;
this.post = post;
this.radix = radix;
}
/**
* <p>Returns whether value should be zero padded.</p>
*
* @return whether value should be zero padded.
*/
public boolean isZeroPadded() {
return zeroPadded;
}
/**
* <p>Returns whether value should be treated as signed.</p>
*
* @return whether value should be treated as signed.
*/
public boolean isSigned() {
return signed;
}
/**
* <p>Returns the prefix string.</p>
*
* @return the prefix string.
*/
public String getPre() {
return pre;
}
/**
* <p>Returns the postfix string.</p>
*
* @return the postfix string.
*/
public String getPost() {
return post;
}
/**
* <p>Returns the radix.</p>
*
* @return the radix.
*/
public int getRadix() {
return radix;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("(radix=" + radix + ", ");
if (zeroPadded) {
buf.append("zero padded, ");
}
if (signed) {
buf.append("signed, ");
}
buf.append("pre='" + pre + "', post='" + post + "')");
return new String(buf);
}
} // ScalarFormat