diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CallDepthChangeInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CallDepthChangeInfo.java
index eb42edc861..4e4436eea3 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CallDepthChangeInfo.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CallDepthChangeInfo.java
@@ -273,8 +273,7 @@ public class CallDepthChangeInfo {
PcodeOp[] pcode = instr.getPcode();
Varnode outVarNode = null;
- for (int i = 0; i < pcode.length; i++) {
- PcodeOp op = pcode[i];
+ for (PcodeOp op : pcode) {
Varnode input0 = op.getInput(0);
Varnode input1 = op.getInput(1);
Varnode output = op.getOutput();
@@ -317,9 +316,10 @@ public class CallDepthChangeInfo {
break;
case PcodeOp.INT_AND: // Assume this is a stack alignment and do the and
if (isStackPointer(input0)) {
- if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE)
+ if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) {
possibleDepthChange =
(int) (currentStackDepth & input1.getOffset()) - currentStackDepth;
+ }
outVarNode = output;
}
else if (input0.equals(outVarNode)) {
@@ -327,9 +327,10 @@ public class CallDepthChangeInfo {
outVarNode = output;
}
else if (isStackPointer(input1)) {
- if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE)
+ if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) {
possibleDepthChange =
(int) (currentStackDepth & input0.getOffset()) - currentStackDepth;
+ }
outVarNode = output;
}
else if (input1.equals(outVarNode)) {
@@ -385,7 +386,7 @@ public class CallDepthChangeInfo {
// TODO: Modify return by normal stack shift....
if (flowType.isTerminal()) {
- depthChange -= program.getCompilerSpec().getCallStackShift();
+ depthChange -= program.getCompilerSpec().getDefaultCallingConvention().getStackshift();
}
// if the current stack depth is still bad, don't return a depth change.
@@ -419,8 +420,9 @@ public class CallDepthChangeInfo {
* @return
*/
private int getDefaultStackDepthChange(int depth) {
- int callStackMod = program.getCompilerSpec().getCallStackMod();
- int callStackShift = program.getCompilerSpec().getCallStackShift();
+ PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention();
+ int callStackMod = defaultModel.getExtrapop();
+ int callStackShift = defaultModel.getStackshift();
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
return callStackShift - callStackMod;
}
@@ -578,8 +580,8 @@ public class CallDepthChangeInfo {
FlowType flow = instr.getFlowType();
if (!flow.isCall()) {
Address[] flows = instr.getFlows();
- for (int i = 0; i < flows.length; i++) {
- st.push(flows[i]);
+ for (Address flow2 : flows) {
+ st.push(flow2);
st.push(new Integer(stackPointerDepth));
st.push(stackOK);
}
@@ -653,7 +655,7 @@ public class CallDepthChangeInfo {
return;
}
- int purge = (short) program.getCompilerSpec().getCallStackMod();
+ int purge = (short) program.getCompilerSpec().getDefaultCallingConvention().getExtrapop();
final boolean possiblePurge = purge == -1 || purge > 3200 || purge < -3200;
// follow all flows building up context
@@ -948,8 +950,8 @@ public class CallDepthChangeInfo {
FlowType flow = instr.getFlowType();
if (!flow.isCall()) {
Address[] flows = instr.getFlows();
- for (int i = 0; i < flows.length; i++) {
- st.push(flows[i]);
+ for (Address flow2 : flows) {
+ st.push(flow2);
st.push(new Integer(stackPointerDepth));
st.push(stackOK);
}
@@ -1027,11 +1029,11 @@ public class CallDepthChangeInfo {
}
// try to find a call destination that the stack frame is known
- for (int i = 0; i < flows.length; i++) {
- if (flows[i] == null) {
+ for (Address flow : flows) {
+ if (flow == null) {
continue;
}
- Function func = program.getListing().getFunctionAt(flows[i]);
+ Function func = program.getListing().getFunctionAt(flow);
if (func != null) {
int purge = func.getStackPurgeSize();
if (func.isStackPurgeSizeValid() && purge != Function.UNKNOWN_STACK_DEPTH_CHANGE &&
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionPurgeAnalysisCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionPurgeAnalysisCmd.java
index 605a427fcd..58bb7a2ba7 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionPurgeAnalysisCmd.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionPurgeAnalysisCmd.java
@@ -17,15 +17,16 @@ package ghidra.app.cmd.function;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
-import ghidra.program.model.address.AddressSet;
-import ghidra.program.model.address.AddressSetView;
+import ghidra.program.model.address.*;
import ghidra.program.model.lang.Processor;
+import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.listing.*;
+import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.scalar.Scalar;
-import ghidra.program.model.symbol.FlowType;
-import ghidra.program.model.symbol.Reference;
+import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
/**
@@ -34,13 +35,17 @@ import ghidra.util.task.TaskMonitor;
public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
private AddressSetView entryPoints;
private Program program;
+ private PrototypeModel[] nearFarModels = null;
+
+ private static final int STDCALL_FAR = 0;
+ private static final int CDECL_FAR = 1;
+ private static final int STDCALL_NEAR = 2;
+ private static final int CDECL_NEAR = 3;
/**
* Constructs a new command for analyzing the Stack.
* @param entries and address set indicating the entry points of functions that have
* stacks to be analyzed.
- * @param forceProcessing flag to force processing of stack references even if the stack
- * has already been defined.
*/
public FunctionPurgeAnalysisCmd(AddressSetView entries) {
super("Compute Function Purge", true, true, false);
@@ -56,12 +61,16 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
program = (Program) obj;
Processor processor = program.getLanguage().getProcessor();
- if (program.getLanguage().getDefaultSpace().getSize() > 32 ||
+ AddressSpace defaultSpace = program.getLanguage().getDefaultSpace();
+ if (defaultSpace.getSize() > 32 ||
!processor.equals(Processor.findOrPossiblyCreateProcessor("x86"))) {
Msg.error(this,
"Unsupported operation for language " + program.getLanguage().getLanguageID());
return false;
}
+ if (defaultSpace instanceof SegmentedAddressSpace) { // For 16-bit x86, prepare to establish near/fear calling convention models
+ setupNearFarModels();
+ }
AddressSetView set = entryPoints;
@@ -95,6 +104,52 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
return true;
}
+ /**
+ * For x86 16-bit find the models stdcallnear, stdcallfar, cdeclnear, and cdeclfar so they can
+ * be applied at the same time function purge is set.
+ */
+ private void setupNearFarModels() {
+ int countModels = 0;
+ nearFarModels = new PrototypeModel[4];
+ nearFarModels[0] = null;
+ nearFarModels[1] = null;
+ nearFarModels[2] = null;
+ nearFarModels[3] = null;
+ PrototypeModel[] models = program.getCompilerSpec().getCallingConventions();
+ for (PrototypeModel model : models) {
+ if (model.isMerged()) {
+ continue;
+ }
+ int pos = -1;
+ if (model.getStackshift() == 4) {
+ if (model.getExtrapop() == PrototypeModel.UNKNOWN_EXTRAPOP) {
+ pos = STDCALL_FAR;
+ }
+ else if (model.getExtrapop() == 4) {
+ pos = CDECL_FAR;
+ }
+ }
+ else if (model.getStackshift() == 2) {
+ if (model.getExtrapop() == PrototypeModel.UNKNOWN_EXTRAPOP) {
+ pos = STDCALL_NEAR;
+ }
+ else if (model.getExtrapop() == 2) {
+ pos = CDECL_NEAR;
+ }
+ }
+ if (pos >= 0) {
+ if (nearFarModels[pos] == null) {
+ nearFarModels[pos] = model;
+ countModels += 1;
+ }
+ }
+ }
+ if (countModels < 4) {
+ Msg.warn(this,
+ "FunctionPurgeAnalysis is missing full range of near/far prototype models");
+ }
+ }
+
/**
* Analyze a function to build a stack frame based on stack references.
* @param function function to be analyzed
@@ -104,39 +159,120 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
*/
private void analyzeFunction(Function function, TaskMonitor monitor) throws CancelledException {
- int purge = -1;
-
- if (function != null) {
- purge = function.getStackPurgeSize();
+ if (function == null) {
+ return;
}
+ int purge = function.getStackPurgeSize();
if (purge == -1 || purge > 128 || purge < -128) {
- purge = locatePurgeReturn(program, function, monitor);
- // if couldn't find it, don't set it!
- if (purge != -1) {
- function.setStackPurgeSize(purge);
+ Instruction purgeInstruction = locatePurgeInstruction(function, monitor);
+ if (purgeInstruction != null) {
+ purge = getPurgeValue(purgeInstruction);
+ // if couldn't find it, don't set it!
+ if (purge != -1) {
+ function.setStackPurgeSize(purge);
+ }
+ setPrototypeModel(function, purgeInstruction);
}
}
}
- private int locatePurgeReturn(Program program, Function func, TaskMonitor monitor) {
- AddressSetView body = func.getBody();
+ private void setPrototypeModel(Function function, Instruction purgeInstruction) {
+ if (nearFarModels == null) {
+ return;
+ }
+ if (purgeInstruction.getFlowType().isCall()) {
+ return;
+ }
+ if (function.getSignatureSource() != SourceType.DEFAULT) {
+ return;
+ }
+ PrototypeModel model = null;
+ try {
+ byte val = purgeInstruction.getBytes()[0];
+ if (val == (byte) 0xc3) {
+ model = nearFarModels[CDECL_NEAR];
+ }
+ else if (val == (byte) 0xcb) {
+ model = nearFarModels[CDECL_FAR];
+ }
+ else if (val == (byte) 0xc2) {
+ model = nearFarModels[STDCALL_NEAR];
+ }
+ else if (val == (byte) 0xca) {
+ model = nearFarModels[STDCALL_FAR];
+ }
+ }
+ catch (MemoryAccessException e) {
+ return;
+ }
+ if (model == null) {
+ return;
+ }
+ try {
+ function.setCallingConvention(model.getName());
+ }
+ catch (InvalidInputException e) {
+ // Ignore if we can't change it
+ }
+ }
- int returnPurge = findReturnPurge(program, body);
- if (returnPurge != -1) {
- return returnPurge;
+ private Instruction locatePurgeInstruction(Function func, TaskMonitor monitor) {
+ AddressSetView body = func.getBody();
+ Instruction purgeInstruction;
+
+ purgeInstruction = findPurgeInstruction(body);
+ if (purgeInstruction != null) {
+ return purgeInstruction;
}
// look harder, maybe something wrong with body, compute with flow.
body = CreateFunctionCmd.getFunctionBody(program, func.getEntryPoint(), monitor);
- returnPurge = findReturnPurge(program, body);
-
- return returnPurge;
+ return findPurgeInstruction(body);
}
- private int findReturnPurge(Program program, AddressSetView body) {
- int tempPurge;
+ /**
+ * Given a terminating instruction, discover the purge value encoded in it
+ * @param instr is the terminating instruction
+ * @return the purge value (or -1 if a value can't be found)
+ */
+ private int getPurgeValue(Instruction instr) {
+ if (instr.getFlowType().isCall()) {
+ // is an override call-return, terminal/call
+ // find a reference to a function, and take it's purge
+ Reference[] referencesFrom = instr.getReferencesFrom();
+ for (Reference reference : referencesFrom) {
+ if (reference.getReferenceType().isFlow()) {
+ Function functionAt =
+ program.getFunctionManager().getFunctionAt(reference.getToAddress());
+ // don't take the purge of a non-returning function
+ if (functionAt != null && !functionAt.hasNoReturn()) {
+ return functionAt.getStackPurgeSize();
+ }
+ }
+ }
+ }
+ else {
+ int tempPurge = 0;
+ Scalar scalar = instr.getScalar(0);
+ if (scalar != null) {
+ tempPurge = (int) scalar.getSignedValue();
+ }
+ return tempPurge;
+ }
+ return -1;
+ }
+
+ /**
+ * Find a terminating instruction in the given set of addresses with a purge encoded in it.
+ * This routine prefers a RET instruction, but if none is available, it will use a
+ * terminating CALL.
+ * @param body is the set of addresses to look through
+ * @return a terminating instruction or null
+ */
+ private Instruction findPurgeInstruction(AddressSetView body) {
InstructionIterator iter = program.getListing().getInstructions(body, true);
int count = 2048;
+ Instruction backupPurge = null;
while (iter.hasNext() && count > 0) {
count--;
Instruction instr = iter.next();
@@ -144,33 +280,15 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
FlowType ftype = instr.getFlowType();
if (ftype.isTerminal()) {
if (instr.getMnemonicString().compareToIgnoreCase("ret") == 0) {
- tempPurge = 0;
- Scalar scalar = instr.getScalar(0);
- if (scalar != null) {
- tempPurge = (int) scalar.getSignedValue();
- return tempPurge;
- }
- return 0;
+ return instr;
}
else if (ftype.isCall()) {
- // is an override call-return, terminal/call
- // find a reference to a function, and take it's purge
- Reference[] referencesFrom = instr.getReferencesFrom();
- for (Reference reference : referencesFrom) {
- if (reference.getReferenceType().isFlow()) {
- Function functionAt = program.getFunctionManager().getFunctionAt(
- reference.getToAddress());
- // don't take the purge of a non-returning function
- if (functionAt != null && !functionAt.hasNoReturn()) {
- return functionAt.getStackPurgeSize();
- }
- }
- }
+ backupPurge = instr; // Use as last resort, if we can't find RET
}
}
}
- return -1;
+ return backupPurge;
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionResultStateStackAnalysisCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionResultStateStackAnalysisCmd.java
index 73e998a5b5..045fe5f9a3 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionResultStateStackAnalysisCmd.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/FunctionResultStateStackAnalysisCmd.java
@@ -169,8 +169,9 @@ public class FunctionResultStateStackAnalysisCmd extends BackgroundCommand {
// Process all the functions identified as needing stack analysis.
// The list will have the lowest level functions analyzed first.
- int default_extraPop = program.getCompilerSpec().getCallStackMod();
- int default_stackshift = program.getCompilerSpec().getCallStackShift();
+ PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention();
+ int default_extraPop = defaultModel.getExtrapop();
+ int default_stackshift = defaultModel.getStackshift();
while (!funcList.isEmpty()) {
monitor.checkCanceled();
@@ -256,19 +257,22 @@ public class FunctionResultStateStackAnalysisCmd extends BackgroundCommand {
int storageSpaceID, RefType refType, TaskMonitor monitor1)
throws CancelledException {
- if (instrOpIndex < 0)
+ if (instrOpIndex < 0) {
return;
+ }
Address fromAddr = op.getSeqnum().getTarget();
Instruction instr = listing.getInstructionAt(fromAddr);
- if (instr == null)
+ if (instr == null) {
return;
+ }
Address stackAddr = addrFactory.getStackSpace().getAddress(stackOffset);
RefType rt = refType;
Reference ref = refMgr.getReference(fromAddr, stackAddr, instrOpIndex);
if (ref != null) {
RefType existingRefType = ref.getReferenceType();
- if (existingRefType == rt)
+ if (existingRefType == rt) {
return;
+ }
if (existingRefType == RefType.READ || existingRefType == RefType.WRITE) {
rt = RefType.READ_WRITE;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/NewExecutable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/NewExecutable.java
index 5cea4c6384..e95d196494 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/NewExecutable.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/NewExecutable.java
@@ -1,6 +1,5 @@
/* ###
* 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.
@@ -16,12 +15,13 @@
*/
package ghidra.app.util.bin.format.ne;
-import generic.continues.*;
-import ghidra.app.util.bin.*;
-import ghidra.app.util.bin.format.*;
-import ghidra.app.util.bin.format.mz.*;
+import java.io.IOException;
-import java.io.*;
+import generic.continues.GenericFactory;
+import ghidra.app.util.bin.ByteProvider;
+import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
+import ghidra.app.util.bin.format.mz.DOSHeader;
+import ghidra.program.model.address.SegmentedAddress;
/**
* A class to manage loading New Executables (NE).
@@ -34,17 +34,20 @@ public class NewExecutable {
private WindowsHeader winHeader;
/**
- * Constructs a new instance of an new executable.
- * @param bp the byte provider
- * @throws IOException if an I/O error occurs.
- */
- public NewExecutable(GenericFactory factory, ByteProvider bp) throws IOException {
+ * Constructs a new instance of an new executable.
+ * @param factory is the object factory to bundle with the reader
+ * @param bp the byte provider
+ * @param baseAddr the image base of the executable
+ * @throws IOException if an I/O error occurs.
+ */
+ public NewExecutable(GenericFactory factory, ByteProvider bp, SegmentedAddress baseAddr)
+ throws IOException {
reader = new FactoryBundledWithBinaryReader(factory, bp, true);
dosHeader = DOSHeader.createDOSHeader(reader);
if (dosHeader.isDosSignature()) {
try {
- winHeader = new WindowsHeader(reader, (short)dosHeader.e_lfanew());
+ winHeader = new WindowsHeader(reader, baseAddr, (short) dosHeader.e_lfanew());
}
catch (InvalidWindowsHeaderException e) {
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/SegmentTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/SegmentTable.java
index 15f0a278bc..41ad4b8822 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/SegmentTable.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/SegmentTable.java
@@ -1,6 +1,5 @@
/* ###
* 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.
@@ -18,7 +17,9 @@ package ghidra.app.util.bin.format.ne;
import java.io.IOException;
-import ghidra.app.util.bin.format.*;
+import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
+import ghidra.program.model.address.SegmentedAddress;
+import ghidra.program.model.address.SegmentedAddressSpace;
import ghidra.util.Conv;
/**
@@ -28,7 +29,8 @@ import ghidra.util.Conv;
public class SegmentTable {
private Segment [] segments;
- SegmentTable(FactoryBundledWithBinaryReader reader, short index, short segmentCount, short shiftAlignCount) throws IOException {
+ SegmentTable(FactoryBundledWithBinaryReader reader, SegmentedAddress baseAddr, short index,
+ short segmentCount, short shiftAlignCount) throws IOException {
long oldIndex = reader.getPointerIndex();
reader.setPointerIndex(Conv.shortToInt(index));
@@ -39,14 +41,29 @@ public class SegmentTable {
segments = new Segment[segmentCountInt];
- int startOffset = 0;
+ SegmentedAddressSpace space;
+ int curSegment;
+ if (baseAddr != null) {
+ space = (SegmentedAddressSpace) baseAddr.getAddressSpace();
+ curSegment = baseAddr.getSegment();
+ }
+ else {
+ space = null;
+ curSegment = 0;
+ }
for (int i = 0 ; i < segmentCountInt ; ++i) {
- segments[i] = new Segment(reader, shiftAlignCount, startOffset >> 4);
+ segments[i] = new Segment(reader, shiftAlignCount, curSegment);
int size = segments[i].getMinAllocSize() & 0xffff;
if (size == 0) {
size = 0x10000;
}
- startOffset = (startOffset + size + 0xf) & ~0xf;
+ if (space != null) {
+ SegmentedAddress endAddr = space.getAddress(curSegment, size - 1);
+ curSegment = space.getNextOpenSegment(endAddr);
+ }
+ else {
+ curSegment += 1;
+ }
}
reader.setPointerIndex(oldIndex);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/WindowsHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/WindowsHeader.java
index a66f040597..825de14d0f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/WindowsHeader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ne/WindowsHeader.java
@@ -1,6 +1,5 @@
/* ###
* 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.
@@ -16,9 +15,11 @@
*/
package ghidra.app.util.bin.format.ne;
-import ghidra.app.util.bin.format.*;
import java.io.IOException;
+import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
+import ghidra.program.model.address.SegmentedAddress;
+
/**
* A class to represent and parse the
* Windows new-style executable (NE) header.
@@ -39,20 +40,22 @@ public class WindowsHeader {
private NonResidentNameTable nonResNameTable;
/**
- * Constructor
- * @param reader the binary reader
- * @param index the index where the windows headers begins
- * @throws InvalidWindowsHeaderException if the bytes defined in the binary reader at
- * the specified index do not constitute a valid windows header.
- */
- public WindowsHeader(FactoryBundledWithBinaryReader reader, short index) throws InvalidWindowsHeaderException, IOException {
+ * Constructor
+ * @param reader the binary reader
+ * @param baseAddr the image base address
+ * @param index the index where the windows headers begins
+ * @throws InvalidWindowsHeaderException if the bytes defined in the binary reader at
+ * the specified index do not constitute a valid windows header.
+ * @throws IOException for problems reading the header bytes
+ */
+ public WindowsHeader(FactoryBundledWithBinaryReader reader, SegmentedAddress baseAddr,
+ short index) throws InvalidWindowsHeaderException, IOException {
this.infoBlock = new InformationBlock(reader, index);
short segTableIndex = (short)(infoBlock.getSegmentTableOffset() + index);
this.segTable = new SegmentTable(reader,
- segTableIndex,
- infoBlock.getSegmentCount(),
- infoBlock.getSegmentAlignmentShiftCount());
+ baseAddr, segTableIndex, infoBlock.getSegmentCount(),
+ infoBlock.getSegmentAlignmentShiftCount());
//if resource table offset == resident name table offset, then
//we do not have any resources...
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java
index 4dbf12095e..7a62948957 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java
@@ -892,14 +892,14 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
if (expSym.hasNoReturn()) {
extFunc.setNoReturn(true);
}
- int stackShift = program.getCompilerSpec().getCallStackShift();
- if (stackShift == -1) {
- stackShift = 0;
- }
+// TODO: This should not be done at time of import and should be done
+// by a late running analyzer (e.g., stack analyzer) if no signature
+// has been established
+// int stackShift = program.getCompilerSpec().getDefaultCallingConvention().getStackshift();
+// if (stackShift == -1) {
+// stackShift = 0;
+// }
- // TODO: This should not be done at time of import and should be done
- // by a late running analyzer (e.g., stack analyzer) if no signature
- // has been established
// int numParams = expSym.getPurge() / 4;
// if (numParams > 0) {
// // HACK: assumes specific stack-based x86 convention
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java
index 0712c72c28..65896e1cd9 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MzLoader.java
@@ -258,6 +258,11 @@ public class MzLoader extends AbstractLibrarySupportLoader {
int dataStart = dos.e_cparhdr() << 4;
HashMap
segMap = new HashMap();
+ SegmentedAddress codeAddress =
+ space.getAddress(Conv.shortToInt(dos.e_cs()) + csStart, 0);
+ segMap.put(codeAddress, codeAddress);
+ codeAddress = space.getAddress(csStart, 0);
+ segMap.put(codeAddress, codeAddress); // This is there data starts loading
int numRelocationEntries = dos.e_crlc();
reader.setPointerIndex(relocationTableOffset);
for (int i = 0; i < numRelocationEntries; i++) {
@@ -290,17 +295,17 @@ public class MzLoader extends AbstractLibrarySupportLoader {
for (int i = 0; i < segStartList.size(); i++) {
SegmentedAddress start = (SegmentedAddress) segStartList.get(i);
- int readLoc = (int) (start.getOffset() - csStartEffective) + dataStart;
+ int readLoc = ((start.getSegment() << 4) - csStartEffective) + dataStart;
if (readLoc < 0) {
Msg.error(this, "Invalid read location " + readLoc);
continue;
}
- byte bytes[] = null;
int numBytes = 0;
if ((i + 1) < segStartList.size()) {
SegmentedAddress end = (SegmentedAddress) segStartList.get(i + 1);
- numBytes = (int) end.subtract(start);
+ int nextLoc = ((end.getSegment() << 4) - csStartEffective) + dataStart;
+ numBytes = nextLoc - readLoc;
}
else {
// last segment length
@@ -317,7 +322,6 @@ public class MzLoader extends AbstractLibrarySupportLoader {
numUninitBytes = calcNumBytes - numBytes;
}
if (numBytes > 0) {
- bytes = reader.readByteArray(readLoc, numBytes);
MemoryBlockUtils.createInitializedBlock(program, false, "Seg_" + i, start,
fileBytes, readLoc, numBytes, "", "mz", true, true, true, log);
}
@@ -399,6 +403,7 @@ public class MzLoader extends AbstractLibrarySupportLoader {
symbolTable.createLabel(addr, ENTRY_NAME, SourceType.IMPORTED);
}
catch (InvalidInputException e) {
+ // Just skip if we can't create
}
symbolTable.addExternalEntryPoint(addr);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java
index 60703c818e..59e648fabb 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java
@@ -51,6 +51,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
private static final String TAB = " ";
private static final long MIN_BYTE_LENGTH = 4;
+ private static final int SEGMENT_START = 0x1000;
private ArrayList entryPointList = new ArrayList<>();
private Comparator comparator = new CallNameComparator();
@@ -65,7 +66,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
if (provider.length() < MIN_BYTE_LENGTH) {
return loadSpecs;
}
- NewExecutable ne = new NewExecutable(RethrowContinuesFactory.INSTANCE, provider);
+ NewExecutable ne = new NewExecutable(RethrowContinuesFactory.INSTANCE, provider, null);
WindowsHeader wh = ne.getWindowsHeader();
if (wh != null) {
List results = QueryOpinionService.query(getName(),
@@ -99,7 +100,9 @@ public class NeLoader extends AbstractLibrarySupportLoader {
// the original bytes.
MemoryBlockUtils.createFileBytes(prog, provider, monitor);
- NewExecutable ne = new NewExecutable(factory, provider);
+ SegmentedAddressSpace space =
+ (SegmentedAddressSpace) prog.getAddressFactory().getDefaultAddressSpace();
+ NewExecutable ne = new NewExecutable(factory, provider, space.getAddress(SEGMENT_START, 0));
WindowsHeader wh = ne.getWindowsHeader();
InformationBlock ib = wh.getInformationBlock();
SegmentTable st = wh.getSegmentTable();
@@ -113,8 +116,6 @@ public class NeLoader extends AbstractLibrarySupportLoader {
Listing listing = prog.getListing();
SymbolTable symbolTable = prog.getSymbolTable();
Memory memory = prog.getMemory();
- SegmentedAddressSpace space =
- (SegmentedAddressSpace) prog.getAddressFactory().getDefaultAddressSpace();
ProgramContext context = prog.getProgramContext();
RelocationTable relocTable = prog.getRelocationTable();
@@ -306,11 +307,6 @@ public class NeLoader extends AbstractLibrarySupportLoader {
}
}
- private int getNextAvailableSegment(Program program) {
- Address addr = program.getMemory().getMaxAddress();
- return ((int) addr.getOffset() >> 4) + 1;
- }
-
private void processResourceTable(MessageLog log, Program program, ResourceTable rt,
SegmentedAddressSpace space, TaskMonitor monitor) throws IOException {
Listing listing = program.getListing();
@@ -326,7 +322,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
Resource[] resources = type.getResources();
for (Resource resource : resources) {
- int segidx = getNextAvailableSegment(program);
+ int segidx = space.getNextOpenSegment(program.getMemory().getMaxAddress());
Address addr = space.getAddress(segidx, 0);
try {
@@ -417,7 +413,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
for (LengthStringSet name : names) {
String[] callnames = getCallNamesForModule(name.getString(), mrt, st, imp);
int length = callnames.length * pointerSize;
- int segment = getNextAvailableSegment(program);
+ int segment = space.getNextOpenSegment(program.getMemory().getMaxAddress());
Address start = space.getAddress(segment, 0);
if (length > 0) {
// This isn't a real block, just place holder addresses, so don't create an initialized block
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java
index 2cb1e058ab..0c89c48bec 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java
@@ -176,10 +176,10 @@ public class ProgramMemoryUtil {
MemoryBlock[] blocks = mem.getBlocks();
MemoryBlock[] tmpBlocks = new MemoryBlock[blocks.length];
int j = 0;
- for (int i = 0; i < blocks.length; i++) {
- if ((blocks[i].isInitialized() && withBytes) ||
- (!blocks[i].isInitialized() && !withBytes)) {
- tmpBlocks[j++] = blocks[i];
+ for (MemoryBlock block : blocks) {
+ if ((block.isInitialized() && withBytes) ||
+ (!block.isInitialized() && !withBytes)) {
+ tmpBlocks[j++] = block;
}
}
MemoryBlock[] typeBlocks = new MemoryBlock[j];
@@ -297,7 +297,7 @@ public class ProgramMemoryUtil {
}
// Just looking for the offset into the segment now, not the whole segment/offset pair
- if (addrSize == 20) {
+ if (toAddress instanceof SegmentedAddress) {
SegmentedAddress segAddr = (SegmentedAddress) toAddress;
currentSegment = (short) segAddr.getSegment();
}
@@ -322,10 +322,10 @@ public class ProgramMemoryUtil {
if (toAddress instanceof SegmentedAddress) {
short offsetShort = memory.getShort(a);
offsetShort &= offsetShort & 0xffff;
- SegmentedAddress sega = ((SegmentedAddress) a);
- short shortSega = (short) (sega.getSegment());
- shortSega &= shortSega & 0xffff;
// this is checking to see if the ref is in the same segment as the toAddr - not sure this is needed anymore
+ // SegmentedAddress sega = ((SegmentedAddress) a);
+ // short shortSega = (short) (sega.getSegment());
+ // shortSega &= shortSega & 0xffff;
// if (offsetShort == shortCurrentOffset) {
//*** commenting this out is making it find the instances of 46 01's not the 0a 00's - closer though
// check for the case where the reference includes both the segment and offset
@@ -441,8 +441,9 @@ public class ProgramMemoryUtil {
}
for (ReferenceAddressPair rap : directReferenceList) {
- if (monitor.isCancelled())
+ if (monitor.isCancelled()) {
return null;
+ }
Address fromAddr = rap.getSource();
if (!results.contains(fromAddr)) {
results.add(fromAddr);
@@ -624,18 +625,18 @@ public class ProgramMemoryUtil {
byte maskBytes[] = null;
MemoryBlock[] blocks = memory.getBlocks();
- for (int i = 0; i < blocks.length; i++) {
- if (!blocks[i].isInitialized()) {
+ for (MemoryBlock block : blocks) {
+ if (!block.isInitialized()) {
continue;
}
if (memoryRange != null &&
- !memoryRange.intersects(blocks[i].getStart(), blocks[i].getEnd())) {
+ !memoryRange.intersects(block.getStart(), block.getEnd())) {
// skip blocks which do not correspond to currentSeg
continue;
}
- Address start = blocks[i].getStart();
- Address end = blocks[i].getEnd();
+ Address start = block.getStart();
+ Address end = block.getEnd();
Address found = null;
while (true) {
monitor.checkCanceled();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java
index 172bf0f20f..39157d281d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java
@@ -1705,8 +1705,9 @@ public class SymbolicPropogator {
* @return
*/
private int getDefaultStackDepthChange(Program prog, int depth) {
- int callStackMod = prog.getCompilerSpec().getCallStackMod();
- int callStackShift = prog.getCompilerSpec().getCallStackShift();
+ PrototypeModel defaultModel = prog.getCompilerSpec().getDefaultCallingConvention();
+ int callStackMod = defaultModel.getExtrapop();
+ int callStackShift = defaultModel.getStackshift();
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP) {
return callStackShift;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/state/ResultsState.java b/Ghidra/Features/Base/src/main/java/ghidra/util/state/ResultsState.java
index 999f4042c1..257d4855b8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/util/state/ResultsState.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/util/state/ResultsState.java
@@ -46,14 +46,17 @@ public class ResultsState {
private static final Iterator emptyContextStateIterator =
new Iterator() {
+ @Override
public boolean hasNext() {
return false;
}
+ @Override
public ContextState next() {
return null;
}
+ @Override
public void remove() {
}
};
@@ -168,10 +171,12 @@ public class ResultsState {
stackGrowsNegative = program.getCompilerSpec().stackGrowsNegative();
Long stackOffset = currentPrototype.getStackParameterOffset();
- if (stackOffset != null)
+ if (stackOffset != null) {
paramBaseStackOffset = stackOffset - currentPrototype.getStackshift();
- else
+ }
+ else {
paramBaseStackOffset = null;
+ }
todoList.add(new BranchDestination(null, entryPt, entryState));
}
@@ -253,9 +258,10 @@ public class ResultsState {
currentState = null;
}
- if (DEBUG)
+ if (DEBUG) {
Msg.debug(this, ">>> At " + nextSeq.getTarget() + "/" + nextSeq.getTime() +
" " + instr);
+ }
SequenceNumber lastSeq = flowFrom;
@@ -272,9 +278,10 @@ public class ResultsState {
if (existingStates.containsKey(flowFrom)) {
// TODO: We have processed this flow before
// TODO: Should we compare existingState with dest.initialState ?
- if (DEBUG)
+ if (DEBUG) {
Msg.debug(this, "Flow ignored - already processed: " +
flowFrom + " -> " + pcodeOp.getSeqnum());
+ }
instr = null; // signal - abort current flow
break;
}
@@ -284,9 +291,10 @@ public class ResultsState {
// Re-use existing state where register values match
addState(flowFrom, otherEntryState);
instr = null; // signal - abort current flow
- if (DEBUG)
+ if (DEBUG) {
Msg.debug(this, "Flow combined - similar state: " +
flowFrom + " -> " + pcodeOp.getSeqnum());
+ }
break;
}
}
@@ -385,6 +393,7 @@ public class ResultsState {
private static Comparator