GP-676 - Updated TableChooserDialog API to allow for bulk transaction

usage
This commit is contained in:
dragonmacher 2021-02-09 17:49:37 -05:00
parent ed3cc10344
commit 83e6e614a5
6 changed files with 118 additions and 488 deletions

View file

@ -1,409 +0,0 @@
/* ###
* 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.
*/
// New Table Stuff
//@category Search
import java.util.ArrayList;
import java.util.List;
import ghidra.app.script.GhidraScript;
import ghidra.app.tablechooser.*;
import ghidra.program.model.address.*;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
public class FindRunsOfPointersWithTableScript extends GhidraScript {
private List<PossiblePtrs> resultsArray = new ArrayList<PossiblePtrs>();
public static final int LITTLE_ENDIAN = 0;
public static final int BIG_ENDIAN = 1;
@Override
public void run() throws Exception {
int size = currentProgram.getAddressFactory().getDefaultAddressSpace().getSize();
if (size != 32) {
println("This script only works on 32-bit programs.");
return;
}
TableChooserExecutor executor = createTableExecutor();
TableChooserDialog tableDialog = createTableChooserDialog("Runs of Pointers", executor);
configureTableColumns(tableDialog);
tableDialog.show();
tableDialog.setMessage("Searching...");
Memory memory = currentProgram.getMemory();
long distance;
// TODO add option to work only on selection
AddressIterator addrIter = memory.getAddresses(true);
//println("Memory range: " + memory.getMinAddress() + " - " + memory.getMaxAddress());
Address prevAddress = null;
while (addrIter.hasNext() && !monitor.isCancelled()) {
Address addr = addrIter.next();
try {
// get the value in address form of the bytes at address a
int addrInt = memory.getInt(addr);
long addrLong = addrInt & 0xffffffffL;
Address testAddr = addr.getNewAddress(addrLong);
if ((addrLong != 0) && (memory.contains(testAddr))) {
if (prevAddress != null) {
distance = addr.subtract(prevAddress);
}
else {
distance = 0;
}
PossiblePtrs pp = new PossiblePtrs(addr, testAddr, distance);
resultsArray.add(pp);
//println(addr.toString() + " " + testAddr.toString() + " " + distance);
prevAddress = addr;
}
}
catch (MemoryAccessException e) {
break;
}
catch (AddressOutOfBoundsException e) {
break;
}
}
// go through the list of pointers and only print out the ones with a run of the same distance between them
// keep the one before the run and include the last one with the same distance
//println("tableAddress distance tableSize");
if (resultsArray.size() == 0) {
tableDialog.setMessage("Done! Found no hits");
return;
}
long dist = resultsArray.get(0).getDistanceFromLast();
int tableSize = 0;
Address topAddress = null;
int i = 1;
while (i < resultsArray.size() && !monitor.isCancelled()) {
// for(int i=1;i<resultsArray.size();i++){
long thisDist = resultsArray.get(i).getDistanceFromLast();
if (thisDist == dist) {
if (tableSize == 0) {
topAddress = resultsArray.get(i - 2).getAddrOfPtr();
tableSize = 1;
}
tableSize++;
}
else {
if (tableSize >= 3) {
tableSize++;
Address ref = findRef(topAddress, dist);
//println(topAddress.toString() + " " + dist + " " + tableSize);
Table pointerTable = new Table(topAddress, dist, tableSize, ref);
tableDialog.add(pointerTable);
}
tableSize = 0;
dist = thisDist;
}
i++;
}
tableDialog.setMessage("Done! Found " + tableDialog.getRowCount() + " hits");
// print out results
// println("Table address Dist bet ptrs Num ptrs Ref found");
// for(int j=0;j<tableArray.size();j++){
// Table ptrTable = tableArray.get(j);
// String refString = new String();
// if(ptrTable.getRef() != null){
// refString = " at " + ptrTable.getRef().toString();
// println(" " + ptrTable.getTopAddr().toString() + " " + ptrTable.getDistance() + " " + ptrTable.getNumPointers() + " " + refString);
// }
// else if(searchNonRefd){
// refString = "No";
// println(" " + ptrTable.getTopAddr().toString() + " " + ptrTable.getDistance() + " " + ptrTable.getNumPointers() + " " + refString);
// }
// }
}
private void configureTableColumns(TableChooserDialog tableDialog) {
StringColumnDisplay distanceColumn = new StringColumnDisplay() {
@Override
public String getColumnName() {
return "Dist bet ptrs";
}
@Override
public String getColumnValue(AddressableRowObject rowObject) {
Table table = (Table) rowObject;
return Long.toString(table.getDistance());
}
@Override
public int compare(AddressableRowObject o1, AddressableRowObject o2) {
Table table1 = (Table) o1;
Table table2 = (Table) o2;
return (int) (table1.getDistance() - table2.getDistance());
}
};
StringColumnDisplay numberOfPointersColumn = new StringColumnDisplay() {
@Override
public String getColumnName() {
return "Num ptrs";
}
@Override
public String getColumnValue(AddressableRowObject rowObject) {
Table table = (Table) rowObject;
return Long.toString(table.getNumPointers());
}
@Override
public int compare(AddressableRowObject o1, AddressableRowObject o2) {
Table table1 = (Table) o1;
Table table2 = (Table) o2;
return table1.getNumPointers() - table2.getNumPointers();
}
};
StringColumnDisplay referenceFoundColumn = new StringColumnDisplay() {
@Override
public String getColumnName() {
return "Ref found";
}
@Override
public String getColumnValue(AddressableRowObject rowObject) {
Table table = (Table) rowObject;
if (table.getRef() != null) {
return " at " + table.getRef();
}
return "No";
}
};
ColumnDisplay<Address> secondAddressColumn =
new AbstractComparableColumnDisplay<Address>() {
@Override
public String getColumnName() {
return "Offset Address";
}
@Override
public Address getColumnValue(AddressableRowObject rowObject) {
Table table = (Table) rowObject;
return table.getAddress().add(100);
}
};
tableDialog.addCustomColumn(distanceColumn);
tableDialog.addCustomColumn(secondAddressColumn);
tableDialog.addCustomColumn(numberOfPointersColumn);
tableDialog.addCustomColumn(referenceFoundColumn);
}
private TableChooserExecutor createTableExecutor() {
TableChooserExecutor executor = new TableChooserExecutor() {
@Override
public String getButtonName() {
return "Hit Me";
}
@Override
public boolean execute(AddressableRowObject rowObject) {
return true;
}
};
return executor;
}
// find the first ref starting at topAddr and working back dist - pointersize
// once a ref is found, stop - it doesn't make much sense that there would be more than one.
Address findRef(Address topAddress, long dist) {
Memory memory = currentProgram.getMemory();
Address ref = null;
//change later to handle 64 bits too
byte[] maskBytes = new byte[4];
for (int i = 0; i < 4; i++) {
maskBytes[i] = (byte) 0xff;
}
// search memory for the byte patterns within the range of topAddr and topAddr - dist
// make a structure of found bytes/topAddr offset????
boolean noRefFound = true;
boolean tryPrevAddr = true;
long longIndex = 0;
while (noRefFound && tryPrevAddr) {
Address testAddr = topAddress.subtract(longIndex);
byte[] addressBytes = turnAddressIntoBytes(testAddr);
//println("TestAddr = " + testAddr.toString());
Address found = memory.findBytes(currentProgram.getMinAddress(), addressBytes,
maskBytes, true, monitor);
if (found != null) {
ref = found;
// println("Found ref at " + found.toString());
noRefFound = false;
}
else {
longIndex++;
// check to see if we are at the top of the range of possible refs
if (longIndex > (dist - 4)) {// change the four to pointer size when I add 64bit
tryPrevAddr = false;
}
}
}
return ref;
}
byte[] turnAddressIntoBytes(Address addr) {
// turn addresses into bytes
byte[] addressBytes = new byte[4]; // only 32-bit for now - change later to add 64 bit
// This is the correct way to do turn a long into an address
long addrLong = addr.getOffset();
int endian = getEndian();
if (endian == BIG_ENDIAN) {
// put bytes in forward order
addressBytes = bytesForward(addrLong);
}
else if (endian == LITTLE_ENDIAN) {
// put bytes in reverse order
addressBytes = bytesReversed(addrLong);
}
else {
println("Unknown endian - cannot find references.");
return null;
}
return addressBytes;
}
byte[] bytesForward(long addr) {
byte[] bytes = new byte[4]; // only works for 32-bit for now-later add 64
for (int i = 0; i < 4; i++) {
bytes[i] = (byte) ((addr >> (24 - (i * 8))) & 0xff);
}
return bytes;
}
byte[] bytesReversed(long addr) {
byte[] bytes = new byte[4]; // only works for 32-bit for now-later add 64
for (int i = 3; i >= 0; i--) {
bytes[3 - i] = (byte) ((addr >> (24 - (i * 8))) & 0xff);
}
return bytes;
}
// find references to the possible table
// start looking at the top of the array and work back the distance between the pointers in
// the table
// Address [] findReferenceToTable(Address topAddress, long dist){
//
// ArrayList<Address> foundAddrs = new ArrayList<Address>();
// long counter = 0;
// while((foundAddrs.size() == 0) || (counter == (dist-1))){
// List<Address> newList = findReferences(topAddress.subtract(dist-counter));
// for(int i=0;i<newList.size();i++){
// Address a = (Address)newList.get(i);
// foundAddrs.add(a);
// }
// counter++;
// }
//
// return (Address[]) foundAddrs.toArray();
// }
//public List<Address> findReferences(Address addr){
// FindPossibleReferences fpr = new FindPossibleReferences(currentProgram,getEndian());
// return fpr.findReferences(addr);
//}
public int getEndian() {
if (currentProgram.getLanguage().isBigEndian()) {
return 1; // BIG_ENDIAN
}
return 0; // LITTLE_ENDIAN
}
// info about the pushed parameter that gets applied to the calling functions params and locals and referenced data
class PossiblePtrs {
private Address addrOfPtr;
private Address possiblePtr;
private long distanceFromLast;
PossiblePtrs(Address addrOfPtr, Address possiblePtr, long distanceFromLast) {
this.addrOfPtr = addrOfPtr;
this.possiblePtr = possiblePtr;
this.distanceFromLast = distanceFromLast;
}
public Address getAddrOfPtr() {
return addrOfPtr;
}
public Address getPossiblePointer() {
return possiblePtr;
}
public long getDistanceFromLast() {
return distanceFromLast;
}
}
class Table implements AddressableRowObject {
private Address topAddr;
private long distance;
private int numPointers;
Address ref;
Table(Address topAddr, long distance, int numPointers, Address ref) {
this.topAddr = topAddr;
this.distance = distance;
this.numPointers = numPointers;
this.ref = ref;
}
@Override
public Address getAddress() {
return getTopAddr();
}
public Address getTopAddr() {
return topAddr;
}
public long getDistance() {
return distance;
}
public int getNumPointers() {
return numPointers;
}
public Address getRef() {
return ref;
}
}
}

View file

@ -75,8 +75,10 @@ public class FindSharedReturnFunctionsScript extends GhidraScript {
@Override @Override
public String getColumnValue(AddressableRowObject rowObject) { public String getColumnValue(AddressableRowObject rowObject) {
SharedReturnLocations entry = (SharedReturnLocations) rowObject; SharedReturnLocations entry = (SharedReturnLocations) rowObject;
Function func = entry.getProgram().getFunctionManager().getFunctionContaining( Function func = entry.getProgram()
entry.getWhyAddr()); .getFunctionManager()
.getFunctionContaining(
entry.getWhyAddr());
if (func == null) { if (func == null) {
return ""; return "";
} }
@ -93,8 +95,10 @@ public class FindSharedReturnFunctionsScript extends GhidraScript {
@Override @Override
public String getColumnValue(AddressableRowObject rowObject) { public String getColumnValue(AddressableRowObject rowObject) {
SharedReturnLocations entry = (SharedReturnLocations) rowObject; SharedReturnLocations entry = (SharedReturnLocations) rowObject;
Function func = entry.getProgram().getFunctionManager().getFunctionContaining( Function func = entry.getProgram()
entry.getAddress()); .getFunctionManager()
.getFunctionContaining(
entry.getAddress());
if (func == null) { if (func == null) {
return ""; return "";
} }
@ -148,29 +152,26 @@ public class FindSharedReturnFunctionsScript extends GhidraScript {
return "Fixup SharedReturn"; return "Fixup SharedReturn";
} }
@Override
public boolean useBulkTransaction() {
return true;
}
@Override @Override
public boolean execute(AddressableRowObject rowObject) { public boolean execute(AddressableRowObject rowObject) {
SharedReturnLocations sharedRetLoc = (SharedReturnLocations) rowObject; SharedReturnLocations sharedRetLoc = (SharedReturnLocations) rowObject;
System.out.println("Fixup Shared Return Jump at : " + rowObject.getAddress()); println("Fixup Shared Return Jump at : " + rowObject.getAddress());
Program cp = sharedRetLoc.getProgram(); Program cp = sharedRetLoc.getProgram();
Address entry = sharedRetLoc.getAddress(); Address entry = sharedRetLoc.getAddress();
// gonna change something, have to open a transaction addBookMark(cp, entry, "Shared Return Jump");
int trans = cp.startTransaction("Fixup Shared Return Jump at " + entry);
try {
addBookMark(cp, entry, "Shared Return Jump");
if (!sharedRetLoc.getStatus().equals("fixed")) { if (!sharedRetLoc.getStatus().equals("fixed")) {
fixSharedReturnLocation(cp, entry); fixSharedReturnLocation(cp, entry);
}
addBookMark(cp, sharedRetLoc.getWhyAddr(), sharedRetLoc.getExplanation());
}
finally {
cp.endTransaction(trans, true);
} }
addBookMark(cp, sharedRetLoc.getWhyAddr(), sharedRetLoc.getExplanation());
return false; // don't remove row return false; // don't remove row
} }

View file

@ -112,8 +112,10 @@ public class FixupNoReturnFunctionsScript extends GhidraScript {
@Override @Override
public String getColumnValue(AddressableRowObject rowObject) { public String getColumnValue(AddressableRowObject rowObject) {
NoReturnLocations entry = (NoReturnLocations) rowObject; NoReturnLocations entry = (NoReturnLocations) rowObject;
Function func = entry.getProgram().getFunctionManager().getFunctionContaining( Function func = entry.getProgram()
entry.getAddress()); .getFunctionManager()
.getFunctionContaining(
entry.getAddress());
if (func == null) { if (func == null) {
return ""; return "";
} }
@ -269,6 +271,11 @@ public class FixupNoReturnFunctionsScript extends GhidraScript {
return "Fixup NoReturn"; return "Fixup NoReturn";
} }
@Override
public boolean useBulkTransaction() {
return true;
}
@Override @Override
public boolean execute(AddressableRowObject rowObject) { public boolean execute(AddressableRowObject rowObject) {
NoReturnLocations noRetLoc = (NoReturnLocations) rowObject; NoReturnLocations noRetLoc = (NoReturnLocations) rowObject;
@ -283,20 +290,13 @@ public class FixupNoReturnFunctionsScript extends GhidraScript {
return false; return false;
} }
// gonna change something, have to open a transaction addBookMark(cp, entry, "Non Returning Function");
int trans = cp.startTransaction("Fixup No Return at " + entry);
try {
addBookMark(cp, entry, "Non Returning Function");
if (!noRetLoc.isFixed()) { if (!noRetLoc.isFixed()) {
repairDamage(cp, func, entry); repairDamage(cp, func, entry);
} }
addBookMark(cp, noRetLoc.getWhyAddr(), noRetLoc.getExplanation()); addBookMark(cp, noRetLoc.getWhyAddr(), noRetLoc.getExplanation());
}
finally {
cp.endTransaction(trans, true);
}
return false; // don't remove row return false; // don't remove row
} }

View file

@ -112,8 +112,9 @@ public class TableChooserDialog extends DialogComponentProvider
navigatable.addNavigatableListener(this); navigatable.addNavigatableListener(this);
table.installNavigation(goToService, navigatable); table.installNavigation(goToService, navigatable);
} }
table.getSelectionModel().addListSelectionListener( table.getSelectionModel()
e -> setOkEnabled(table.getSelectedRowCount() > 0)); .addListSelectionListener(
e -> setOkEnabled(table.getSelectedRowCount() > 0));
GhidraTableFilterPanel<AddressableRowObject> filterPanel = GhidraTableFilterPanel<AddressableRowObject> filterPanel =
new GhidraTableFilterPanel<>(table, model); new GhidraTableFilterPanel<>(table, model);
@ -241,7 +242,14 @@ public class TableChooserDialog extends DialogComponentProvider
monitor.initialize(rowObjects.size()); monitor.initialize(rowObjects.size());
try { try {
List<AddressableRowObject> deleted = doProcessRowObjects(rowObjects, monitor); List<AddressableRowObject> deleted;
if (executor.useBulkTransaction()) {
deleted = doProcessRowsInTransaction(rowObjects, monitor);
}
else {
deleted = doProcessRows(rowObjects, monitor);
}
for (AddressableRowObject rowObject : deleted) { for (AddressableRowObject rowObject : deleted) {
model.removeObject(rowObject); model.removeObject(rowObject);
} }
@ -254,8 +262,9 @@ public class TableChooserDialog extends DialogComponentProvider
} }
} }
private List<AddressableRowObject> doProcessRowObjects(List<AddressableRowObject> rowObjects, private List<AddressableRowObject> doProcessRows(List<AddressableRowObject> rowObjects,
TaskMonitor monitor) { TaskMonitor monitor) {
List<AddressableRowObject> deleted = new ArrayList<>(); List<AddressableRowObject> deleted = new ArrayList<>();
for (AddressableRowObject rowObject : rowObjects) { for (AddressableRowObject rowObject : rowObjects) {
if (monitor.isCancelled()) { if (monitor.isCancelled()) {
@ -280,6 +289,18 @@ public class TableChooserDialog extends DialogComponentProvider
return deleted; return deleted;
} }
private List<AddressableRowObject> doProcessRowsInTransaction(
List<AddressableRowObject> rowObjects, TaskMonitor monitor) {
int tx = program.startTransaction("Table Chooser: " + getTitle());
try {
return doProcessRows(rowObjects, monitor);
}
finally {
program.endTransaction(tx, true);
}
}
public void addCustomColumn(ColumnDisplay<?> columnDisplay) { public void addCustomColumn(ColumnDisplay<?> columnDisplay) {
model.addCustomColumn(columnDisplay); model.addCustomColumn(columnDisplay);
} }

View file

@ -15,6 +15,14 @@
*/ */
package ghidra.app.tablechooser; package ghidra.app.tablechooser;
/**
* The interface clients must implement to use the {@link TableChooserDialog}. This class is the
* callback that is used to process items from the dialog's table as users select one or more
* rows in the table and then press the table's "apply" button.
*
* <P>See the notes on {@link #useBulkTransaction()}. We recommend you override that method to
* return true.
*/
public interface TableChooserExecutor { public interface TableChooserExecutor {
/** /**
@ -33,4 +41,30 @@ public interface TableChooserExecutor {
* @return true if the rowObject should be removed from the table, false otherwise * @return true if the rowObject should be removed from the table, false otherwise
*/ */
public boolean execute(AddressableRowObject rowObject); public boolean execute(AddressableRowObject rowObject);
/**
* When true, the calls to {@link #execute(AddressableRowObject)} will be wrapped in a
* transaction. This allows clients to not use transactions themselves. This can increase
* performance when the user selects a large number of rows in the table to be executed, as
* this API will only use on transaction for all rows, instead of one per row.
*
* <P>When true, this will use one transaction per button press of the
* {@link TableChooserDialog}. Thus, if the user only processes a single row per button
* press, then there is no performance gain over the traditional use of transactions.
*
* <P><B>We recommend clients override this method to return true</B>.
*
* <P>Note: when false is returned from this method, <b>no transaction is created before the
* call to {@link #execute(AddressableRowObject)}</b>--the client is responsible for
* transaction management in this case.
*
* <P>For backward compatibility, this method defaults to returning false. You must override
* this method to return true in your code to make use of the single bulk transaction.
*
* @return true to use bulk transactions; false to use no transaction at all when calling
* {@link #execute(AddressableRowObject)}; default is false
*/
public default boolean useBulkTransaction() {
return false; // false by default for backward compatibility
}
} }

View file

@ -40,8 +40,7 @@ import ghidra.program.model.pcode.*;
import ghidra.program.model.symbol.Reference; import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceIterator; import ghidra.program.model.symbol.ReferenceIterator;
import ghidra.program.util.*; import ghidra.program.util.*;
import ghidra.util.SystemUtilities; import ghidra.util.*;
import ghidra.util.UndefinedFunction;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException; import ghidra.util.exception.InvalidInputException;
@ -157,10 +156,9 @@ public class ShowConstantUse extends GhidraScript {
} }
/** /**
* Builds the configurable columns for the TableDialog. More columns could * Builds the configurable columns for the TableDialog. More columns could be added.
* be added.
* *
* @param tableChooserDialog * @param tableChooserDialog the dialog
*/ */
private void configureTableColumns(TableChooserDialog tableChooserDialog) { private void configureTableColumns(TableChooserDialog tableChooserDialog) {
// First column added is the Constant value that is found. // First column added is the Constant value that is found.
@ -254,8 +252,10 @@ public class ShowConstantUse extends GhidraScript {
@Override @Override
public String getColumnValue(AddressableRowObject rowObject) { public String getColumnValue(AddressableRowObject rowObject) {
ConstUseLocation entry = (ConstUseLocation) rowObject; ConstUseLocation entry = (ConstUseLocation) rowObject;
Function func = entry.getProgram().getFunctionManager().getFunctionContaining( Function func = entry.getProgram()
entry.getAddress()); .getFunctionManager()
.getFunctionContaining(
entry.getAddress());
if (func == null) { if (func == null) {
return ""; return "";
} }
@ -299,7 +299,7 @@ public class ShowConstantUse extends GhidraScript {
* script by creating an artificial ScriptState. This is a useful technique * script by creating an artificial ScriptState. This is a useful technique
* for other scripts as well. * for other scripts as well.
* *
* @return * @return the executor
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
private TableChooserExecutor createTableExecutor() { private TableChooserExecutor createTableExecutor() {
@ -311,26 +311,22 @@ public class ShowConstantUse extends GhidraScript {
return "Create Structure"; return "Create Structure";
} }
@Override
public boolean useBulkTransaction() {
return true;
}
@Override @Override
public boolean execute(AddressableRowObject rowObject) { public boolean execute(AddressableRowObject rowObject) {
ConstUseLocation constLoc = (ConstUseLocation) rowObject; ConstUseLocation constLoc = (ConstUseLocation) rowObject;
System.out.println("Follow Structure : " + rowObject.getAddress()); println("Follow Structure : " + rowObject.getAddress());
Program cp = constLoc.getProgram(); Program cp = constLoc.getProgram();
Address entry = constLoc.getAddress(); Address entry = constLoc.getAddress();
// If we will change something in program, have to open a println("Create Structure at " + entry);
// transaction
int trans = cp.startTransaction("Run Script" + entry);
try {
System.out.println("Create Structure at " + entry);
runScript("CreateStructure.java", cp, entry);
}
finally {
cp.endTransaction(trans, true);
}
runScript("CreateStructure.java", cp, entry);
return false; // don't remove row from display table return false; // don't remove row from display table
} }
@ -347,7 +343,7 @@ public class ShowConstantUse extends GhidraScript {
} }
} }
catch (Exception exc) { catch (Exception exc) {
exc.printStackTrace(); Msg.error(this, "Exception running script", exc);
} }
throw new IllegalArgumentException("Script does not exist: " + name); throw new IllegalArgumentException("Script does not exist: " + name);
} }
@ -393,7 +389,7 @@ public class ShowConstantUse extends GhidraScript {
* decompiler. In the decompiler this could be a local/parameter at any * decompiler. In the decompiler this could be a local/parameter at any
* point in the decompiler. In the listing, it must be a parameter variable. * point in the decompiler. In the listing, it must be a parameter variable.
* *
* @return * @return the varnode
*/ */
private Varnode getVarnodeLocation() { private Varnode getVarnodeLocation() {
Varnode var = null; Varnode var = null;
@ -559,7 +555,7 @@ public class ShowConstantUse extends GhidraScript {
* - accumulate entries. Don't like passing it, but this way the * - accumulate entries. Don't like passing it, but this way the
* user gets immediate feedback as locations are found * user gets immediate feedback as locations are found
* @return a map of Addresses->constants (constants could be NULL) * @return a map of Addresses->constants (constants could be NULL)
* @throws CancelledException * @throws CancelledException if cancelled
*/ */
private HashMap<Address, Long> backtrackToConstant(Varnode var, private HashMap<Address, Long> backtrackToConstant(Varnode var,
TableChooserDialog tableChooserDialog) throws CancelledException { TableChooserDialog tableChooserDialog) throws CancelledException {
@ -587,15 +583,12 @@ public class ShowConstantUse extends GhidraScript {
* Backtrack to a constant given a start position of a parameter of a given * Backtrack to a constant given a start position of a parameter of a given
* function Useful if you want to start from a function paramter. * function Useful if you want to start from a function paramter.
* *
* @param f * @param f function to start in
* - function to start in * @param paramIndex parameter index to backtrack from
* @param paramIndex * @param tableChooserDialog accumulate entries. Don't like passing it, but this way the
* - parameter index to backtrack from * user gets immediate feedback as locations are found
* @param tableChooserDialog * @return a map of Addresses to constants (constants could be NULL)
* - accumulate entries. Don't like passing it, but this way the * @throws CancelledException if cancelled
* user gets immediate feedback as locations are found
* @return a map of Addresses->constants (constants could be NULL)
* @throws CancelledException
*/ */
private HashMap<Address, Long> backtrackParamToConstant(Function f, int paramIndex, private HashMap<Address, Long> backtrackParamToConstant(Function f, int paramIndex,
TableChooserDialog tableChooserDialog) throws CancelledException { TableChooserDialog tableChooserDialog) throws CancelledException {
@ -699,14 +692,7 @@ public class ShowConstantUse extends GhidraScript {
this.addConstantProblem(tableDialog, address, problem); this.addConstantProblem(tableDialog, address, problem);
} }
/** private void analyzeFunction(HashMap<Address, Long> constUse, DecompInterface decompInterface,
* Analyze a functions references
*
* @param constUse
* @param funcVarUse
* @param funcList
*/
public void analyzeFunction(HashMap<Address, Long> constUse, DecompInterface decompInterface,
Program prog, Function f, Address refAddr, FunctionParamUse funcVarUse, int paramIndex, Program prog, Function f, Address refAddr, FunctionParamUse funcVarUse, int paramIndex,
ArrayList<PcodeOp> defUseList, ArrayList<FunctionParamUse> funcList) { ArrayList<PcodeOp> defUseList, ArrayList<FunctionParamUse> funcList) {
if (f == null) { if (f == null) {
@ -722,12 +708,9 @@ public class ShowConstantUse extends GhidraScript {
Iterator<PcodeOpAST> ops = hfunction.getPcodeOps(refAddr.getPhysicalAddress()); Iterator<PcodeOpAST> ops = hfunction.getPcodeOps(refAddr.getPhysicalAddress());
while (ops.hasNext() && !monitor.isCancelled()) { while (ops.hasNext() && !monitor.isCancelled()) {
PcodeOpAST pcodeOpAST = ops.next(); PcodeOpAST pcodeOpAST = ops.next();
// System.out.println(pcodeOpAST);
if (pcodeOpAST.getOpcode() == PcodeOp.CALL) { if (pcodeOpAST.getOpcode() == PcodeOp.CALL) {
// get the second parameter // get the second parameter
Varnode parm = pcodeOpAST.getInput(paramIndex + 1); // 1st param Varnode parm = pcodeOpAST.getInput(paramIndex + 1); // 1st param is the call dest
// is the
// call dest
if (parm == null) { if (parm == null) {
constUse.put(instr.getAddress(), null); constUse.put(instr.getAddress(), null);
String problem = " *** Warning, it appears that function '" + String problem = " *** Warning, it appears that function '" +