mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/GT-3090_16bit_analysis'
This commit is contained in:
commit
23d1e9ad22
50 changed files with 1000 additions and 877 deletions
|
@ -273,8 +273,7 @@ public class CallDepthChangeInfo {
|
||||||
|
|
||||||
PcodeOp[] pcode = instr.getPcode();
|
PcodeOp[] pcode = instr.getPcode();
|
||||||
Varnode outVarNode = null;
|
Varnode outVarNode = null;
|
||||||
for (int i = 0; i < pcode.length; i++) {
|
for (PcodeOp op : pcode) {
|
||||||
PcodeOp op = pcode[i];
|
|
||||||
Varnode input0 = op.getInput(0);
|
Varnode input0 = op.getInput(0);
|
||||||
Varnode input1 = op.getInput(1);
|
Varnode input1 = op.getInput(1);
|
||||||
Varnode output = op.getOutput();
|
Varnode output = op.getOutput();
|
||||||
|
@ -317,9 +316,10 @@ public class CallDepthChangeInfo {
|
||||||
break;
|
break;
|
||||||
case PcodeOp.INT_AND: // Assume this is a stack alignment and do the and
|
case PcodeOp.INT_AND: // Assume this is a stack alignment and do the and
|
||||||
if (isStackPointer(input0)) {
|
if (isStackPointer(input0)) {
|
||||||
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE)
|
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) {
|
||||||
possibleDepthChange =
|
possibleDepthChange =
|
||||||
(int) (currentStackDepth & input1.getOffset()) - currentStackDepth;
|
(int) (currentStackDepth & input1.getOffset()) - currentStackDepth;
|
||||||
|
}
|
||||||
outVarNode = output;
|
outVarNode = output;
|
||||||
}
|
}
|
||||||
else if (input0.equals(outVarNode)) {
|
else if (input0.equals(outVarNode)) {
|
||||||
|
@ -327,9 +327,10 @@ public class CallDepthChangeInfo {
|
||||||
outVarNode = output;
|
outVarNode = output;
|
||||||
}
|
}
|
||||||
else if (isStackPointer(input1)) {
|
else if (isStackPointer(input1)) {
|
||||||
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE)
|
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) {
|
||||||
possibleDepthChange =
|
possibleDepthChange =
|
||||||
(int) (currentStackDepth & input0.getOffset()) - currentStackDepth;
|
(int) (currentStackDepth & input0.getOffset()) - currentStackDepth;
|
||||||
|
}
|
||||||
outVarNode = output;
|
outVarNode = output;
|
||||||
}
|
}
|
||||||
else if (input1.equals(outVarNode)) {
|
else if (input1.equals(outVarNode)) {
|
||||||
|
@ -385,7 +386,7 @@ public class CallDepthChangeInfo {
|
||||||
|
|
||||||
// TODO: Modify return by normal stack shift....
|
// TODO: Modify return by normal stack shift....
|
||||||
if (flowType.isTerminal()) {
|
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.
|
// if the current stack depth is still bad, don't return a depth change.
|
||||||
|
@ -419,8 +420,9 @@ public class CallDepthChangeInfo {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private int getDefaultStackDepthChange(int depth) {
|
private int getDefaultStackDepthChange(int depth) {
|
||||||
int callStackMod = program.getCompilerSpec().getCallStackMod();
|
PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention();
|
||||||
int callStackShift = program.getCompilerSpec().getCallStackShift();
|
int callStackMod = defaultModel.getExtrapop();
|
||||||
|
int callStackShift = defaultModel.getStackshift();
|
||||||
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
|
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
|
||||||
return callStackShift - callStackMod;
|
return callStackShift - callStackMod;
|
||||||
}
|
}
|
||||||
|
@ -578,8 +580,8 @@ public class CallDepthChangeInfo {
|
||||||
FlowType flow = instr.getFlowType();
|
FlowType flow = instr.getFlowType();
|
||||||
if (!flow.isCall()) {
|
if (!flow.isCall()) {
|
||||||
Address[] flows = instr.getFlows();
|
Address[] flows = instr.getFlows();
|
||||||
for (int i = 0; i < flows.length; i++) {
|
for (Address flow2 : flows) {
|
||||||
st.push(flows[i]);
|
st.push(flow2);
|
||||||
st.push(new Integer(stackPointerDepth));
|
st.push(new Integer(stackPointerDepth));
|
||||||
st.push(stackOK);
|
st.push(stackOK);
|
||||||
}
|
}
|
||||||
|
@ -653,7 +655,7 @@ public class CallDepthChangeInfo {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int purge = (short) program.getCompilerSpec().getCallStackMod();
|
int purge = (short) program.getCompilerSpec().getDefaultCallingConvention().getExtrapop();
|
||||||
final boolean possiblePurge = purge == -1 || purge > 3200 || purge < -3200;
|
final boolean possiblePurge = purge == -1 || purge > 3200 || purge < -3200;
|
||||||
|
|
||||||
// follow all flows building up context
|
// follow all flows building up context
|
||||||
|
@ -948,8 +950,8 @@ public class CallDepthChangeInfo {
|
||||||
FlowType flow = instr.getFlowType();
|
FlowType flow = instr.getFlowType();
|
||||||
if (!flow.isCall()) {
|
if (!flow.isCall()) {
|
||||||
Address[] flows = instr.getFlows();
|
Address[] flows = instr.getFlows();
|
||||||
for (int i = 0; i < flows.length; i++) {
|
for (Address flow2 : flows) {
|
||||||
st.push(flows[i]);
|
st.push(flow2);
|
||||||
st.push(new Integer(stackPointerDepth));
|
st.push(new Integer(stackPointerDepth));
|
||||||
st.push(stackOK);
|
st.push(stackOK);
|
||||||
}
|
}
|
||||||
|
@ -1027,11 +1029,11 @@ public class CallDepthChangeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to find a call destination that the stack frame is known
|
// try to find a call destination that the stack frame is known
|
||||||
for (int i = 0; i < flows.length; i++) {
|
for (Address flow : flows) {
|
||||||
if (flows[i] == null) {
|
if (flow == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Function func = program.getListing().getFunctionAt(flows[i]);
|
Function func = program.getListing().getFunctionAt(flow);
|
||||||
if (func != null) {
|
if (func != null) {
|
||||||
int purge = func.getStackPurgeSize();
|
int purge = func.getStackPurgeSize();
|
||||||
if (func.isStackPurgeSizeValid() && purge != Function.UNKNOWN_STACK_DEPTH_CHANGE &&
|
if (func.isStackPurgeSizeValid() && purge != Function.UNKNOWN_STACK_DEPTH_CHANGE &&
|
||||||
|
|
|
@ -17,15 +17,16 @@ package ghidra.app.cmd.function;
|
||||||
|
|
||||||
import ghidra.framework.cmd.BackgroundCommand;
|
import ghidra.framework.cmd.BackgroundCommand;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.DomainObject;
|
||||||
import ghidra.program.model.address.AddressSet;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
|
||||||
import ghidra.program.model.lang.Processor;
|
import ghidra.program.model.lang.Processor;
|
||||||
|
import ghidra.program.model.lang.PrototypeModel;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.scalar.Scalar;
|
import ghidra.program.model.scalar.Scalar;
|
||||||
import ghidra.program.model.symbol.FlowType;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.symbol.Reference;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,13 +35,17 @@ import ghidra.util.task.TaskMonitor;
|
||||||
public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||||
private AddressSetView entryPoints;
|
private AddressSetView entryPoints;
|
||||||
private Program program;
|
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.
|
* Constructs a new command for analyzing the Stack.
|
||||||
* @param entries and address set indicating the entry points of functions that have
|
* @param entries and address set indicating the entry points of functions that have
|
||||||
* stacks to be analyzed.
|
* 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) {
|
public FunctionPurgeAnalysisCmd(AddressSetView entries) {
|
||||||
super("Compute Function Purge", true, true, false);
|
super("Compute Function Purge", true, true, false);
|
||||||
|
@ -56,12 +61,16 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||||
program = (Program) obj;
|
program = (Program) obj;
|
||||||
|
|
||||||
Processor processor = program.getLanguage().getProcessor();
|
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"))) {
|
!processor.equals(Processor.findOrPossiblyCreateProcessor("x86"))) {
|
||||||
Msg.error(this,
|
Msg.error(this,
|
||||||
"Unsupported operation for language " + program.getLanguage().getLanguageID());
|
"Unsupported operation for language " + program.getLanguage().getLanguageID());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (defaultSpace instanceof SegmentedAddressSpace) { // For 16-bit x86, prepare to establish near/fear calling convention models
|
||||||
|
setupNearFarModels();
|
||||||
|
}
|
||||||
|
|
||||||
AddressSetView set = entryPoints;
|
AddressSetView set = entryPoints;
|
||||||
|
|
||||||
|
@ -95,6 +104,52 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||||
return true;
|
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.
|
* Analyze a function to build a stack frame based on stack references.
|
||||||
* @param function function to be analyzed
|
* @param function function to be analyzed
|
||||||
|
@ -104,39 +159,120 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||||
*/
|
*/
|
||||||
private void analyzeFunction(Function function, TaskMonitor monitor) throws CancelledException {
|
private void analyzeFunction(Function function, TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
int purge = -1;
|
if (function == null) {
|
||||||
|
return;
|
||||||
if (function != null) {
|
|
||||||
purge = function.getStackPurgeSize();
|
|
||||||
}
|
}
|
||||||
|
int purge = function.getStackPurgeSize();
|
||||||
if (purge == -1 || purge > 128 || purge < -128) {
|
if (purge == -1 || purge > 128 || purge < -128) {
|
||||||
purge = locatePurgeReturn(program, function, monitor);
|
Instruction purgeInstruction = locatePurgeInstruction(function, monitor);
|
||||||
// if couldn't find it, don't set it!
|
if (purgeInstruction != null) {
|
||||||
if (purge != -1) {
|
purge = getPurgeValue(purgeInstruction);
|
||||||
function.setStackPurgeSize(purge);
|
// 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) {
|
private void setPrototypeModel(Function function, Instruction purgeInstruction) {
|
||||||
AddressSetView body = func.getBody();
|
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);
|
private Instruction locatePurgeInstruction(Function func, TaskMonitor monitor) {
|
||||||
if (returnPurge != -1) {
|
AddressSetView body = func.getBody();
|
||||||
return returnPurge;
|
Instruction purgeInstruction;
|
||||||
|
|
||||||
|
purgeInstruction = findPurgeInstruction(body);
|
||||||
|
if (purgeInstruction != null) {
|
||||||
|
return purgeInstruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
// look harder, maybe something wrong with body, compute with flow.
|
// look harder, maybe something wrong with body, compute with flow.
|
||||||
body = CreateFunctionCmd.getFunctionBody(program, func.getEntryPoint(), monitor);
|
body = CreateFunctionCmd.getFunctionBody(program, func.getEntryPoint(), monitor);
|
||||||
returnPurge = findReturnPurge(program, body);
|
return findPurgeInstruction(body);
|
||||||
|
|
||||||
return returnPurge;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
InstructionIterator iter = program.getListing().getInstructions(body, true);
|
||||||
int count = 2048;
|
int count = 2048;
|
||||||
|
Instruction backupPurge = null;
|
||||||
while (iter.hasNext() && count > 0) {
|
while (iter.hasNext() && count > 0) {
|
||||||
count--;
|
count--;
|
||||||
Instruction instr = iter.next();
|
Instruction instr = iter.next();
|
||||||
|
@ -144,33 +280,15 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||||
FlowType ftype = instr.getFlowType();
|
FlowType ftype = instr.getFlowType();
|
||||||
if (ftype.isTerminal()) {
|
if (ftype.isTerminal()) {
|
||||||
if (instr.getMnemonicString().compareToIgnoreCase("ret") == 0) {
|
if (instr.getMnemonicString().compareToIgnoreCase("ret") == 0) {
|
||||||
tempPurge = 0;
|
return instr;
|
||||||
Scalar scalar = instr.getScalar(0);
|
|
||||||
if (scalar != null) {
|
|
||||||
tempPurge = (int) scalar.getSignedValue();
|
|
||||||
return tempPurge;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else if (ftype.isCall()) {
|
else if (ftype.isCall()) {
|
||||||
// is an override call-return, terminal/call
|
backupPurge = instr; // Use as last resort, if we can't find RET
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return backupPurge;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,8 +169,9 @@ public class FunctionResultStateStackAnalysisCmd extends BackgroundCommand {
|
||||||
|
|
||||||
// Process all the functions identified as needing stack analysis.
|
// Process all the functions identified as needing stack analysis.
|
||||||
// The list will have the lowest level functions analyzed first.
|
// The list will have the lowest level functions analyzed first.
|
||||||
int default_extraPop = program.getCompilerSpec().getCallStackMod();
|
PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention();
|
||||||
int default_stackshift = program.getCompilerSpec().getCallStackShift();
|
int default_extraPop = defaultModel.getExtrapop();
|
||||||
|
int default_stackshift = defaultModel.getStackshift();
|
||||||
|
|
||||||
while (!funcList.isEmpty()) {
|
while (!funcList.isEmpty()) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
|
@ -256,19 +257,22 @@ public class FunctionResultStateStackAnalysisCmd extends BackgroundCommand {
|
||||||
int storageSpaceID, RefType refType, TaskMonitor monitor1)
|
int storageSpaceID, RefType refType, TaskMonitor monitor1)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
if (instrOpIndex < 0)
|
if (instrOpIndex < 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
Address fromAddr = op.getSeqnum().getTarget();
|
Address fromAddr = op.getSeqnum().getTarget();
|
||||||
Instruction instr = listing.getInstructionAt(fromAddr);
|
Instruction instr = listing.getInstructionAt(fromAddr);
|
||||||
if (instr == null)
|
if (instr == null) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
Address stackAddr = addrFactory.getStackSpace().getAddress(stackOffset);
|
Address stackAddr = addrFactory.getStackSpace().getAddress(stackOffset);
|
||||||
RefType rt = refType;
|
RefType rt = refType;
|
||||||
Reference ref = refMgr.getReference(fromAddr, stackAddr, instrOpIndex);
|
Reference ref = refMgr.getReference(fromAddr, stackAddr, instrOpIndex);
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
RefType existingRefType = ref.getReferenceType();
|
RefType existingRefType = ref.getReferenceType();
|
||||||
if (existingRefType == rt)
|
if (existingRefType == rt) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (existingRefType == RefType.READ || existingRefType == RefType.WRITE) {
|
if (existingRefType == RefType.READ || existingRefType == RefType.WRITE) {
|
||||||
rt = RefType.READ_WRITE;
|
rt = RefType.READ_WRITE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
package ghidra.app.util.bin.format.ne;
|
||||||
|
|
||||||
import generic.continues.*;
|
import java.io.IOException;
|
||||||
import ghidra.app.util.bin.*;
|
|
||||||
import ghidra.app.util.bin.format.*;
|
|
||||||
import ghidra.app.util.bin.format.mz.*;
|
|
||||||
|
|
||||||
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).
|
* A class to manage loading New Executables (NE).
|
||||||
|
@ -34,17 +34,20 @@ public class NewExecutable {
|
||||||
private WindowsHeader winHeader;
|
private WindowsHeader winHeader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new instance of an new executable.
|
* Constructs a new instance of an new executable.
|
||||||
* @param bp the byte provider
|
* @param factory is the object factory to bundle with the reader
|
||||||
* @throws IOException if an I/O error occurs.
|
* @param bp the byte provider
|
||||||
*/
|
* @param baseAddr the image base of the executable
|
||||||
public NewExecutable(GenericFactory factory, ByteProvider bp) throws IOException {
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
public NewExecutable(GenericFactory factory, ByteProvider bp, SegmentedAddress baseAddr)
|
||||||
|
throws IOException {
|
||||||
reader = new FactoryBundledWithBinaryReader(factory, bp, true);
|
reader = new FactoryBundledWithBinaryReader(factory, bp, true);
|
||||||
dosHeader = DOSHeader.createDOSHeader(reader);
|
dosHeader = DOSHeader.createDOSHeader(reader);
|
||||||
|
|
||||||
if (dosHeader.isDosSignature()) {
|
if (dosHeader.isDosSignature()) {
|
||||||
try {
|
try {
|
||||||
winHeader = new WindowsHeader(reader, (short)dosHeader.e_lfanew());
|
winHeader = new WindowsHeader(reader, baseAddr, (short) dosHeader.e_lfanew());
|
||||||
}
|
}
|
||||||
catch (InvalidWindowsHeaderException e) {
|
catch (InvalidWindowsHeaderException e) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 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;
|
import ghidra.util.Conv;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,7 +29,8 @@ import ghidra.util.Conv;
|
||||||
public class SegmentTable {
|
public class SegmentTable {
|
||||||
private Segment [] segments;
|
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();
|
long oldIndex = reader.getPointerIndex();
|
||||||
reader.setPointerIndex(Conv.shortToInt(index));
|
reader.setPointerIndex(Conv.shortToInt(index));
|
||||||
|
|
||||||
|
@ -39,14 +41,29 @@ public class SegmentTable {
|
||||||
|
|
||||||
segments = new Segment[segmentCountInt];
|
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) {
|
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;
|
int size = segments[i].getMinAllocSize() & 0xffff;
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
size = 0x10000;
|
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);
|
reader.setPointerIndex(oldIndex);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
package ghidra.app.util.bin.format.ne;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.*;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
|
||||||
|
import ghidra.program.model.address.SegmentedAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to represent and parse the
|
* A class to represent and parse the
|
||||||
* Windows new-style executable (NE) header.
|
* Windows new-style executable (NE) header.
|
||||||
|
@ -39,20 +40,22 @@ public class WindowsHeader {
|
||||||
private NonResidentNameTable nonResNameTable;
|
private NonResidentNameTable nonResNameTable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param reader the binary reader
|
* @param reader the binary reader
|
||||||
* @param index the index where the windows headers begins
|
* @param baseAddr the image base address
|
||||||
* @throws InvalidWindowsHeaderException if the bytes defined in the binary reader at
|
* @param index the index where the windows headers begins
|
||||||
* the specified index do not constitute a valid windows header.
|
* @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 {
|
* @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);
|
this.infoBlock = new InformationBlock(reader, index);
|
||||||
|
|
||||||
short segTableIndex = (short)(infoBlock.getSegmentTableOffset() + index);
|
short segTableIndex = (short)(infoBlock.getSegmentTableOffset() + index);
|
||||||
this.segTable = new SegmentTable(reader,
|
this.segTable = new SegmentTable(reader,
|
||||||
segTableIndex,
|
baseAddr, segTableIndex, infoBlock.getSegmentCount(),
|
||||||
infoBlock.getSegmentCount(),
|
infoBlock.getSegmentAlignmentShiftCount());
|
||||||
infoBlock.getSegmentAlignmentShiftCount());
|
|
||||||
|
|
||||||
//if resource table offset == resident name table offset, then
|
//if resource table offset == resident name table offset, then
|
||||||
//we do not have any resources...
|
//we do not have any resources...
|
||||||
|
|
|
@ -892,14 +892,14 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||||
if (expSym.hasNoReturn()) {
|
if (expSym.hasNoReturn()) {
|
||||||
extFunc.setNoReturn(true);
|
extFunc.setNoReturn(true);
|
||||||
}
|
}
|
||||||
int stackShift = program.getCompilerSpec().getCallStackShift();
|
// TODO: This should not be done at time of import and should be done
|
||||||
if (stackShift == -1) {
|
// by a late running analyzer (e.g., stack analyzer) if no signature
|
||||||
stackShift = 0;
|
// 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;
|
// int numParams = expSym.getPurge() / 4;
|
||||||
// if (numParams > 0) {
|
// if (numParams > 0) {
|
||||||
// // HACK: assumes specific stack-based x86 convention
|
// // HACK: assumes specific stack-based x86 convention
|
||||||
|
|
|
@ -258,6 +258,11 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
||||||
int dataStart = dos.e_cparhdr() << 4;
|
int dataStart = dos.e_cparhdr() << 4;
|
||||||
|
|
||||||
HashMap<Address, Address> segMap = new HashMap<Address, Address>();
|
HashMap<Address, Address> segMap = new HashMap<Address, Address>();
|
||||||
|
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();
|
int numRelocationEntries = dos.e_crlc();
|
||||||
reader.setPointerIndex(relocationTableOffset);
|
reader.setPointerIndex(relocationTableOffset);
|
||||||
for (int i = 0; i < numRelocationEntries; i++) {
|
for (int i = 0; i < numRelocationEntries; i++) {
|
||||||
|
@ -290,17 +295,17 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
||||||
for (int i = 0; i < segStartList.size(); i++) {
|
for (int i = 0; i < segStartList.size(); i++) {
|
||||||
SegmentedAddress start = (SegmentedAddress) segStartList.get(i);
|
SegmentedAddress start = (SegmentedAddress) segStartList.get(i);
|
||||||
|
|
||||||
int readLoc = (int) (start.getOffset() - csStartEffective) + dataStart;
|
int readLoc = ((start.getSegment() << 4) - csStartEffective) + dataStart;
|
||||||
if (readLoc < 0) {
|
if (readLoc < 0) {
|
||||||
Msg.error(this, "Invalid read location " + readLoc);
|
Msg.error(this, "Invalid read location " + readLoc);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte bytes[] = null;
|
|
||||||
int numBytes = 0;
|
int numBytes = 0;
|
||||||
if ((i + 1) < segStartList.size()) {
|
if ((i + 1) < segStartList.size()) {
|
||||||
SegmentedAddress end = (SegmentedAddress) segStartList.get(i + 1);
|
SegmentedAddress end = (SegmentedAddress) segStartList.get(i + 1);
|
||||||
numBytes = (int) end.subtract(start);
|
int nextLoc = ((end.getSegment() << 4) - csStartEffective) + dataStart;
|
||||||
|
numBytes = nextLoc - readLoc;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// last segment length
|
// last segment length
|
||||||
|
@ -317,7 +322,6 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
||||||
numUninitBytes = calcNumBytes - numBytes;
|
numUninitBytes = calcNumBytes - numBytes;
|
||||||
}
|
}
|
||||||
if (numBytes > 0) {
|
if (numBytes > 0) {
|
||||||
bytes = reader.readByteArray(readLoc, numBytes);
|
|
||||||
MemoryBlockUtils.createInitializedBlock(program, false, "Seg_" + i, start,
|
MemoryBlockUtils.createInitializedBlock(program, false, "Seg_" + i, start,
|
||||||
fileBytes, readLoc, numBytes, "", "mz", true, true, true, log);
|
fileBytes, readLoc, numBytes, "", "mz", true, true, true, log);
|
||||||
}
|
}
|
||||||
|
@ -399,6 +403,7 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
||||||
symbolTable.createLabel(addr, ENTRY_NAME, SourceType.IMPORTED);
|
symbolTable.createLabel(addr, ENTRY_NAME, SourceType.IMPORTED);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
|
// Just skip if we can't create
|
||||||
}
|
}
|
||||||
|
|
||||||
symbolTable.addExternalEntryPoint(addr);
|
symbolTable.addExternalEntryPoint(addr);
|
||||||
|
|
|
@ -51,6 +51,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
||||||
|
|
||||||
private static final String TAB = " ";
|
private static final String TAB = " ";
|
||||||
private static final long MIN_BYTE_LENGTH = 4;
|
private static final long MIN_BYTE_LENGTH = 4;
|
||||||
|
private static final int SEGMENT_START = 0x1000;
|
||||||
|
|
||||||
private ArrayList<Address> entryPointList = new ArrayList<>();
|
private ArrayList<Address> entryPointList = new ArrayList<>();
|
||||||
private Comparator<String> comparator = new CallNameComparator();
|
private Comparator<String> comparator = new CallNameComparator();
|
||||||
|
@ -65,7 +66,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
||||||
if (provider.length() < MIN_BYTE_LENGTH) {
|
if (provider.length() < MIN_BYTE_LENGTH) {
|
||||||
return loadSpecs;
|
return loadSpecs;
|
||||||
}
|
}
|
||||||
NewExecutable ne = new NewExecutable(RethrowContinuesFactory.INSTANCE, provider);
|
NewExecutable ne = new NewExecutable(RethrowContinuesFactory.INSTANCE, provider, null);
|
||||||
WindowsHeader wh = ne.getWindowsHeader();
|
WindowsHeader wh = ne.getWindowsHeader();
|
||||||
if (wh != null) {
|
if (wh != null) {
|
||||||
List<QueryResult> results = QueryOpinionService.query(getName(),
|
List<QueryResult> results = QueryOpinionService.query(getName(),
|
||||||
|
@ -99,7 +100,9 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
||||||
// the original bytes.
|
// the original bytes.
|
||||||
MemoryBlockUtils.createFileBytes(prog, provider, monitor);
|
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();
|
WindowsHeader wh = ne.getWindowsHeader();
|
||||||
InformationBlock ib = wh.getInformationBlock();
|
InformationBlock ib = wh.getInformationBlock();
|
||||||
SegmentTable st = wh.getSegmentTable();
|
SegmentTable st = wh.getSegmentTable();
|
||||||
|
@ -113,8 +116,6 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
||||||
Listing listing = prog.getListing();
|
Listing listing = prog.getListing();
|
||||||
SymbolTable symbolTable = prog.getSymbolTable();
|
SymbolTable symbolTable = prog.getSymbolTable();
|
||||||
Memory memory = prog.getMemory();
|
Memory memory = prog.getMemory();
|
||||||
SegmentedAddressSpace space =
|
|
||||||
(SegmentedAddressSpace) prog.getAddressFactory().getDefaultAddressSpace();
|
|
||||||
ProgramContext context = prog.getProgramContext();
|
ProgramContext context = prog.getProgramContext();
|
||||||
RelocationTable relocTable = prog.getRelocationTable();
|
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,
|
private void processResourceTable(MessageLog log, Program program, ResourceTable rt,
|
||||||
SegmentedAddressSpace space, TaskMonitor monitor) throws IOException {
|
SegmentedAddressSpace space, TaskMonitor monitor) throws IOException {
|
||||||
Listing listing = program.getListing();
|
Listing listing = program.getListing();
|
||||||
|
@ -326,7 +322,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
||||||
Resource[] resources = type.getResources();
|
Resource[] resources = type.getResources();
|
||||||
for (Resource resource : resources) {
|
for (Resource resource : resources) {
|
||||||
|
|
||||||
int segidx = getNextAvailableSegment(program);
|
int segidx = space.getNextOpenSegment(program.getMemory().getMaxAddress());
|
||||||
Address addr = space.getAddress(segidx, 0);
|
Address addr = space.getAddress(segidx, 0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -417,7 +413,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
||||||
for (LengthStringSet name : names) {
|
for (LengthStringSet name : names) {
|
||||||
String[] callnames = getCallNamesForModule(name.getString(), mrt, st, imp);
|
String[] callnames = getCallNamesForModule(name.getString(), mrt, st, imp);
|
||||||
int length = callnames.length * pointerSize;
|
int length = callnames.length * pointerSize;
|
||||||
int segment = getNextAvailableSegment(program);
|
int segment = space.getNextOpenSegment(program.getMemory().getMaxAddress());
|
||||||
Address start = space.getAddress(segment, 0);
|
Address start = space.getAddress(segment, 0);
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
// This isn't a real block, just place holder addresses, so don't create an initialized block
|
// This isn't a real block, just place holder addresses, so don't create an initialized block
|
||||||
|
|
|
@ -176,10 +176,10 @@ public class ProgramMemoryUtil {
|
||||||
MemoryBlock[] blocks = mem.getBlocks();
|
MemoryBlock[] blocks = mem.getBlocks();
|
||||||
MemoryBlock[] tmpBlocks = new MemoryBlock[blocks.length];
|
MemoryBlock[] tmpBlocks = new MemoryBlock[blocks.length];
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < blocks.length; i++) {
|
for (MemoryBlock block : blocks) {
|
||||||
if ((blocks[i].isInitialized() && withBytes) ||
|
if ((block.isInitialized() && withBytes) ||
|
||||||
(!blocks[i].isInitialized() && !withBytes)) {
|
(!block.isInitialized() && !withBytes)) {
|
||||||
tmpBlocks[j++] = blocks[i];
|
tmpBlocks[j++] = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MemoryBlock[] typeBlocks = new MemoryBlock[j];
|
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
|
// 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;
|
SegmentedAddress segAddr = (SegmentedAddress) toAddress;
|
||||||
currentSegment = (short) segAddr.getSegment();
|
currentSegment = (short) segAddr.getSegment();
|
||||||
}
|
}
|
||||||
|
@ -322,10 +322,10 @@ public class ProgramMemoryUtil {
|
||||||
if (toAddress instanceof SegmentedAddress) {
|
if (toAddress instanceof SegmentedAddress) {
|
||||||
short offsetShort = memory.getShort(a);
|
short offsetShort = memory.getShort(a);
|
||||||
offsetShort &= offsetShort & 0xffff;
|
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
|
// 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) {
|
// if (offsetShort == shortCurrentOffset) {
|
||||||
//*** commenting this out is making it find the instances of 46 01's not the 0a 00's - closer though
|
//*** 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
|
// check for the case where the reference includes both the segment and offset
|
||||||
|
@ -441,8 +441,9 @@ public class ProgramMemoryUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ReferenceAddressPair rap : directReferenceList) {
|
for (ReferenceAddressPair rap : directReferenceList) {
|
||||||
if (monitor.isCancelled())
|
if (monitor.isCancelled()) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
Address fromAddr = rap.getSource();
|
Address fromAddr = rap.getSource();
|
||||||
if (!results.contains(fromAddr)) {
|
if (!results.contains(fromAddr)) {
|
||||||
results.add(fromAddr);
|
results.add(fromAddr);
|
||||||
|
@ -624,18 +625,18 @@ public class ProgramMemoryUtil {
|
||||||
byte maskBytes[] = null;
|
byte maskBytes[] = null;
|
||||||
|
|
||||||
MemoryBlock[] blocks = memory.getBlocks();
|
MemoryBlock[] blocks = memory.getBlocks();
|
||||||
for (int i = 0; i < blocks.length; i++) {
|
for (MemoryBlock block : blocks) {
|
||||||
if (!blocks[i].isInitialized()) {
|
if (!block.isInitialized()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (memoryRange != null &&
|
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
|
// skip blocks which do not correspond to currentSeg
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Address start = blocks[i].getStart();
|
Address start = block.getStart();
|
||||||
Address end = blocks[i].getEnd();
|
Address end = block.getEnd();
|
||||||
Address found = null;
|
Address found = null;
|
||||||
while (true) {
|
while (true) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
|
|
|
@ -1705,8 +1705,9 @@ public class SymbolicPropogator {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private int getDefaultStackDepthChange(Program prog, int depth) {
|
private int getDefaultStackDepthChange(Program prog, int depth) {
|
||||||
int callStackMod = prog.getCompilerSpec().getCallStackMod();
|
PrototypeModel defaultModel = prog.getCompilerSpec().getDefaultCallingConvention();
|
||||||
int callStackShift = prog.getCompilerSpec().getCallStackShift();
|
int callStackMod = defaultModel.getExtrapop();
|
||||||
|
int callStackShift = defaultModel.getStackshift();
|
||||||
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP) {
|
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||||
return callStackShift;
|
return callStackShift;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,14 +46,17 @@ public class ResultsState {
|
||||||
|
|
||||||
private static final Iterator<ContextState> emptyContextStateIterator =
|
private static final Iterator<ContextState> emptyContextStateIterator =
|
||||||
new Iterator<ContextState>() {
|
new Iterator<ContextState>() {
|
||||||
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ContextState next() {
|
public ContextState next() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void remove() {
|
public void remove() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -168,10 +171,12 @@ public class ResultsState {
|
||||||
|
|
||||||
stackGrowsNegative = program.getCompilerSpec().stackGrowsNegative();
|
stackGrowsNegative = program.getCompilerSpec().stackGrowsNegative();
|
||||||
Long stackOffset = currentPrototype.getStackParameterOffset();
|
Long stackOffset = currentPrototype.getStackParameterOffset();
|
||||||
if (stackOffset != null)
|
if (stackOffset != null) {
|
||||||
paramBaseStackOffset = stackOffset - currentPrototype.getStackshift();
|
paramBaseStackOffset = stackOffset - currentPrototype.getStackshift();
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
paramBaseStackOffset = null;
|
paramBaseStackOffset = null;
|
||||||
|
}
|
||||||
|
|
||||||
todoList.add(new BranchDestination(null, entryPt, entryState));
|
todoList.add(new BranchDestination(null, entryPt, entryState));
|
||||||
}
|
}
|
||||||
|
@ -253,9 +258,10 @@ public class ResultsState {
|
||||||
currentState = null;
|
currentState = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, ">>> At " + nextSeq.getTarget() + "/" + nextSeq.getTime() +
|
Msg.debug(this, ">>> At " + nextSeq.getTarget() + "/" + nextSeq.getTime() +
|
||||||
" " + instr);
|
" " + instr);
|
||||||
|
}
|
||||||
|
|
||||||
SequenceNumber lastSeq = flowFrom;
|
SequenceNumber lastSeq = flowFrom;
|
||||||
|
|
||||||
|
@ -272,9 +278,10 @@ public class ResultsState {
|
||||||
if (existingStates.containsKey(flowFrom)) {
|
if (existingStates.containsKey(flowFrom)) {
|
||||||
// TODO: We have processed this flow before
|
// TODO: We have processed this flow before
|
||||||
// TODO: Should we compare existingState with dest.initialState ?
|
// TODO: Should we compare existingState with dest.initialState ?
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Flow ignored - already processed: " +
|
Msg.debug(this, "Flow ignored - already processed: " +
|
||||||
flowFrom + " -> " + pcodeOp.getSeqnum());
|
flowFrom + " -> " + pcodeOp.getSeqnum());
|
||||||
|
}
|
||||||
instr = null; // signal - abort current flow
|
instr = null; // signal - abort current flow
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -284,9 +291,10 @@ public class ResultsState {
|
||||||
// Re-use existing state where register values match
|
// Re-use existing state where register values match
|
||||||
addState(flowFrom, otherEntryState);
|
addState(flowFrom, otherEntryState);
|
||||||
instr = null; // signal - abort current flow
|
instr = null; // signal - abort current flow
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Flow combined - similar state: " +
|
Msg.debug(this, "Flow combined - similar state: " +
|
||||||
flowFrom + " -> " + pcodeOp.getSeqnum());
|
flowFrom + " -> " + pcodeOp.getSeqnum());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,6 +393,7 @@ public class ResultsState {
|
||||||
|
|
||||||
private static Comparator<Object> CONTEXT_STATE_SET_SEQUENCE_COMPARATOR =
|
private static Comparator<Object> CONTEXT_STATE_SET_SEQUENCE_COMPARATOR =
|
||||||
new Comparator<Object>() {
|
new Comparator<Object>() {
|
||||||
|
@Override
|
||||||
public int compare(Object o1, Object o2) {
|
public int compare(Object o1, Object o2) {
|
||||||
ContextStateSet set = (ContextStateSet) o1;
|
ContextStateSet set = (ContextStateSet) o1;
|
||||||
SequenceNumber seq = (SequenceNumber) o2;
|
SequenceNumber seq = (SequenceNumber) o2;
|
||||||
|
@ -468,14 +477,16 @@ public class ResultsState {
|
||||||
private ContextState performInlineCall(Address inlineCallAddress, ContextState currentState,
|
private ContextState performInlineCall(Address inlineCallAddress, ContextState currentState,
|
||||||
TaskMonitor monitor) throws CancelledException {
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "*** Start Inline Call to " + inlineCallAddress + " ***");
|
Msg.debug(this, "*** Start Inline Call to " + inlineCallAddress + " ***");
|
||||||
|
}
|
||||||
ResultsState inlineState =
|
ResultsState inlineState =
|
||||||
new ResultsState(new SequenceNumber(inlineCallAddress, 0), null, currentState,
|
new ResultsState(new SequenceNumber(inlineCallAddress, 0), null, currentState,
|
||||||
maintainInstructionResults);
|
maintainInstructionResults);
|
||||||
inlineState.processFunction(monitor);
|
inlineState.processFunction(monitor);
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "*** End Inline Call to " + inlineCallAddress + " ***");
|
Msg.debug(this, "*** End Inline Call to " + inlineCallAddress + " ***");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: How should multiple return states be handled ??
|
// TODO: How should multiple return states be handled ??
|
||||||
|
|
||||||
|
@ -746,9 +757,10 @@ public class ResultsState {
|
||||||
|
|
||||||
if (values[1].isConstant() && values[1].getOffset() == 0) {
|
if (values[1].isConstant() && values[1].getOffset() == 0) {
|
||||||
// TODO: This is a problem, since branch case may never be evaluated!
|
// TODO: This is a problem, since branch case may never be evaluated!
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Conditional Branch to " + inputs[0].getAddress() +
|
Msg.debug(this, "Conditional Branch to " + inputs[0].getAddress() +
|
||||||
" - Not taken due to false condition value");
|
" - Not taken due to false condition value");
|
||||||
|
}
|
||||||
break; // Fall-through case - assume that a pre-condition is steering the execution
|
break; // Fall-through case - assume that a pre-condition is steering the execution
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,16 +774,18 @@ public class ResultsState {
|
||||||
SequenceNumber dest =
|
SequenceNumber dest =
|
||||||
new SequenceNumber(seq.getTarget(), seq.getTime() +
|
new SequenceNumber(seq.getTarget(), seq.getTime() +
|
||||||
(int) inputs[0].getOffset());
|
(int) inputs[0].getOffset());
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Internal " +
|
Msg.debug(this, "Internal " +
|
||||||
(pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional " : "") +
|
(pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional " : "") +
|
||||||
"Branch to " + dest);
|
"Branch to " + dest);
|
||||||
|
}
|
||||||
todoList.add(new BranchDestination(pcodeOp.getSeqnum(), dest, currentState));
|
todoList.add(new BranchDestination(pcodeOp.getSeqnum(), dest, currentState));
|
||||||
}
|
}
|
||||||
else if (inputs[0].isAddress()) {
|
else if (inputs[0].isAddress()) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, (pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional "
|
Msg.debug(this, (pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional "
|
||||||
: "") + "Branch to " + inputs[0].getAddress());
|
: "") + "Branch to " + inputs[0].getAddress());
|
||||||
|
}
|
||||||
handleDirectFlow(pcodeOp, inputs[0].getAddress(), currentState, monitor);
|
handleDirectFlow(pcodeOp, inputs[0].getAddress(), currentState, monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -786,8 +800,9 @@ public class ResultsState {
|
||||||
AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace();
|
AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||||
Address destAddr =
|
Address destAddr =
|
||||||
space.getAddress(getUnsignedOffset(values[0], space.getPointerSize()));
|
space.getAddress(getUnsignedOffset(values[0], space.getPointerSize()));
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Branch to " + destAddr);
|
Msg.debug(this, "Branch to " + destAddr);
|
||||||
|
}
|
||||||
handleDirectFlow(pcodeOp, destAddr, currentState, monitor);
|
handleDirectFlow(pcodeOp, destAddr, currentState, monitor);
|
||||||
}
|
}
|
||||||
else if (values[0].isAddress()) {
|
else if (values[0].isAddress()) {
|
||||||
|
@ -798,32 +813,36 @@ public class ResultsState {
|
||||||
currentState.getEntryPoint().getTarget().getAddressSpace();
|
currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||||
Address destAddr =
|
Address destAddr =
|
||||||
space.getAddress(getUnsignedOffset(brOffset, space.getPointerSize()));
|
space.getAddress(getUnsignedOffset(brOffset, space.getPointerSize()));
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Indirect Branch to [" + values[0].getAddress() +
|
Msg.debug(this, "Indirect Branch to [" + values[0].getAddress() +
|
||||||
"] -> " + destAddr);
|
"] -> " + destAddr);
|
||||||
|
}
|
||||||
handleDirectFlow(pcodeOp, destAddr, currentState, monitor);
|
handleDirectFlow(pcodeOp, destAddr, currentState, monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"Indirect Branch to [" + values[0].toString(program.getLanguage()) +
|
"Indirect Branch to [" + values[0].toString(program.getLanguage()) +
|
||||||
"]");
|
"]");
|
||||||
|
}
|
||||||
handleIndirectFlow(pcodeOp, values[0], currentState, monitor);
|
handleIndirectFlow(pcodeOp, values[0], currentState, monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"Indirect Branch to [" + values[0].toString(program.getLanguage()) +
|
"Indirect Branch to [" + values[0].toString(program.getLanguage()) +
|
||||||
"]");
|
"]");
|
||||||
|
}
|
||||||
handleIndirectFlow(pcodeOp, values[0], currentState, monitor);
|
handleIndirectFlow(pcodeOp, values[0], currentState, monitor);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case PcodeOp.CALL: // A call with absolute address
|
case PcodeOp.CALL: // A call with absolute address
|
||||||
if (inputs[0].isAddress()) {
|
if (inputs[0].isAddress()) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Call to " + inputs[0].getAddress());
|
Msg.debug(this, "Call to " + inputs[0].getAddress());
|
||||||
|
}
|
||||||
handleCall(pcodeOp, null, inputs[0].getAddress(), currentState, monitor);
|
handleCall(pcodeOp, null, inputs[0].getAddress(), currentState, monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -839,8 +858,9 @@ public class ResultsState {
|
||||||
AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace();
|
AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||||
Address destAddr =
|
Address destAddr =
|
||||||
space.getAddress(getUnsignedOffset(values[0], space.getPointerSize()));
|
space.getAddress(getUnsignedOffset(values[0], space.getPointerSize()));
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Call to " + destAddr);
|
Msg.debug(this, "Call to " + destAddr);
|
||||||
|
}
|
||||||
handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor);
|
handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor);
|
||||||
}
|
}
|
||||||
else if (values[0].isAddress()) {
|
else if (values[0].isAddress()) {
|
||||||
|
@ -852,23 +872,26 @@ public class ResultsState {
|
||||||
currentState.getEntryPoint().getTarget().getAddressSpace();
|
currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||||
Address destAddr =
|
Address destAddr =
|
||||||
space.getAddress(getUnsignedOffset(callOffset, space.getPointerSize()));
|
space.getAddress(getUnsignedOffset(callOffset, space.getPointerSize()));
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Indirect Call to [" + values[0].getAddress() +
|
Msg.debug(this, "Indirect Call to [" + values[0].getAddress() +
|
||||||
"] -> " + destAddr);
|
"] -> " + destAddr);
|
||||||
|
}
|
||||||
handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor);
|
handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"Indirect Call to [" + values[0].toString(program.getLanguage()) +
|
"Indirect Call to [" + values[0].toString(program.getLanguage()) +
|
||||||
"]");
|
"]");
|
||||||
|
}
|
||||||
handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor);
|
handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"Indirect Call to [" + values[0].toString(program.getLanguage()) + "]");
|
"Indirect Call to [" + values[0].toString(program.getLanguage()) + "]");
|
||||||
|
}
|
||||||
handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor);
|
handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1737,8 +1760,9 @@ public class ResultsState {
|
||||||
BookmarkType.ERROR, "Instruction Expected", "Expected instruction at " + address);
|
BookmarkType.ERROR, "Instruction Expected", "Expected instruction at " + address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Disassemble at " + address);
|
Msg.debug(this, "Disassemble at " + address);
|
||||||
|
}
|
||||||
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
|
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
|
||||||
cmd.applyTo(program, monitor);
|
cmd.applyTo(program, monitor);
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
|
@ -1772,8 +1796,9 @@ public class ResultsState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (addRegister(reg, registersModified)) {
|
if (addRegister(reg, registersModified)) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "MODIFIED: " + reg + " = " + value);
|
Msg.debug(this, "MODIFIED: " + reg + " = " + value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Msg.debug(this, "SET: " + output + " = " + value);
|
Msg.debug(this, "SET: " + output + " = " + value);
|
||||||
|
@ -2068,10 +2093,11 @@ public class ResultsState {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Function not found at " + indirectPtr +
|
Msg.debug(this, "Function not found at " + indirectPtr +
|
||||||
" indirectly called from " + pcodeOp.getSeqnum().getTarget() +
|
" indirectly called from " + pcodeOp.getSeqnum().getTarget() +
|
||||||
" - call affects unknown");
|
" - call affects unknown");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2104,9 +2130,10 @@ public class ResultsState {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Function not found at " + destAddr + " called from " +
|
Msg.debug(this, "Function not found at " + destAddr + " called from " +
|
||||||
pcodeOp.getSeqnum().getTarget() + " - call affects unknown");
|
pcodeOp.getSeqnum().getTarget() + " - call affects unknown");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2133,10 +2160,11 @@ public class ResultsState {
|
||||||
// Must invalidate return varnode
|
// Must invalidate return varnode
|
||||||
DataType returnType = null;
|
DataType returnType = null;
|
||||||
if (func == null) {
|
if (func == null) {
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"No function at " + destAddr + " called from " + calledFrom.getTarget() +
|
"No function at " + destAddr + " called from " + calledFrom.getTarget() +
|
||||||
" - default return/affects assumed");
|
" - default return/affects assumed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
returnType = func.getReturnType();
|
returnType = func.getReturnType();
|
||||||
|
@ -2147,8 +2175,9 @@ public class ResultsState {
|
||||||
|
|
||||||
VariableStorage retStorage = callingConvention.getReturnLocation(returnType, program);
|
VariableStorage retStorage = callingConvention.getReturnLocation(returnType, program);
|
||||||
Varnode varnode = null;
|
Varnode varnode = null;
|
||||||
if (retStorage.isValid() && (retStorage.getVarnodeCount()==1))
|
if (retStorage.isValid() && (retStorage.getVarnodeCount()==1)) {
|
||||||
varnode = retStorage.getFirstVarnode();
|
varnode = retStorage.getFirstVarnode();
|
||||||
|
}
|
||||||
if (varnode != null) {
|
if (varnode != null) {
|
||||||
// invalidate stored value
|
// invalidate stored value
|
||||||
currentState.store(varnode, getInvalidatedVarnode(calledFrom, varnode));
|
currentState.store(varnode, getInvalidatedVarnode(calledFrom, varnode));
|
||||||
|
@ -2183,9 +2212,10 @@ public class ResultsState {
|
||||||
if (purge == Function.UNKNOWN_STACK_DEPTH_CHANGE ||
|
if (purge == Function.UNKNOWN_STACK_DEPTH_CHANGE ||
|
||||||
purge == Function.INVALID_STACK_DEPTH_CHANGE) {
|
purge == Function.INVALID_STACK_DEPTH_CHANGE) {
|
||||||
String name = func != null ? func.getName() : ("at " + destAddr);
|
String name = func != null ? func.getName() : ("at " + destAddr);
|
||||||
if (DEBUG)
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Stack purge unknown for function " + name + " called from " +
|
Msg.debug(this, "Stack purge unknown for function " + name + " called from " +
|
||||||
calledFrom.getTarget() + " - stack pointer invalidated");
|
calledFrom.getTarget() + " - stack pointer invalidated");
|
||||||
|
}
|
||||||
currentState.store(getStackPointerVarnode(),
|
currentState.store(getStackPointerVarnode(),
|
||||||
getInvalidatedVarnode(calledFrom, getStackPointerVarnode()));
|
getInvalidatedVarnode(calledFrom, getStackPointerVarnode()));
|
||||||
return;
|
return;
|
||||||
|
@ -2255,8 +2285,9 @@ public class ResultsState {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private static int getDefaultStackDepthChange(Program depthProgram, int depth) {
|
private static int getDefaultStackDepthChange(Program depthProgram, int depth) {
|
||||||
int callStackMod = depthProgram.getCompilerSpec().getCallStackMod();
|
PrototypeModel defaultModel = depthProgram.getCompilerSpec().getDefaultCallingConvention();
|
||||||
int callStackShift = depthProgram.getCompilerSpec().getCallStackShift();
|
int callStackMod = defaultModel.getExtrapop();
|
||||||
|
int callStackShift = defaultModel.getStackshift();
|
||||||
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
|
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
|
||||||
return callStackShift - callStackMod;
|
return callStackShift - callStackMod;
|
||||||
}
|
}
|
||||||
|
|
|
@ -962,32 +962,35 @@ void Architecture::parseProcessorConfig(DocumentStorage &store)
|
||||||
List::const_iterator iter;
|
List::const_iterator iter;
|
||||||
|
|
||||||
for(iter=list.begin();iter!=list.end();++iter) {
|
for(iter=list.begin();iter!=list.end();++iter) {
|
||||||
if ((*iter)->getName() == "programcounter") {
|
const string &elname( (*iter)->getName() );
|
||||||
|
if (elname == "programcounter") {
|
||||||
}
|
}
|
||||||
else if ((*iter)->getName() == "volatile")
|
else if (elname == "volatile")
|
||||||
parseVolatile(*iter);
|
parseVolatile(*iter);
|
||||||
else if ((*iter)->getName() == "incidentalcopy")
|
else if (elname == "incidentalcopy")
|
||||||
parseIncidentalCopy(*iter);
|
parseIncidentalCopy(*iter);
|
||||||
else if ((*iter)->getName() == "context_data")
|
else if (elname == "context_data")
|
||||||
context->restoreFromSpec(*iter,this);
|
context->restoreFromSpec(*iter,this);
|
||||||
else if ((*iter)->getName() == "jumpassist")
|
else if (elname == "jumpassist")
|
||||||
userops.parseJumpAssist(*iter, this);
|
userops.parseJumpAssist(*iter, this);
|
||||||
else if ((*iter)->getName() == "register_data") {
|
else if (elname == "segmentop")
|
||||||
|
userops.parseSegmentOp(*iter,this);
|
||||||
|
else if (elname == "register_data") {
|
||||||
}
|
}
|
||||||
else if ((*iter)->getName() == "segmented_address") {
|
else if (elname == "segmented_address") {
|
||||||
}
|
}
|
||||||
else if ((*iter)->getName() == "default_symbols") {
|
else if (elname == "default_symbols") {
|
||||||
}
|
}
|
||||||
else if ((*iter)->getName() == "default_memory_blocks") {
|
else if (elname == "default_memory_blocks") {
|
||||||
}
|
}
|
||||||
else if ((*iter)->getName() == "address_shift_amount") {
|
else if (elname == "address_shift_amount") {
|
||||||
}
|
}
|
||||||
else if ((*iter)->getName() == "properties") {
|
else if (elname == "properties") {
|
||||||
}
|
}
|
||||||
else if ((*iter)->getName() == "data_space") {
|
else if (elname == "data_space") {
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw LowlevelError("Unknown element in <processor_spec>: "+(*iter)->getName());
|
throw LowlevelError("Unknown element in <processor_spec>: "+elname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1135,7 +1138,7 @@ void Architecture::init(DocumentStorage &store)
|
||||||
fillinReadOnlyFromLoader();
|
fillinReadOnlyFromLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point)
|
Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point,uintb &fullEncoding)
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 innersz = segop->getInnerSize();
|
int4 innersz = segop->getInnerSize();
|
||||||
|
@ -1145,6 +1148,7 @@ Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point)
|
||||||
// (as with near pointers)
|
// (as with near pointers)
|
||||||
if (segop->getResolve().space != (AddrSpace *)0) {
|
if (segop->getResolve().space != (AddrSpace *)0) {
|
||||||
uintb base = glb->context->getTrackedValue(segop->getResolve(),point);
|
uintb base = glb->context->getTrackedValue(segop->getResolve(),point);
|
||||||
|
fullEncoding = (base << 8 * innersz) + (val & calc_mask(innersz));
|
||||||
vector<uintb> seginput;
|
vector<uintb> seginput;
|
||||||
seginput.push_back(val);
|
seginput.push_back(val);
|
||||||
seginput.push_back(base);
|
seginput.push_back(base);
|
||||||
|
@ -1153,6 +1157,7 @@ Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // For anything else, consider it a "far" pointer
|
else { // For anything else, consider it a "far" pointer
|
||||||
|
fullEncoding = val;
|
||||||
int4 outersz = segop->getBaseSize();
|
int4 outersz = segop->getBaseSize();
|
||||||
uintb base = (val >> 8*innersz) & calc_mask(outersz);
|
uintb base = (val >> 8*innersz) & calc_mask(outersz);
|
||||||
val = val & calc_mask(innersz);
|
val = val & calc_mask(innersz);
|
||||||
|
|
|
@ -284,7 +284,7 @@ public:
|
||||||
/// \param sp is the segmented space
|
/// \param sp is the segmented space
|
||||||
/// \param sop is the segment operator
|
/// \param sop is the segment operator
|
||||||
SegmentedResolver(Architecture *g,AddrSpace *sp,SegmentOp *sop) { glb=g; spc=sp; segop=sop; }
|
SegmentedResolver(Architecture *g,AddrSpace *sp,SegmentOp *sop) { glb=g; spc=sp; segop=sop; }
|
||||||
virtual Address resolve(uintb val,int4 sz,const Address &point);
|
virtual Address resolve(uintb val,int4 sz,const Address &point,uintb &fullEncoding);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The Translate object keeps track of address ranges for which
|
/// The Translate object keeps track of address ranges for which
|
||||||
|
|
|
@ -269,8 +269,14 @@ bool CastStrategyC::isSubpieceCast(Datatype *outtype,Datatype *intype,uint4 offs
|
||||||
(outmeta!=TYPE_PTR)&&
|
(outmeta!=TYPE_PTR)&&
|
||||||
(outmeta!=TYPE_FLOAT))
|
(outmeta!=TYPE_FLOAT))
|
||||||
return false;
|
return false;
|
||||||
if ((inmeta==TYPE_PTR)&&((outmeta!=TYPE_INT) && (outmeta!=TYPE_UINT)))
|
if (inmeta==TYPE_PTR) {
|
||||||
return false; //other casts don't make sense for pointers
|
if (outmeta == TYPE_PTR) {
|
||||||
|
if (outtype->getSize() < intype->getSize())
|
||||||
|
return true; // Cast from far pointer to near pointer
|
||||||
|
}
|
||||||
|
if ((outmeta!=TYPE_INT) && (outmeta!=TYPE_UINT))
|
||||||
|
return false; //other casts don't make sense for pointers
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -827,14 +827,14 @@ int4 ActionShadowVar::apply(Funcdata &data)
|
||||||
/// \param rampoint will hold the Address of the resolved symbol
|
/// \param rampoint will hold the Address of the resolved symbol
|
||||||
/// \param data is the function being analyzed
|
/// \param data is the function being analyzed
|
||||||
/// \return the recovered symbol or NULL
|
/// \return the recovered symbol or NULL
|
||||||
SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,Address &rampoint,Funcdata &data)
|
SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,Address &rampoint,uintb &fullEncoding,Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
bool needexacthit;
|
bool needexacthit;
|
||||||
Architecture *glb = data.getArch();
|
Architecture *glb = data.getArch();
|
||||||
Varnode *outvn;
|
Varnode *outvn;
|
||||||
if (vn->getType()->getMetatype() == TYPE_PTR) { // Are we explicitly marked as a pointer
|
if (vn->getType()->getMetatype() == TYPE_PTR) { // Are we explicitly marked as a pointer
|
||||||
rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr());
|
rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr(),fullEncoding);
|
||||||
needexacthit = false;
|
needexacthit = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -881,7 +881,7 @@ SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op
|
||||||
// Check if the constant looks like a single bit or mask
|
// Check if the constant looks like a single bit or mask
|
||||||
if (bit_transitions(vn->getOffset(),vn->getSize()) < 3)
|
if (bit_transitions(vn->getOffset(),vn->getSize()) < 3)
|
||||||
return (SymbolEntry *)0;
|
return (SymbolEntry *)0;
|
||||||
rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr());
|
rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr(),fullEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rampoint.isInvalid()) return (SymbolEntry *)0;
|
if (rampoint.isInvalid()) return (SymbolEntry *)0;
|
||||||
|
@ -943,10 +943,11 @@ int4 ActionConstantPtr::apply(Funcdata &data)
|
||||||
else if ((opc == CPUI_PTRSUB)||(opc==CPUI_PTRADD))
|
else if ((opc == CPUI_PTRSUB)||(opc==CPUI_PTRADD))
|
||||||
continue;
|
continue;
|
||||||
Address rampoint;
|
Address rampoint;
|
||||||
entry = isPointer(rspc,vn,op,rampoint,data);
|
uintb fullEncoding;
|
||||||
|
entry = isPointer(rspc,vn,op,rampoint,fullEncoding,data);
|
||||||
vn->setPtrCheck(); // Set check flag AFTER searching for symbol
|
vn->setPtrCheck(); // Set check flag AFTER searching for symbol
|
||||||
if (entry != (SymbolEntry *)0) {
|
if (entry != (SymbolEntry *)0) {
|
||||||
data.spacebaseConstant(op,slot,entry,rampoint,vn->getOffset(),vn->getSize());
|
data.spacebaseConstant(op,slot,entry,rampoint,fullEncoding,vn->getSize());
|
||||||
if ((opc == CPUI_INT_ADD)&&(slot==1))
|
if ((opc == CPUI_INT_ADD)&&(slot==1))
|
||||||
data.opSwapInput(op,0,1);
|
data.opSwapInput(op,0,1);
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
|
@ -162,7 +162,7 @@ public:
|
||||||
/// \brief Check for constants, with pointer type, that correspond to global symbols
|
/// \brief Check for constants, with pointer type, that correspond to global symbols
|
||||||
class ActionConstantPtr : public Action {
|
class ActionConstantPtr : public Action {
|
||||||
int4 localcount; ///< Number of passes made for this function
|
int4 localcount; ///< Number of passes made for this function
|
||||||
static SymbolEntry *isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,Address &rampoint,Funcdata &data);
|
static SymbolEntry *isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,Address &rampoint,uintb &fullEncoding,Funcdata &data);
|
||||||
public:
|
public:
|
||||||
ActionConstantPtr(const string &g) : Action(0,"constantptr",g) {} ///< Constructor
|
ActionConstantPtr(const string &g) : Action(0,"constantptr",g) {} ///< Constructor
|
||||||
virtual void reset(Funcdata &data) { localcount = 0; }
|
virtual void reset(Funcdata &data) { localcount = 0; }
|
||||||
|
|
|
@ -333,7 +333,7 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const
|
||||||
outvn = outvn2;
|
outvn = outvn2;
|
||||||
opInsertBefore(extraop,op);
|
opInsertBefore(extraop,op);
|
||||||
}
|
}
|
||||||
if (sz != origsize) { // There is a change in size from address -> varnode
|
if (sz < origsize) { // The new constant is smaller than the original varnode, so we extend it
|
||||||
PcodeOp *zextop = newOp(1,op->getAddr());
|
PcodeOp *zextop = newOp(1,op->getAddr());
|
||||||
Varnode *outvn2 = newUniqueOut(origsize,zextop);
|
Varnode *outvn2 = newUniqueOut(origsize,zextop);
|
||||||
opSetOpcode(zextop,CPUI_INT_ZEXT); // Create an extension to get back to original varnode size
|
opSetOpcode(zextop,CPUI_INT_ZEXT); // Create an extension to get back to original varnode size
|
||||||
|
@ -341,6 +341,15 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const
|
||||||
opInsertBefore(zextop,op);
|
opInsertBefore(zextop,op);
|
||||||
outvn = outvn2;
|
outvn = outvn2;
|
||||||
}
|
}
|
||||||
|
else if (origsize < sz) { // The new constant is bigger than the original varnode, truncate it
|
||||||
|
PcodeOp *subOp = newOp(2,op->getAddr());
|
||||||
|
Varnode *outvn3 = newUniqueOut(origsize,subOp);
|
||||||
|
opSetOpcode(subOp,CPUI_SUBPIECE);
|
||||||
|
opSetInput(subOp,outvn,0);
|
||||||
|
opSetInput(subOp,newConstant(4, 0), 1); // Take least significant piece
|
||||||
|
opInsertBefore(subOp,op);
|
||||||
|
outvn = outvn3;
|
||||||
|
}
|
||||||
opSetInput(op,outvn,slot);
|
opSetInput(op,outvn,slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1403,7 +1403,8 @@ bool PrintC::pushPtrCharConstant(uintb val,const TypePointer *ct,const Varnode *
|
||||||
{
|
{
|
||||||
if (val==0) return false;
|
if (val==0) return false;
|
||||||
AddrSpace *spc = glb->getDefaultSpace();
|
AddrSpace *spc = glb->getDefaultSpace();
|
||||||
Address stringaddr = glb->resolveConstant(spc,val,ct->getSize(),op->getAddr());
|
uintb fullEncoding;
|
||||||
|
Address stringaddr = glb->resolveConstant(spc,val,ct->getSize(),op->getAddr(),fullEncoding);
|
||||||
if (stringaddr.isInvalid()) return false;
|
if (stringaddr.isInvalid()) return false;
|
||||||
if (!glb->symboltab->getGlobalScope()->isReadOnly(stringaddr,1,Address()))
|
if (!glb->symboltab->getGlobalScope()->isReadOnly(stringaddr,1,Address()))
|
||||||
return false; // Check that string location is readonly
|
return false; // Check that string location is readonly
|
||||||
|
|
|
@ -485,15 +485,27 @@ AddrSpace *AddrSpaceManager::getSpaceByShortcut(char sc) const
|
||||||
return (*iter).second;
|
return (*iter).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
Address AddrSpaceManager::resolveConstant(AddrSpace *spc,uintb val,int4 sz,const Address &point) const
|
/// \brief Resolve a native constant into an Address
|
||||||
|
///
|
||||||
|
/// If there is a special resolver for the AddrSpace, this is invoked, otherwise
|
||||||
|
/// basic wordsize conversion and wrapping is performed. If the address encoding is
|
||||||
|
/// partial (as in a \e near pointer) and the full encoding can be recovered, it is passed back.
|
||||||
|
/// \param spc is the space to generate the address from
|
||||||
|
/// \param val is the constant encoding of the address
|
||||||
|
/// \param sz is the size of the constant encoding
|
||||||
|
/// \param point is the context address (for recovering full encoding info if necessary)
|
||||||
|
/// \param fullEncoding is used to pass back the recovered full encoding of the pointer
|
||||||
|
/// \return the formal Address associated with the encoding
|
||||||
|
Address AddrSpaceManager::resolveConstant(AddrSpace *spc,uintb val,int4 sz,const Address &point,uintb &fullEncoding) const
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 ind = spc->getIndex();
|
int4 ind = spc->getIndex();
|
||||||
if (ind < resolvelist.size()) {
|
if (ind < resolvelist.size()) {
|
||||||
AddressResolver *resolve = resolvelist[ind];
|
AddressResolver *resolve = resolvelist[ind];
|
||||||
if (resolve != (AddressResolver *)0)
|
if (resolve != (AddressResolver *)0)
|
||||||
return resolve->resolve(val,sz,point);
|
return resolve->resolve(val,sz,point,fullEncoding);
|
||||||
}
|
}
|
||||||
|
fullEncoding = val;
|
||||||
val = AddrSpace::addressToByte(val,spc->getWordSize());
|
val = AddrSpace::addressToByte(val,spc->getWordSize());
|
||||||
val = spc->wrapOffset(val);
|
val = spc->wrapOffset(val);
|
||||||
return Address(spc,val);
|
return Address(spc,val);
|
||||||
|
|
|
@ -147,8 +147,9 @@ public:
|
||||||
/// \param val is constant to be resolved to an address
|
/// \param val is constant to be resolved to an address
|
||||||
/// \param sz is the size of \e val in context.
|
/// \param sz is the size of \e val in context.
|
||||||
/// \param point is the address at which this constant is being used
|
/// \param point is the address at which this constant is being used
|
||||||
|
/// \param fullEncoding is used to hold the full pointer encoding if \b val is a partial encoding
|
||||||
/// \return the resolved Address
|
/// \return the resolved Address
|
||||||
virtual Address resolve(uintb val,int4 sz,const Address &point)=0;
|
virtual Address resolve(uintb val,int4 sz,const Address &point,uintb &fullEncoding)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief A virtual space \e stack space
|
/// \brief A virtual space \e stack space
|
||||||
|
@ -249,7 +250,7 @@ public:
|
||||||
AddrSpace *getConstantSpace(void) const; ///< Get the constant space
|
AddrSpace *getConstantSpace(void) const; ///< Get the constant space
|
||||||
Address getConstant(uintb val) const; ///< Get a constant encoded as an Address
|
Address getConstant(uintb val) const; ///< Get a constant encoded as an Address
|
||||||
Address createConstFromSpace(AddrSpace *spc) const; ///< Create a constant address encoding an address space
|
Address createConstFromSpace(AddrSpace *spc) const; ///< Create a constant address encoding an address space
|
||||||
Address resolveConstant(AddrSpace *spc,uintb val,int4 sz,const Address &point) const; ///< Resolve native constant to address
|
Address resolveConstant(AddrSpace *spc,uintb val,int4 sz,const Address &point,uintb &fullEncoding) const;
|
||||||
int4 numSpaces(void) const; ///< Get the number of address spaces for this processor
|
int4 numSpaces(void) const; ///< Get the number of address spaces for this processor
|
||||||
AddrSpace *getSpace(int4 i) const; ///< Get an address space via its index
|
AddrSpace *getSpace(int4 i) const; ///< Get an address space via its index
|
||||||
AddrSpace *getNextSpaceInOrder(AddrSpace *spc) const; ///< Get the next \e contiguous address space
|
AddrSpace *getNextSpaceInOrder(AddrSpace *spc) const; ///< Get the next \e contiguous address space
|
||||||
|
|
|
@ -1124,13 +1124,17 @@ Datatype *TypeSpacebase::getSubType(uintb off,uintb *newoff) const
|
||||||
|
|
||||||
{
|
{
|
||||||
Scope *scope = getMap();
|
Scope *scope = getMap();
|
||||||
// uintb unoff = (uintb)(intb)off; // Make sure this is a sign-extension
|
off = AddrSpace::byteToAddress(off, spaceid->getWordSize()); // Convert from byte offset to address unit
|
||||||
Address addr(spaceid,spaceid->wrapOffset(off));
|
// It should always be the case that given offset represents a full encoding of the
|
||||||
|
// pointer, so the point of context is unused
|
||||||
|
Address nullPoint;
|
||||||
|
uintb fullEncoding;
|
||||||
|
Address addr = glb->resolveConstant(spaceid, off, spaceid->getAddrSize(), nullPoint, fullEncoding);
|
||||||
SymbolEntry *smallest;
|
SymbolEntry *smallest;
|
||||||
|
|
||||||
// Assume symbol being referenced is address tied,
|
// Assume symbol being referenced is address tied,
|
||||||
// so we use empty usepoint
|
// so we use empty usepoint
|
||||||
smallest = scope->queryContainer(addr,1,Address());
|
smallest = scope->queryContainer(addr,1,nullPoint);
|
||||||
|
|
||||||
if (smallest == (SymbolEntry *)0) {
|
if (smallest == (SymbolEntry *)0) {
|
||||||
*newoff = 0;
|
*newoff = 0;
|
||||||
|
@ -1167,7 +1171,8 @@ int4 TypeSpacebase::compareDependency(const Datatype &op) const
|
||||||
Address TypeSpacebase::getAddress(uintb off,int4 sz,const Address &point) const
|
Address TypeSpacebase::getAddress(uintb off,int4 sz,const Address &point) const
|
||||||
|
|
||||||
{
|
{
|
||||||
return glb->resolveConstant(spaceid,off,sz,point);
|
uintb fullEncoding;
|
||||||
|
return glb->resolveConstant(spaceid,off,sz,point,fullEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeSpacebase::saveXml(ostream &s) const
|
void TypeSpacebase::saveXml(ostream &s) const
|
||||||
|
|
|
@ -124,31 +124,6 @@ SegmentOp::SegmentOp(Architecture *g,const string &nm,int4 ind)
|
||||||
constresolve.space = (AddrSpace *)0;
|
constresolve.space = (AddrSpace *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Execute a stream of operations (OpFollow) given a starting input value
|
|
||||||
///
|
|
||||||
/// Each operation is performed in turn, with output from the previous becoming
|
|
||||||
/// input of the next. The final output is returned.
|
|
||||||
/// \param follow is the ordered set of operations to perform
|
|
||||||
/// \param input is the constant input for the first operation
|
|
||||||
/// \return the final constant output
|
|
||||||
uintb SegmentOp::executeSide(const vector<OpFollow> &follow,uintb input)
|
|
||||||
|
|
||||||
{
|
|
||||||
for(int4 i=0;i<follow.size();++i) {
|
|
||||||
switch(follow[i].opc) {
|
|
||||||
case CPUI_INT_AND:
|
|
||||||
input &= follow[i].val;
|
|
||||||
break;
|
|
||||||
case CPUI_INT_LEFT:
|
|
||||||
input <<= follow[i].val;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SegmentOp::unify(Funcdata &data,PcodeOp *op,
|
bool SegmentOp::unify(Funcdata &data,PcodeOp *op,
|
||||||
vector<Varnode *> &bindlist) const
|
vector<Varnode *> &bindlist) const
|
||||||
{
|
{
|
||||||
|
@ -163,7 +138,7 @@ bool SegmentOp::unify(Funcdata &data,PcodeOp *op,
|
||||||
if (op->getIn(0)->getOffset() != useropindex) return false;
|
if (op->getIn(0)->getOffset() != useropindex) return false;
|
||||||
if (op->numInput() != 3) return false;
|
if (op->numInput() != 3) return false;
|
||||||
innervn = op->getIn(1);
|
innervn = op->getIn(1);
|
||||||
if (basepresent) {
|
if (baseinsize != 0) {
|
||||||
basevn = op->getIn(1);
|
basevn = op->getIn(1);
|
||||||
innervn = op->getIn(2);
|
innervn = op->getIn(2);
|
||||||
if (basevn->isConstant())
|
if (basevn->isConstant())
|
||||||
|
@ -181,40 +156,23 @@ bool SegmentOp::unify(Funcdata &data,PcodeOp *op,
|
||||||
uintb SegmentOp::execute(const vector<uintb> &input) const
|
uintb SegmentOp::execute(const vector<uintb> &input) const
|
||||||
|
|
||||||
{
|
{
|
||||||
uintb base,inner;
|
ExecutablePcode *pcodeScript = (ExecutablePcode *)glb->pcodeinjectlib->getPayload(injectId);
|
||||||
|
return pcodeScript->evaluate(input);
|
||||||
if (basepresent)
|
|
||||||
base = executeSide(basefollow,input[1]);
|
|
||||||
else
|
|
||||||
base = 0;
|
|
||||||
|
|
||||||
inner = executeSide(innerfollow,input[0]);
|
|
||||||
return (base+inner);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SegmentOp::restoreXml(const Element *el)
|
void SegmentOp::restoreXml(const Element *el)
|
||||||
|
|
||||||
{
|
{
|
||||||
spc = glb->getSpaceByName(el->getAttributeValue("space"));
|
spc = glb->getSpaceByName(el->getAttributeValue("space"));
|
||||||
|
injectId = -1;
|
||||||
baseinsize = 0;
|
baseinsize = 0;
|
||||||
innerinsize = 0;
|
innerinsize = 0;
|
||||||
bool userdefined = false;
|
bool userdefined = false;
|
||||||
forcesegment = true;
|
|
||||||
supportsfarpointer = false;
|
supportsfarpointer = false;
|
||||||
name = "segment"; // Default name, might be overridden by userop attribute
|
name = "segment"; // Default name, might be overridden by userop attribute
|
||||||
for(int4 i=0;i<el->getNumAttributes();++i) {
|
for(int4 i=0;i<el->getNumAttributes();++i) {
|
||||||
const string &nm(el->getAttributeName(i));
|
const string &nm(el->getAttributeName(i));
|
||||||
if (nm == "space") continue;
|
if (nm == "space") continue;
|
||||||
else if (nm == "baseinsize") {
|
|
||||||
istringstream s(el->getAttributeValue(i));
|
|
||||||
s.unsetf(ios::dec | ios::hex | ios::oct);
|
|
||||||
s >> baseinsize;
|
|
||||||
}
|
|
||||||
else if (nm == "innerinsize") {
|
|
||||||
istringstream s1(el->getAttributeValue(i));
|
|
||||||
s1.unsetf(ios::dec | ios::hex | ios::oct);
|
|
||||||
s1 >> innerinsize;
|
|
||||||
}
|
|
||||||
else if (nm == "farpointer")
|
else if (nm == "farpointer")
|
||||||
supportsfarpointer = true;
|
supportsfarpointer = true;
|
||||||
else if (nm == "userop") { // Based on existing sleigh op
|
else if (nm == "userop") { // Based on existing sleigh op
|
||||||
|
@ -227,28 +185,17 @@ void SegmentOp::restoreXml(const Element *el)
|
||||||
throw LowlevelError("Redefining userop "+name);
|
throw LowlevelError("Redefining userop "+name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (nm == "force")
|
|
||||||
forcesegment = xml_readbool(el->getAttributeValue(i));
|
|
||||||
else
|
else
|
||||||
throw LowlevelError("Bad segmentop tag attribute: "+nm);
|
throw LowlevelError("Bad segmentop tag attribute: "+nm);
|
||||||
}
|
}
|
||||||
if (!userdefined)
|
if (!userdefined)
|
||||||
throw LowlevelError("Missing userop attribute in segmentop tag");
|
throw LowlevelError("Missing userop attribute in segmentop tag");
|
||||||
basepresent = (baseinsize != 0);
|
|
||||||
|
|
||||||
const List &list(el->getChildren());
|
const List &list(el->getChildren());
|
||||||
List::const_iterator iter;
|
List::const_iterator iter;
|
||||||
for(iter=list.begin();iter!=list.end();++iter) {
|
for(iter=list.begin();iter!=list.end();++iter) {
|
||||||
const Element *subel = *iter;
|
const Element *subel = *iter;
|
||||||
if (subel->getName()=="baseop") {
|
if (subel->getName()=="constresolve") {
|
||||||
basefollow.push_back(OpFollow());
|
|
||||||
basefollow.back().restoreXml(subel);
|
|
||||||
}
|
|
||||||
else if (subel->getName()=="innerop") {
|
|
||||||
innerfollow.push_back(OpFollow());
|
|
||||||
innerfollow.back().restoreXml(subel);
|
|
||||||
}
|
|
||||||
else if (subel->getName()=="constresolve") {
|
|
||||||
int4 sz;
|
int4 sz;
|
||||||
const List &sublist(subel->getChildren());
|
const List &sublist(subel->getChildren());
|
||||||
if (!sublist.empty()) {
|
if (!sublist.empty()) {
|
||||||
|
@ -260,9 +207,28 @@ void SegmentOp::restoreXml(const Element *el)
|
||||||
constresolve.size = sz;
|
constresolve.size = sz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (subel->getName() == "pcode") {
|
||||||
|
string nm = name + "_pcode";
|
||||||
|
string source = "cspec";
|
||||||
|
injectId = glb->pcodeinjectlib->restoreXmlInject(source, nm, InjectPayload::EXECUTABLEPCODE_TYPE, subel);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw LowlevelError("Bad segment pattern tag: "+subel->getName());
|
throw LowlevelError("Bad segment pattern tag: "+subel->getName());
|
||||||
}
|
}
|
||||||
|
if (injectId < 0)
|
||||||
|
throw LowlevelError("Missing <execute> child in <segmentop> tag");
|
||||||
|
InjectPayload *payload = glb->pcodeinjectlib->getPayload(injectId);
|
||||||
|
if (payload->sizeOutput() != 1)
|
||||||
|
throw LowlevelError("<execute> child of <segmentop> tag must declare one <output>");
|
||||||
|
if (payload->sizeInput() == 1) {
|
||||||
|
innerinsize = payload->getInput(0).getSize();
|
||||||
|
}
|
||||||
|
else if (payload->sizeInput() == 2) {
|
||||||
|
baseinsize = payload->getInput(0).getSize();
|
||||||
|
innerinsize = payload->getInput(1).getSize();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw LowlevelError("<execute> child of <segmentop> tag must declare one or two <input> tags");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \param g is the Architecture owning this set of jump assist scripts
|
/// \param g is the Architecture owning this set of jump assist scripts
|
||||||
|
|
|
@ -198,24 +198,19 @@ struct OpFollow {
|
||||||
/// The core routine that looks for the term-tree is unify().
|
/// The core routine that looks for the term-tree is unify().
|
||||||
class SegmentOp : public TermPatternOp {
|
class SegmentOp : public TermPatternOp {
|
||||||
AddrSpace *spc; ///< The physical address space into which a segmented pointer points
|
AddrSpace *spc; ///< The physical address space into which a segmented pointer points
|
||||||
|
int4 injectId; ///< Id of InjectPayload that emulates \b this operation
|
||||||
int4 baseinsize; ///< The size in bytes of the \e base or \e segment value
|
int4 baseinsize; ///< The size in bytes of the \e base or \e segment value
|
||||||
int4 innerinsize; ///< The size in bytes of the \e near pointer value
|
int4 innerinsize; ///< The size in bytes of the \e near pointer value
|
||||||
bool basepresent; ///< Is \b true is a base value must be present in the raw p-code
|
|
||||||
bool forcesegment; ///< Is \b true if an exception is thrown when a segment op can't be unified
|
|
||||||
bool supportsfarpointer; ///< Is \b true if the joined pair base:near acts as a \b far pointer
|
bool supportsfarpointer; ///< Is \b true if the joined pair base:near acts as a \b far pointer
|
||||||
vector<OpFollow> basefollow; ///< Sequence of operations performed on the \b base value
|
|
||||||
vector<OpFollow> innerfollow; ///< Sequence of operations performed on the \b near value
|
|
||||||
VarnodeData constresolve; ///< How to resolve constant near pointers
|
VarnodeData constresolve; ///< How to resolve constant near pointers
|
||||||
static uintb executeSide(const vector<OpFollow> &follow,uintb input);
|
|
||||||
public:
|
public:
|
||||||
SegmentOp(Architecture *g,const string &nm,int4 ind); ///< Constructor
|
SegmentOp(Architecture *g,const string &nm,int4 ind); ///< Constructor
|
||||||
AddrSpace *getSpace(void) const { return spc; } ///< Get the address space being pointed to
|
AddrSpace *getSpace(void) const { return spc; } ///< Get the address space being pointed to
|
||||||
bool hasFarPointerSupport(void) const { return supportsfarpointer; } ///< Return \b true, if \b this op supports far pointers
|
bool hasFarPointerSupport(void) const { return supportsfarpointer; } ///< Return \b true, if \b this op supports far pointers
|
||||||
bool isForced(void) const { return forcesegment; } ///< Return \b true if exceptions are thrown for bad unification
|
|
||||||
int4 getBaseSize(void) const { return baseinsize; } ///< Get size in bytes of the base/segment value
|
int4 getBaseSize(void) const { return baseinsize; } ///< Get size in bytes of the base/segment value
|
||||||
int4 getInnerSize(void) const { return innerinsize; } ///< Get size in bytes of the near value
|
int4 getInnerSize(void) const { return innerinsize; } ///< Get size in bytes of the near value
|
||||||
const VarnodeData &getResolve(void) const { return constresolve; } ///< Get the default register for resolving indirect segments
|
const VarnodeData &getResolve(void) const { return constresolve; } ///< Get the default register for resolving indirect segments
|
||||||
virtual int4 getNumVariableTerms(void) const { if (basepresent) return 2; return 1; }
|
virtual int4 getNumVariableTerms(void) const { if (baseinsize!=0) return 2; return 1; }
|
||||||
virtual bool unify(Funcdata &data,PcodeOp *op,vector<Varnode *> &bindlist) const;
|
virtual bool unify(Funcdata &data,PcodeOp *op,vector<Varnode *> &bindlist) const;
|
||||||
virtual uintb execute(const vector<uintb> &input) const;
|
virtual uintb execute(const vector<uintb> &input) const;
|
||||||
virtual void restoreXml(const Element *el);
|
virtual void restoreXml(const Element *el);
|
||||||
|
|
|
@ -40,7 +40,7 @@ import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.UndefinedFunction;
|
import ghidra.util.UndefinedFunction;
|
||||||
import ghidra.util.exception.UsrException;
|
import ghidra.util.exception.UsrException;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.util.xml.SpecXmlUtils;
|
import ghidra.util.xml.SpecXmlUtils;
|
||||||
import ghidra.util.xml.XmlUtilities;
|
import ghidra.util.xml.XmlUtilities;
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ public class DecompileCallback {
|
||||||
listing = program.getListing();
|
listing = program.getListing();
|
||||||
addrfactory = program.getAddressFactory();
|
addrfactory = program.getAddressFactory();
|
||||||
dtmanage = dt;
|
dtmanage = dt;
|
||||||
default_extrapop = pcodecompilerspec.getCallStackMod();
|
default_extrapop = pcodecompilerspec.getDefaultCallingConvention().getExtrapop();
|
||||||
cpool = null;
|
cpool = null;
|
||||||
nativeMessage = null;
|
nativeMessage = null;
|
||||||
debug = null;
|
debug = null;
|
||||||
|
@ -103,6 +103,7 @@ public class DecompileCallback {
|
||||||
* Establish function and debug context for next decompilation
|
* Establish function and debug context for next decompilation
|
||||||
*
|
*
|
||||||
* @param func is the function to be decompiled
|
* @param func is the function to be decompiled
|
||||||
|
* @param entry is the function's entry address
|
||||||
* @param dbg is the debugging context (or null)
|
* @param dbg is the debugging context (or null)
|
||||||
*/
|
*/
|
||||||
public void setFunction(Function func, Address entry, DecompileDebug dbg) {
|
public void setFunction(Function func, Address entry, DecompileDebug dbg) {
|
||||||
|
@ -132,11 +133,11 @@ public class DecompileCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by the decompiler to return a message
|
* Cache a message returned by the decompiler process
|
||||||
*
|
*
|
||||||
* @param msg
|
* @param msg is the message
|
||||||
*/
|
*/
|
||||||
public void setNativeMessage(String msg) {
|
void setNativeMessage(String msg) {
|
||||||
nativeMessage = msg;
|
nativeMessage = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +214,8 @@ public class DecompileCallback {
|
||||||
* Collect any/all comments for the function starting at the indicated
|
* Collect any/all comments for the function starting at the indicated
|
||||||
* address
|
* address
|
||||||
*
|
*
|
||||||
* @param addrstring = string rep of function address
|
* @param addrstring is the XML rep of function address
|
||||||
|
* @param types is the string encoding of the comment type flags
|
||||||
* @return XML document describing comments
|
* @return XML document describing comments
|
||||||
*/
|
*/
|
||||||
public String getComments(String addrstring, String types) {
|
public String getComments(String addrstring, String types) {
|
||||||
|
@ -300,13 +302,6 @@ public class DecompileCallback {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param ops pcode ops
|
|
||||||
* @param fallthruoffset number of bytes after instruction start that pcode
|
|
||||||
* flow falls into
|
|
||||||
*
|
|
||||||
* @return XML document string representing all the pcode
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Build an XML representation of all the pcode op's a given Instruction is
|
* Build an XML representation of all the pcode op's a given Instruction is
|
||||||
* defined to perform.
|
* defined to perform.
|
||||||
|
@ -315,8 +310,8 @@ public class DecompileCallback {
|
||||||
* @param fallthruoffset number of bytes after instruction start that pcode
|
* @param fallthruoffset number of bytes after instruction start that pcode
|
||||||
* flow falls into
|
* flow falls into
|
||||||
* @param paramshift special instructions for injection use
|
* @param paramshift special instructions for injection use
|
||||||
* @param addrFactory
|
* @param addrFactory is the address factory for recovering address space names
|
||||||
* @return XML document as string
|
* @return XML document as string representing all the p-code
|
||||||
*/
|
*/
|
||||||
public static String buildInstruction(PcodeOp[] ops, int fallthruoffset, int paramshift,
|
public static String buildInstruction(PcodeOp[] ops, int fallthruoffset, int paramshift,
|
||||||
AddressFactory addrFactory) {
|
AddressFactory addrFactory) {
|
||||||
|
@ -446,7 +441,7 @@ public class DecompileCallback {
|
||||||
|
|
||||||
if (pseudoDisassembler == null) {
|
if (pseudoDisassembler == null) {
|
||||||
pseudoDisassembler = Disassembler.getDisassembler(program, false, false, false,
|
pseudoDisassembler = Disassembler.getDisassembler(program, false, false, false,
|
||||||
TaskMonitorAdapter.DUMMY_MONITOR, msg -> {
|
TaskMonitor.DUMMY, msg -> {
|
||||||
// TODO: Should we log errors?
|
// TODO: Should we log errors?
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -859,35 +854,11 @@ public class DecompileCallback {
|
||||||
return resBuf;
|
return resBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * For registers, return their name.
|
|
||||||
// *
|
|
||||||
// * TODO: should look in the scope and return the global register.
|
|
||||||
// *
|
|
||||||
// * @param addr
|
|
||||||
// * @return xml string
|
|
||||||
// */
|
|
||||||
// private String buildRegisterRef(Register reg) {
|
|
||||||
// Symbol sym = program.getSymbolTable().getPrimarySymbol(reg.getAddress());
|
|
||||||
// if (sym==null)
|
|
||||||
// return null;
|
|
||||||
//
|
|
||||||
// boolean readonly = false;
|
|
||||||
// DataType dt = dtmanage.findInteger(reg.getMinimumByteSize());
|
|
||||||
// String symstring =
|
|
||||||
// HighVariable.buildMappedSymbolXML(dtmanage, reg.getName(), dt,
|
|
||||||
// reg.getMinimumByteSize(), true, true, readonly, false, -1, -1);
|
|
||||||
// if (debug != null)
|
|
||||||
// debug.getType(dt);
|
|
||||||
//// Namespace namespc = sym.getParentNamespace();
|
|
||||||
// return buildResult(reg.getAddress(), null, symstring, null);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate non-data symbol, probably a code label
|
* Generate description of a non-data symbol, probably a code label
|
||||||
*
|
*
|
||||||
* @param sym
|
* @param sym is the symbol
|
||||||
* @return
|
* @return the XML description
|
||||||
*/
|
*/
|
||||||
private String buildLabel(Symbol sym, Address addr) {
|
private String buildLabel(Symbol sym, Address addr) {
|
||||||
// TODO: Assume this is not data
|
// TODO: Assume this is not data
|
||||||
|
@ -973,7 +944,7 @@ public class DecompileCallback {
|
||||||
* @param addr The queried address
|
* @param addr The queried address
|
||||||
* @param includeDefaultNames true if default parameter names should be
|
* @param includeDefaultNames true if default parameter names should be
|
||||||
* included
|
* included
|
||||||
* @return
|
* @return XML string describing the function or the hole
|
||||||
*/
|
*/
|
||||||
private String buildFunctionXML(Function func, Address addr, boolean includeDefaultNames) {
|
private String buildFunctionXML(Function func, Address addr, boolean includeDefaultNames) {
|
||||||
Address entry = func.getEntryPoint();
|
Address entry = func.getEntryPoint();
|
||||||
|
@ -1179,7 +1150,7 @@ public class DecompileCallback {
|
||||||
* Return the global object being referred to by addr
|
* Return the global object being referred to by addr
|
||||||
*
|
*
|
||||||
* @param addr = Address being queried
|
* @param addr = Address being queried
|
||||||
* @return
|
* @return the global object
|
||||||
*/
|
*/
|
||||||
private Object lookupSymbol(Address addr) {
|
private Object lookupSymbol(Address addr) {
|
||||||
ExternalReference ref = getExternalReference(addr);
|
ExternalReference ref = getExternalReference(addr);
|
||||||
|
|
|
@ -229,35 +229,7 @@
|
||||||
</zeroOrMore>
|
</zeroOrMore>
|
||||||
|
|
||||||
<zeroOrMore>
|
<zeroOrMore>
|
||||||
<element name="segmentop">
|
<ref name="segmentop_type"/>
|
||||||
<attribute name="space"/>
|
|
||||||
<optional> <attribute name="userop"/> </optional>
|
|
||||||
<optional> <attribute name="baseinsize"/> </optional>
|
|
||||||
<optional> <attribute name="innerinsize"/> </optional>
|
|
||||||
<optional> <attribute name="farpointer"/> </optional>
|
|
||||||
<optional>
|
|
||||||
<attribute name="force">
|
|
||||||
<ref name="boolean_type"/>
|
|
||||||
</attribute>
|
|
||||||
</optional>
|
|
||||||
<interleave>
|
|
||||||
<zeroOrMore>
|
|
||||||
<element name="baseop">
|
|
||||||
<ref name="segment_op_type"/>
|
|
||||||
</element>
|
|
||||||
</zeroOrMore>
|
|
||||||
<zeroOrMore>
|
|
||||||
<element name="innerop">
|
|
||||||
<ref name="segment_op_type"/>
|
|
||||||
</element>
|
|
||||||
</zeroOrMore>
|
|
||||||
<optional>
|
|
||||||
<element name="constresolve">
|
|
||||||
<ref name="varnode_tags_type"/>
|
|
||||||
</element>
|
|
||||||
</optional>
|
|
||||||
</interleave>
|
|
||||||
</element>
|
|
||||||
</zeroOrMore>
|
</zeroOrMore>
|
||||||
|
|
||||||
<element name="default_proto">
|
<element name="default_proto">
|
||||||
|
@ -299,22 +271,6 @@
|
||||||
</element>
|
</element>
|
||||||
</start>
|
</start>
|
||||||
|
|
||||||
<define name="segment_op_type">
|
|
||||||
<attribute name="code">
|
|
||||||
<choice>
|
|
||||||
<value type="string">INT_ZEXT</value>
|
|
||||||
<value type="string">INT_LEFT</value>
|
|
||||||
<value type="string">INT_AND</value>
|
|
||||||
</choice>
|
|
||||||
</attribute>
|
|
||||||
<optional>
|
|
||||||
<attribute name="value"/>
|
|
||||||
</optional>
|
|
||||||
<optional>
|
|
||||||
<attribute name="slot"/>
|
|
||||||
</optional>
|
|
||||||
</define>
|
|
||||||
|
|
||||||
<define name="pentry_type">
|
<define name="pentry_type">
|
||||||
<optional> <attribute name="maxsize"/> </optional>
|
<optional> <attribute name="maxsize"/> </optional>
|
||||||
<optional> <attribute name="minsize"/> </optional>
|
<optional> <attribute name="minsize"/> </optional>
|
||||||
|
|
|
@ -226,6 +226,22 @@
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
<define name="segmentop_type">
|
||||||
|
<element name="segmentop">
|
||||||
|
<attribute name="space"/>
|
||||||
|
<optional> <attribute name="userop"/> </optional>
|
||||||
|
<optional> <attribute name="farpointer"/> </optional>
|
||||||
|
<element name="pcode">
|
||||||
|
<ref name="pcode_type"/>
|
||||||
|
</element>
|
||||||
|
<optional>
|
||||||
|
<element name="constresolve">
|
||||||
|
<ref name="varnode_tags_type"/>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
|
</element>
|
||||||
|
</define>
|
||||||
|
|
||||||
<define name="jumpassist_type">
|
<define name="jumpassist_type">
|
||||||
<attribute name="name"/>
|
<attribute name="name"/>
|
||||||
|
|
|
@ -43,9 +43,16 @@
|
||||||
<optional>
|
<optional>
|
||||||
<element name="segmented_address">
|
<element name="segmented_address">
|
||||||
<attribute name="space"/>
|
<attribute name="space"/>
|
||||||
|
<optional>
|
||||||
|
<attribute name="type"/>
|
||||||
|
</optional>
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
|
||||||
|
<zeroOrMore>
|
||||||
|
<ref name="segmentop_type"/>
|
||||||
|
</zeroOrMore>
|
||||||
|
|
||||||
<!-- see language_common.rxg -->
|
<!-- see language_common.rxg -->
|
||||||
<optional>
|
<optional>
|
||||||
<element name="context_data">
|
<element name="context_data">
|
||||||
|
|
|
@ -79,6 +79,7 @@ public class SleighLanguage implements Language {
|
||||||
* Non-null if a space should yes segmented addressing
|
* Non-null if a space should yes segmented addressing
|
||||||
*/
|
*/
|
||||||
String segmentedspace = "";
|
String segmentedspace = "";
|
||||||
|
String segmentType = "";
|
||||||
AddressSet volatileAddresses;
|
AddressSet volatileAddresses;
|
||||||
private ContextCache contextcache = null;
|
private ContextCache contextcache = null;
|
||||||
/**
|
/**
|
||||||
|
@ -100,6 +101,13 @@ public class SleighLanguage implements Language {
|
||||||
initialize(description);
|
initialize(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addAdditionInject(InjectPayloadSleigh payload) {
|
||||||
|
if (additionalInject == null) {
|
||||||
|
additionalInject = new ArrayList<>();
|
||||||
|
}
|
||||||
|
additionalInject.add(payload);
|
||||||
|
}
|
||||||
|
|
||||||
private void initialize(SleighLanguageDescription langDescription)
|
private void initialize(SleighLanguageDescription langDescription)
|
||||||
throws SAXException, IOException, UnknownInstructionException {
|
throws SAXException, IOException, UnknownInstructionException {
|
||||||
this.defaultSymbols = new ArrayList<>();
|
this.defaultSymbols = new ArrayList<>();
|
||||||
|
@ -508,6 +516,10 @@ public class SleighLanguage implements Language {
|
||||||
if (nextElement != null) {
|
if (nextElement != null) {
|
||||||
XmlElement element = parser.start(); // segmented_address element
|
XmlElement element = parser.start(); // segmented_address element
|
||||||
segmentedspace = element.getAttribute("space");
|
segmentedspace = element.getAttribute("space");
|
||||||
|
segmentType = element.getAttribute("type");
|
||||||
|
if (segmentType == null) {
|
||||||
|
segmentType = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
parser.dispose();
|
parser.dispose();
|
||||||
}
|
}
|
||||||
|
@ -586,20 +598,40 @@ public class SleighLanguage implements Language {
|
||||||
}
|
}
|
||||||
InjectPayloadSleigh payload =
|
InjectPayloadSleigh payload =
|
||||||
new InjectPayloadSleigh(subName, InjectPayload.EXECUTABLEPCODE_TYPE, source);
|
new InjectPayloadSleigh(subName, InjectPayload.EXECUTABLEPCODE_TYPE, source);
|
||||||
if (additionalInject == null) {
|
|
||||||
additionalInject = new ArrayList<>();
|
|
||||||
}
|
|
||||||
payload.restoreXml(parser);
|
payload.restoreXml(parser);
|
||||||
additionalInject.add(payload);
|
addAdditionInject(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InjectPayloadSleigh parseSegmentOp(XmlElement el, XmlPullParser parser) {
|
||||||
|
String name = el.getAttribute("userop");
|
||||||
|
if (name == null) {
|
||||||
|
name = "segment";
|
||||||
|
}
|
||||||
|
name = name + "_pcode";
|
||||||
|
String source = "pspec: " + getLanguageID().getIdAsString();
|
||||||
|
InjectPayloadSleigh payload = null;
|
||||||
|
if (parser.peek().isStart()) {
|
||||||
|
if (parser.peek().getName().equals("pcode")) {
|
||||||
|
payload = new InjectPayloadSleigh(name, InjectPayload.EXECUTABLEPCODE_TYPE, source);
|
||||||
|
payload.restoreXml(parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (parser.peek().isStart()) {
|
||||||
|
parser.discardSubTree();
|
||||||
|
}
|
||||||
|
if (payload == null) {
|
||||||
|
throw new SleighException("Missing <pcode> child for <segmentop> tag");
|
||||||
|
}
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
private void read(XmlPullParser parser) {
|
private void read(XmlPullParser parser) {
|
||||||
Set<String> registerDataSet = new HashSet<>();
|
Set<String> registerDataSet = new HashSet<>();
|
||||||
|
|
||||||
XmlElement element = parser.start("processor_spec");
|
XmlElement element = parser.start("processor_spec");
|
||||||
while (!parser.peek().isEnd()) {
|
while (!parser.peek().isEnd()) {
|
||||||
element = parser.start("properties", "segmented_address", "programcounter",
|
element = parser.start("properties", "segmented_address", "segmentop", "programcounter",
|
||||||
"data_space", "context_data", "volatile", "jumpassist", "incidentalcopy",
|
"data_space", "context_data", "volatile", "jumpassist", "incidentalcopy",
|
||||||
"register_data", "default_symbols", "default_memory_blocks");
|
"register_data", "default_symbols", "default_memory_blocks");
|
||||||
if (element.getName().equals("properties")) {
|
if (element.getName().equals("properties")) {
|
||||||
|
@ -769,6 +801,10 @@ public class SleighLanguage implements Language {
|
||||||
parser.discardSubTree();
|
parser.discardSubTree();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (element.getName().equals("segmentop")) {
|
||||||
|
InjectPayloadSleigh payload = parseSegmentOp(element, parser);
|
||||||
|
addAdditionInject(payload);
|
||||||
|
}
|
||||||
// get rid of the end tag of whatever we started with at the top of the while
|
// get rid of the end tag of whatever we started with at the top of the while
|
||||||
parser.end(element);
|
parser.end(element);
|
||||||
}
|
}
|
||||||
|
@ -896,7 +932,12 @@ public class SleighLanguage implements Language {
|
||||||
throw new SleighException(
|
throw new SleighException(
|
||||||
"Segmented space does not support truncation: " + name);
|
"Segmented space does not support truncation: " + name);
|
||||||
}
|
}
|
||||||
spc = new SegmentedAddressSpace(name, index);
|
if (segmentType.equals("protected")) {
|
||||||
|
spc = new ProtectedAddressSpace(name, index);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spc = new SegmentedAddressSpace(name, index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (truncateSpace) {
|
if (truncateSpace) {
|
||||||
|
@ -1378,8 +1419,8 @@ public class SleighLanguage implements Language {
|
||||||
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "index", element.getUnique());
|
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "index", element.getUnique());
|
||||||
|
|
||||||
int size = element.getSize(); // Size in bits
|
int size = element.getSize(); // Size in bits
|
||||||
if (size == 20) {
|
if (element instanceof SegmentedAddressSpace) {
|
||||||
// TODO: SegmentedAddressSpace shouldn't really return 20
|
// TODO: SegmentedAddressSpace shouldn't really return 21
|
||||||
size = 32;
|
size = 32;
|
||||||
}
|
}
|
||||||
if (size > 64) {
|
if (size > 64) {
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/* ###
|
||||||
|
* 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.program.model.address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address Space for (intel) 16-bit protected mode programs. This space produces
|
||||||
|
* SegmentedAddress objects whose underlying (flat) offset encodes both the
|
||||||
|
* segment and the segment offset without losing information. There is no possibility
|
||||||
|
* of alternate encodings for a single address as with real-mode.
|
||||||
|
*/
|
||||||
|
public class ProtectedAddressSpace extends SegmentedAddressSpace {
|
||||||
|
|
||||||
|
private final static int PROTECTEDMODE_SIZE = 32;
|
||||||
|
private final static int PROTECTEDMODE_OFFSETSIZE = 16;
|
||||||
|
|
||||||
|
private int offsetSize; // Number of bits in the segment offset
|
||||||
|
private long offsetMask; // Mask for retrieving the segment offset
|
||||||
|
|
||||||
|
public ProtectedAddressSpace(String name, int unique) {
|
||||||
|
super(name, PROTECTEDMODE_SIZE, unique);
|
||||||
|
offsetSize = PROTECTEDMODE_OFFSETSIZE;
|
||||||
|
offsetMask = 1;
|
||||||
|
offsetMask <<= offsetSize;
|
||||||
|
offsetMask -= 1;
|
||||||
|
maxAddress = getUncheckedAddress(maxOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long getFlatOffset(int segment, long offset) {
|
||||||
|
long res = segment;
|
||||||
|
res <<= offsetSize;
|
||||||
|
res += offset;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDefaultSegmentFromFlat(long flat) {
|
||||||
|
return (int) (flat >>> offsetSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long getDefaultOffsetFromFlat(long flat) {
|
||||||
|
return (flat & offsetMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long getOffsetFromFlat(long flat, int segment) {
|
||||||
|
return (flat & offsetMask); // segment does not affect the offset
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SegmentedAddress getAddressInSegment(long flat, int preferredSegment) {
|
||||||
|
return null; // The segment cannot be changed as the flat explicitly encodes it
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNextOpenSegment(Address addr) {
|
||||||
|
int res = getDefaultSegmentFromFlat(addr.getOffset());
|
||||||
|
// Advance the selector by 8, accounting for the descriptor table bit and the privilege level bits
|
||||||
|
res = (res + 8) & 0xfff8;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,74 +17,56 @@ package ghidra.program.model.address;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Address class for dealing with intel 20 bit segmented addresses.
|
* Address class for dealing with (intel) segmented addresses. The class itself is agnostic
|
||||||
|
* about the mapping from segmented encoding to flat address offset, it uses the
|
||||||
|
* SegmentedAddressSpace to perform this mapping. So the same class can be used to represent
|
||||||
|
* either a real-mode address or a protected-mode address. The class uses the underlying
|
||||||
|
* offset field to hold the flat encoding.
|
||||||
*/
|
*/
|
||||||
public class SegmentedAddress extends GenericAddress {
|
public class SegmentedAddress extends GenericAddress {
|
||||||
|
|
||||||
private static final long serialVersionUID = 0;
|
private final int segment; // The specific segment value associated with this address
|
||||||
public static final int OFFSET_SIZE = 16;
|
|
||||||
public static final int SEGMENT_SIZE = 16;
|
|
||||||
|
|
||||||
private final SegmentedAddressSpace addrSpace;
|
|
||||||
private final int segment;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for SegmentedAddress.
|
* Constructor for SegmentedAddress.
|
||||||
* Offset is not validated against address space.
|
* Offset is not validated against address space.
|
||||||
* @param addrSpace address space for this address
|
* @param addrSpace is the address space for this address
|
||||||
* @param offset offset into the space
|
* @param flat is the flat offset into the space
|
||||||
*/
|
*/
|
||||||
SegmentedAddress(long offset, SegmentedAddressSpace addrSpace) {
|
SegmentedAddress(long flat, SegmentedAddressSpace addrSpace) {
|
||||||
super(adjustOffset(offset), addrSpace);
|
super(adjustOffset(flat, addrSpace), addrSpace);
|
||||||
this.addrSpace = addrSpace;
|
segment = addrSpace.getDefaultSegmentFromFlat(flat);
|
||||||
if (offset > 0xFFFFF) {
|
|
||||||
this.segment = 0xFFFF;
|
|
||||||
} else {
|
|
||||||
this.segment = (int) ((offset >> 4) & 0xf000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for SegmentedAddress.
|
* Constructor for SegmentedAddress.
|
||||||
* @param addrSpace address space for this address
|
* @param addrSpace is the address space for this address
|
||||||
* @param segmentOffset offset into the segment
|
* @param segment is the segment number
|
||||||
* @param overlayId overlay number
|
* @param segmentOffset is the offset into the segment
|
||||||
* @param segment segment number
|
* @throws AddressOutOfBoundsException if the address does not fit in the space
|
||||||
*/
|
*/
|
||||||
SegmentedAddress(SegmentedAddressSpace addrSpace, int segment, int segmentOffset)
|
SegmentedAddress(SegmentedAddressSpace addrSpace, int segment, int segmentOffset)
|
||||||
throws AddressOutOfBoundsException {
|
throws AddressOutOfBoundsException {
|
||||||
super(addrSpace, (segment << 4) + segmentOffset);
|
super(addrSpace, addrSpace.getFlatOffset(segment, segmentOffset));
|
||||||
this.addrSpace = addrSpace;
|
this.segment = segment;
|
||||||
if (offset > 0xFFFFF) {
|
|
||||||
this.segment = 0xFFFF;
|
|
||||||
} else {
|
|
||||||
this.segment = segment;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for SegmentedAddress.
|
* Constructor for SegmentedAddress.
|
||||||
* @param addrSpace address space for this address
|
* @param addrSpace address space for this address
|
||||||
* @param offset offset into the space
|
* @param flat is the flat offset into the space
|
||||||
|
* @throws AddressOutOfBoundsException if the flat address does not fit in the space
|
||||||
*/
|
*/
|
||||||
SegmentedAddress(SegmentedAddressSpace addrSpace, long offset)
|
SegmentedAddress(SegmentedAddressSpace addrSpace, long flat)
|
||||||
throws AddressOutOfBoundsException {
|
throws AddressOutOfBoundsException {
|
||||||
super(addrSpace, adjustOffset(offset));
|
super(addrSpace, adjustOffset(flat, addrSpace));
|
||||||
this.addrSpace = addrSpace;
|
segment = addrSpace.getDefaultSegmentFromFlat(flat);
|
||||||
if (offset > 0xFFFFF) {
|
|
||||||
this.segment = 0xFFFF;
|
|
||||||
} else {
|
|
||||||
this.segment = (int) ((offset >> 4) & 0xf000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long adjustOffset(long offset) {
|
private static long adjustOffset(long flat, SegmentedAddressSpace addrSpace) {
|
||||||
// Decompiler treats segmented space as a 32-bit space and may produce an address offset
|
int seg = addrSpace.getDefaultSegmentFromFlat(flat);
|
||||||
// of 0xffffffff for a first use offset (= 0 minus 1).
|
long offset = addrSpace.getDefaultOffsetFromFlat(flat);
|
||||||
if (offset == 0x0ffffffffL) {
|
return addrSpace.getFlatOffset(seg, offset);
|
||||||
offset = 0x0fffffL;
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,25 +79,24 @@ public class SegmentedAddress extends GenericAddress {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the offset within the segment.
|
* Returns the offset within the segment.
|
||||||
|
* @return the offset value
|
||||||
*/
|
*/
|
||||||
public int getSegmentOffset() {
|
public int getSegmentOffset() {
|
||||||
return (int) (offset - (segment << 4));
|
return (int) ((SegmentedAddressSpace) addrSpace).getOffsetFromFlat(offset, segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new address that is equivalent to this address using
|
* Returns a new address that is equivalent to this address using
|
||||||
* the given segment number.
|
* the given segment number.
|
||||||
* @param seg the seqment value to normalize to.
|
* @param seg the seqment value to normalize to.
|
||||||
|
* @return the new address
|
||||||
*/
|
*/
|
||||||
public SegmentedAddress normalize(int seg) {
|
public SegmentedAddress normalize(int seg) {
|
||||||
if ((seg << 4) > offset) {
|
SegmentedAddress res = ((SegmentedAddressSpace) addrSpace).getAddressInSegment(offset, seg);
|
||||||
|
if (res == null) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
int off = (int) (offset - (seg << 4));
|
return res;
|
||||||
if (off > 0xffff) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
return new SegmentedAddress(addrSpace, seg, off);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,8 +105,12 @@ public class SegmentedAddress extends GenericAddress {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Address getNewAddress(long byteOffset) {
|
public Address getNewAddress(long byteOffset) {
|
||||||
SegmentedAddress segAddr = addrSpace.getAddress(byteOffset);
|
SegmentedAddressSpace segSpace = (SegmentedAddressSpace) addrSpace;
|
||||||
return segAddr.normalize(segment);
|
SegmentedAddress res = segSpace.getAddressInSegment(byteOffset, segment);
|
||||||
|
if (res == null) {
|
||||||
|
return segSpace.getAddress(byteOffset);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -174,33 +159,4 @@ public class SegmentedAddress extends GenericAddress {
|
||||||
}
|
}
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.GenericAddress#next()
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
@Override
|
|
||||||
public Address next() {
|
|
||||||
if ((offset & SegmentedAddressSpace.MASK) == SegmentedAddressSpace.MASK) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
long newOffset = (offset + 1) & SegmentedAddressSpace.MASK;
|
|
||||||
return new SegmentedAddress(addrSpace, newOffset).normalize(segment);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.GenericAddress#previous()
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
@Override
|
|
||||||
public Address previous() {
|
|
||||||
if ((offset & SegmentedAddressSpace.MASK) == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
long newOffset = (offset - 1) & SegmentedAddressSpace.MASK;
|
|
||||||
return new SegmentedAddress(addrSpace, newOffset).normalize(segment);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,30 +20,120 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import ghidra.util.NumericUtilities;
|
import ghidra.util.NumericUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Address Space for dealing with Intel 20 bit segmented addresses.
|
* Address Space for dealing with (intel) segmented address spaces.
|
||||||
|
* It understands the mapping between the segmented encoding (seg:offset) and
|
||||||
|
* the flat address encoding necessary to produce an Address object that can be
|
||||||
|
* used by other analyses. This mapping is inherent in protected methods:
|
||||||
|
* - getDefaultOffsetFromFlat
|
||||||
|
* - getDefaultSegmentFromFlat
|
||||||
|
* - getFlatOffset
|
||||||
|
* - getOffsetFromFlat
|
||||||
|
* - getAddressInSegment
|
||||||
|
*
|
||||||
|
* These 5 methods can be overridden to get a different mapping. This base class is
|
||||||
|
* set up to map as for x86 16-bit real-mode.
|
||||||
*/
|
*/
|
||||||
public class SegmentedAddressSpace extends GenericAddressSpace {
|
public class SegmentedAddressSpace extends GenericAddressSpace {
|
||||||
|
|
||||||
private final static int SIZE = 21;
|
private final static int REALMODE_SIZE = 21;
|
||||||
|
private final static long REALMODE_MAXOFFSET = 0x10FFEF;
|
||||||
//private final static int SEGMENT_OFFSET_MASK = 0xffff;
|
|
||||||
//final static long MASK = (1L << SIZE) - 1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new Segmented AddressSpace.
|
* Constructor for larger size address spaces (than the real-mode space)
|
||||||
*
|
* @param name is the name of the space
|
||||||
* @param name
|
* @param size is the number of bits in a (flat) address
|
||||||
* the name of the space
|
* @param unique is the unique id for the space
|
||||||
* @param unique
|
*/
|
||||||
* the unique id for the space.
|
protected SegmentedAddressSpace(String name, int size, int unique) {
|
||||||
|
super(name, size, TYPE_RAM, unique);
|
||||||
|
// maxAddress = getUncheckedAddress(maxOffset);
|
||||||
|
// Constructors for derived classes that call this will
|
||||||
|
// need to reconstruct maxAddress themselves.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Segmented AddressSpace for x86 real-mode, with 21-bit addresses.
|
||||||
|
* @param name is the name of the space
|
||||||
|
* @param unique is the unique id for the space.
|
||||||
*/
|
*/
|
||||||
public SegmentedAddressSpace(String name, int unique) {
|
public SegmentedAddressSpace(String name, int unique) {
|
||||||
super(name, SIZE, TYPE_RAM, unique);
|
super(name, REALMODE_SIZE, TYPE_RAM, unique);
|
||||||
maxOffset = 0x10FFEF;
|
maxOffset = REALMODE_MAXOFFSET;
|
||||||
spaceSize = maxOffset + 1;
|
spaceSize = maxOffset + 1;
|
||||||
maxAddress = getUncheckedAddress(maxOffset);
|
maxAddress = getUncheckedAddress(maxOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a 16-bit segment and an offset, produce the flat address offset
|
||||||
|
* @param segment is the segment value
|
||||||
|
* @param offset is the 16-bit offset into the segment
|
||||||
|
* @return the encoded flat offset
|
||||||
|
*/
|
||||||
|
protected long getFlatOffset(int segment, long offset) {
|
||||||
|
long res = segment;
|
||||||
|
res <<= 4;
|
||||||
|
res += offset;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a flat address offset, extract the default 16-bit segment portion
|
||||||
|
* @param flat is the flat offset
|
||||||
|
* @return the segment value
|
||||||
|
*/
|
||||||
|
protected int getDefaultSegmentFromFlat(long flat) {
|
||||||
|
if (flat > 0xFFFFFL) {
|
||||||
|
return 0xFFFF;
|
||||||
|
}
|
||||||
|
return (int) ((flat >> 4) & 0xF000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a flat address offset, extract the offset portion assuming the
|
||||||
|
* default segment.
|
||||||
|
* @param flat is the flat offset
|
||||||
|
* @return the offset value
|
||||||
|
*/
|
||||||
|
protected long getDefaultOffsetFromFlat(long flat) {
|
||||||
|
if (flat > 0xFFFFFL) {
|
||||||
|
return flat - 0xFFFF0;
|
||||||
|
}
|
||||||
|
return flat & 0xFFFFL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a flat address offset, extract a segment offset assuming a
|
||||||
|
* specific segment value.
|
||||||
|
* @param flat is the flat offset
|
||||||
|
* @param segment is the specific segment value
|
||||||
|
* @return the segment offset
|
||||||
|
*/
|
||||||
|
protected long getOffsetFromFlat(long flat, int segment) {
|
||||||
|
return flat - (segment << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a flat address offset and a preferred segment, try
|
||||||
|
* to create an address that maps to the offset and is in the segment. For
|
||||||
|
* architectures like x86 real-mode, multiple address encodings can map to
|
||||||
|
* the same flat address offset. This method tries to select between the different
|
||||||
|
* encodings. If the flat offset cannot be encoded with the preferred segment,
|
||||||
|
* null is returned.
|
||||||
|
*
|
||||||
|
* @param flat is the flat offset
|
||||||
|
* @param preferredSegment is the 16-bit preferred segment value
|
||||||
|
* @return the segment encoded address or null
|
||||||
|
*/
|
||||||
|
protected SegmentedAddress getAddressInSegment(long flat, int preferredSegment) {
|
||||||
|
if ((preferredSegment << 4) <= flat) {
|
||||||
|
int off = (int) (flat - (preferredSegment << 4));
|
||||||
|
if (off <= 0xffff) {
|
||||||
|
return new SegmentedAddress(this, preferredSegment, off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @see ghidra.program.model.address.AddressSpace#getAddress(java.lang.String)
|
* @see ghidra.program.model.address.AddressSpace#getAddress(java.lang.String)
|
||||||
|
@ -98,62 +188,16 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
|
||||||
long off = addr.getOffset() - displacement;
|
long off = addr.getOffset() - displacement;
|
||||||
if (off >= 0) {
|
if (off >= 0) {
|
||||||
SegmentedAddress saddr = (SegmentedAddress) addr;
|
SegmentedAddress saddr = (SegmentedAddress) addr;
|
||||||
return new SegmentedAddress(this, off).normalize(saddr.getSegment());
|
Address resaddr = getAddressInSegment(off, saddr.getSegment());
|
||||||
|
if (resaddr == null) { // Could not map into desired segment
|
||||||
|
resaddr = new SegmentedAddress(this, off); // just use default
|
||||||
|
}
|
||||||
|
return resaddr;
|
||||||
}
|
}
|
||||||
throw new AddressOutOfBoundsException(
|
throw new AddressOutOfBoundsException(
|
||||||
"Address Overflow in subtract: " + addr + " + " + displacement);
|
"Address Overflow in subtract: " + addr + " + " + displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.AddressSpace#subtractWrap(ghidra.program.model.address.Address,
|
|
||||||
* long)
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
@Override
|
|
||||||
public Address subtractWrap(Address addr, long displacement) {
|
|
||||||
|
|
||||||
testAddressSpace(addr);
|
|
||||||
SegmentedAddress saddr = (SegmentedAddress) addr;
|
|
||||||
|
|
||||||
int segOffset = (int) ((saddr.getSegmentOffset() - displacement) & SEGMENT_OFFSET_MASK);
|
|
||||||
return new SegmentedAddress(this, saddr.getSegment(), segOffset);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.AbstractAddressSpace#subtractWrapSpace(ghidra.program.model.address.Address, long)
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
@Override
|
|
||||||
public Address subtractWrapSpace(Address addr, long displacement) {
|
|
||||||
testAddressSpace(addr);
|
|
||||||
return new SegmentedAddress(this, (addr.getOffset() - displacement) & MASK);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.AddressSpace#subtractNoWrap(ghidra.program.model.address.Address,
|
|
||||||
* long)
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
@Override
|
|
||||||
public Address subtractNoWrap(Address addr, long displacement) throws AddressOverflowException {
|
|
||||||
|
|
||||||
testAddressSpace(addr);
|
|
||||||
SegmentedAddress saddr = (SegmentedAddress) addr;
|
|
||||||
|
|
||||||
long off = addr.getOffset() - displacement;
|
|
||||||
if ((off & MASK) != off) {
|
|
||||||
throw new AddressOverflowException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new SegmentedAddress(this, off).normalize(saddr.getSegment());
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @see ghidra.program.model.address.AddressSpace#add(ghidra.program.model.address.Address,
|
* @see ghidra.program.model.address.AddressSpace#add(ghidra.program.model.address.Address,
|
||||||
|
@ -175,82 +219,35 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
|
||||||
//if ((off & MASK) == off) {
|
//if ((off & MASK) == off) {
|
||||||
if (off >= 0 && off <= maxOffset) {
|
if (off >= 0 && off <= maxOffset) {
|
||||||
SegmentedAddress saddr = (SegmentedAddress) addr;
|
SegmentedAddress saddr = (SegmentedAddress) addr;
|
||||||
return new SegmentedAddress(this, off).normalize(saddr.getSegment());
|
Address resaddr = getAddressInSegment(off, saddr.getSegment());
|
||||||
|
if (resaddr == null) { // Could not map into desired segment
|
||||||
|
resaddr = new SegmentedAddress(this, off); // just use default
|
||||||
|
}
|
||||||
|
return resaddr;
|
||||||
}
|
}
|
||||||
throw new AddressOutOfBoundsException(
|
throw new AddressOutOfBoundsException(
|
||||||
"Address Overflow in add: " + addr + " + " + displacement);
|
"Address Overflow in add: " + addr + " + " + displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.AddressSpace#addWrap(ghidra.program.model.address.Address,
|
|
||||||
* long)
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
@Override
|
|
||||||
public Address addWrap(Address addr, long displacement) {
|
|
||||||
testAddressSpace(addr);
|
|
||||||
SegmentedAddress saddr = (SegmentedAddress) addr;
|
|
||||||
|
|
||||||
int segOffset = (int) ((saddr.getSegmentOffset() + displacement) & SEGMENT_OFFSET_MASK);
|
|
||||||
return new SegmentedAddress(this, saddr.getSegment(), segOffset);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.address.AddressSpace#addWrapSpace(ghidra.program.model.address.Address,
|
|
||||||
* long)
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
@Override
|
|
||||||
public Address addWrapSpace(Address addr, long displacement) {
|
|
||||||
testAddressSpace(addr);
|
|
||||||
return new SegmentedAddress(this, (addr.getOffset() + displacement) & MASK);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @see ghidra.program.model.address.AddressSpace#addNoWrap(ghidra.program.model.address.Address,
|
|
||||||
* long)
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
@Override
|
|
||||||
public Address addNoWrap(Address addr, long displacement) throws AddressOverflowException {
|
|
||||||
|
|
||||||
SegmentedAddress saddr = (SegmentedAddress) addr;
|
|
||||||
testAddressSpace(addr);
|
|
||||||
|
|
||||||
long off = addr.getOffset() + displacement;
|
|
||||||
if ((off & MASK) != off) {
|
|
||||||
throw new AddressOverflowException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new SegmentedAddress(this, off).normalize(saddr.getSegment());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
private long parseString(String addr) {
|
private long parseString(String addr) {
|
||||||
if (addr.startsWith("0x") || addr.startsWith("0X")) {
|
if (addr.startsWith("0x") || addr.startsWith("0X")) {
|
||||||
return NumericUtilities.parseHexLong(addr.substring(2));
|
return NumericUtilities.parseHexLong(addr.substring(2));
|
||||||
}
|
}
|
||||||
return NumericUtilities.parseHexLong(addr);
|
return NumericUtilities.parseHexLong(addr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SegmentedAddress parseNonSegmented(String offStr) throws AddressFormatException {
|
private SegmentedAddress parseNonSegmented(String offStr) throws AddressFormatException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
long off = (int) parseString(offStr);
|
long off = (int) parseString(offStr);
|
||||||
if (off < 0 || off > 0xfffff) {
|
|
||||||
throw new AddressFormatException("Offset is outside the range 0 to 0xfffff");
|
|
||||||
}
|
|
||||||
return new SegmentedAddress(this, off);
|
return new SegmentedAddress(this, off);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (NumberFormatException e) {
|
catch (NumberFormatException e) {
|
||||||
throw new AddressFormatException("Cannot parse (" + offStr + ") as a number.");
|
throw new AddressFormatException("Cannot parse (" + offStr + ") as a number.");
|
||||||
}
|
}
|
||||||
|
catch (AddressOutOfBoundsException e) {
|
||||||
|
throw new AddressFormatException(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SegmentedAddress parseSegmented(String segStr, String offStr)
|
private SegmentedAddress parseSegmented(String segStr, String offStr)
|
||||||
|
@ -262,23 +259,22 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
|
||||||
catch (NumberFormatException e) {
|
catch (NumberFormatException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (seg < 0 || seg > 0xffff) {
|
|
||||||
throw new AddressFormatException("Segment is outside the range 0 to 0xffff");
|
int off = -1;
|
||||||
|
try {
|
||||||
|
off = (int) parseString(offStr);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
throw new AddressFormatException(
|
||||||
|
"Cannot parse (" + segStr + ':' + offStr + ") as a number.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int off = (int) parseString(offStr);
|
return getAddress(seg, off);
|
||||||
if (off < 0 || off > 0xffff) {
|
|
||||||
throw new AddressFormatException("Offset is outside the range 0 to 0xffff");
|
|
||||||
}
|
|
||||||
return new SegmentedAddress(this, seg, off);
|
|
||||||
}
|
}
|
||||||
catch (AddressOutOfBoundsException e) {
|
catch (AddressOutOfBoundsException e) {
|
||||||
throw new AddressFormatException(e.getMessage());
|
throw new AddressFormatException(e.getMessage());
|
||||||
}
|
}
|
||||||
catch (NumberFormatException e) {
|
|
||||||
throw new AddressFormatException("Cannot parse (" + offStr + ") as a number.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -315,12 +311,24 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
|
||||||
if (segmentOffset > 0xffff) {
|
if (segmentOffset > 0xffff) {
|
||||||
throw new AddressOutOfBoundsException("Offset is too large.");
|
throw new AddressOutOfBoundsException("Offset is too large.");
|
||||||
}
|
}
|
||||||
if ((segment << 4) + segmentOffset > maxOffset) {
|
if (segment > 0xffff) {
|
||||||
throw new AddressOutOfBoundsException("Segmented address is too large.");
|
throw new AddressOutOfBoundsException("Segment is too large.");
|
||||||
}
|
}
|
||||||
return new SegmentedAddress(this, segment, segmentOffset);
|
return new SegmentedAddress(this, segment, segmentOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the segment index for the first segment whose start address
|
||||||
|
* comes after the given address
|
||||||
|
* @param addr is the given address
|
||||||
|
* @return the segment index
|
||||||
|
*/
|
||||||
|
public int getNextOpenSegment(Address addr) {
|
||||||
|
int res = (int) addr.getOffset(); // The "flat" offset (presumably real-mode encoded)
|
||||||
|
res = (res >> 4) + 1;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @see ghidra.program.model.address.AddressSpace#getPhysicalSpace()
|
* @see ghidra.program.model.address.AddressSpace#getPhysicalSpace()
|
||||||
|
|
|
@ -163,29 +163,30 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||||
language.getProperty(GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
language.getProperty(GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
||||||
if (classname == null) {
|
if (classname == null) {
|
||||||
pcodeInject = new PcodeInjectLibrary(language); // This is the default implementation
|
pcodeInject = new PcodeInjectLibrary(language); // This is the default implementation
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
try {
|
else {
|
||||||
Class<?> c = Class.forName(classname);
|
try {
|
||||||
if (!PcodeInjectLibrary.class.isAssignableFrom(c)) {
|
Class<?> c = Class.forName(classname);
|
||||||
|
if (!PcodeInjectLibrary.class.isAssignableFrom(c)) {
|
||||||
|
Msg.error(this,
|
||||||
|
"Language " + language.getLanguageID() + " does not specify a valid " +
|
||||||
|
GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
||||||
|
throw new RuntimeException(classname + " does not implement interface " +
|
||||||
|
PcodeInjectLibrary.class.getName());
|
||||||
|
}
|
||||||
|
Class<? extends PcodeInjectLibrary> injectLibraryClass =
|
||||||
|
(Class<? extends PcodeInjectLibrary>) c;
|
||||||
|
Constructor<? extends PcodeInjectLibrary> constructor =
|
||||||
|
injectLibraryClass.getConstructor(SleighLanguage.class);
|
||||||
|
pcodeInject = constructor.newInstance(language);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
Msg.error(this,
|
Msg.error(this,
|
||||||
"Language " + language.getLanguageID() + " does not specify a valid " +
|
"Language " + language.getLanguageID() + " does not specify a valid " +
|
||||||
GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
||||||
throw new RuntimeException(classname + " does not implement interface " +
|
throw new RuntimeException("Failed to instantiate " + classname + " for language " +
|
||||||
PcodeInjectLibrary.class.getName());
|
language.getLanguageID(), e);
|
||||||
}
|
}
|
||||||
Class<? extends PcodeInjectLibrary> injectLibraryClass =
|
|
||||||
(Class<? extends PcodeInjectLibrary>) c;
|
|
||||||
Constructor<? extends PcodeInjectLibrary> constructor =
|
|
||||||
injectLibraryClass.getConstructor(SleighLanguage.class);
|
|
||||||
pcodeInject = constructor.newInstance(language);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
Msg.error(this, "Language " + language.getLanguageID() + " does not specify a valid " +
|
|
||||||
GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
|
||||||
throw new RuntimeException(
|
|
||||||
"Failed to instantiate " + classname + " for language " + language.getLanguageID(),
|
|
||||||
e);
|
|
||||||
}
|
}
|
||||||
List<InjectPayloadSleigh> additionalInject = language.getAdditionalInject();
|
List<InjectPayloadSleigh> additionalInject = language.getAdditionalInject();
|
||||||
if (additionalInject != null) {
|
if (additionalInject != null) {
|
||||||
|
@ -254,16 +255,6 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||||
ctxsetting.add(new ContextSetting(reg, value, begad, endad));
|
ctxsetting.add(new ContextSetting(reg, value, begad, endad));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCallStackMod() {
|
|
||||||
return defaultModel.getExtrapop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCallStackShift() {
|
|
||||||
return defaultModel.getStackshift();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrototypeModel[] getCallingConventions() {
|
public PrototypeModel[] getCallingConventions() {
|
||||||
return models;
|
return models;
|
||||||
|
@ -491,6 +482,12 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||||
evalCurrentPrototype = parser.start().getAttribute("name");
|
evalCurrentPrototype = parser.start().getAttribute("name");
|
||||||
parser.end();
|
parser.end();
|
||||||
}
|
}
|
||||||
|
else if (name.equals("segmentop")) {
|
||||||
|
XmlElement el = parser.start();
|
||||||
|
InjectPayloadSleigh payload = language.parseSegmentOp(el, parser);
|
||||||
|
parser.end();
|
||||||
|
pcodeInject.registerInject(payload);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
XmlElement el = parser.start();
|
XmlElement el = parser.start();
|
||||||
parser.discardSubTree(el);
|
parser.discardSubTree(el);
|
||||||
|
|
|
@ -89,22 +89,6 @@ public interface CompilerSpec {
|
||||||
*/
|
*/
|
||||||
public AddressSpace getStackBaseSpace();
|
public AddressSpace getStackBaseSpace();
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of extra bytes popped from the stack on return
|
|
||||||
* -1 if it is unknown.
|
|
||||||
* @return # of bytes popped from the stack by a called function on return.
|
|
||||||
*/
|
|
||||||
public int getCallStackMod();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the normal shift in the stack at the call to this routine.
|
|
||||||
* This will be the things pushed on the stack as part of the calling
|
|
||||||
* conventions. Normally the return value.
|
|
||||||
*
|
|
||||||
* @return entry stack shift or -1 if it is unknown
|
|
||||||
*/
|
|
||||||
public int getCallStackShift();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if stack grows with negative offsets
|
* Returns true if stack grows with negative offsets
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -112,18 +112,19 @@ public class FunctionPrototype {
|
||||||
// function pointer, in which case forcing the void
|
// function pointer, in which case forcing the void
|
||||||
// causes the decompiler to drop real parameters.
|
// causes the decompiler to drop real parameters.
|
||||||
// At the moment, we turn on varargs if there are no params
|
// At the moment, we turn on varargs if there are no params
|
||||||
if (voidimpliesdotdotdot && voidinputlock)
|
if (voidimpliesdotdotdot && voidinputlock) {
|
||||||
dotdotdot = true;
|
dotdotdot = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate Function Prototype from information attached to a function in the Program DB.
|
* Populate Function Prototype from information attached to a function in the Program DB.
|
||||||
*
|
*
|
||||||
* @param f is the function to grab prototype from
|
* @param f is the function to grab prototype from
|
||||||
* @param default_extrapop
|
* @param overrideExtrapop is the override value to use for extrapop
|
||||||
* @param override_extrapop
|
* @param doOverride is true if the override value should be used
|
||||||
*/
|
*/
|
||||||
void grabFromFunction(Function f, int default_extrapop, boolean override_extrapop) {
|
void grabFromFunction(Function f, int overrideExtrapop, boolean doOverride) {
|
||||||
modelname = f.getCallingConventionName();
|
modelname = f.getCallingConventionName();
|
||||||
modellock =
|
modellock =
|
||||||
((modelname != null) && (modelname != Function.UNKNOWN_CALLING_CONVENTION_STRING));
|
((modelname != null) && (modelname != Function.UNKNOWN_CALLING_CONVENTION_STRING));
|
||||||
|
@ -134,10 +135,12 @@ public class FunctionPrototype {
|
||||||
returnstorage = returnparam.getVariableStorage();
|
returnstorage = returnparam.getVariableStorage();
|
||||||
|
|
||||||
SourceType sigSource = f.getSignatureSource();
|
SourceType sigSource = f.getSignatureSource();
|
||||||
if (sigSource != SourceType.DEFAULT)
|
if (sigSource != SourceType.DEFAULT) {
|
||||||
outputlock = DataType.DEFAULT != returntype;
|
outputlock = DataType.DEFAULT != returntype;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
outputlock = false;
|
outputlock = false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((returnstorage == null) || (!returnstorage.isValid())) { // Unassigned or otherwise invalid storage
|
if ((returnstorage == null) || (!returnstorage.isValid())) { // Unassigned or otherwise invalid storage
|
||||||
outputlock = false;
|
outputlock = false;
|
||||||
|
@ -157,12 +160,21 @@ public class FunctionPrototype {
|
||||||
// stackshift is the normal stack change because of a call.
|
// stackshift is the normal stack change because of a call.
|
||||||
//
|
//
|
||||||
int purge = f.getStackPurgeSize();
|
int purge = f.getStackPurgeSize();
|
||||||
if (override_extrapop || purge == Function.INVALID_STACK_DEPTH_CHANGE ||
|
if (doOverride) {
|
||||||
purge == Function.UNKNOWN_STACK_DEPTH_CHANGE) {
|
extrapop = overrideExtrapop;
|
||||||
extrapop = default_extrapop;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
extrapop = purge + f.getProgram().getCompilerSpec().getCallStackShift();
|
PrototypeModel protoModel = f.getCallingConvention();
|
||||||
|
if (protoModel == null) {
|
||||||
|
protoModel = f.getProgram().getCompilerSpec().getDefaultCallingConvention();
|
||||||
|
}
|
||||||
|
if (purge == Function.INVALID_STACK_DEPTH_CHANGE ||
|
||||||
|
purge == Function.UNKNOWN_STACK_DEPTH_CHANGE) {
|
||||||
|
extrapop = protoModel.getExtrapop();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
extrapop = purge + protoModel.getStackshift();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,8 +199,9 @@ public class FunctionPrototype {
|
||||||
* @return the number of defined parameters for this function prototype
|
* @return the number of defined parameters for this function prototype
|
||||||
*/
|
*/
|
||||||
public int getNumParams() {
|
public int getNumParams() {
|
||||||
if (localsyms != null)
|
if (localsyms != null) {
|
||||||
return localsyms.getNumParams();
|
return localsyms.getNumParams();
|
||||||
|
}
|
||||||
return params.length;
|
return params.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,8 +211,9 @@ public class FunctionPrototype {
|
||||||
* if this prototype is not backed by a LocalSymbolMap
|
* if this prototype is not backed by a LocalSymbolMap
|
||||||
*/
|
*/
|
||||||
public HighParam getParam(int i) {
|
public HighParam getParam(int i) {
|
||||||
if (localsyms != null)
|
if (localsyms != null) {
|
||||||
return localsyms.getParam(i);
|
return localsyms.getParam(i);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,36 +313,50 @@ public class FunctionPrototype {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* append an XML string representing this function prototype
|
* append an XML string representing this function prototype
|
||||||
|
* @param res is where the string should be appended
|
||||||
|
* @param dtmanage is the DataTypeManager for building type reference tags
|
||||||
*/
|
*/
|
||||||
public void buildPrototypeXML(StringBuilder res, PcodeDataTypeManager dtmanage) {
|
public void buildPrototypeXML(StringBuilder res, PcodeDataTypeManager dtmanage) {
|
||||||
res.append("<prototype");
|
res.append("<prototype");
|
||||||
if (extrapop == PrototypeModel.UNKNOWN_EXTRAPOP)
|
if (extrapop == PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||||
SpecXmlUtils.encodeStringAttribute(res, "extrapop", "unknown");
|
SpecXmlUtils.encodeStringAttribute(res, "extrapop", "unknown");
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
SpecXmlUtils.encodeSignedIntegerAttribute(res, "extrapop", extrapop);
|
SpecXmlUtils.encodeSignedIntegerAttribute(res, "extrapop", extrapop);
|
||||||
|
}
|
||||||
SpecXmlUtils.encodeStringAttribute(res, "model", modelname);
|
SpecXmlUtils.encodeStringAttribute(res, "model", modelname);
|
||||||
if (modellock)
|
if (modellock) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "modellock", modellock);
|
SpecXmlUtils.encodeBooleanAttribute(res, "modellock", modellock);
|
||||||
if (dotdotdot)
|
}
|
||||||
|
if (dotdotdot) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "dotdotdot", dotdotdot);
|
SpecXmlUtils.encodeBooleanAttribute(res, "dotdotdot", dotdotdot);
|
||||||
if (voidinputlock)
|
}
|
||||||
|
if (voidinputlock) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "voidlock", voidinputlock);
|
SpecXmlUtils.encodeBooleanAttribute(res, "voidlock", voidinputlock);
|
||||||
if (isinline)
|
}
|
||||||
|
if (isinline) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "inline", isinline);
|
SpecXmlUtils.encodeBooleanAttribute(res, "inline", isinline);
|
||||||
if (noreturn)
|
}
|
||||||
|
if (noreturn) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "noreturn", noreturn);
|
SpecXmlUtils.encodeBooleanAttribute(res, "noreturn", noreturn);
|
||||||
if (custom)
|
}
|
||||||
|
if (custom) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "custom", custom);
|
SpecXmlUtils.encodeBooleanAttribute(res, "custom", custom);
|
||||||
if (hasThis)
|
}
|
||||||
|
if (hasThis) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "hasthis", hasThis);
|
SpecXmlUtils.encodeBooleanAttribute(res, "hasthis", hasThis);
|
||||||
if (isConstruct)
|
}
|
||||||
|
if (isConstruct) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "constructor", isConstruct);
|
SpecXmlUtils.encodeBooleanAttribute(res, "constructor", isConstruct);
|
||||||
if (isDestruct)
|
}
|
||||||
|
if (isDestruct) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "destructor", isDestruct);
|
SpecXmlUtils.encodeBooleanAttribute(res, "destructor", isDestruct);
|
||||||
|
}
|
||||||
res.append(">\n");
|
res.append(">\n");
|
||||||
res.append(" <returnsym");
|
res.append(" <returnsym");
|
||||||
if (outputlock)
|
if (outputlock) {
|
||||||
SpecXmlUtils.encodeBooleanAttribute(res, "typelock", outputlock);
|
SpecXmlUtils.encodeBooleanAttribute(res, "typelock", outputlock);
|
||||||
|
}
|
||||||
res.append(">\n ");
|
res.append(">\n ");
|
||||||
int sz = returntype.getLength();
|
int sz = returntype.getLength();
|
||||||
if (sz < 0) {
|
if (sz < 0) {
|
||||||
|
@ -338,14 +366,16 @@ public class FunctionPrototype {
|
||||||
if ((returnstorage != null) && returnstorage.isValid() &&
|
if ((returnstorage != null) && returnstorage.isValid() &&
|
||||||
(!returnstorage.isVoidStorage())) {
|
(!returnstorage.isVoidStorage())) {
|
||||||
int logicalsize = 0; // Assume logicalsize of return matches datatype size
|
int logicalsize = 0; // Assume logicalsize of return matches datatype size
|
||||||
if (sz != returnstorage.size()) // If the sizes do not match
|
if (sz != returnstorage.size()) { // If the sizes do no match
|
||||||
logicalsize = sz; // force the logical size on the varnode
|
logicalsize = sz; // force the logical size on the varnode
|
||||||
|
}
|
||||||
String addrstring = Varnode.buildXMLAddress(returnstorage.getVarnodes(), logicalsize);
|
String addrstring = Varnode.buildXMLAddress(returnstorage.getVarnodes(), logicalsize);
|
||||||
res.append(addrstring).append("\n ");
|
res.append(addrstring).append("\n ");
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
// Decompiler will use model for storage
|
// Decompiler will use model for storage
|
||||||
res.append("<addr/>\n "); // Don't specify where return type is stored
|
res.append("<addr/>\n "); // Don't specify where return type is stored
|
||||||
|
}
|
||||||
|
|
||||||
res.append(dtmanage.buildTypeRef(returntype, sz));
|
res.append(dtmanage.buildTypeRef(returntype, sz));
|
||||||
res.append(" </returnsym>\n");
|
res.append(" </returnsym>\n");
|
||||||
|
@ -370,8 +400,9 @@ public class FunctionPrototype {
|
||||||
res.append("\">\n");
|
res.append("\">\n");
|
||||||
res.append(" <addr/>\n "); // Blank address
|
res.append(" <addr/>\n "); // Blank address
|
||||||
sz = dt.getLength();
|
sz = dt.getLength();
|
||||||
if (sz < 0)
|
if (sz < 0) {
|
||||||
sz = 1;
|
sz = 1;
|
||||||
|
}
|
||||||
res.append(dtmanage.buildTypeRef(dt, sz));
|
res.append(dtmanage.buildTypeRef(dt, sz));
|
||||||
res.append("</param>\n");
|
res.append("</param>\n");
|
||||||
}
|
}
|
||||||
|
@ -381,21 +412,22 @@ public class FunctionPrototype {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the function prototype from an XML tree node.
|
* Parse the function prototype from <prototype> tag.
|
||||||
*
|
* @param parser is the XML document to parse
|
||||||
* @param node XML tree node from a parsing of a larger XML document
|
* @param dtmanage is the DataTypeManager used to parse data-type tags
|
||||||
*
|
* @throws PcodeXMLException for any problems parsing
|
||||||
* @throws PcodeXMLException
|
|
||||||
*/
|
*/
|
||||||
public void readPrototypeXML(XmlPullParser parser, PcodeDataTypeManager dtmanage)
|
public void readPrototypeXML(XmlPullParser parser, PcodeDataTypeManager dtmanage)
|
||||||
throws PcodeXMLException {
|
throws PcodeXMLException {
|
||||||
XmlElement node = parser.start("prototype");
|
XmlElement node = parser.start("prototype");
|
||||||
modelname = node.getAttribute("model");
|
modelname = node.getAttribute("model");
|
||||||
String val = node.getAttribute("extrapop");
|
String val = node.getAttribute("extrapop");
|
||||||
if (val.equals("unknown"))
|
if (val.equals("unknown")) {
|
||||||
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
extrapop = SpecXmlUtils.decodeInt(val);
|
extrapop = SpecXmlUtils.decodeInt(val);
|
||||||
|
}
|
||||||
modellock = false;
|
modellock = false;
|
||||||
if (node.hasAttribute("modellock")) {
|
if (node.hasAttribute("modellock")) {
|
||||||
modellock = SpecXmlUtils.decodeBoolean(node.getAttribute("modellock"));
|
modellock = SpecXmlUtils.decodeBoolean(node.getAttribute("modellock"));
|
||||||
|
@ -434,16 +466,18 @@ public class FunctionPrototype {
|
||||||
}
|
}
|
||||||
XmlElement retel = parser.start("returnsym");
|
XmlElement retel = parser.start("returnsym");
|
||||||
outputlock = false;
|
outputlock = false;
|
||||||
if (retel.hasAttribute("typelock"))
|
if (retel.hasAttribute("typelock")) {
|
||||||
outputlock = SpecXmlUtils.decodeBoolean(retel.getAttribute("typelock"));
|
outputlock = SpecXmlUtils.decodeBoolean(retel.getAttribute("typelock"));
|
||||||
|
}
|
||||||
parser.discardSubTree();
|
parser.discardSubTree();
|
||||||
returnstorage = null; // For now don't use decompiler's return storage
|
returnstorage = null; // For now don't use decompiler's return storage
|
||||||
returntype = dtmanage.readXMLDataType(parser);
|
returntype = dtmanage.readXMLDataType(parser);
|
||||||
parser.end(retel);
|
parser.end(retel);
|
||||||
|
|
||||||
XmlElement peeknode = parser.peek();
|
XmlElement peeknode = parser.peek();
|
||||||
if ((peeknode != null) && peeknode.isStart())
|
if ((peeknode != null) && peeknode.isStart()) {
|
||||||
parser.discardSubTree(); // The decompiler may return an <inject> tag
|
parser.discardSubTree(); // The decompiler may return an <inject> tag
|
||||||
|
}
|
||||||
parser.end(node);
|
parser.end(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,8 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param function function associated with the higher level function abstraction.
|
* @param function function associated with the higher level function abstraction.
|
||||||
* @param langParser language parser used to disassemble/get info on the language
|
* @param language description of the processor language of the function
|
||||||
|
* @param compilerSpec description of the compiler that produced the function
|
||||||
* @param dtManager data type manager
|
* @param dtManager data type manager
|
||||||
* @param showNamespace true signals to print function names with their namespace
|
* @param showNamespace true signals to print function names with their namespace
|
||||||
*/
|
*/
|
||||||
|
@ -124,33 +125,20 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate the information for the HighFunction from the information stored in Ghidra attached
|
* Populate the information for the HighFunction from the information in the
|
||||||
* to the function.
|
* Function object.
|
||||||
*
|
*
|
||||||
* @param default_extrapop
|
* @param overrideExtrapop is the value to use if extrapop is overridden
|
||||||
* @param includeDefaultNames
|
* @param includeDefaultNames is true if default symbol names should be considered locked
|
||||||
* @param override_extrapop
|
* @param doOverride is true if extrapop is overridden
|
||||||
*/
|
*/
|
||||||
public void grabFromFunction(int default_extrapop, boolean includeDefaultNames,
|
public void grabFromFunction(int overrideExtrapop, boolean includeDefaultNames,
|
||||||
boolean override_extrapop) {
|
boolean doOverride) {
|
||||||
localSymbols.grabFromFunction(includeDefaultNames); // Locals must be read first
|
localSymbols.grabFromFunction(includeDefaultNames); // Locals must be read first
|
||||||
proto.grabFromFunction(func, default_extrapop, override_extrapop);
|
proto.grabFromFunction(func, overrideExtrapop, doOverride);
|
||||||
jumpTables = null;
|
jumpTables = null;
|
||||||
protoOverrides = null;
|
protoOverrides = null;
|
||||||
grabOverrides();
|
grabOverrides();
|
||||||
|
|
||||||
// This reads any old actions from the StringProperty
|
|
||||||
// This is needed for backward compatibility
|
|
||||||
// String actstring = HighFunction.tagFindInclude("actionlist",funcstring);
|
|
||||||
// if (actstring != null) {
|
|
||||||
// try {
|
|
||||||
// Element el = stringTree(actstring);
|
|
||||||
// readActionXML(el,this);
|
|
||||||
// } catch (PcodeXMLException e) {
|
|
||||||
// Err.error(this, null, "Error", "Unexpected Exception: " + e.getMessage(), e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -312,10 +300,10 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read in the Jump Table list for this function from an XML rep
|
* Read in the Jump Table list for this function from XML
|
||||||
*
|
*
|
||||||
* @param el
|
* @param parser is the XML stream
|
||||||
* @throws PcodeXMLException
|
* @throws PcodeXMLException for any format errors
|
||||||
*/
|
*/
|
||||||
private void readJumpTableListXML(XmlPullParser parser) throws PcodeXMLException {
|
private void readJumpTableListXML(XmlPullParser parser) throws PcodeXMLException {
|
||||||
XmlElement el = parser.start("jumptablelist");
|
XmlElement el = parser.start("jumptablelist");
|
||||||
|
@ -425,11 +413,9 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
* @param high is the HighVariable to split
|
* @param high is the HighVariable to split
|
||||||
* @param vn is a representative of the merge group to split out
|
* @param vn is a representative of the merge group to split out
|
||||||
* @return a HighVariable containing just the forced merge group of vn
|
* @return a HighVariable containing just the forced merge group of vn
|
||||||
* @throws PcodeException
|
* @throws PcodeException if the split can't be performed
|
||||||
*/
|
*/
|
||||||
public HighVariable splitOutMergeGroup(HighVariable high, Varnode vn) throws PcodeException {
|
public HighVariable splitOutMergeGroup(HighVariable high, Varnode vn) throws PcodeException {
|
||||||
// if (high.isNameLocked() || high.isTypeLocked())
|
|
||||||
// return high; // Locked variable should not be speculatively merged
|
|
||||||
try {
|
try {
|
||||||
ArrayList<Varnode> newinst = new ArrayList<Varnode>();
|
ArrayList<Varnode> newinst = new ArrayList<Varnode>();
|
||||||
ArrayList<Varnode> oldinst = new ArrayList<Varnode>();
|
ArrayList<Varnode> oldinst = new ArrayList<Varnode>();
|
||||||
|
@ -508,9 +494,13 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build an XML string that represents all the information about this HighFunction.
|
* Build an XML string that represents all the information about this HighFunction. The
|
||||||
|
* size describes how many bytes starting from the entry point are used by the function, but
|
||||||
|
* this doesn't need to be strictly accurate as it is only used to associate the function with
|
||||||
|
* addresses near its entry point.
|
||||||
*
|
*
|
||||||
* @param entryPoint pass null to use the function entryPoint, pass an address to force an entry point
|
* @param entryPoint pass null to use the function entryPoint, pass an address to force an entry point
|
||||||
|
* @param size describes how many bytes the function occupies as code
|
||||||
* @return the XML string
|
* @return the XML string
|
||||||
*/
|
*/
|
||||||
public String buildFunctionXML(Address entryPoint, int size) {
|
public String buildFunctionXML(Address entryPoint, int size) {
|
||||||
|
@ -588,28 +578,6 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
return resBuf.toString();
|
return resBuf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert old decompiler tags to new Register variables
|
|
||||||
*/
|
|
||||||
// public void updateVersion() {
|
|
||||||
// StringPropertyMap stringmap = func.getProgram().getUsrPropertyManager().getStringPropertyMap(DECOMPILER_TAG_MAP);
|
|
||||||
// String funcstring = null;
|
|
||||||
// if (stringmap != null)
|
|
||||||
// funcstring = stringmap.getString(func.getEntryPoint());
|
|
||||||
//
|
|
||||||
// String actstring = HighFunction.tagFindInclude("actionlist",funcstring);
|
|
||||||
// if (actstring == null) return;
|
|
||||||
// try {
|
|
||||||
// Element el = stringTree(actstring);
|
|
||||||
// readActionXML(el,this);
|
|
||||||
// } catch (PcodeXMLException e) {
|
|
||||||
// Err.error(this, null, "Error", "Unexpected Exception: " + e.getMessage(), e);
|
|
||||||
// }
|
|
||||||
// locals.grabFromFunction();
|
|
||||||
// getLocalVariableMap().storeUnMappedToDatabase();
|
|
||||||
// updateProperties();
|
|
||||||
// }
|
|
||||||
|
|
||||||
public static ErrorHandler getErrorHandler(final Object errOriginator,
|
public static ErrorHandler getErrorHandler(final Object errOriginator,
|
||||||
final String targetName) {
|
final String targetName) {
|
||||||
return new ErrorHandler() {
|
return new ErrorHandler() {
|
||||||
|
@ -708,14 +676,15 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and XML SAX parse tree from an input XML string
|
* Create XML parse tree from an input XML string
|
||||||
*
|
*
|
||||||
* TODO: this probably doesn't belong here.
|
* TODO: this probably doesn't belong here.
|
||||||
*
|
*
|
||||||
* @param xml string to parse
|
* @param xml is the XML string to parse
|
||||||
* @return an XML tree element
|
* @param handler is the handler to use for parsing errors
|
||||||
|
* @return the XML tree
|
||||||
*
|
*
|
||||||
* @throws PcodeXMLException
|
* @throws PcodeXMLException for format errors in the XML
|
||||||
*/
|
*/
|
||||||
static public XmlPullParser stringTree(InputStream xml, ErrorHandler handler)
|
static public XmlPullParser stringTree(InputStream xml, ErrorHandler handler)
|
||||||
throws PcodeXMLException {
|
throws PcodeXMLException {
|
||||||
|
|
|
@ -539,16 +539,6 @@ class TemporaryCompilerSpec implements CompilerSpec {
|
||||||
public void applyContextSettings(DefaultProgramContext ctx) {
|
public void applyContextSettings(DefaultProgramContext ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCallStackMod() {
|
|
||||||
return newCompilerSpec.getCallStackMod();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCallStackShift() {
|
|
||||||
return newCompilerSpec.getCallStackShift();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrototypeModel[] getCallingConventions() {
|
public PrototypeModel[] getCallingConventions() {
|
||||||
return new PrototypeModel[0];
|
return new PrototypeModel[0];
|
||||||
|
|
|
@ -9,10 +9,15 @@
|
||||||
<range space="io"/>
|
<range space="io"/>
|
||||||
</global>
|
</global>
|
||||||
<stackpointer register="SP" space="ram"/>
|
<stackpointer register="SP" space="ram"/>
|
||||||
<segmentop space="ram" userop="segment" baseinsize="2" innerinsize="2" farpointer="yes">
|
<segmentop space="ram" userop="segment" farpointer="yes">
|
||||||
<baseop code="INT_ZEXT"/>
|
<pcode>
|
||||||
<baseop code="INT_LEFT" value="12"/>
|
<input name="inner" size="2"/>
|
||||||
<innerop code="INT_ZEXT"/>
|
<input name="base" size="2"/>
|
||||||
|
<output name="res" size="2"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
res = (base << 12) + inner;
|
||||||
|
]]></body>
|
||||||
|
</pcode>
|
||||||
<constresolve>
|
<constresolve>
|
||||||
<register name="rBBR"/>
|
<register name="rBBR"/>
|
||||||
</constresolve>
|
</constresolve>
|
||||||
|
|
|
@ -27,6 +27,7 @@ data/languages/rdseed.sinc||GHIDRA||||END|
|
||||||
data/languages/sgx.sinc||GHIDRA||||END|
|
data/languages/sgx.sinc||GHIDRA||||END|
|
||||||
data/languages/sha.sinc||GHIDRA||||END|
|
data/languages/sha.sinc||GHIDRA||||END|
|
||||||
data/languages/smx.sinc||GHIDRA||||END|
|
data/languages/smx.sinc||GHIDRA||||END|
|
||||||
|
data/languages/x86-16-real.pspec||GHIDRA||||END|
|
||||||
data/languages/x86-16.cspec||GHIDRA||||END|
|
data/languages/x86-16.cspec||GHIDRA||||END|
|
||||||
data/languages/x86-16.pspec||GHIDRA||||END|
|
data/languages/x86-16.pspec||GHIDRA||||END|
|
||||||
data/languages/x86-64-gcc.cspec||GHIDRA||||END|
|
data/languages/x86-64-gcc.cspec||GHIDRA||||END|
|
||||||
|
@ -34,8 +35,6 @@ data/languages/x86-64-win.cspec||GHIDRA||||END|
|
||||||
data/languages/x86-64.dwarf||GHIDRA||||END|
|
data/languages/x86-64.dwarf||GHIDRA||||END|
|
||||||
data/languages/x86-64.pspec||GHIDRA||||END|
|
data/languages/x86-64.pspec||GHIDRA||||END|
|
||||||
data/languages/x86-64.slaspec||GHIDRA||||END|
|
data/languages/x86-64.slaspec||GHIDRA||||END|
|
||||||
data/languages/x86-smm.cspec||GHIDRA||||END|
|
|
||||||
data/languages/x86-smm.pspec||GHIDRA||||END|
|
|
||||||
data/languages/x86.dwarf||GHIDRA||||END|
|
data/languages/x86.dwarf||GHIDRA||||END|
|
||||||
data/languages/x86.ldefs||GHIDRA||||END|
|
data/languages/x86.ldefs||GHIDRA||||END|
|
||||||
data/languages/x86.opinion||GHIDRA||||END|
|
data/languages/x86.opinion||GHIDRA||||END|
|
||||||
|
|
|
@ -251,7 +251,7 @@ define context contextreg
|
||||||
opsize=(2,3) # =0 16-bit operands =1 32-bit operands =2 64-bit operands
|
opsize=(2,3) # =0 16-bit operands =1 32-bit operands =2 64-bit operands
|
||||||
segover=(4,6) # 0=default 1=cs 2=ss 3=ds 4=es 5=fs 6=gs
|
segover=(4,6) # 0=default 1=cs 2=ss 3=ds 4=es 5=fs 6=gs
|
||||||
highseg=(4,4) # high bit of segover will be set for ES, FS, GS
|
highseg=(4,4) # high bit of segover will be set for ES, FS, GS
|
||||||
# sstype=(7,7) # 0=DS default 1=SS default
|
protectedMode=(7,7) # 0 for real mode, 1 for protected mode
|
||||||
|
|
||||||
repneprefx=(8,8) # 0xf2 REPNE prefix
|
repneprefx=(8,8) # 0xf2 REPNE prefix
|
||||||
repprefx=(9,9) # 0xf3 REP prefix
|
repprefx=(9,9) # 0xf3 REP prefix
|
||||||
|
@ -1056,7 +1056,9 @@ addr64: [Base64 + Index64*ss] is mod=2 & r_m=4; Index64 & Base64 & ss; imm32=0
|
||||||
addr64: [Base64] is mod=2 & r_m=4; rexXprefix=0 & index64=4 & Base64; imm32=0 { export Base64; }
|
addr64: [Base64] is mod=2 & r_m=4; rexXprefix=0 & index64=4 & Base64; imm32=0 { export Base64; }
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
currentCS: CS is protectedMode=0 & CS { tmp:4 = (inst_next >> 4) & 0xf000; CS = tmp:2; export CS; }
|
||||||
|
currentCS: CS is protectedMode=1 & CS { tmp:4 = (inst_next >> 16) & 0xffff; CS = tmp:2; export CS; }
|
||||||
|
|
||||||
segWide: is segover=0 { export 0:$(SIZE); }
|
segWide: is segover=0 { export 0:$(SIZE); }
|
||||||
segWide: CS: is segover=1 & CS { export 0:$(SIZE); }
|
segWide: CS: is segover=1 & CS { export 0:$(SIZE); }
|
||||||
segWide: SS: is segover=2 & SS { export 0:$(SIZE); }
|
segWide: SS: is segover=2 & SS { export 0:$(SIZE); }
|
||||||
|
@ -1066,7 +1068,7 @@ segWide: FS: is segover=5 & FS { export FS_OFFSET; }
|
||||||
segWide: GS: is segover=6 & GS { export GS_OFFSET; }
|
segWide: GS: is segover=6 & GS { export GS_OFFSET; }
|
||||||
|
|
||||||
seg16: is segover=0 { export DS; }
|
seg16: is segover=0 { export DS; }
|
||||||
seg16: CS: is segover=1 & CS { export CS; }
|
seg16: currentCS: is segover=1 & currentCS { export currentCS; }
|
||||||
seg16: SS: is segover=2 & SS { export SS; }
|
seg16: SS: is segover=2 & SS { export SS; }
|
||||||
seg16: DS: is segover=3 & DS { export DS; }
|
seg16: DS: is segover=3 & DS { export DS; }
|
||||||
seg16: ES: is segover=4 & ES { export ES; }
|
seg16: ES: is segover=4 & ES { export ES; }
|
||||||
|
@ -1387,10 +1389,8 @@ check_Rmr32_dest: is epsilon { }
|
||||||
check_rm32_dest: is epsilon { }
|
check_rm32_dest: is epsilon { }
|
||||||
check_EAX_dest: is epsilon { }
|
check_EAX_dest: is epsilon { }
|
||||||
|
|
||||||
# The far addresses listed here actually specify the CS segment to use
|
ptr1616: reloc is protectedMode=0 & imm16; j16 [ reloc = j16*0x10 + imm16; ] { CS = j16; export *[ram]:4 reloc; }
|
||||||
# but we do not model changing the CS segment in protected mode
|
ptr1616: reloc is protectedMode=1 & imm16; j16 [ reloc = j16*0x10000 + imm16; ] { CS = j16; export *[ram]:4 reloc; }
|
||||||
# so we just use the offset portion of the address
|
|
||||||
ptr1616: reloc is imm16; j16 [ reloc = j16*16 + imm16; ] { CS = j16; export *[ram]:4 reloc; }
|
|
||||||
ptr1632: j16":"imm32 is imm32; j16 { CS = j16; export *:4 imm32; }
|
ptr1632: j16":"imm32 is imm32; j16 { CS = j16; export *:4 imm32; }
|
||||||
|
|
||||||
|
|
||||||
|
@ -2711,7 +2711,7 @@ Suffix3D: imm8 is imm8 [ suffix3D=imm8; ] { }
|
||||||
@ifdef IA64
|
@ifdef IA64
|
||||||
:CALL rel32 is vexMode=0 & addrsize=2 & (opsize=1 | opsize=2) & byte=0xe8; simm32=0 & rel32 { push88(&:8 inst_next); goto rel32; }
|
:CALL rel32 is vexMode=0 & addrsize=2 & (opsize=1 | opsize=2) & byte=0xe8; simm32=0 & rel32 { push88(&:8 inst_next); goto rel32; }
|
||||||
@endif
|
@endif
|
||||||
:CALL rm16 is addrsize=0 & opsize=0 & byte=0xff; rm16 & reg_opcode=2 ... { push22(&:2 inst_next); tmp:4 = segment(CS,rm16); call [tmp]; }
|
:CALL rm16 is addrsize=0 & opsize=0 & byte=0xff & currentCS; rm16 & reg_opcode=2 ... { push22(&:2 inst_next); tmp:4 = segment(currentCS,rm16); call [tmp]; }
|
||||||
:CALL rm16 is vexMode=0 & addrsize=1 & opsize=0 & byte=0xff; rm16 & reg_opcode=2 ... { push42(&:2 inst_next); call [rm16]; }
|
:CALL rm16 is vexMode=0 & addrsize=1 & opsize=0 & byte=0xff; rm16 & reg_opcode=2 ... { push42(&:2 inst_next); call [rm16]; }
|
||||||
@ifdef IA64
|
@ifdef IA64
|
||||||
:CALL rm16 is vexMode=0 & addrsize=2 & opsize=0 & byte=0xff; rm16 & reg_opcode=2 ... { push82(&:2 inst_next); tmp:8 = inst_next + zext(rm16); call [tmp]; }
|
:CALL rm16 is vexMode=0 & addrsize=2 & opsize=0 & byte=0xff; rm16 & reg_opcode=2 ... { push82(&:2 inst_next); tmp:8 = inst_next + zext(rm16); call [tmp]; }
|
||||||
|
@ -3415,7 +3415,7 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; }
|
||||||
:JMP rel16 is vexMode=0 & opsize=0 & byte=0xe9; rel16 { goto rel16; }
|
:JMP rel16 is vexMode=0 & opsize=0 & byte=0xe9; rel16 { goto rel16; }
|
||||||
:JMP rel32 is vexMode=0 & opsize=1 & byte=0xe9; rel32 { goto rel32; }
|
:JMP rel32 is vexMode=0 & opsize=1 & byte=0xe9; rel32 { goto rel32; }
|
||||||
:JMP rel32 is vexMode=0 & opsize=2 & byte=0xe9; rel32 { goto rel32; }
|
:JMP rel32 is vexMode=0 & opsize=2 & byte=0xe9; rel32 { goto rel32; }
|
||||||
:JMP rm16 is vexMode=0 & addrsize=0 & opsize=0 & byte=0xff; rm16 & reg_opcode=4 ... { target:4 = segment(CS,rm16); goto [target]; }
|
:JMP rm16 is vexMode=0 & addrsize=0 & opsize=0 & byte=0xff & currentCS; rm16 & reg_opcode=4 ... { target:4 = segment(currentCS,rm16); goto [target]; }
|
||||||
:JMP rm16 is vexMode=0 & addrsize=1 & opsize=0 & byte=0xff; rm16 & reg_opcode=4 ... { goto [rm16]; }
|
:JMP rm16 is vexMode=0 & addrsize=1 & opsize=0 & byte=0xff; rm16 & reg_opcode=4 ... { goto [rm16]; }
|
||||||
:JMP rm32 is vexMode=0 & addrsize=1 & opsize=1 & byte=0xff; rm32 & reg_opcode=4 ... { goto [rm32]; }
|
:JMP rm32 is vexMode=0 & addrsize=1 & opsize=1 & byte=0xff; rm32 & reg_opcode=4 ... { goto [rm32]; }
|
||||||
@ifdef IA64
|
@ifdef IA64
|
||||||
|
|
33
Ghidra/Processors/x86/data/languages/x86-16-real.pspec
Normal file
33
Ghidra/Processors/x86/data/languages/x86-16-real.pspec
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!-- Set up x86 16-bit in real mode -->
|
||||||
|
<processor_spec>
|
||||||
|
<properties>
|
||||||
|
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
|
||||||
|
</properties>
|
||||||
|
<programcounter register="EIP"/>
|
||||||
|
<segmented_address space="ram" type="real" />
|
||||||
|
<segmentop space="ram" userop="segment" farpointer="yes">
|
||||||
|
<pcode>
|
||||||
|
<input name="inner" size="2"/>
|
||||||
|
<input name="base" size="2"/>
|
||||||
|
<output name="res" size="4"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
res = (zext(base) << 4) + zext(inner);
|
||||||
|
]]></body>
|
||||||
|
</pcode>
|
||||||
|
<constresolve>
|
||||||
|
<register name="DS"/>
|
||||||
|
</constresolve>
|
||||||
|
</segmentop>
|
||||||
|
<context_data>
|
||||||
|
<context_set space="ram">
|
||||||
|
<set name="addrsize" val="0"/>
|
||||||
|
<set name="opsize" val="0"/>
|
||||||
|
<set name="protectedMode" val="0"/>
|
||||||
|
</context_set>
|
||||||
|
<tracked_set space="ram">
|
||||||
|
<set name="DF" val="0"/>
|
||||||
|
</tracked_set>
|
||||||
|
</context_data>
|
||||||
|
</processor_spec>
|
|
@ -31,14 +31,6 @@
|
||||||
<range space="ram"/>
|
<range space="ram"/>
|
||||||
</global>
|
</global>
|
||||||
<stackpointer register="SP" space="ram"/>
|
<stackpointer register="SP" space="ram"/>
|
||||||
<segmentop space="ram" userop="segment" baseinsize="2" innerinsize="2" farpointer="yes">
|
|
||||||
<baseop code="INT_ZEXT"/>
|
|
||||||
<baseop code="INT_LEFT" value="4"/>
|
|
||||||
<innerop code="INT_ZEXT"/>
|
|
||||||
<constresolve>
|
|
||||||
<register name="DS"/>
|
|
||||||
</constresolve>
|
|
||||||
</segmentop>
|
|
||||||
<default_proto>
|
<default_proto>
|
||||||
<prototype name="__stdcall16near" extrapop="unknown" stackshift="2">
|
<prototype name="__stdcall16near" extrapop="unknown" stackshift="2">
|
||||||
<input>
|
<input>
|
||||||
|
@ -93,7 +85,7 @@
|
||||||
<register name="DF"/>
|
<register name="DF"/>
|
||||||
</unaffected>
|
</unaffected>
|
||||||
</prototype>
|
</prototype>
|
||||||
<prototype name="__stdcall16far" extrapop="unknown" stackshift="2">
|
<prototype name="__stdcall16far" extrapop="unknown" stackshift="4">
|
||||||
<input>
|
<input>
|
||||||
<pentry minsize="1" maxsize="500" align="2">
|
<pentry minsize="1" maxsize="500" align="2">
|
||||||
<addr offset="4" space="stack"/>
|
<addr offset="4" space="stack"/>
|
||||||
|
@ -119,7 +111,7 @@
|
||||||
<register name="DF"/>
|
<register name="DF"/>
|
||||||
</unaffected>
|
</unaffected>
|
||||||
</prototype>
|
</prototype>
|
||||||
<prototype name="__cdecl16far" extrapop="4" stackshift="2">
|
<prototype name="__cdecl16far" extrapop="4" stackshift="4">
|
||||||
<input>
|
<input>
|
||||||
<pentry minsize="1" maxsize="500" align="2">
|
<pentry minsize="1" maxsize="500" align="2">
|
||||||
<addr offset="4" space="stack"/>
|
<addr offset="4" space="stack"/>
|
||||||
|
|
|
@ -1,15 +1,31 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!-- Set up x86 16-bit in protected mode -->
|
||||||
|
|
||||||
<processor_spec>
|
<processor_spec>
|
||||||
<properties>
|
<properties>
|
||||||
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
|
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
|
||||||
</properties>
|
</properties>
|
||||||
<programcounter register="EIP"/>
|
<programcounter register="EIP"/>
|
||||||
<segmented_address space="ram"/>
|
<segmented_address space="ram" type="protected"/>
|
||||||
|
<segmentop space="ram" userop="segment" farpointer="yes">
|
||||||
|
<pcode>
|
||||||
|
<input name="inner" size="2"/>
|
||||||
|
<input name="base" size="2"/>
|
||||||
|
<output name="res" size="4"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
res = (zext(base) << 16) + zext(inner);
|
||||||
|
]]></body>
|
||||||
|
</pcode>
|
||||||
|
<constresolve>
|
||||||
|
<register name="DS"/>
|
||||||
|
</constresolve>
|
||||||
|
</segmentop>
|
||||||
<context_data>
|
<context_data>
|
||||||
<context_set space="ram">
|
<context_set space="ram">
|
||||||
<set name="addrsize" val="0"/>
|
<set name="addrsize" val="0"/>
|
||||||
<set name="opsize" val="0"/>
|
<set name="opsize" val="0"/>
|
||||||
|
<set name="protectedMode" val="1"/>
|
||||||
</context_set>
|
</context_set>
|
||||||
<tracked_set space="ram">
|
<tracked_set space="ram">
|
||||||
<set name="DF" val="0"/>
|
<set name="DF" val="0"/>
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<compiler_spec>
|
|
||||||
<global>
|
|
||||||
<range space="ram"/>
|
|
||||||
</global>
|
|
||||||
<stackpointer register="SP" space="ram"/>
|
|
||||||
<segmentop space="ram"
|
|
||||||
userop="segment"
|
|
||||||
baseinsize="2"
|
|
||||||
innerinsize="2"
|
|
||||||
farpointer="yes"
|
|
||||||
force="false">
|
|
||||||
<baseop code="INT_ZEXT"/>
|
|
||||||
<baseop code="INT_LEFT" value="16"/>
|
|
||||||
<innerop code="INT_ZEXT"/>
|
|
||||||
</segmentop>
|
|
||||||
<default_proto>
|
|
||||||
<prototype name="__stdcall16near" extrapop="unknown" stackshift="2">
|
|
||||||
<input>
|
|
||||||
<pentry minsize="1" maxsize="500" align="2">
|
|
||||||
<addr offset="2" space="stack"/>
|
|
||||||
</pentry>
|
|
||||||
</input>
|
|
||||||
<output>
|
|
||||||
<pentry minsize="1" maxsize="2">
|
|
||||||
<register name="AX"/>
|
|
||||||
</pentry>
|
|
||||||
</output>
|
|
||||||
<unaffected>
|
|
||||||
<register name="SP"/>
|
|
||||||
<register name="BP"/>
|
|
||||||
<register name="SI"/>
|
|
||||||
<register name="DI"/>
|
|
||||||
<register name="DS"/>
|
|
||||||
<register name="CS"/>
|
|
||||||
<register name="ES"/>
|
|
||||||
<register name="SS"/>
|
|
||||||
</unaffected>
|
|
||||||
</prototype>
|
|
||||||
</default_proto>
|
|
||||||
<prototype name="__cdecl16near" extrapop="2" stackshift="2">
|
|
||||||
<input>
|
|
||||||
<pentry minsize="1" maxsize="500" align="2">
|
|
||||||
<addr offset="2" space="stack"/>
|
|
||||||
</pentry>
|
|
||||||
</input>
|
|
||||||
<output>
|
|
||||||
<pentry minsize="1" maxsize="2">
|
|
||||||
<register name="AX"/>
|
|
||||||
</pentry>
|
|
||||||
</output>
|
|
||||||
<unaffected>
|
|
||||||
<register name="SP"/>
|
|
||||||
<register name="BP"/>
|
|
||||||
<register name="SI"/>
|
|
||||||
<register name="DI"/>
|
|
||||||
<register name="DS"/>
|
|
||||||
<register name="CS"/>
|
|
||||||
<register name="ES"/>
|
|
||||||
<register name="SS"/>
|
|
||||||
</unaffected>
|
|
||||||
</prototype>
|
|
||||||
<prototype name="__stdcall16far" extrapop="unknown" stackshift="2">
|
|
||||||
<input>
|
|
||||||
<pentry minsize="1" maxsize="500" align="2">
|
|
||||||
<addr offset="4" space="stack"/>
|
|
||||||
</pentry>
|
|
||||||
</input>
|
|
||||||
<output>
|
|
||||||
<pentry minsize="1" maxsize="2">
|
|
||||||
<register name="AX"/>
|
|
||||||
</pentry>
|
|
||||||
</output>
|
|
||||||
<unaffected>
|
|
||||||
<register name="SP"/>
|
|
||||||
<register name="BP"/>
|
|
||||||
<register name="SI"/>
|
|
||||||
<register name="DI"/>
|
|
||||||
<register name="DS"/>
|
|
||||||
<register name="CS"/>
|
|
||||||
<register name="ES"/>
|
|
||||||
<register name="SS"/>
|
|
||||||
</unaffected>
|
|
||||||
</prototype>
|
|
||||||
<prototype name="__cdecl16far" extrapop="4" stackshift="2">
|
|
||||||
<input>
|
|
||||||
<pentry minsize="1" maxsize="500" align="2">
|
|
||||||
<addr offset="4" space="stack"/>
|
|
||||||
</pentry>
|
|
||||||
</input>
|
|
||||||
<output>
|
|
||||||
<pentry minsize="1" maxsize="2">
|
|
||||||
<register name="AX"/>
|
|
||||||
</pentry>
|
|
||||||
</output>
|
|
||||||
<unaffected>
|
|
||||||
<register name="SP"/>
|
|
||||||
<register name="BP"/>
|
|
||||||
<register name="SI"/>
|
|
||||||
<register name="DI"/>
|
|
||||||
<register name="DS"/>
|
|
||||||
<register name="CS"/>
|
|
||||||
<register name="ES"/>
|
|
||||||
<register name="SS"/>
|
|
||||||
</unaffected>
|
|
||||||
</prototype>
|
|
||||||
</compiler_spec>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<processor_spec>
|
|
||||||
<properties>
|
|
||||||
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
|
|
||||||
</properties>
|
|
||||||
<context_data>
|
|
||||||
<context_set space="ram">
|
|
||||||
<set name="addrsize" val="0"/>
|
|
||||||
<set name="opsize" val="0"/>
|
|
||||||
</context_set>
|
|
||||||
</context_data>
|
|
||||||
</processor_spec>
|
|
|
@ -34,11 +34,11 @@
|
||||||
variant="System Management Mode"
|
variant="System Management Mode"
|
||||||
version="2.8"
|
version="2.8"
|
||||||
slafile="x86.sla"
|
slafile="x86.sla"
|
||||||
processorspec="x86-smm.pspec"
|
processorspec="x86-16.pspec"
|
||||||
manualindexfile="../manuals/x86.idx"
|
manualindexfile="../manuals/x86.idx"
|
||||||
id="x86:LE:32:System Management Mode">
|
id="x86:LE:32:System Management Mode">
|
||||||
<description>Intel/AMD 32-bit x86 System Management Mode</description>
|
<description>Intel/AMD 32-bit x86 System Management Mode</description>
|
||||||
<compiler name="default" spec="x86-smm.cspec" id="default"/>
|
<compiler name="default" spec="x86-16.cspec" id="default"/>
|
||||||
<external_name tool="DWARF.register.mapping.file" name="x86.dwarf"/>
|
<external_name tool="DWARF.register.mapping.file" name="x86.dwarf"/>
|
||||||
</language>
|
</language>
|
||||||
<language processor="x86"
|
<language processor="x86"
|
||||||
|
@ -47,19 +47,31 @@
|
||||||
variant="Real Mode"
|
variant="Real Mode"
|
||||||
version="2.8"
|
version="2.8"
|
||||||
slafile="x86.sla"
|
slafile="x86.sla"
|
||||||
processorspec="x86-16.pspec"
|
processorspec="x86-16-real.pspec"
|
||||||
manualindexfile="../manuals/x86.idx"
|
manualindexfile="../manuals/x86.idx"
|
||||||
id="x86:LE:16:Real Mode">
|
id="x86:LE:16:Real Mode">
|
||||||
<description>Intel/AMD 16-bit x86 Real Mode</description>
|
<description>Intel/AMD 16-bit x86 Real Mode</description>
|
||||||
<compiler name="default" spec="x86-16.cspec" id="default"/>
|
<compiler name="default" spec="x86-16.cspec" id="default"/>
|
||||||
<external_name tool="IDA-PRO" name="8086"/>
|
<external_name tool="IDA-PRO" name="8086"/>
|
||||||
<external_name tool="IDA-PRO" name="8086r"/>
|
<external_name tool="IDA-PRO" name="8086r"/>
|
||||||
<external_name tool="IDA-PRO" name="8086p"/>
|
|
||||||
<external_name tool="IDA-PRO" name="80386r"/>
|
<external_name tool="IDA-PRO" name="80386r"/>
|
||||||
<external_name tool="IDA-PRO" name="80486r"/>
|
<external_name tool="IDA-PRO" name="80486r"/>
|
||||||
<external_name tool="IDA-PRO" name="80586r"/>
|
<external_name tool="IDA-PRO" name="80586r"/>
|
||||||
<external_name tool="IDA-PRO" name="metapc"/>
|
<external_name tool="IDA-PRO" name="metapc"/>
|
||||||
</language>
|
</language>
|
||||||
|
<language processor="x86"
|
||||||
|
endian="little"
|
||||||
|
size="16"
|
||||||
|
variant="Protected Mode"
|
||||||
|
version="2.8"
|
||||||
|
slafile="x86.sla"
|
||||||
|
processorspec="x86-16.pspec"
|
||||||
|
manualindexfile="../manuals/x86.idx"
|
||||||
|
id="x86:LE:16:Protected Mode">
|
||||||
|
<description>Intel/AMD 16-bit x86 Protected Mode</description>
|
||||||
|
<compiler name="default" spec="x86-16.cspec" id="default"/>
|
||||||
|
<external_name tool="IDA-PRO" name="8086p"/>
|
||||||
|
</language>
|
||||||
<language processor="x86"
|
<language processor="x86"
|
||||||
endian="little"
|
endian="little"
|
||||||
size="64"
|
size="64"
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
<constraint primary="23117" processor="x86" endian="little" size="16" variant="Real Mode"/>
|
<constraint primary="23117" processor="x86" endian="little" size="16" variant="Real Mode"/>
|
||||||
</constraint>
|
</constraint>
|
||||||
<constraint loader="New Executable (NE)" compilerSpecID="default">
|
<constraint loader="New Executable (NE)" compilerSpecID="default">
|
||||||
<constraint primary="17742" processor="x86" endian="little" size="16" variant="Real Mode"/>
|
<constraint primary="17742" processor="x86" endian="little" size="16" variant="Protected Mode"/>
|
||||||
</constraint>
|
</constraint>
|
||||||
<constraint loader="Mac OS X Mach-O" compilerSpecID="gcc">
|
<constraint loader="Mac OS X Mach-O" compilerSpecID="gcc">
|
||||||
<constraint primary="7" processor="x86" endian="little" size="32" />
|
<constraint primary="7" processor="x86" endian="little" size="32" />
|
||||||
|
|
|
@ -29,4 +29,9 @@
|
||||||
</compiler>
|
</compiler>
|
||||||
</language>
|
</language>
|
||||||
|
|
||||||
|
<language id="x86:LE:16:Protected Mode">
|
||||||
|
<compiler id="default">
|
||||||
|
<patternfile>x86-16_default_patterns.xml</patternfile>
|
||||||
|
</compiler>
|
||||||
|
</language>
|
||||||
</patternconstraints>
|
</patternconstraints>
|
||||||
|
|
|
@ -6,14 +6,17 @@
|
||||||
<data>0x4dcb</data> <!-- DEC(BP) RET() -->
|
<data>0x4dcb</data> <!-- DEC(BP) RET() -->
|
||||||
<data>0.011... 1100.011</data> <!-- POP(BP|BX|DS|SI) RET -->
|
<data>0.011... 1100.011</data> <!-- POP(BP|BX|DS|SI) RET -->
|
||||||
<data>1100.010 .0.....0 0x00</data> <!-- RET(constant) -->
|
<data>1100.010 .0.....0 0x00</data> <!-- RET(constant) -->
|
||||||
<data>0xc390</data> <!-- RET NOP -->
|
<data>1100.010 .0.....0 0x00 0x90</data> <!-- RET(constant) NOP -->
|
||||||
|
<data>0xc390</data> <!-- RET NOP -->
|
||||||
<data>0xcb90</data>
|
<data>0xcb90</data>
|
||||||
|
<data>0xc3</data>
|
||||||
</prepatterns>
|
</prepatterns>
|
||||||
<postpatterns>
|
<postpatterns>
|
||||||
<data>0x558bec</data> <!-- PUSH(BP) MOV(BP,SP) -->
|
<data>0x558bec</data> <!-- PUSH(BP) MOV(BP,SP) -->
|
||||||
<data>0x5589e5</data> <!-- PUSH(BP) MOV(BP,SP) -->
|
<data>0x5589e5</data> <!-- PUSH(BP) MOV(BP,SP) -->
|
||||||
<data>0xc8 000....0 0x0000</data> <!-- ENTER (constant, 0x0) -->
|
<data>0xc8 000....0 0x0000</data> <!-- ENTER (constant, 0x0) -->
|
||||||
<data>0x8cd89045</data> <!-- MOV(AX,DS) NOP INC(BP) -->
|
<data>0x8cd89045</data> <!-- MOV(AX,DS) NOP INC(BP) -->
|
||||||
|
<data>0x8cd055</data> <!-- MOV(AX,SS) PUSH(BP) -->
|
||||||
<funcstart/>
|
<funcstart/>
|
||||||
</postpatterns>
|
</postpatterns>
|
||||||
</patternpairs>
|
</patternpairs>
|
||||||
|
|
|
@ -11,14 +11,6 @@
|
||||||
<range space="io"/>
|
<range space="io"/>
|
||||||
</global>
|
</global>
|
||||||
<stackpointer register="SP" space="ram"/>
|
<stackpointer register="SP" space="ram"/>
|
||||||
<segmentop space="ram" userop="segment" baseinsize="2" innerinsize="2" farpointer="yes">
|
|
||||||
<baseop code="INT_ZEXT"/>
|
|
||||||
<baseop code="INT_LEFT" value="12"/>
|
|
||||||
<innerop code="INT_ZEXT"/>
|
|
||||||
<constresolve>
|
|
||||||
<register name="rBBR"/>
|
|
||||||
</constresolve>
|
|
||||||
</segmentop>
|
|
||||||
<default_proto>
|
<default_proto>
|
||||||
<prototype name="__asmA" extrapop="2" stackshift="2" strategy="register">
|
<prototype name="__asmA" extrapop="2" stackshift="2" strategy="register">
|
||||||
<input>
|
<input>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue