Merge remote-tracking branch 'origin/patch'

This commit is contained in:
ghidra1 2023-08-24 18:13:42 -04:00
commit 514564292f
12 changed files with 223 additions and 34 deletions

View file

@ -133,12 +133,13 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
// repair the damage for all non-returning functions
if (repairDamageEnabled) {
AddressSet clearInstSet = new AddressSet();
noreturns = noReturnSet.getAddresses(true);
for (Address address : noreturns) {
clearInstSet.add(findPotentialDamagedLocations(program, address));
AddressSet potentialDamagedLocations = findPotentialDamagedLocations(program, address);
repairDamagedLocations(monitor, potentialDamagedLocations, noReturnSet);
}
repairDamagedLocations(monitor, clearInstSet);
}
}
finally {
@ -154,8 +155,9 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
*
* @param taskMonitor for cancellation
* @param clearInstSet locations to clear and repair
* @param protectedLocations - locations that should be protected from clearing
*/
private void repairDamagedLocations(TaskMonitor taskMonitor, AddressSet clearInstSet) {
private void repairDamagedLocations(TaskMonitor taskMonitor, AddressSet clearInstSet, AddressSet protectedLocations) {
if (clearInstSet == null || clearInstSet.isEmpty()) {
return;
}
@ -163,6 +165,14 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
AddressSetView protectedSet = analysisManager.getProtectedLocations();
protectedSet = protectedSet.union(protectedLocations);
// TODO: are there other protected locations,
// that should never be seeds for locations to be cleared?
// For example:
// - functions that were marked non-returning by the analyzer.
// - locations that are known function start patterns?
// entries including data flow referenced from instructions will be repaired
ClearFlowAndRepairCmd cmd =
@ -243,7 +253,8 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
}
/**
* Find locations that need repairing
* Find locations that need repairing. The locations returned are only the
* start of a flow that occurs after a call to a non-returning function.
*
* @param cp current program
* @param entry non-returning function entry point
@ -281,6 +292,11 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
continue;
}
// never add in the entry point that is being marked no return
if (fallthruAddr.equals(entry)) {
continue;
}
// if location right below is an entry point, don't clear it
Address checkAddr = skipNOPS(fallthruAddr);
if (program.getSymbolTable().isExternalEntryPoint(checkAddr) ||

View file

@ -457,7 +457,7 @@ public class EnumEditorProvider extends ComponentProviderAdapter
}
private void applyName(Enum newEnuum) {
String editorName = editorPanel.getEnumName();
String editorName = editorPanel.getEnumName().trim();
if (originalEnumName.equals(editorName)) {
return; // nothing to do
}

View file

@ -604,7 +604,11 @@ public class AddEditDialog extends DialogComponentProvider {
}
private String getText() {
return labelNameChoices.getText();
String text = labelNameChoices.getText();
if (text != null) {
text = text.trim();
}
return text;
}
public class NamespaceWrapper {

View file

@ -66,6 +66,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
Category cat = program.getListing()
.getDataTypeManager()
.getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0);
enumm.add("Green", 0x10);
@ -102,6 +103,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
Category cat = program.getListing()
.getDataTypeManager()
.getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0);
enumm.add("Green", 0x10);
@ -185,6 +187,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
Category cat = program.getListing()
.getDataTypeManager()
.getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0);
enumm.add("Green", 0x10);
@ -230,6 +233,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
Category cat = program.getListing()
.getDataTypeManager()
.getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0);
enumm.add("Green", 0x10);
@ -484,6 +488,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
Category cat = program.getListing()
.getDataTypeManager()
.getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0);
enumm.add("Green", 0x10);
@ -528,6 +533,48 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
}
@Test
public void testNameTrim() throws Exception {
Enum enummDt = editSampleEnum();
EnumEditorPanel panel = findEditorPanel(tool.getToolFrame());
String newName = " MyNewName ";
runSwing(() -> {
JTextField nameField = getTextField(panel, "Name");
nameField.setText(newName);
});
DockingActionIf applyAction = getAction(plugin, "Apply Enum Changes");
assertTrue(applyAction.isEnabled());
performAction(applyAction);
waitForProgram(program);
assertEquals(newName.trim(), enummDt.getName());
}
@Test
public void testDescriptionTrim() throws Exception {
Enum enummDt = editSampleEnum();
EnumEditorPanel panel = findEditorPanel(tool.getToolFrame());
String newDescription = " My new description ";
runSwing(() -> {
JTextField nameField = getTextField(panel, "Description");
nameField.setText(newDescription);
});
DockingActionIf applyAction = getAction(plugin, "Apply Enum Changes");
assertTrue(applyAction.isEnabled());
performAction(applyAction);
waitForProgram(program);
assertEquals(newDescription.trim(), enummDt.getDescription());
}
@Test
public void testDuplicateValue() throws Exception {
@ -775,8 +822,8 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
return null;
}
private void addEntry(JTable table, EnumTableModel model, String name,
long value) throws Exception {
private void addEntry(JTable table, EnumTableModel model, String name, long value)
throws Exception {
runSwing(() -> {
int lastRow = model.getRowCount() - 1;
if (lastRow >= 0) {
@ -868,6 +915,7 @@ public class EnumEditor2Test extends AbstractGhidraHeadedIntegrationTest {
Category cat = program.getListing()
.getDataTypeManager()
.getCategory(new CategoryPath(CategoryPath.ROOT, "Category1"));
Enum enumm = new EnumDataType("Colors", 1);
enumm.add("Red", 0);
enumm.add("Green", 0x10);

View file

@ -95,7 +95,7 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest {
@After
public void tearDown() throws Exception {
dialog.close();
close(dialog);
env.dispose();
}
@ -362,6 +362,34 @@ public class AddEditDialoglTest extends AbstractGhidraHeadedIntegrationTest {
assertTrue(function.getSymbol().isPrimary());
}
@Test
public void testRenameFunction_Trim() throws Exception {
Symbol s = getUniqueSymbol(program, "entry", null);
Function function = program.getFunctionManager().getFunctionAt(s.getAddress());
if (function == null) {
tool.execute(new CreateFunctionCmd(s.getAddress()), program);
program.flushEvents();
waitForSwing();
function = program.getFunctionManager().getFunctionAt(s.getAddress());
s = getUniqueSymbol(program, "entry", null);
}
// add another label at this address
AddLabelCmd cmd = new AddLabelCmd(addr(0x01006420), "fred", SourceType.USER_DEFINED);
tool.execute(cmd, program);
// now attempt to rename the entry label
editLabel(s);
assertEquals("entry", getText());
String newText = " bob ";
setText(newText);
pressOk();
program.flushEvents();
waitForSwing();
assertEquals("bob", function.getName());
assertTrue(function.getSymbol().isPrimary());
}
@Test
public void testSetPrimaryOnOtherLabel() throws Exception {
Symbol s = getUniqueSymbol(program, "entry", null);

View file

@ -15,13 +15,11 @@
*/
package ghidra.program.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.math.BigInteger;
import org.junit.*;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.app.plugin.core.analysis.ConstantPropagationAnalyzer;
@ -34,6 +32,7 @@ import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceIterator;
import ghidra.program.util.SymbolicPropogator.Value;
import ghidra.util.exception.NotFoundException;
import ghidra.util.task.TaskMonitor;
@ -308,6 +307,53 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
assertOperandReferenceTo(1, instr, addr("0x00040100"));
}
@Test
public void testPIC_Call_X86_64() throws Exception {
builder = new ProgramBuilder("PICCode", ProgramBuilder._X64, "gcc", this);
// entry
// 48 83 ec 28 SUB RSP,0x28
// e8 00 00 00 00 CALL LAB_140020119
// LAB_140020119
// 8f c3 POP RBX
// 48 8d 43 e0 LEA RAX,[RBX + -0x20]
// ff d0 CALL RAX
// 48 83 c4 28 ADD RSP,0x28
// c3 RET
builder.setBytes("0x140020110",
"48 83 ec 28 e8 00 00 00 00 8f c3 48 8d 43 e0 ff d0 48 83 c4 28 c3");
builder.setBytes("0x1400200f9",
"15 02 2f 00 00 89 05 e8 b9 00 00 48 83 c4 38");
builder.disassemble("0x140020110", 21);
analyzer = new ConstantPropagationAnalyzer();
program = builder.getProgram();
program.startTransaction("Test");
Address codeStart = addr("140020110");
Listing listing = program.getListing();
assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart));
AddressSet addressSet = new AddressSet(codeStart, codeStart.add(21));
analyze(addressSet);
Instruction instr = listing.getInstructionAt(addr("0x140020114"));
assertOperandReferenceTo(0, instr, addr("0x140020119"));
instr = listing.getInstructionAt(addr("0x140020119"));
ReferenceIterator referenceIteratorTo = instr.getReferenceIteratorTo();
Reference ref = referenceIteratorTo.next();
assertTrue(ref.getReferenceType().isJump());
instr = listing.getInstructionAt(addr("0x14002011f"));
Reference[] referencesFrom = instr.getReferencesFrom();
assertTrue(referencesFrom[0].getReferenceType().isFlow());
assertEquals("1400200f9", referencesFrom[0].getToAddress().toString());
}
private void assertNoOperandReference(int opIndex, Instruction instr) {
Reference[] refs = instr.getOperandReferences(opIndex);
assertEquals("No reference on operand " + opIndex, 0, refs.length);

View file

@ -1023,6 +1023,28 @@ AddrSpace *ActionConstantPtr::selectInferSpace(Varnode *vn,PcodeOp *op,const vec
return resSpace;
}
/// \brief Check if we need to try to infer a constant pointer from the input of the given COPY
///
/// In general, we do want try, but there is a special case where the COPY feeds into a RETURN and
/// the function does \e not return a pointer. We also consider the \b infer_pointers boolean.
/// \param op is the given COPY op
/// \param data is the function
/// \return \b true if we should try to infer
bool ActionConstantPtr::checkCopy(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
PcodeOp *retOp = vn->loneDescend();
if (retOp != (PcodeOp *)0 && retOp->code() == CPUI_RETURN && data.getFuncProto().isOutputLocked()) {
type_metatype meta = data.getFuncProto().getOutput()->getType()->getMetatype();
if (meta != TYPE_PTR && meta != TYPE_UNKNOWN) {
return false; // Do NOT infer, we know the constant can't be pointer
}
return true; // Try to infer, regardless of infer_pointers config, because we KNOW it is a pointer
}
return data.getArch()->infer_pointers;
}
/// \brief Determine if given Varnode might be a pointer constant.
///
/// If it is a pointer, return the symbol it points to, or NULL otherwise. If it is determined
@ -1054,23 +1076,36 @@ SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op
// Check if the constant is involved in a potential pointer expression
// as the base
switch(op->code()) {
case CPUI_RETURN:
case CPUI_CALL:
case CPUI_CALLIND:
// A constant parameter or return value could be a pointer
if (!glb->infer_pointers)
return (SymbolEntry *)0;
{
if (slot==0)
return (SymbolEntry *)0;
// A constant parameter could be a pointer
FuncCallSpecs *fc = data.getCallSpecs(op);
if (fc != (FuncCallSpecs *)0 && fc->isInputLocked() && fc->numParams() > slot-1) {
type_metatype meta = fc->getParam(slot-1)->getType()->getMetatype();
if (meta != TYPE_PTR && meta != TYPE_UNKNOWN) {
return (SymbolEntry *)0; // Definitely not passing a pointer
}
}
else if (!glb->infer_pointers)
return (SymbolEntry *)0;
break;
}
case CPUI_COPY:
if (!checkCopy(op, data))
return (SymbolEntry *)0;
break;
case CPUI_PIECE:
// Pointers get concatenated in structures
case CPUI_COPY:
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
case CPUI_INT_LESS:
case CPUI_INT_LESSEQUAL:
// A comparison with a constant could be a pointer
if (!glb->infer_pointers)
return (SymbolEntry *)0;
break;
case CPUI_INT_ADD:
outvn = op->getOut();

View file

@ -189,6 +189,7 @@ class ActionConstantPtr : public Action {
int4 localcount; ///< Number of passes made for this function
static AddrSpace *searchForSpaceAttribute(Varnode *vn,PcodeOp *op);
static AddrSpace *selectInferSpace(Varnode *vn,PcodeOp *op,const vector<AddrSpace *> &spaceList);
static bool checkCopy(PcodeOp *op,Funcdata &data);
static SymbolEntry *isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,int4 slot,
Address &rampoint,uintb &fullEncoding,Funcdata &data);
public:

View file

@ -75,6 +75,8 @@ public abstract class RenameTask {
dialog.setStatusText("Cannot have empty name");
return false;
}
name = name.trim();
if (name.equals(oldName)) { // No change to name
newName = name;
return true; // but valid (ends up being equivalent to cancel

View file

@ -303,6 +303,17 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
* @return combined reference type, or the newType if unable to combine
*/
private RefType combineReferenceType(RefType newType, RefType oldType) {
// check if types are the same, if same no use doing work replacing reference
if (newType == oldType) {
return oldType;
}
// any flow reference should be used over the existing ref to the same location
if (newType.isFlow()) {
return newType; // allow any new flow ref to replace old type
}
if (oldType.isFlow()) {
return oldType; // always keep flow over new data ref
}
if (newType == RefType.DATA) {
if (oldType.isData()) {
return oldType;

View file

@ -1,7 +1,5 @@
##VERSION: 2.0
Module.manifest||GHIDRA||||END|
data/languages/ARM-32-golang.cspec||GHIDRA||||END|
data/languages/ARM-32-golang.register.info||GHIDRA||||END|
data/languages/ARM.cspec||GHIDRA||||END|
data/languages/ARM.dwarf||GHIDRA||||END|
data/languages/ARM.gdis||GHIDRA||||END|

View file

@ -495,14 +495,14 @@ vcvt_56_128_dt: ".u32.f32"
is ((TMode=0 & ARMcond=0 & c2831=0b1111 & c2327=0b00111 & c2021=0b11 & c1819=0b10 & c1617=0b11 & c0911=0b011 & c0404=0 & c0606=0)
| (TMode=1 & thv_c2831=0b1111 & thv_c2327=0b11111 & thv_c2021=0b11 & thv_c1819=0b10 & thv_c1617=0b11 & thv_c0911=0b011 & thv_c0404=0 & thv_c0606=0))
& vcvt_56_64_dt & Dd & Dm
unimpl
{ }
# F6.1.60 p8002 A1 Q == 1 (c0606)
:vcvt^vcvt_56_128_dt Qd,Qm
is ((TMode=0 & ARMcond=0 & c2831=0b1111 & c2327=0b00111 & c2021=0b11 & c1819=0b10 & c1617=0b11 & c0911=0b011 & c0404=0 & c0606=1)
| (TMode=1 & thv_c2831=0b1111 & thv_c2327=0b11111 & thv_c2021=0b11 & thv_c1819=0b10 & thv_c1617=0b11 & thv_c0911=0b011 & thv_c0404=0 & thv_c0606=1))
& vcvt_56_128_dt & Qd & Qm
unimpl
{ }
# F6.1.61 p8005 A1 opc2==100 && size==10 (c1618, c0809)
:vcvt^COND^".u32.f32" Sd,Sm
@ -516,7 +516,7 @@ vcvt_56_128_dt: ".u32.f32"
is ((TMode=0 & ARMcond=1 & c2327=0b11101 & c1921=0b111 & c1011=0b10 & c0607=0b11 & c0404=0 & c1618=0b101 & c0809=0b10)
| (TMode=1 & thv_c2831=0b1110 & thv_c2327=0b11101 & thv_c1921=0b111 & thv_c1011=0b10 & thv_c0607=0b11 & thv_c0404=0 & thv_c1618=0b101 & thv_c0809=0b10))
& COND & Sd & Sm
{ build COND; Sd = zext(Sm f> 0) * (trunc(Sm)); }
{ build COND; Sd = trunc(Sm); }
# F6.1.61 p8005 A1 opc2==100 && size==11 (c1618, c0809)
:vcvt^COND^".u32.f64" Sd,Dm
@ -530,7 +530,7 @@ vcvt_56_128_dt: ".u32.f32"
is ((TMode=0 & ARMcond=1 & c2327=0b11101 & c1921=0b111 & c1011=0b10 & c0607=0b11 & c0404=0 & c1618=0b101 & c0809=0b11)
| (TMode=1 & thv_c2831=0b1110 & thv_c2327=0b11101 & thv_c1921=0b111 & thv_c1011=0b10 & thv_c0607=0b11 & thv_c0404=0 & thv_c1618=0b101 & thv_c0809=0b11))
& COND & Sd & Dm
{ build COND; local tmp:8 = zext(Dm f> 0:8) * (trunc(Dm)); Sd = tmp:4; }
{ build COND; local tmp:8 = trunc(Dm); Sd = tmp:4; }
# The rounding mode depends on c0707=0 => FPSCR else ZERO
@ -665,14 +665,14 @@ vcvt_59_64_dt: ".u16.f16"
is ((TMode=0 & ARMcond=0 & c2831=0b1111 & c2527=0b001 & c2323=1 & c2121=1 & c1011=0b11 & c0707=0 & c0404=1 & c0606=0)
| (TMode=1 & thv_c2931=0b111 & thv_c2327=0b11111 & thv_c2121=1 & thv_c1011=0b11 & thv_c0707=0 & thv_c0404=1 & thv_c0606=0))
& vcvt_59_32_dt & vcvt_59_fbits & Dd & Dm
unimpl
{ }
# F6.1.63 p8012 A1 Q = 1 (c0606)
:vcvt^vcvt_59_64_dt Qd,Qm,vcvt_59_fbits
is ((TMode=0 & ARMcond=0 & c2831=0b1111 & c2527=0b001 & c2323=1 & c2121=1 & c1011=0b11 & c0707=0 & c0404=1 & c0606=1)
| (TMode=1 & thv_c2931=0b111 & thv_c2327=0b11111 & thv_c2121=1 & thv_c1011=0b11 & thv_c0707=0 & thv_c0404=1 & thv_c0606=1))
& vcvt_59_64_dt & vcvt_59_fbits & Qd & Qm
unimpl
{ }
vcvt_60_fbits_built: fbits is TMode=0 & c0707=0 & c0505 & c0003 [fbits = 16 - ( c0003 * 2 + c0505); ] { export * [const]:1 fbits; }
vcvt_60_fbits_built: fbits is TMode=1 & thv_c0707=0 & thv_c0505 & thv_c0003 [fbits = 16 - (thv_c0003 * 2 + thv_c0505); ] { export * [const]:1 fbits; }
@ -814,14 +814,14 @@ vcvt_amnp_simd_128_dt: ".u32" is TMode=1 & thv_c0707=1 & thv_c0809 & vcvt_amnp_s
is ((TMode=0 & ARMcond=0 & c2831=0b1111 & c2327=0b00111 & c2021=0b11 & c1819=0b10 & c1617=0b11 & c1011=0b00 & c0404=0 & c0606=0)
| (TMode=1 & thv_c2831=0b1111 & thv_c2327=0b11111 & thv_c2021=0b11 & thv_c1819=0b10 & thv_c1617=0b11 & thv_c1011=0b00 & thv_c0404=0 & thv_c0606=0))
& vcvt_amnp_simd_RM & vcvt_amnp_simd_64_dt & Dd & Dm
unimpl
{ }
# F6.1.65,69,71,73 p8019,8028,8032,8036 A1 128-bit SIMD vector variant Q = 1(c0606)
:vcvt^vcvt_amnp_simd_RM^vcvt_amnp_simd_128_dt^".f32" Qd,Qm
is ((TMode=0 & ARMcond=0 & c2831=0b1111 & c2327=0b00111 & c2021=0b11 & c1819=0b10 & c1617=0b11 & c1011=0b00 & c0404=0 & c0606=1)
| (TMode=1 & thv_c2831=0b1111 & thv_c2327=0b11111 & thv_c2021=0b11 & thv_c1819=0b10 & thv_c1617=0b11 & thv_c1011=0b00 & thv_c0404=0 & thv_c0606=1))
& vcvt_amnp_simd_RM & vcvt_amnp_simd_128_dt & Qd & Qm
unimpl
{ }
vcvt_amnp_fp_RM: "a"
is ((TMode=0 & c1617=0b00)
@ -862,14 +862,14 @@ vcvt_amnp_fp_d_dt: ".s32" is TMode=1 & thv_c0707=1 & thv_c1617 & vcvt_amnp_fp_RM
is ((TMode=0 & ARMcond=0 & c2831=0b1111 & c2327=0b11101 & c2021=0b11 & c1819=0b11 & c1011=0b10 & c0606=1 & c0404=0 & c0809=0b10)
| (TMode=1 & thv_c2831=0b1111 & thv_c2327=0b11101 & thv_c2021=0b11 & thv_c1819=0b11 & thv_c1011=0b10 & thv_c0606=1 & thv_c0404=0 & thv_c0809=0b10))
& vcvt_amnp_fp_RM & vcvt_amnp_fp_s_dt & Sd & Sm
unimpl
{ }
# F6.1.66,70,72,74 p8021,8030,8034,8038 Double-precision scalar variant size = 11 (c0809)
:vcvt^vcvt_amnp_fp_RM^vcvt_amnp_fp_d_dt^".f64" Sd,Dm
is ((TMode=0 & ARMcond=0 & c2831=0b1111 & c2327=0b11101 & c2021=0b11 & c1819=0b11 & c1011=0b10 & c0606=1 & c0404=0 & c0809=0b11)
| (TMode=1 & thv_c2831=0b1111 & thv_c2327=0b11101 & thv_c2021=0b11 & thv_c1819=0b11 & thv_c1011=0b10 & thv_c0606=1 & thv_c0404=0 & thv_c0809=0b11))
& vcvt_amnp_fp_RM & vcvt_amnp_fp_d_dt & Sd & Dm
unimpl
{ }
# vcvtb and vcvtt