Merge remote-tracking branch 'origin/GT-3090_16bit_analysis'

This commit is contained in:
Ryan Kurtz 2019-09-06 13:24:34 -04:00
commit 23d1e9ad22
50 changed files with 1000 additions and 877 deletions

View file

@ -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 &&

View file

@ -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;
} }
} }

View file

@ -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;
} }

View file

@ -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) {
} }

View file

@ -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);

View file

@ -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...

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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();

View file

@ -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;
} }

View file

@ -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;
} }

View file

@ -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);

View file

@ -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

View file

@ -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;
} }

View file

@ -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;

View file

@ -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; }

View file

@ -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);
} }

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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>

View file

@ -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"/>

View file

@ -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">

View file

@ -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) {

View file

@ -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;
}
}

View file

@ -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);
}
*/
} }

View file

@ -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()

View file

@ -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);

View file

@ -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
*/ */

View file

@ -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);
} }

View file

@ -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 {

View file

@ -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];

View file

@ -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>

View file

@ -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|

View file

@ -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

View 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>

View file

@ -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"/>

View file

@ -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"/>

View file

@ -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>

View file

@ -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>

View file

@ -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"

View file

@ -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" />

View file

@ -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>

View file

@ -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>

View file

@ -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>