mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/GT-3090_16bit_analysis'
This commit is contained in:
commit
23d1e9ad22
50 changed files with 1000 additions and 877 deletions
|
@ -273,8 +273,7 @@ public class CallDepthChangeInfo {
|
|||
|
||||
PcodeOp[] pcode = instr.getPcode();
|
||||
Varnode outVarNode = null;
|
||||
for (int i = 0; i < pcode.length; i++) {
|
||||
PcodeOp op = pcode[i];
|
||||
for (PcodeOp op : pcode) {
|
||||
Varnode input0 = op.getInput(0);
|
||||
Varnode input1 = op.getInput(1);
|
||||
Varnode output = op.getOutput();
|
||||
|
@ -317,9 +316,10 @@ public class CallDepthChangeInfo {
|
|||
break;
|
||||
case PcodeOp.INT_AND: // Assume this is a stack alignment and do the and
|
||||
if (isStackPointer(input0)) {
|
||||
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE)
|
||||
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) {
|
||||
possibleDepthChange =
|
||||
(int) (currentStackDepth & input1.getOffset()) - currentStackDepth;
|
||||
}
|
||||
outVarNode = output;
|
||||
}
|
||||
else if (input0.equals(outVarNode)) {
|
||||
|
@ -327,9 +327,10 @@ public class CallDepthChangeInfo {
|
|||
outVarNode = output;
|
||||
}
|
||||
else if (isStackPointer(input1)) {
|
||||
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE)
|
||||
if (currentStackDepth != Function.UNKNOWN_STACK_DEPTH_CHANGE) {
|
||||
possibleDepthChange =
|
||||
(int) (currentStackDepth & input0.getOffset()) - currentStackDepth;
|
||||
}
|
||||
outVarNode = output;
|
||||
}
|
||||
else if (input1.equals(outVarNode)) {
|
||||
|
@ -385,7 +386,7 @@ public class CallDepthChangeInfo {
|
|||
|
||||
// TODO: Modify return by normal stack shift....
|
||||
if (flowType.isTerminal()) {
|
||||
depthChange -= program.getCompilerSpec().getCallStackShift();
|
||||
depthChange -= program.getCompilerSpec().getDefaultCallingConvention().getStackshift();
|
||||
}
|
||||
|
||||
// if the current stack depth is still bad, don't return a depth change.
|
||||
|
@ -419,8 +420,9 @@ public class CallDepthChangeInfo {
|
|||
* @return
|
||||
*/
|
||||
private int getDefaultStackDepthChange(int depth) {
|
||||
int callStackMod = program.getCompilerSpec().getCallStackMod();
|
||||
int callStackShift = program.getCompilerSpec().getCallStackShift();
|
||||
PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention();
|
||||
int callStackMod = defaultModel.getExtrapop();
|
||||
int callStackShift = defaultModel.getStackshift();
|
||||
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
|
||||
return callStackShift - callStackMod;
|
||||
}
|
||||
|
@ -578,8 +580,8 @@ public class CallDepthChangeInfo {
|
|||
FlowType flow = instr.getFlowType();
|
||||
if (!flow.isCall()) {
|
||||
Address[] flows = instr.getFlows();
|
||||
for (int i = 0; i < flows.length; i++) {
|
||||
st.push(flows[i]);
|
||||
for (Address flow2 : flows) {
|
||||
st.push(flow2);
|
||||
st.push(new Integer(stackPointerDepth));
|
||||
st.push(stackOK);
|
||||
}
|
||||
|
@ -653,7 +655,7 @@ public class CallDepthChangeInfo {
|
|||
return;
|
||||
}
|
||||
|
||||
int purge = (short) program.getCompilerSpec().getCallStackMod();
|
||||
int purge = (short) program.getCompilerSpec().getDefaultCallingConvention().getExtrapop();
|
||||
final boolean possiblePurge = purge == -1 || purge > 3200 || purge < -3200;
|
||||
|
||||
// follow all flows building up context
|
||||
|
@ -948,8 +950,8 @@ public class CallDepthChangeInfo {
|
|||
FlowType flow = instr.getFlowType();
|
||||
if (!flow.isCall()) {
|
||||
Address[] flows = instr.getFlows();
|
||||
for (int i = 0; i < flows.length; i++) {
|
||||
st.push(flows[i]);
|
||||
for (Address flow2 : flows) {
|
||||
st.push(flow2);
|
||||
st.push(new Integer(stackPointerDepth));
|
||||
st.push(stackOK);
|
||||
}
|
||||
|
@ -1027,11 +1029,11 @@ public class CallDepthChangeInfo {
|
|||
}
|
||||
|
||||
// try to find a call destination that the stack frame is known
|
||||
for (int i = 0; i < flows.length; i++) {
|
||||
if (flows[i] == null) {
|
||||
for (Address flow : flows) {
|
||||
if (flow == null) {
|
||||
continue;
|
||||
}
|
||||
Function func = program.getListing().getFunctionAt(flows[i]);
|
||||
Function func = program.getListing().getFunctionAt(flow);
|
||||
if (func != null) {
|
||||
int purge = func.getStackPurgeSize();
|
||||
if (func.isStackPurgeSizeValid() && purge != Function.UNKNOWN_STACK_DEPTH_CHANGE &&
|
||||
|
|
|
@ -17,15 +17,16 @@ package ghidra.app.cmd.function;
|
|||
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Processor;
|
||||
import ghidra.program.model.lang.PrototypeModel;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.FlowType;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -34,13 +35,17 @@ import ghidra.util.task.TaskMonitor;
|
|||
public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
||||
private AddressSetView entryPoints;
|
||||
private Program program;
|
||||
private PrototypeModel[] nearFarModels = null;
|
||||
|
||||
private static final int STDCALL_FAR = 0;
|
||||
private static final int CDECL_FAR = 1;
|
||||
private static final int STDCALL_NEAR = 2;
|
||||
private static final int CDECL_NEAR = 3;
|
||||
|
||||
/**
|
||||
* Constructs a new command for analyzing the Stack.
|
||||
* @param entries and address set indicating the entry points of functions that have
|
||||
* stacks to be analyzed.
|
||||
* @param forceProcessing flag to force processing of stack references even if the stack
|
||||
* has already been defined.
|
||||
*/
|
||||
public FunctionPurgeAnalysisCmd(AddressSetView entries) {
|
||||
super("Compute Function Purge", true, true, false);
|
||||
|
@ -56,12 +61,16 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
|||
program = (Program) obj;
|
||||
|
||||
Processor processor = program.getLanguage().getProcessor();
|
||||
if (program.getLanguage().getDefaultSpace().getSize() > 32 ||
|
||||
AddressSpace defaultSpace = program.getLanguage().getDefaultSpace();
|
||||
if (defaultSpace.getSize() > 32 ||
|
||||
!processor.equals(Processor.findOrPossiblyCreateProcessor("x86"))) {
|
||||
Msg.error(this,
|
||||
"Unsupported operation for language " + program.getLanguage().getLanguageID());
|
||||
return false;
|
||||
}
|
||||
if (defaultSpace instanceof SegmentedAddressSpace) { // For 16-bit x86, prepare to establish near/fear calling convention models
|
||||
setupNearFarModels();
|
||||
}
|
||||
|
||||
AddressSetView set = entryPoints;
|
||||
|
||||
|
@ -95,6 +104,52 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For x86 16-bit find the models stdcallnear, stdcallfar, cdeclnear, and cdeclfar so they can
|
||||
* be applied at the same time function purge is set.
|
||||
*/
|
||||
private void setupNearFarModels() {
|
||||
int countModels = 0;
|
||||
nearFarModels = new PrototypeModel[4];
|
||||
nearFarModels[0] = null;
|
||||
nearFarModels[1] = null;
|
||||
nearFarModels[2] = null;
|
||||
nearFarModels[3] = null;
|
||||
PrototypeModel[] models = program.getCompilerSpec().getCallingConventions();
|
||||
for (PrototypeModel model : models) {
|
||||
if (model.isMerged()) {
|
||||
continue;
|
||||
}
|
||||
int pos = -1;
|
||||
if (model.getStackshift() == 4) {
|
||||
if (model.getExtrapop() == PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||
pos = STDCALL_FAR;
|
||||
}
|
||||
else if (model.getExtrapop() == 4) {
|
||||
pos = CDECL_FAR;
|
||||
}
|
||||
}
|
||||
else if (model.getStackshift() == 2) {
|
||||
if (model.getExtrapop() == PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||
pos = STDCALL_NEAR;
|
||||
}
|
||||
else if (model.getExtrapop() == 2) {
|
||||
pos = CDECL_NEAR;
|
||||
}
|
||||
}
|
||||
if (pos >= 0) {
|
||||
if (nearFarModels[pos] == null) {
|
||||
nearFarModels[pos] = model;
|
||||
countModels += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (countModels < 4) {
|
||||
Msg.warn(this,
|
||||
"FunctionPurgeAnalysis is missing full range of near/far prototype models");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze a function to build a stack frame based on stack references.
|
||||
* @param function function to be analyzed
|
||||
|
@ -104,62 +159,91 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
|||
*/
|
||||
private void analyzeFunction(Function function, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
int purge = -1;
|
||||
|
||||
if (function != null) {
|
||||
purge = function.getStackPurgeSize();
|
||||
if (function == null) {
|
||||
return;
|
||||
}
|
||||
int purge = function.getStackPurgeSize();
|
||||
if (purge == -1 || purge > 128 || purge < -128) {
|
||||
purge = locatePurgeReturn(program, function, monitor);
|
||||
Instruction purgeInstruction = locatePurgeInstruction(function, monitor);
|
||||
if (purgeInstruction != null) {
|
||||
purge = getPurgeValue(purgeInstruction);
|
||||
// if couldn't find it, don't set it!
|
||||
if (purge != -1) {
|
||||
function.setStackPurgeSize(purge);
|
||||
}
|
||||
setPrototypeModel(function, purgeInstruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int locatePurgeReturn(Program program, Function func, TaskMonitor monitor) {
|
||||
private void setPrototypeModel(Function function, Instruction purgeInstruction) {
|
||||
if (nearFarModels == null) {
|
||||
return;
|
||||
}
|
||||
if (purgeInstruction.getFlowType().isCall()) {
|
||||
return;
|
||||
}
|
||||
if (function.getSignatureSource() != SourceType.DEFAULT) {
|
||||
return;
|
||||
}
|
||||
PrototypeModel model = null;
|
||||
try {
|
||||
byte val = purgeInstruction.getBytes()[0];
|
||||
if (val == (byte) 0xc3) {
|
||||
model = nearFarModels[CDECL_NEAR];
|
||||
}
|
||||
else if (val == (byte) 0xcb) {
|
||||
model = nearFarModels[CDECL_FAR];
|
||||
}
|
||||
else if (val == (byte) 0xc2) {
|
||||
model = nearFarModels[STDCALL_NEAR];
|
||||
}
|
||||
else if (val == (byte) 0xca) {
|
||||
model = nearFarModels[STDCALL_FAR];
|
||||
}
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
return;
|
||||
}
|
||||
if (model == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
function.setCallingConvention(model.getName());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// Ignore if we can't change it
|
||||
}
|
||||
}
|
||||
|
||||
private Instruction locatePurgeInstruction(Function func, TaskMonitor monitor) {
|
||||
AddressSetView body = func.getBody();
|
||||
Instruction purgeInstruction;
|
||||
|
||||
int returnPurge = findReturnPurge(program, body);
|
||||
if (returnPurge != -1) {
|
||||
return returnPurge;
|
||||
purgeInstruction = findPurgeInstruction(body);
|
||||
if (purgeInstruction != null) {
|
||||
return purgeInstruction;
|
||||
}
|
||||
|
||||
// look harder, maybe something wrong with body, compute with flow.
|
||||
body = CreateFunctionCmd.getFunctionBody(program, func.getEntryPoint(), monitor);
|
||||
returnPurge = findReturnPurge(program, body);
|
||||
|
||||
return returnPurge;
|
||||
return findPurgeInstruction(body);
|
||||
}
|
||||
|
||||
private int findReturnPurge(Program program, AddressSetView body) {
|
||||
int tempPurge;
|
||||
InstructionIterator iter = program.getListing().getInstructions(body, true);
|
||||
int count = 2048;
|
||||
while (iter.hasNext() && count > 0) {
|
||||
count--;
|
||||
Instruction instr = iter.next();
|
||||
|
||||
FlowType ftype = instr.getFlowType();
|
||||
if (ftype.isTerminal()) {
|
||||
if (instr.getMnemonicString().compareToIgnoreCase("ret") == 0) {
|
||||
tempPurge = 0;
|
||||
Scalar scalar = instr.getScalar(0);
|
||||
if (scalar != null) {
|
||||
tempPurge = (int) scalar.getSignedValue();
|
||||
return tempPurge;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (ftype.isCall()) {
|
||||
/**
|
||||
* 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());
|
||||
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();
|
||||
|
@ -167,10 +251,44 @@ public class FunctionPurgeAnalysisCmd extends BackgroundCommand {
|
|||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
int tempPurge = 0;
|
||||
Scalar scalar = instr.getScalar(0);
|
||||
if (scalar != null) {
|
||||
tempPurge = (int) scalar.getSignedValue();
|
||||
}
|
||||
return tempPurge;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a terminating instruction in the given set of addresses with a purge encoded in it.
|
||||
* This routine prefers a RET instruction, but if none is available, it will use a
|
||||
* terminating CALL.
|
||||
* @param body is the set of addresses to look through
|
||||
* @return a terminating instruction or null
|
||||
*/
|
||||
private Instruction findPurgeInstruction(AddressSetView body) {
|
||||
InstructionIterator iter = program.getListing().getInstructions(body, true);
|
||||
int count = 2048;
|
||||
Instruction backupPurge = null;
|
||||
while (iter.hasNext() && count > 0) {
|
||||
count--;
|
||||
Instruction instr = iter.next();
|
||||
|
||||
FlowType ftype = instr.getFlowType();
|
||||
if (ftype.isTerminal()) {
|
||||
if (instr.getMnemonicString().compareToIgnoreCase("ret") == 0) {
|
||||
return instr;
|
||||
}
|
||||
else if (ftype.isCall()) {
|
||||
backupPurge = instr; // Use as last resort, if we can't find RET
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return backupPurge;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -169,8 +169,9 @@ public class FunctionResultStateStackAnalysisCmd extends BackgroundCommand {
|
|||
|
||||
// Process all the functions identified as needing stack analysis.
|
||||
// The list will have the lowest level functions analyzed first.
|
||||
int default_extraPop = program.getCompilerSpec().getCallStackMod();
|
||||
int default_stackshift = program.getCompilerSpec().getCallStackShift();
|
||||
PrototypeModel defaultModel = program.getCompilerSpec().getDefaultCallingConvention();
|
||||
int default_extraPop = defaultModel.getExtrapop();
|
||||
int default_stackshift = defaultModel.getStackshift();
|
||||
|
||||
while (!funcList.isEmpty()) {
|
||||
monitor.checkCanceled();
|
||||
|
@ -256,19 +257,22 @@ public class FunctionResultStateStackAnalysisCmd extends BackgroundCommand {
|
|||
int storageSpaceID, RefType refType, TaskMonitor monitor1)
|
||||
throws CancelledException {
|
||||
|
||||
if (instrOpIndex < 0)
|
||||
if (instrOpIndex < 0) {
|
||||
return;
|
||||
}
|
||||
Address fromAddr = op.getSeqnum().getTarget();
|
||||
Instruction instr = listing.getInstructionAt(fromAddr);
|
||||
if (instr == null)
|
||||
if (instr == null) {
|
||||
return;
|
||||
}
|
||||
Address stackAddr = addrFactory.getStackSpace().getAddress(stackOffset);
|
||||
RefType rt = refType;
|
||||
Reference ref = refMgr.getReference(fromAddr, stackAddr, instrOpIndex);
|
||||
if (ref != null) {
|
||||
RefType existingRefType = ref.getReferenceType();
|
||||
if (existingRefType == rt)
|
||||
if (existingRefType == rt) {
|
||||
return;
|
||||
}
|
||||
if (existingRefType == RefType.READ || existingRefType == RefType.WRITE) {
|
||||
rt = RefType.READ_WRITE;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,12 +15,13 @@
|
|||
*/
|
||||
package ghidra.app.util.bin.format.ne;
|
||||
|
||||
import generic.continues.*;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.*;
|
||||
import ghidra.app.util.bin.format.mz.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.io.*;
|
||||
import generic.continues.GenericFactory;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
|
||||
import ghidra.app.util.bin.format.mz.DOSHeader;
|
||||
import ghidra.program.model.address.SegmentedAddress;
|
||||
|
||||
/**
|
||||
* A class to manage loading New Executables (NE).
|
||||
|
@ -35,16 +35,19 @@ public class NewExecutable {
|
|||
|
||||
/**
|
||||
* Constructs a new instance of an new executable.
|
||||
* @param factory is the object factory to bundle with the reader
|
||||
* @param bp the byte provider
|
||||
* @param baseAddr the image base of the executable
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public NewExecutable(GenericFactory factory, ByteProvider bp) throws IOException {
|
||||
public NewExecutable(GenericFactory factory, ByteProvider bp, SegmentedAddress baseAddr)
|
||||
throws IOException {
|
||||
reader = new FactoryBundledWithBinaryReader(factory, bp, true);
|
||||
dosHeader = DOSHeader.createDOSHeader(reader);
|
||||
|
||||
if (dosHeader.isDosSignature()) {
|
||||
try {
|
||||
winHeader = new WindowsHeader(reader, (short)dosHeader.e_lfanew());
|
||||
winHeader = new WindowsHeader(reader, baseAddr, (short) dosHeader.e_lfanew());
|
||||
}
|
||||
catch (InvalidWindowsHeaderException e) {
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,7 +17,9 @@ package ghidra.app.util.bin.format.ne;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.format.*;
|
||||
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
|
||||
import ghidra.program.model.address.SegmentedAddress;
|
||||
import ghidra.program.model.address.SegmentedAddressSpace;
|
||||
import ghidra.util.Conv;
|
||||
|
||||
/**
|
||||
|
@ -28,7 +29,8 @@ import ghidra.util.Conv;
|
|||
public class SegmentTable {
|
||||
private Segment [] segments;
|
||||
|
||||
SegmentTable(FactoryBundledWithBinaryReader reader, short index, short segmentCount, short shiftAlignCount) throws IOException {
|
||||
SegmentTable(FactoryBundledWithBinaryReader reader, SegmentedAddress baseAddr, short index,
|
||||
short segmentCount, short shiftAlignCount) throws IOException {
|
||||
long oldIndex = reader.getPointerIndex();
|
||||
reader.setPointerIndex(Conv.shortToInt(index));
|
||||
|
||||
|
@ -39,14 +41,29 @@ public class SegmentTable {
|
|||
|
||||
segments = new Segment[segmentCountInt];
|
||||
|
||||
int startOffset = 0;
|
||||
SegmentedAddressSpace space;
|
||||
int curSegment;
|
||||
if (baseAddr != null) {
|
||||
space = (SegmentedAddressSpace) baseAddr.getAddressSpace();
|
||||
curSegment = baseAddr.getSegment();
|
||||
}
|
||||
else {
|
||||
space = null;
|
||||
curSegment = 0;
|
||||
}
|
||||
for (int i = 0 ; i < segmentCountInt ; ++i) {
|
||||
segments[i] = new Segment(reader, shiftAlignCount, startOffset >> 4);
|
||||
segments[i] = new Segment(reader, shiftAlignCount, curSegment);
|
||||
int size = segments[i].getMinAllocSize() & 0xffff;
|
||||
if (size == 0) {
|
||||
size = 0x10000;
|
||||
}
|
||||
startOffset = (startOffset + size + 0xf) & ~0xf;
|
||||
if (space != null) {
|
||||
SegmentedAddress endAddr = space.getAddress(curSegment, size - 1);
|
||||
curSegment = space.getNextOpenSegment(endAddr);
|
||||
}
|
||||
else {
|
||||
curSegment += 1;
|
||||
}
|
||||
}
|
||||
|
||||
reader.setPointerIndex(oldIndex);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,9 +15,11 @@
|
|||
*/
|
||||
package ghidra.app.util.bin.format.ne;
|
||||
|
||||
import ghidra.app.util.bin.format.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
|
||||
import ghidra.program.model.address.SegmentedAddress;
|
||||
|
||||
/**
|
||||
* A class to represent and parse the
|
||||
* Windows new-style executable (NE) header.
|
||||
|
@ -41,17 +42,19 @@ public class WindowsHeader {
|
|||
/**
|
||||
* Constructor
|
||||
* @param reader the binary reader
|
||||
* @param baseAddr the image base address
|
||||
* @param index the index where the windows headers begins
|
||||
* @throws InvalidWindowsHeaderException if the bytes defined in the binary reader at
|
||||
* the specified index do not constitute a valid windows header.
|
||||
* @throws IOException for problems reading the header bytes
|
||||
*/
|
||||
public WindowsHeader(FactoryBundledWithBinaryReader reader, short index) throws InvalidWindowsHeaderException, IOException {
|
||||
public WindowsHeader(FactoryBundledWithBinaryReader reader, SegmentedAddress baseAddr,
|
||||
short index) throws InvalidWindowsHeaderException, IOException {
|
||||
this.infoBlock = new InformationBlock(reader, index);
|
||||
|
||||
short segTableIndex = (short)(infoBlock.getSegmentTableOffset() + index);
|
||||
this.segTable = new SegmentTable(reader,
|
||||
segTableIndex,
|
||||
infoBlock.getSegmentCount(),
|
||||
baseAddr, segTableIndex, infoBlock.getSegmentCount(),
|
||||
infoBlock.getSegmentAlignmentShiftCount());
|
||||
|
||||
//if resource table offset == resident name table offset, then
|
||||
|
|
|
@ -892,14 +892,14 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
if (expSym.hasNoReturn()) {
|
||||
extFunc.setNoReturn(true);
|
||||
}
|
||||
int stackShift = program.getCompilerSpec().getCallStackShift();
|
||||
if (stackShift == -1) {
|
||||
stackShift = 0;
|
||||
}
|
||||
|
||||
// TODO: This should not be done at time of import and should be done
|
||||
// by a late running analyzer (e.g., stack analyzer) if no signature
|
||||
// has been established
|
||||
// int stackShift = program.getCompilerSpec().getDefaultCallingConvention().getStackshift();
|
||||
// if (stackShift == -1) {
|
||||
// stackShift = 0;
|
||||
// }
|
||||
|
||||
// int numParams = expSym.getPurge() / 4;
|
||||
// if (numParams > 0) {
|
||||
// // HACK: assumes specific stack-based x86 convention
|
||||
|
|
|
@ -258,6 +258,11 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
|||
int dataStart = dos.e_cparhdr() << 4;
|
||||
|
||||
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();
|
||||
reader.setPointerIndex(relocationTableOffset);
|
||||
for (int i = 0; i < numRelocationEntries; i++) {
|
||||
|
@ -290,17 +295,17 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
|||
for (int i = 0; i < segStartList.size(); i++) {
|
||||
SegmentedAddress start = (SegmentedAddress) segStartList.get(i);
|
||||
|
||||
int readLoc = (int) (start.getOffset() - csStartEffective) + dataStart;
|
||||
int readLoc = ((start.getSegment() << 4) - csStartEffective) + dataStart;
|
||||
if (readLoc < 0) {
|
||||
Msg.error(this, "Invalid read location " + readLoc);
|
||||
continue;
|
||||
}
|
||||
|
||||
byte bytes[] = null;
|
||||
int numBytes = 0;
|
||||
if ((i + 1) < segStartList.size()) {
|
||||
SegmentedAddress end = (SegmentedAddress) segStartList.get(i + 1);
|
||||
numBytes = (int) end.subtract(start);
|
||||
int nextLoc = ((end.getSegment() << 4) - csStartEffective) + dataStart;
|
||||
numBytes = nextLoc - readLoc;
|
||||
}
|
||||
else {
|
||||
// last segment length
|
||||
|
@ -317,7 +322,6 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
|||
numUninitBytes = calcNumBytes - numBytes;
|
||||
}
|
||||
if (numBytes > 0) {
|
||||
bytes = reader.readByteArray(readLoc, numBytes);
|
||||
MemoryBlockUtils.createInitializedBlock(program, false, "Seg_" + i, start,
|
||||
fileBytes, readLoc, numBytes, "", "mz", true, true, true, log);
|
||||
}
|
||||
|
@ -399,6 +403,7 @@ public class MzLoader extends AbstractLibrarySupportLoader {
|
|||
symbolTable.createLabel(addr, ENTRY_NAME, SourceType.IMPORTED);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// Just skip if we can't create
|
||||
}
|
||||
|
||||
symbolTable.addExternalEntryPoint(addr);
|
||||
|
|
|
@ -51,6 +51,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
|||
|
||||
private static final String TAB = " ";
|
||||
private static final long MIN_BYTE_LENGTH = 4;
|
||||
private static final int SEGMENT_START = 0x1000;
|
||||
|
||||
private ArrayList<Address> entryPointList = new ArrayList<>();
|
||||
private Comparator<String> comparator = new CallNameComparator();
|
||||
|
@ -65,7 +66,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
|||
if (provider.length() < MIN_BYTE_LENGTH) {
|
||||
return loadSpecs;
|
||||
}
|
||||
NewExecutable ne = new NewExecutable(RethrowContinuesFactory.INSTANCE, provider);
|
||||
NewExecutable ne = new NewExecutable(RethrowContinuesFactory.INSTANCE, provider, null);
|
||||
WindowsHeader wh = ne.getWindowsHeader();
|
||||
if (wh != null) {
|
||||
List<QueryResult> results = QueryOpinionService.query(getName(),
|
||||
|
@ -99,7 +100,9 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
|||
// the original bytes.
|
||||
MemoryBlockUtils.createFileBytes(prog, provider, monitor);
|
||||
|
||||
NewExecutable ne = new NewExecutable(factory, provider);
|
||||
SegmentedAddressSpace space =
|
||||
(SegmentedAddressSpace) prog.getAddressFactory().getDefaultAddressSpace();
|
||||
NewExecutable ne = new NewExecutable(factory, provider, space.getAddress(SEGMENT_START, 0));
|
||||
WindowsHeader wh = ne.getWindowsHeader();
|
||||
InformationBlock ib = wh.getInformationBlock();
|
||||
SegmentTable st = wh.getSegmentTable();
|
||||
|
@ -113,8 +116,6 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
|||
Listing listing = prog.getListing();
|
||||
SymbolTable symbolTable = prog.getSymbolTable();
|
||||
Memory memory = prog.getMemory();
|
||||
SegmentedAddressSpace space =
|
||||
(SegmentedAddressSpace) prog.getAddressFactory().getDefaultAddressSpace();
|
||||
ProgramContext context = prog.getProgramContext();
|
||||
RelocationTable relocTable = prog.getRelocationTable();
|
||||
|
||||
|
@ -306,11 +307,6 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
|||
}
|
||||
}
|
||||
|
||||
private int getNextAvailableSegment(Program program) {
|
||||
Address addr = program.getMemory().getMaxAddress();
|
||||
return ((int) addr.getOffset() >> 4) + 1;
|
||||
}
|
||||
|
||||
private void processResourceTable(MessageLog log, Program program, ResourceTable rt,
|
||||
SegmentedAddressSpace space, TaskMonitor monitor) throws IOException {
|
||||
Listing listing = program.getListing();
|
||||
|
@ -326,7 +322,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
|||
Resource[] resources = type.getResources();
|
||||
for (Resource resource : resources) {
|
||||
|
||||
int segidx = getNextAvailableSegment(program);
|
||||
int segidx = space.getNextOpenSegment(program.getMemory().getMaxAddress());
|
||||
Address addr = space.getAddress(segidx, 0);
|
||||
|
||||
try {
|
||||
|
@ -417,7 +413,7 @@ public class NeLoader extends AbstractLibrarySupportLoader {
|
|||
for (LengthStringSet name : names) {
|
||||
String[] callnames = getCallNamesForModule(name.getString(), mrt, st, imp);
|
||||
int length = callnames.length * pointerSize;
|
||||
int segment = getNextAvailableSegment(program);
|
||||
int segment = space.getNextOpenSegment(program.getMemory().getMaxAddress());
|
||||
Address start = space.getAddress(segment, 0);
|
||||
if (length > 0) {
|
||||
// This isn't a real block, just place holder addresses, so don't create an initialized block
|
||||
|
|
|
@ -176,10 +176,10 @@ public class ProgramMemoryUtil {
|
|||
MemoryBlock[] blocks = mem.getBlocks();
|
||||
MemoryBlock[] tmpBlocks = new MemoryBlock[blocks.length];
|
||||
int j = 0;
|
||||
for (int i = 0; i < blocks.length; i++) {
|
||||
if ((blocks[i].isInitialized() && withBytes) ||
|
||||
(!blocks[i].isInitialized() && !withBytes)) {
|
||||
tmpBlocks[j++] = blocks[i];
|
||||
for (MemoryBlock block : blocks) {
|
||||
if ((block.isInitialized() && withBytes) ||
|
||||
(!block.isInitialized() && !withBytes)) {
|
||||
tmpBlocks[j++] = block;
|
||||
}
|
||||
}
|
||||
MemoryBlock[] typeBlocks = new MemoryBlock[j];
|
||||
|
@ -297,7 +297,7 @@ public class ProgramMemoryUtil {
|
|||
}
|
||||
|
||||
// Just looking for the offset into the segment now, not the whole segment/offset pair
|
||||
if (addrSize == 20) {
|
||||
if (toAddress instanceof SegmentedAddress) {
|
||||
SegmentedAddress segAddr = (SegmentedAddress) toAddress;
|
||||
currentSegment = (short) segAddr.getSegment();
|
||||
}
|
||||
|
@ -322,10 +322,10 @@ public class ProgramMemoryUtil {
|
|||
if (toAddress instanceof SegmentedAddress) {
|
||||
short offsetShort = memory.getShort(a);
|
||||
offsetShort &= offsetShort & 0xffff;
|
||||
SegmentedAddress sega = ((SegmentedAddress) a);
|
||||
short shortSega = (short) (sega.getSegment());
|
||||
shortSega &= shortSega & 0xffff;
|
||||
// this is checking to see if the ref is in the same segment as the toAddr - not sure this is needed anymore
|
||||
// SegmentedAddress sega = ((SegmentedAddress) a);
|
||||
// short shortSega = (short) (sega.getSegment());
|
||||
// shortSega &= shortSega & 0xffff;
|
||||
// if (offsetShort == shortCurrentOffset) {
|
||||
//*** commenting this out is making it find the instances of 46 01's not the 0a 00's - closer though
|
||||
// check for the case where the reference includes both the segment and offset
|
||||
|
@ -441,8 +441,9 @@ public class ProgramMemoryUtil {
|
|||
}
|
||||
|
||||
for (ReferenceAddressPair rap : directReferenceList) {
|
||||
if (monitor.isCancelled())
|
||||
if (monitor.isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
Address fromAddr = rap.getSource();
|
||||
if (!results.contains(fromAddr)) {
|
||||
results.add(fromAddr);
|
||||
|
@ -624,18 +625,18 @@ public class ProgramMemoryUtil {
|
|||
byte maskBytes[] = null;
|
||||
|
||||
MemoryBlock[] blocks = memory.getBlocks();
|
||||
for (int i = 0; i < blocks.length; i++) {
|
||||
if (!blocks[i].isInitialized()) {
|
||||
for (MemoryBlock block : blocks) {
|
||||
if (!block.isInitialized()) {
|
||||
continue;
|
||||
}
|
||||
if (memoryRange != null &&
|
||||
!memoryRange.intersects(blocks[i].getStart(), blocks[i].getEnd())) {
|
||||
!memoryRange.intersects(block.getStart(), block.getEnd())) {
|
||||
// skip blocks which do not correspond to currentSeg
|
||||
continue;
|
||||
}
|
||||
|
||||
Address start = blocks[i].getStart();
|
||||
Address end = blocks[i].getEnd();
|
||||
Address start = block.getStart();
|
||||
Address end = block.getEnd();
|
||||
Address found = null;
|
||||
while (true) {
|
||||
monitor.checkCanceled();
|
||||
|
|
|
@ -1705,8 +1705,9 @@ public class SymbolicPropogator {
|
|||
* @return
|
||||
*/
|
||||
private int getDefaultStackDepthChange(Program prog, int depth) {
|
||||
int callStackMod = prog.getCompilerSpec().getCallStackMod();
|
||||
int callStackShift = prog.getCompilerSpec().getCallStackShift();
|
||||
PrototypeModel defaultModel = prog.getCompilerSpec().getDefaultCallingConvention();
|
||||
int callStackMod = defaultModel.getExtrapop();
|
||||
int callStackShift = defaultModel.getStackshift();
|
||||
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||
return callStackShift;
|
||||
}
|
||||
|
|
|
@ -46,14 +46,17 @@ public class ResultsState {
|
|||
|
||||
private static final Iterator<ContextState> emptyContextStateIterator =
|
||||
new Iterator<ContextState>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextState next() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
}
|
||||
};
|
||||
|
@ -168,10 +171,12 @@ public class ResultsState {
|
|||
|
||||
stackGrowsNegative = program.getCompilerSpec().stackGrowsNegative();
|
||||
Long stackOffset = currentPrototype.getStackParameterOffset();
|
||||
if (stackOffset != null)
|
||||
if (stackOffset != null) {
|
||||
paramBaseStackOffset = stackOffset - currentPrototype.getStackshift();
|
||||
else
|
||||
}
|
||||
else {
|
||||
paramBaseStackOffset = null;
|
||||
}
|
||||
|
||||
todoList.add(new BranchDestination(null, entryPt, entryState));
|
||||
}
|
||||
|
@ -253,9 +258,10 @@ public class ResultsState {
|
|||
currentState = null;
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, ">>> At " + nextSeq.getTarget() + "/" + nextSeq.getTime() +
|
||||
" " + instr);
|
||||
}
|
||||
|
||||
SequenceNumber lastSeq = flowFrom;
|
||||
|
||||
|
@ -272,9 +278,10 @@ public class ResultsState {
|
|||
if (existingStates.containsKey(flowFrom)) {
|
||||
// TODO: We have processed this flow before
|
||||
// TODO: Should we compare existingState with dest.initialState ?
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Flow ignored - already processed: " +
|
||||
flowFrom + " -> " + pcodeOp.getSeqnum());
|
||||
}
|
||||
instr = null; // signal - abort current flow
|
||||
break;
|
||||
}
|
||||
|
@ -284,9 +291,10 @@ public class ResultsState {
|
|||
// Re-use existing state where register values match
|
||||
addState(flowFrom, otherEntryState);
|
||||
instr = null; // signal - abort current flow
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Flow combined - similar state: " +
|
||||
flowFrom + " -> " + pcodeOp.getSeqnum());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -385,6 +393,7 @@ public class ResultsState {
|
|||
|
||||
private static Comparator<Object> CONTEXT_STATE_SET_SEQUENCE_COMPARATOR =
|
||||
new Comparator<Object>() {
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
ContextStateSet set = (ContextStateSet) o1;
|
||||
SequenceNumber seq = (SequenceNumber) o2;
|
||||
|
@ -468,14 +477,16 @@ public class ResultsState {
|
|||
private ContextState performInlineCall(Address inlineCallAddress, ContextState currentState,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "*** Start Inline Call to " + inlineCallAddress + " ***");
|
||||
}
|
||||
ResultsState inlineState =
|
||||
new ResultsState(new SequenceNumber(inlineCallAddress, 0), null, currentState,
|
||||
maintainInstructionResults);
|
||||
inlineState.processFunction(monitor);
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "*** End Inline Call to " + inlineCallAddress + " ***");
|
||||
}
|
||||
|
||||
// TODO: How should multiple return states be handled ??
|
||||
|
||||
|
@ -746,9 +757,10 @@ public class ResultsState {
|
|||
|
||||
if (values[1].isConstant() && values[1].getOffset() == 0) {
|
||||
// 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() +
|
||||
" - Not taken due to false condition value");
|
||||
}
|
||||
break; // Fall-through case - assume that a pre-condition is steering the execution
|
||||
}
|
||||
|
||||
|
@ -762,16 +774,18 @@ public class ResultsState {
|
|||
SequenceNumber dest =
|
||||
new SequenceNumber(seq.getTarget(), seq.getTime() +
|
||||
(int) inputs[0].getOffset());
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Internal " +
|
||||
(pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional " : "") +
|
||||
"Branch to " + dest);
|
||||
}
|
||||
todoList.add(new BranchDestination(pcodeOp.getSeqnum(), dest, currentState));
|
||||
}
|
||||
else if (inputs[0].isAddress()) {
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, (pcodeOp.getOpcode() == PcodeOp.CBRANCH ? "Conditional "
|
||||
: "") + "Branch to " + inputs[0].getAddress());
|
||||
}
|
||||
handleDirectFlow(pcodeOp, inputs[0].getAddress(), currentState, monitor);
|
||||
}
|
||||
else {
|
||||
|
@ -786,8 +800,9 @@ public class ResultsState {
|
|||
AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||
Address destAddr =
|
||||
space.getAddress(getUnsignedOffset(values[0], space.getPointerSize()));
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Branch to " + destAddr);
|
||||
}
|
||||
handleDirectFlow(pcodeOp, destAddr, currentState, monitor);
|
||||
}
|
||||
else if (values[0].isAddress()) {
|
||||
|
@ -798,32 +813,36 @@ public class ResultsState {
|
|||
currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||
Address destAddr =
|
||||
space.getAddress(getUnsignedOffset(brOffset, space.getPointerSize()));
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Indirect Branch to [" + values[0].getAddress() +
|
||||
"] -> " + destAddr);
|
||||
}
|
||||
handleDirectFlow(pcodeOp, destAddr, currentState, monitor);
|
||||
}
|
||||
else {
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this,
|
||||
"Indirect Branch to [" + values[0].toString(program.getLanguage()) +
|
||||
"]");
|
||||
}
|
||||
handleIndirectFlow(pcodeOp, values[0], currentState, monitor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this,
|
||||
"Indirect Branch to [" + values[0].toString(program.getLanguage()) +
|
||||
"]");
|
||||
}
|
||||
handleIndirectFlow(pcodeOp, values[0], currentState, monitor);
|
||||
}
|
||||
return false;
|
||||
|
||||
case PcodeOp.CALL: // A call with absolute address
|
||||
if (inputs[0].isAddress()) {
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Call to " + inputs[0].getAddress());
|
||||
}
|
||||
handleCall(pcodeOp, null, inputs[0].getAddress(), currentState, monitor);
|
||||
}
|
||||
else {
|
||||
|
@ -839,8 +858,9 @@ public class ResultsState {
|
|||
AddressSpace space = currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||
Address destAddr =
|
||||
space.getAddress(getUnsignedOffset(values[0], space.getPointerSize()));
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Call to " + destAddr);
|
||||
}
|
||||
handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor);
|
||||
}
|
||||
else if (values[0].isAddress()) {
|
||||
|
@ -852,23 +872,26 @@ public class ResultsState {
|
|||
currentState.getEntryPoint().getTarget().getAddressSpace();
|
||||
Address destAddr =
|
||||
space.getAddress(getUnsignedOffset(callOffset, space.getPointerSize()));
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Indirect Call to [" + values[0].getAddress() +
|
||||
"] -> " + destAddr);
|
||||
}
|
||||
handleCall(pcodeOp, indirectPtr, destAddr, currentState, monitor);
|
||||
}
|
||||
else {
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this,
|
||||
"Indirect Call to [" + values[0].toString(program.getLanguage()) +
|
||||
"]");
|
||||
}
|
||||
handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this,
|
||||
"Indirect Call to [" + values[0].toString(program.getLanguage()) + "]");
|
||||
}
|
||||
handleIndirectCall(pcodeOp, indirectPtr, values[0], currentState, monitor);
|
||||
}
|
||||
return false;
|
||||
|
@ -1737,8 +1760,9 @@ public class ResultsState {
|
|||
BookmarkType.ERROR, "Instruction Expected", "Expected instruction at " + address);
|
||||
return;
|
||||
}
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Disassemble at " + address);
|
||||
}
|
||||
DisassembleCommand cmd = new DisassembleCommand(address, null, true);
|
||||
cmd.applyTo(program, monitor);
|
||||
monitor.checkCanceled();
|
||||
|
@ -1772,9 +1796,10 @@ public class ResultsState {
|
|||
return;
|
||||
}
|
||||
if (addRegister(reg, registersModified)) {
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "MODIFIED: " + reg + " = " + value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Msg.debug(this, "SET: " + output + " = " + value);
|
||||
}
|
||||
|
@ -2068,10 +2093,11 @@ public class ResultsState {
|
|||
}
|
||||
|
||||
if (func == null) {
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Function not found at " + indirectPtr +
|
||||
" indirectly called from " + pcodeOp.getSeqnum().getTarget() +
|
||||
" - call affects unknown");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2104,9 +2130,10 @@ public class ResultsState {
|
|||
}
|
||||
|
||||
if (func == null) {
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Function not found at " + destAddr + " called from " +
|
||||
pcodeOp.getSeqnum().getTarget() + " - call affects unknown");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2133,11 +2160,12 @@ public class ResultsState {
|
|||
// Must invalidate return varnode
|
||||
DataType returnType = null;
|
||||
if (func == null) {
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this,
|
||||
"No function at " + destAddr + " called from " + calledFrom.getTarget() +
|
||||
" - default return/affects assumed");
|
||||
}
|
||||
}
|
||||
else {
|
||||
returnType = func.getReturnType();
|
||||
if (VoidDataType.dataType.isEquivalent(returnType)) {
|
||||
|
@ -2147,8 +2175,9 @@ public class ResultsState {
|
|||
|
||||
VariableStorage retStorage = callingConvention.getReturnLocation(returnType, program);
|
||||
Varnode varnode = null;
|
||||
if (retStorage.isValid() && (retStorage.getVarnodeCount()==1))
|
||||
if (retStorage.isValid() && (retStorage.getVarnodeCount()==1)) {
|
||||
varnode = retStorage.getFirstVarnode();
|
||||
}
|
||||
if (varnode != null) {
|
||||
// invalidate stored value
|
||||
currentState.store(varnode, getInvalidatedVarnode(calledFrom, varnode));
|
||||
|
@ -2183,9 +2212,10 @@ public class ResultsState {
|
|||
if (purge == Function.UNKNOWN_STACK_DEPTH_CHANGE ||
|
||||
purge == Function.INVALID_STACK_DEPTH_CHANGE) {
|
||||
String name = func != null ? func.getName() : ("at " + destAddr);
|
||||
if (DEBUG)
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Stack purge unknown for function " + name + " called from " +
|
||||
calledFrom.getTarget() + " - stack pointer invalidated");
|
||||
}
|
||||
currentState.store(getStackPointerVarnode(),
|
||||
getInvalidatedVarnode(calledFrom, getStackPointerVarnode()));
|
||||
return;
|
||||
|
@ -2255,8 +2285,9 @@ public class ResultsState {
|
|||
* @return
|
||||
*/
|
||||
private static int getDefaultStackDepthChange(Program depthProgram, int depth) {
|
||||
int callStackMod = depthProgram.getCompilerSpec().getCallStackMod();
|
||||
int callStackShift = depthProgram.getCompilerSpec().getCallStackShift();
|
||||
PrototypeModel defaultModel = depthProgram.getCompilerSpec().getDefaultCallingConvention();
|
||||
int callStackMod = defaultModel.getExtrapop();
|
||||
int callStackShift = defaultModel.getStackshift();
|
||||
if (callStackMod != PrototypeModel.UNKNOWN_EXTRAPOP && callStackShift >= 0) {
|
||||
return callStackShift - callStackMod;
|
||||
}
|
||||
|
|
|
@ -962,32 +962,35 @@ void Architecture::parseProcessorConfig(DocumentStorage &store)
|
|||
List::const_iterator 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);
|
||||
else if ((*iter)->getName() == "incidentalcopy")
|
||||
else if (elname == "incidentalcopy")
|
||||
parseIncidentalCopy(*iter);
|
||||
else if ((*iter)->getName() == "context_data")
|
||||
else if (elname == "context_data")
|
||||
context->restoreFromSpec(*iter,this);
|
||||
else if ((*iter)->getName() == "jumpassist")
|
||||
else if (elname == "jumpassist")
|
||||
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
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -1145,6 +1148,7 @@ Address SegmentedResolver::resolve(uintb val,int4 sz,const Address &point)
|
|||
// (as with near pointers)
|
||||
if (segop->getResolve().space != (AddrSpace *)0) {
|
||||
uintb base = glb->context->getTrackedValue(segop->getResolve(),point);
|
||||
fullEncoding = (base << 8 * innersz) + (val & calc_mask(innersz));
|
||||
vector<uintb> seginput;
|
||||
seginput.push_back(val);
|
||||
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
|
||||
fullEncoding = val;
|
||||
int4 outersz = segop->getBaseSize();
|
||||
uintb base = (val >> 8*innersz) & calc_mask(outersz);
|
||||
val = val & calc_mask(innersz);
|
||||
|
|
|
@ -284,7 +284,7 @@ public:
|
|||
/// \param sp is the segmented space
|
||||
/// \param sop is the segment operator
|
||||
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
|
||||
|
|
|
@ -269,8 +269,14 @@ bool CastStrategyC::isSubpieceCast(Datatype *outtype,Datatype *intype,uint4 offs
|
|||
(outmeta!=TYPE_PTR)&&
|
||||
(outmeta!=TYPE_FLOAT))
|
||||
return false;
|
||||
if ((inmeta==TYPE_PTR)&&((outmeta!=TYPE_INT) && (outmeta!=TYPE_UINT)))
|
||||
if (inmeta==TYPE_PTR) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -827,14 +827,14 @@ int4 ActionShadowVar::apply(Funcdata &data)
|
|||
/// \param rampoint will hold the Address of the resolved symbol
|
||||
/// \param data is the function being analyzed
|
||||
/// \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;
|
||||
Architecture *glb = data.getArch();
|
||||
Varnode *outvn;
|
||||
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;
|
||||
}
|
||||
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
|
||||
if (bit_transitions(vn->getOffset(),vn->getSize()) < 3)
|
||||
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;
|
||||
|
@ -943,10 +943,11 @@ int4 ActionConstantPtr::apply(Funcdata &data)
|
|||
else if ((opc == CPUI_PTRSUB)||(opc==CPUI_PTRADD))
|
||||
continue;
|
||||
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
|
||||
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))
|
||||
data.opSwapInput(op,0,1);
|
||||
count += 1;
|
||||
|
|
|
@ -162,7 +162,7 @@ public:
|
|||
/// \brief Check for constants, with pointer type, that correspond to global symbols
|
||||
class ActionConstantPtr : public Action {
|
||||
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:
|
||||
ActionConstantPtr(const string &g) : Action(0,"constantptr",g) {} ///< Constructor
|
||||
virtual void reset(Funcdata &data) { localcount = 0; }
|
||||
|
|
|
@ -333,7 +333,7 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const
|
|||
outvn = outvn2;
|
||||
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());
|
||||
Varnode *outvn2 = newUniqueOut(origsize,zextop);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1403,7 +1403,8 @@ bool PrintC::pushPtrCharConstant(uintb val,const TypePointer *ct,const Varnode *
|
|||
{
|
||||
if (val==0) return false;
|
||||
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 (!glb->symboltab->getGlobalScope()->isReadOnly(stringaddr,1,Address()))
|
||||
return false; // Check that string location is readonly
|
||||
|
|
|
@ -485,15 +485,27 @@ AddrSpace *AddrSpaceManager::getSpaceByShortcut(char sc) const
|
|||
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();
|
||||
if (ind < resolvelist.size()) {
|
||||
AddressResolver *resolve = resolvelist[ind];
|
||||
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 = spc->wrapOffset(val);
|
||||
return Address(spc,val);
|
||||
|
|
|
@ -147,8 +147,9 @@ public:
|
|||
/// \param val is constant to be resolved to an address
|
||||
/// \param sz is the size of \e val in context.
|
||||
/// \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
|
||||
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
|
||||
|
@ -249,7 +250,7 @@ public:
|
|||
AddrSpace *getConstantSpace(void) const; ///< Get the constant space
|
||||
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 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
|
||||
AddrSpace *getSpace(int4 i) const; ///< Get an address space via its index
|
||||
AddrSpace *getNextSpaceInOrder(AddrSpace *spc) const; ///< Get the next \e contiguous address space
|
||||
|
|
|
@ -1124,13 +1124,17 @@ Datatype *TypeSpacebase::getSubType(uintb off,uintb *newoff) const
|
|||
|
||||
{
|
||||
Scope *scope = getMap();
|
||||
// uintb unoff = (uintb)(intb)off; // Make sure this is a sign-extension
|
||||
Address addr(spaceid,spaceid->wrapOffset(off));
|
||||
off = AddrSpace::byteToAddress(off, spaceid->getWordSize()); // Convert from byte offset to address unit
|
||||
// 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;
|
||||
|
||||
// Assume symbol being referenced is address tied,
|
||||
// so we use empty usepoint
|
||||
smallest = scope->queryContainer(addr,1,Address());
|
||||
smallest = scope->queryContainer(addr,1,nullPoint);
|
||||
|
||||
if (smallest == (SymbolEntry *)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
|
||||
|
||||
{
|
||||
return glb->resolveConstant(spaceid,off,sz,point);
|
||||
uintb fullEncoding;
|
||||
return glb->resolveConstant(spaceid,off,sz,point,fullEncoding);
|
||||
}
|
||||
|
||||
void TypeSpacebase::saveXml(ostream &s) const
|
||||
|
|
|
@ -124,31 +124,6 @@ SegmentOp::SegmentOp(Architecture *g,const string &nm,int4 ind)
|
|||
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,
|
||||
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->numInput() != 3) return false;
|
||||
innervn = op->getIn(1);
|
||||
if (basepresent) {
|
||||
if (baseinsize != 0) {
|
||||
basevn = op->getIn(1);
|
||||
innervn = op->getIn(2);
|
||||
if (basevn->isConstant())
|
||||
|
@ -181,40 +156,23 @@ bool SegmentOp::unify(Funcdata &data,PcodeOp *op,
|
|||
uintb SegmentOp::execute(const vector<uintb> &input) const
|
||||
|
||||
{
|
||||
uintb base,inner;
|
||||
|
||||
if (basepresent)
|
||||
base = executeSide(basefollow,input[1]);
|
||||
else
|
||||
base = 0;
|
||||
|
||||
inner = executeSide(innerfollow,input[0]);
|
||||
return (base+inner);
|
||||
ExecutablePcode *pcodeScript = (ExecutablePcode *)glb->pcodeinjectlib->getPayload(injectId);
|
||||
return pcodeScript->evaluate(input);
|
||||
}
|
||||
|
||||
void SegmentOp::restoreXml(const Element *el)
|
||||
|
||||
{
|
||||
spc = glb->getSpaceByName(el->getAttributeValue("space"));
|
||||
injectId = -1;
|
||||
baseinsize = 0;
|
||||
innerinsize = 0;
|
||||
bool userdefined = false;
|
||||
forcesegment = true;
|
||||
supportsfarpointer = false;
|
||||
name = "segment"; // Default name, might be overridden by userop attribute
|
||||
for(int4 i=0;i<el->getNumAttributes();++i) {
|
||||
const string &nm(el->getAttributeName(i));
|
||||
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")
|
||||
supportsfarpointer = true;
|
||||
else if (nm == "userop") { // Based on existing sleigh op
|
||||
|
@ -227,28 +185,17 @@ void SegmentOp::restoreXml(const Element *el)
|
|||
throw LowlevelError("Redefining userop "+name);
|
||||
}
|
||||
}
|
||||
else if (nm == "force")
|
||||
forcesegment = xml_readbool(el->getAttributeValue(i));
|
||||
else
|
||||
throw LowlevelError("Bad segmentop tag attribute: "+nm);
|
||||
}
|
||||
if (!userdefined)
|
||||
throw LowlevelError("Missing userop attribute in segmentop tag");
|
||||
basepresent = (baseinsize != 0);
|
||||
|
||||
const List &list(el->getChildren());
|
||||
List::const_iterator iter;
|
||||
for(iter=list.begin();iter!=list.end();++iter) {
|
||||
const Element *subel = *iter;
|
||||
if (subel->getName()=="baseop") {
|
||||
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") {
|
||||
if (subel->getName()=="constresolve") {
|
||||
int4 sz;
|
||||
const List &sublist(subel->getChildren());
|
||||
if (!sublist.empty()) {
|
||||
|
@ -260,9 +207,28 @@ void SegmentOp::restoreXml(const Element *el)
|
|||
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
|
||||
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
|
||||
|
|
|
@ -198,24 +198,19 @@ struct OpFollow {
|
|||
/// The core routine that looks for the term-tree is unify().
|
||||
class SegmentOp : public TermPatternOp {
|
||||
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 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
|
||||
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
|
||||
static uintb executeSide(const vector<OpFollow> &follow,uintb input);
|
||||
public:
|
||||
SegmentOp(Architecture *g,const string &nm,int4 ind); ///< Constructor
|
||||
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 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 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
|
||||
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 uintb execute(const vector<uintb> &input) const;
|
||||
virtual void restoreXml(const Element *el);
|
||||
|
|
|
@ -40,7 +40,7 @@ import ghidra.program.model.symbol.*;
|
|||
import ghidra.util.Msg;
|
||||
import ghidra.util.UndefinedFunction;
|
||||
import ghidra.util.exception.UsrException;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.util.xml.XmlUtilities;
|
||||
|
||||
|
@ -80,7 +80,7 @@ public class DecompileCallback {
|
|||
listing = program.getListing();
|
||||
addrfactory = program.getAddressFactory();
|
||||
dtmanage = dt;
|
||||
default_extrapop = pcodecompilerspec.getCallStackMod();
|
||||
default_extrapop = pcodecompilerspec.getDefaultCallingConvention().getExtrapop();
|
||||
cpool = null;
|
||||
nativeMessage = null;
|
||||
debug = null;
|
||||
|
@ -103,6 +103,7 @@ public class DecompileCallback {
|
|||
* Establish function and debug context for next decompilation
|
||||
*
|
||||
* @param func is the function to be decompiled
|
||||
* @param entry is the function's entry address
|
||||
* @param dbg is the debugging context (or null)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -213,7 +214,8 @@ public class DecompileCallback {
|
|||
* Collect any/all comments for the function starting at the indicated
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
* defined to perform.
|
||||
|
@ -315,8 +310,8 @@ public class DecompileCallback {
|
|||
* @param fallthruoffset number of bytes after instruction start that pcode
|
||||
* flow falls into
|
||||
* @param paramshift special instructions for injection use
|
||||
* @param addrFactory
|
||||
* @return XML document as string
|
||||
* @param addrFactory is the address factory for recovering address space names
|
||||
* @return XML document as string representing all the p-code
|
||||
*/
|
||||
public static String buildInstruction(PcodeOp[] ops, int fallthruoffset, int paramshift,
|
||||
AddressFactory addrFactory) {
|
||||
|
@ -446,7 +441,7 @@ public class DecompileCallback {
|
|||
|
||||
if (pseudoDisassembler == null) {
|
||||
pseudoDisassembler = Disassembler.getDisassembler(program, false, false, false,
|
||||
TaskMonitorAdapter.DUMMY_MONITOR, msg -> {
|
||||
TaskMonitor.DUMMY, msg -> {
|
||||
// TODO: Should we log errors?
|
||||
});
|
||||
}
|
||||
|
@ -859,35 +854,11 @@ public class DecompileCallback {
|
|||
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
|
||||
* @return
|
||||
* @param sym is the symbol
|
||||
* @return the XML description
|
||||
*/
|
||||
private String buildLabel(Symbol sym, Address addr) {
|
||||
// TODO: Assume this is not data
|
||||
|
@ -973,7 +944,7 @@ public class DecompileCallback {
|
|||
* @param addr The queried address
|
||||
* @param includeDefaultNames true if default parameter names should be
|
||||
* included
|
||||
* @return
|
||||
* @return XML string describing the function or the hole
|
||||
*/
|
||||
private String buildFunctionXML(Function func, Address addr, boolean includeDefaultNames) {
|
||||
Address entry = func.getEntryPoint();
|
||||
|
@ -1179,7 +1150,7 @@ public class DecompileCallback {
|
|||
* Return the global object being referred to by addr
|
||||
*
|
||||
* @param addr = Address being queried
|
||||
* @return
|
||||
* @return the global object
|
||||
*/
|
||||
private Object lookupSymbol(Address addr) {
|
||||
ExternalReference ref = getExternalReference(addr);
|
||||
|
|
|
@ -229,35 +229,7 @@
|
|||
</zeroOrMore>
|
||||
|
||||
<zeroOrMore>
|
||||
<element name="segmentop">
|
||||
<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>
|
||||
<ref name="segmentop_type"/>
|
||||
</zeroOrMore>
|
||||
|
||||
<element name="default_proto">
|
||||
|
@ -299,22 +271,6 @@
|
|||
</element>
|
||||
</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">
|
||||
<optional> <attribute name="maxsize"/> </optional>
|
||||
<optional> <attribute name="minsize"/> </optional>
|
||||
|
|
|
@ -227,6 +227,22 @@
|
|||
</optional>
|
||||
</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">
|
||||
<attribute name="name"/>
|
||||
<interleave>
|
||||
|
|
|
@ -43,9 +43,16 @@
|
|||
<optional>
|
||||
<element name="segmented_address">
|
||||
<attribute name="space"/>
|
||||
<optional>
|
||||
<attribute name="type"/>
|
||||
</optional>
|
||||
</element>
|
||||
</optional>
|
||||
|
||||
<zeroOrMore>
|
||||
<ref name="segmentop_type"/>
|
||||
</zeroOrMore>
|
||||
|
||||
<!-- see language_common.rxg -->
|
||||
<optional>
|
||||
<element name="context_data">
|
||||
|
|
|
@ -79,6 +79,7 @@ public class SleighLanguage implements Language {
|
|||
* Non-null if a space should yes segmented addressing
|
||||
*/
|
||||
String segmentedspace = "";
|
||||
String segmentType = "";
|
||||
AddressSet volatileAddresses;
|
||||
private ContextCache contextcache = null;
|
||||
/**
|
||||
|
@ -100,6 +101,13 @@ public class SleighLanguage implements Language {
|
|||
initialize(description);
|
||||
}
|
||||
|
||||
private void addAdditionInject(InjectPayloadSleigh payload) {
|
||||
if (additionalInject == null) {
|
||||
additionalInject = new ArrayList<>();
|
||||
}
|
||||
additionalInject.add(payload);
|
||||
}
|
||||
|
||||
private void initialize(SleighLanguageDescription langDescription)
|
||||
throws SAXException, IOException, UnknownInstructionException {
|
||||
this.defaultSymbols = new ArrayList<>();
|
||||
|
@ -508,6 +516,10 @@ public class SleighLanguage implements Language {
|
|||
if (nextElement != null) {
|
||||
XmlElement element = parser.start(); // segmented_address element
|
||||
segmentedspace = element.getAttribute("space");
|
||||
segmentType = element.getAttribute("type");
|
||||
if (segmentType == null) {
|
||||
segmentType = "";
|
||||
}
|
||||
}
|
||||
parser.dispose();
|
||||
}
|
||||
|
@ -586,20 +598,40 @@ public class SleighLanguage implements Language {
|
|||
}
|
||||
InjectPayloadSleigh payload =
|
||||
new InjectPayloadSleigh(subName, InjectPayload.EXECUTABLEPCODE_TYPE, source);
|
||||
if (additionalInject == null) {
|
||||
additionalInject = new ArrayList<>();
|
||||
}
|
||||
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) {
|
||||
Set<String> registerDataSet = new HashSet<>();
|
||||
|
||||
XmlElement element = parser.start("processor_spec");
|
||||
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",
|
||||
"register_data", "default_symbols", "default_memory_blocks");
|
||||
if (element.getName().equals("properties")) {
|
||||
|
@ -769,6 +801,10 @@ public class SleighLanguage implements Language {
|
|||
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
|
||||
parser.end(element);
|
||||
}
|
||||
|
@ -896,8 +932,13 @@ public class SleighLanguage implements Language {
|
|||
throw new SleighException(
|
||||
"Segmented space does not support truncation: " + name);
|
||||
}
|
||||
if (segmentType.equals("protected")) {
|
||||
spc = new ProtectedAddressSpace(name, index);
|
||||
}
|
||||
else {
|
||||
spc = new SegmentedAddressSpace(name, index);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (truncateSpace) {
|
||||
int truncatedSize = description.getTruncatedSpaceSize(name);
|
||||
|
@ -1378,8 +1419,8 @@ public class SleighLanguage implements Language {
|
|||
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "index", element.getUnique());
|
||||
|
||||
int size = element.getSize(); // Size in bits
|
||||
if (size == 20) {
|
||||
// TODO: SegmentedAddressSpace shouldn't really return 20
|
||||
if (element instanceof SegmentedAddressSpace) {
|
||||
// TODO: SegmentedAddressSpace shouldn't really return 21
|
||||
size = 32;
|
||||
}
|
||||
if (size > 64) {
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.address;
|
||||
|
||||
/**
|
||||
* Address Space for (intel) 16-bit protected mode programs. This space produces
|
||||
* SegmentedAddress objects whose underlying (flat) offset encodes both the
|
||||
* segment and the segment offset without losing information. There is no possibility
|
||||
* of alternate encodings for a single address as with real-mode.
|
||||
*/
|
||||
public class ProtectedAddressSpace extends SegmentedAddressSpace {
|
||||
|
||||
private final static int PROTECTEDMODE_SIZE = 32;
|
||||
private final static int PROTECTEDMODE_OFFSETSIZE = 16;
|
||||
|
||||
private int offsetSize; // Number of bits in the segment offset
|
||||
private long offsetMask; // Mask for retrieving the segment offset
|
||||
|
||||
public ProtectedAddressSpace(String name, int unique) {
|
||||
super(name, PROTECTEDMODE_SIZE, unique);
|
||||
offsetSize = PROTECTEDMODE_OFFSETSIZE;
|
||||
offsetMask = 1;
|
||||
offsetMask <<= offsetSize;
|
||||
offsetMask -= 1;
|
||||
maxAddress = getUncheckedAddress(maxOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getFlatOffset(int segment, long offset) {
|
||||
long res = segment;
|
||||
res <<= offsetSize;
|
||||
res += offset;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultSegmentFromFlat(long flat) {
|
||||
return (int) (flat >>> offsetSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDefaultOffsetFromFlat(long flat) {
|
||||
return (flat & offsetMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getOffsetFromFlat(long flat, int segment) {
|
||||
return (flat & offsetMask); // segment does not affect the offset
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SegmentedAddress getAddressInSegment(long flat, int preferredSegment) {
|
||||
return null; // The segment cannot be changed as the flat explicitly encodes it
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextOpenSegment(Address addr) {
|
||||
int res = getDefaultSegmentFromFlat(addr.getOffset());
|
||||
// Advance the selector by 8, accounting for the descriptor table bit and the privilege level bits
|
||||
res = (res + 8) & 0xfff8;
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -17,74 +17,56 @@ package ghidra.program.model.address;
|
|||
|
||||
|
||||
/**
|
||||
* Address class for dealing with intel 20 bit segmented addresses.
|
||||
* Address class for dealing with (intel) segmented addresses. The class itself is agnostic
|
||||
* about the mapping from segmented encoding to flat address offset, it uses the
|
||||
* SegmentedAddressSpace to perform this mapping. So the same class can be used to represent
|
||||
* either a real-mode address or a protected-mode address. The class uses the underlying
|
||||
* offset field to hold the flat encoding.
|
||||
*/
|
||||
public class SegmentedAddress extends GenericAddress {
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
public static final int OFFSET_SIZE = 16;
|
||||
public static final int SEGMENT_SIZE = 16;
|
||||
|
||||
private final SegmentedAddressSpace addrSpace;
|
||||
private final int segment;
|
||||
private final int segment; // The specific segment value associated with this address
|
||||
|
||||
/**
|
||||
* Constructor for SegmentedAddress.
|
||||
* Offset is not validated against address space.
|
||||
* @param addrSpace address space for this address
|
||||
* @param offset offset into the space
|
||||
* @param addrSpace is the address space for this address
|
||||
* @param flat is the flat offset into the space
|
||||
*/
|
||||
SegmentedAddress(long offset, SegmentedAddressSpace addrSpace) {
|
||||
super(adjustOffset(offset), addrSpace);
|
||||
this.addrSpace = addrSpace;
|
||||
if (offset > 0xFFFFF) {
|
||||
this.segment = 0xFFFF;
|
||||
} else {
|
||||
this.segment = (int) ((offset >> 4) & 0xf000);
|
||||
}
|
||||
SegmentedAddress(long flat, SegmentedAddressSpace addrSpace) {
|
||||
super(adjustOffset(flat, addrSpace), addrSpace);
|
||||
segment = addrSpace.getDefaultSegmentFromFlat(flat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for SegmentedAddress.
|
||||
* @param addrSpace address space for this address
|
||||
* @param segmentOffset offset into the segment
|
||||
* @param overlayId overlay number
|
||||
* @param segment segment number
|
||||
* @param addrSpace is the address space for this address
|
||||
* @param segment is the segment number
|
||||
* @param segmentOffset is the offset into the segment
|
||||
* @throws AddressOutOfBoundsException if the address does not fit in the space
|
||||
*/
|
||||
SegmentedAddress(SegmentedAddressSpace addrSpace, int segment, int segmentOffset)
|
||||
throws AddressOutOfBoundsException {
|
||||
super(addrSpace, (segment << 4) + segmentOffset);
|
||||
this.addrSpace = addrSpace;
|
||||
if (offset > 0xFFFFF) {
|
||||
this.segment = 0xFFFF;
|
||||
} else {
|
||||
super(addrSpace, addrSpace.getFlatOffset(segment, segmentOffset));
|
||||
this.segment = segment;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for SegmentedAddress.
|
||||
* @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 {
|
||||
super(addrSpace, adjustOffset(offset));
|
||||
this.addrSpace = addrSpace;
|
||||
if (offset > 0xFFFFF) {
|
||||
this.segment = 0xFFFF;
|
||||
} else {
|
||||
this.segment = (int) ((offset >> 4) & 0xf000);
|
||||
}
|
||||
super(addrSpace, adjustOffset(flat, addrSpace));
|
||||
segment = addrSpace.getDefaultSegmentFromFlat(flat);
|
||||
}
|
||||
|
||||
private static long adjustOffset(long offset) {
|
||||
// Decompiler treats segmented space as a 32-bit space and may produce an address offset
|
||||
// of 0xffffffff for a first use offset (= 0 minus 1).
|
||||
if (offset == 0x0ffffffffL) {
|
||||
offset = 0x0fffffL;
|
||||
}
|
||||
return offset;
|
||||
private static long adjustOffset(long flat, SegmentedAddressSpace addrSpace) {
|
||||
int seg = addrSpace.getDefaultSegmentFromFlat(flat);
|
||||
long offset = addrSpace.getDefaultOffsetFromFlat(flat);
|
||||
return addrSpace.getFlatOffset(seg, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,25 +79,24 @@ public class SegmentedAddress extends GenericAddress {
|
|||
|
||||
/**
|
||||
* Returns the offset within the segment.
|
||||
* @return the offset value
|
||||
*/
|
||||
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
|
||||
* the given segment number.
|
||||
* @param seg the seqment value to normalize to.
|
||||
* @return the new address
|
||||
*/
|
||||
public SegmentedAddress normalize(int seg) {
|
||||
if ((seg << 4) > offset) {
|
||||
SegmentedAddress res = ((SegmentedAddressSpace) addrSpace).getAddressInSegment(offset, seg);
|
||||
if (res == null) {
|
||||
return this;
|
||||
}
|
||||
int off = (int) (offset - (seg << 4));
|
||||
if (off > 0xffff) {
|
||||
return this;
|
||||
}
|
||||
return new SegmentedAddress(addrSpace, seg, off);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,8 +105,12 @@ public class SegmentedAddress extends GenericAddress {
|
|||
*/
|
||||
@Override
|
||||
public Address getNewAddress(long byteOffset) {
|
||||
SegmentedAddress segAddr = addrSpace.getAddress(byteOffset);
|
||||
return segAddr.normalize(segment);
|
||||
SegmentedAddressSpace segSpace = (SegmentedAddressSpace) addrSpace;
|
||||
SegmentedAddress res = segSpace.getAddressInSegment(byteOffset, segment);
|
||||
if (res == null) {
|
||||
return segSpace.getAddress(byteOffset);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -174,33 +159,4 @@ public class SegmentedAddress extends GenericAddress {
|
|||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.address.GenericAddress#next()
|
||||
*/
|
||||
/*
|
||||
@Override
|
||||
public Address next() {
|
||||
if ((offset & SegmentedAddressSpace.MASK) == SegmentedAddressSpace.MASK) {
|
||||
return null;
|
||||
}
|
||||
long newOffset = (offset + 1) & SegmentedAddressSpace.MASK;
|
||||
return new SegmentedAddress(addrSpace, newOffset).normalize(segment);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.address.GenericAddress#previous()
|
||||
*/
|
||||
/*
|
||||
@Override
|
||||
public Address previous() {
|
||||
if ((offset & SegmentedAddressSpace.MASK) == 0) {
|
||||
return null;
|
||||
}
|
||||
long newOffset = (offset - 1) & SegmentedAddressSpace.MASK;
|
||||
return new SegmentedAddress(addrSpace, newOffset).normalize(segment);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
|
@ -20,30 +20,120 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import ghidra.util.NumericUtilities;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
private final static int SIZE = 21;
|
||||
|
||||
//private final static int SEGMENT_OFFSET_MASK = 0xffff;
|
||||
//final static long MASK = (1L << SIZE) - 1;
|
||||
private final static int REALMODE_SIZE = 21;
|
||||
private final static long REALMODE_MAXOFFSET = 0x10FFEF;
|
||||
|
||||
/**
|
||||
* Constructs a new Segmented AddressSpace.
|
||||
*
|
||||
* @param name
|
||||
* the name of the space
|
||||
* @param unique
|
||||
* the unique id for the space.
|
||||
* Constructor for larger size address spaces (than the real-mode space)
|
||||
* @param name is the name of the space
|
||||
* @param size is the number of bits in a (flat) address
|
||||
* @param unique is 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) {
|
||||
super(name, SIZE, TYPE_RAM, unique);
|
||||
maxOffset = 0x10FFEF;
|
||||
super(name, REALMODE_SIZE, TYPE_RAM, unique);
|
||||
maxOffset = REALMODE_MAXOFFSET;
|
||||
spaceSize = maxOffset + 1;
|
||||
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)
|
||||
|
@ -98,62 +188,16 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
|
|||
long off = addr.getOffset() - displacement;
|
||||
if (off >= 0) {
|
||||
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(
|
||||
"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,
|
||||
|
@ -175,82 +219,35 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
|
|||
//if ((off & MASK) == off) {
|
||||
if (off >= 0 && off <= maxOffset) {
|
||||
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(
|
||||
"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) {
|
||||
if (addr.startsWith("0x") || addr.startsWith("0X")) {
|
||||
return NumericUtilities.parseHexLong(addr.substring(2));
|
||||
}
|
||||
return NumericUtilities.parseHexLong(addr);
|
||||
|
||||
}
|
||||
|
||||
private SegmentedAddress parseNonSegmented(String offStr) throws AddressFormatException {
|
||||
|
||||
try {
|
||||
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);
|
||||
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new AddressFormatException("Cannot parse (" + offStr + ") as a number.");
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
throw new AddressFormatException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private SegmentedAddress parseSegmented(String segStr, String offStr)
|
||||
|
@ -262,23 +259,22 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
|
|||
catch (NumberFormatException e) {
|
||||
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 {
|
||||
int off = (int) parseString(offStr);
|
||||
if (off < 0 || off > 0xffff) {
|
||||
throw new AddressFormatException("Offset is outside the range 0 to 0xffff");
|
||||
}
|
||||
return new SegmentedAddress(this, seg, off);
|
||||
return getAddress(seg, off);
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
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) {
|
||||
throw new AddressOutOfBoundsException("Offset is too large.");
|
||||
}
|
||||
if ((segment << 4) + segmentOffset > maxOffset) {
|
||||
throw new AddressOutOfBoundsException("Segmented address is too large.");
|
||||
if (segment > 0xffff) {
|
||||
throw new AddressOutOfBoundsException("Segment is too large.");
|
||||
}
|
||||
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()
|
||||
|
|
|
@ -163,8 +163,8 @@ public class BasicCompilerSpec implements CompilerSpec {
|
|||
language.getProperty(GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
|
||||
if (classname == null) {
|
||||
pcodeInject = new PcodeInjectLibrary(language); // This is the default implementation
|
||||
return;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Class<?> c = Class.forName(classname);
|
||||
if (!PcodeInjectLibrary.class.isAssignableFrom(c)) {
|
||||
|
@ -181,11 +181,12 @@ public class BasicCompilerSpec implements CompilerSpec {
|
|||
pcodeInject = constructor.newInstance(language);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, "Language " + language.getLanguageID() + " does not specify a valid " +
|
||||
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);
|
||||
throw new RuntimeException("Failed to instantiate " + classname + " for language " +
|
||||
language.getLanguageID(), e);
|
||||
}
|
||||
}
|
||||
List<InjectPayloadSleigh> additionalInject = language.getAdditionalInject();
|
||||
if (additionalInject != null) {
|
||||
|
@ -254,16 +255,6 @@ public class BasicCompilerSpec implements CompilerSpec {
|
|||
ctxsetting.add(new ContextSetting(reg, value, begad, endad));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCallStackMod() {
|
||||
return defaultModel.getExtrapop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCallStackShift() {
|
||||
return defaultModel.getStackshift();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrototypeModel[] getCallingConventions() {
|
||||
return models;
|
||||
|
@ -491,6 +482,12 @@ public class BasicCompilerSpec implements CompilerSpec {
|
|||
evalCurrentPrototype = parser.start().getAttribute("name");
|
||||
parser.end();
|
||||
}
|
||||
else if (name.equals("segmentop")) {
|
||||
XmlElement el = parser.start();
|
||||
InjectPayloadSleigh payload = language.parseSegmentOp(el, parser);
|
||||
parser.end();
|
||||
pcodeInject.registerInject(payload);
|
||||
}
|
||||
else {
|
||||
XmlElement el = parser.start();
|
||||
parser.discardSubTree(el);
|
||||
|
|
|
@ -89,22 +89,6 @@ public interface CompilerSpec {
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -112,18 +112,19 @@ public class FunctionPrototype {
|
|||
// function pointer, in which case forcing the void
|
||||
// causes the decompiler to drop real parameters.
|
||||
// At the moment, we turn on varargs if there are no params
|
||||
if (voidimpliesdotdotdot && voidinputlock)
|
||||
if (voidimpliesdotdotdot && voidinputlock) {
|
||||
dotdotdot = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate Function Prototype from information attached to a function in the Program DB.
|
||||
*
|
||||
* @param f is the function to grab prototype from
|
||||
* @param default_extrapop
|
||||
* @param override_extrapop
|
||||
* @param overrideExtrapop is the override value to use for 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();
|
||||
modellock =
|
||||
((modelname != null) && (modelname != Function.UNKNOWN_CALLING_CONVENTION_STRING));
|
||||
|
@ -134,10 +135,12 @@ public class FunctionPrototype {
|
|||
returnstorage = returnparam.getVariableStorage();
|
||||
|
||||
SourceType sigSource = f.getSignatureSource();
|
||||
if (sigSource != SourceType.DEFAULT)
|
||||
if (sigSource != SourceType.DEFAULT) {
|
||||
outputlock = DataType.DEFAULT != returntype;
|
||||
else
|
||||
}
|
||||
else {
|
||||
outputlock = false;
|
||||
}
|
||||
|
||||
if ((returnstorage == null) || (!returnstorage.isValid())) { // Unassigned or otherwise invalid storage
|
||||
outputlock = false;
|
||||
|
@ -157,12 +160,21 @@ public class FunctionPrototype {
|
|||
// stackshift is the normal stack change because of a call.
|
||||
//
|
||||
int purge = f.getStackPurgeSize();
|
||||
if (override_extrapop || purge == Function.INVALID_STACK_DEPTH_CHANGE ||
|
||||
purge == Function.UNKNOWN_STACK_DEPTH_CHANGE) {
|
||||
extrapop = default_extrapop;
|
||||
if (doOverride) {
|
||||
extrapop = overrideExtrapop;
|
||||
}
|
||||
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
|
||||
*/
|
||||
public int getNumParams() {
|
||||
if (localsyms != null)
|
||||
if (localsyms != null) {
|
||||
return localsyms.getNumParams();
|
||||
}
|
||||
return params.length;
|
||||
}
|
||||
|
||||
|
@ -198,8 +211,9 @@ public class FunctionPrototype {
|
|||
* if this prototype is not backed by a LocalSymbolMap
|
||||
*/
|
||||
public HighParam getParam(int i) {
|
||||
if (localsyms != null)
|
||||
if (localsyms != null) {
|
||||
return localsyms.getParam(i);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -299,36 +313,50 @@ public class FunctionPrototype {
|
|||
|
||||
/**
|
||||
* 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) {
|
||||
res.append("<prototype");
|
||||
if (extrapop == PrototypeModel.UNKNOWN_EXTRAPOP)
|
||||
if (extrapop == PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||
SpecXmlUtils.encodeStringAttribute(res, "extrapop", "unknown");
|
||||
else
|
||||
}
|
||||
else {
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(res, "extrapop", extrapop);
|
||||
}
|
||||
SpecXmlUtils.encodeStringAttribute(res, "model", modelname);
|
||||
if (modellock)
|
||||
if (modellock) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "modellock", modellock);
|
||||
if (dotdotdot)
|
||||
}
|
||||
if (dotdotdot) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "dotdotdot", dotdotdot);
|
||||
if (voidinputlock)
|
||||
}
|
||||
if (voidinputlock) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "voidlock", voidinputlock);
|
||||
if (isinline)
|
||||
}
|
||||
if (isinline) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "inline", isinline);
|
||||
if (noreturn)
|
||||
}
|
||||
if (noreturn) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "noreturn", noreturn);
|
||||
if (custom)
|
||||
}
|
||||
if (custom) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "custom", custom);
|
||||
if (hasThis)
|
||||
}
|
||||
if (hasThis) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "hasthis", hasThis);
|
||||
if (isConstruct)
|
||||
}
|
||||
if (isConstruct) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "constructor", isConstruct);
|
||||
if (isDestruct)
|
||||
}
|
||||
if (isDestruct) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "destructor", isDestruct);
|
||||
}
|
||||
res.append(">\n");
|
||||
res.append(" <returnsym");
|
||||
if (outputlock)
|
||||
if (outputlock) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "typelock", outputlock);
|
||||
}
|
||||
res.append(">\n ");
|
||||
int sz = returntype.getLength();
|
||||
if (sz < 0) {
|
||||
|
@ -338,14 +366,16 @@ public class FunctionPrototype {
|
|||
if ((returnstorage != null) && returnstorage.isValid() &&
|
||||
(!returnstorage.isVoidStorage())) {
|
||||
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
|
||||
}
|
||||
String addrstring = Varnode.buildXMLAddress(returnstorage.getVarnodes(), logicalsize);
|
||||
res.append(addrstring).append("\n ");
|
||||
}
|
||||
else
|
||||
else {
|
||||
// Decompiler will use model for storage
|
||||
res.append("<addr/>\n "); // Don't specify where return type is stored
|
||||
}
|
||||
|
||||
res.append(dtmanage.buildTypeRef(returntype, sz));
|
||||
res.append(" </returnsym>\n");
|
||||
|
@ -370,8 +400,9 @@ public class FunctionPrototype {
|
|||
res.append("\">\n");
|
||||
res.append(" <addr/>\n "); // Blank address
|
||||
sz = dt.getLength();
|
||||
if (sz < 0)
|
||||
if (sz < 0) {
|
||||
sz = 1;
|
||||
}
|
||||
res.append(dtmanage.buildTypeRef(dt, sz));
|
||||
res.append("</param>\n");
|
||||
}
|
||||
|
@ -381,21 +412,22 @@ public class FunctionPrototype {
|
|||
}
|
||||
|
||||
/**
|
||||
* Parse the function prototype from an XML tree node.
|
||||
*
|
||||
* @param node XML tree node from a parsing of a larger XML document
|
||||
*
|
||||
* @throws PcodeXMLException
|
||||
* Parse the function prototype from <prototype> tag.
|
||||
* @param parser is the XML document to parse
|
||||
* @param dtmanage is the DataTypeManager used to parse data-type tags
|
||||
* @throws PcodeXMLException for any problems parsing
|
||||
*/
|
||||
public void readPrototypeXML(XmlPullParser parser, PcodeDataTypeManager dtmanage)
|
||||
throws PcodeXMLException {
|
||||
XmlElement node = parser.start("prototype");
|
||||
modelname = node.getAttribute("model");
|
||||
String val = node.getAttribute("extrapop");
|
||||
if (val.equals("unknown"))
|
||||
if (val.equals("unknown")) {
|
||||
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||
else
|
||||
}
|
||||
else {
|
||||
extrapop = SpecXmlUtils.decodeInt(val);
|
||||
}
|
||||
modellock = false;
|
||||
if (node.hasAttribute("modellock")) {
|
||||
modellock = SpecXmlUtils.decodeBoolean(node.getAttribute("modellock"));
|
||||
|
@ -434,16 +466,18 @@ public class FunctionPrototype {
|
|||
}
|
||||
XmlElement retel = parser.start("returnsym");
|
||||
outputlock = false;
|
||||
if (retel.hasAttribute("typelock"))
|
||||
if (retel.hasAttribute("typelock")) {
|
||||
outputlock = SpecXmlUtils.decodeBoolean(retel.getAttribute("typelock"));
|
||||
}
|
||||
parser.discardSubTree();
|
||||
returnstorage = null; // For now don't use decompiler's return storage
|
||||
returntype = dtmanage.readXMLDataType(parser);
|
||||
parser.end(retel);
|
||||
|
||||
XmlElement peeknode = parser.peek();
|
||||
if ((peeknode != null) && peeknode.isStart())
|
||||
if ((peeknode != null) && peeknode.isStart()) {
|
||||
parser.discardSubTree(); // The decompiler may return an <inject> tag
|
||||
}
|
||||
parser.end(node);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,8 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
|
||||
/**
|
||||
* @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 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
|
||||
* to the function.
|
||||
* Populate the information for the HighFunction from the information in the
|
||||
* Function object.
|
||||
*
|
||||
* @param default_extrapop
|
||||
* @param includeDefaultNames
|
||||
* @param override_extrapop
|
||||
* @param overrideExtrapop is the value to use if extrapop is overridden
|
||||
* @param includeDefaultNames is true if default symbol names should be considered locked
|
||||
* @param doOverride is true if extrapop is overridden
|
||||
*/
|
||||
public void grabFromFunction(int default_extrapop, boolean includeDefaultNames,
|
||||
boolean override_extrapop) {
|
||||
public void grabFromFunction(int overrideExtrapop, boolean includeDefaultNames,
|
||||
boolean doOverride) {
|
||||
localSymbols.grabFromFunction(includeDefaultNames); // Locals must be read first
|
||||
proto.grabFromFunction(func, default_extrapop, override_extrapop);
|
||||
proto.grabFromFunction(func, overrideExtrapop, doOverride);
|
||||
jumpTables = null;
|
||||
protoOverrides = null;
|
||||
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
|
||||
* @throws PcodeXMLException
|
||||
* @param parser is the XML stream
|
||||
* @throws PcodeXMLException for any format errors
|
||||
*/
|
||||
private void readJumpTableListXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement el = parser.start("jumptablelist");
|
||||
|
@ -425,11 +413,9 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
* @param high is the HighVariable to split
|
||||
* @param vn is a representative of the merge group to split out
|
||||
* @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 {
|
||||
// if (high.isNameLocked() || high.isTypeLocked())
|
||||
// return high; // Locked variable should not be speculatively merged
|
||||
try {
|
||||
ArrayList<Varnode> newinst = 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 size describes how many bytes the function occupies as code
|
||||
* @return the XML string
|
||||
*/
|
||||
public String buildFunctionXML(Address entryPoint, int size) {
|
||||
|
@ -588,28 +578,6 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
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,
|
||||
final String targetName) {
|
||||
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.
|
||||
*
|
||||
* @param xml string to parse
|
||||
* @return an XML tree element
|
||||
* @param xml is the XML string to parse
|
||||
* @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)
|
||||
throws PcodeXMLException {
|
||||
|
|
|
@ -539,16 +539,6 @@ class TemporaryCompilerSpec implements CompilerSpec {
|
|||
public void applyContextSettings(DefaultProgramContext ctx) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCallStackMod() {
|
||||
return newCompilerSpec.getCallStackMod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCallStackShift() {
|
||||
return newCompilerSpec.getCallStackShift();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrototypeModel[] getCallingConventions() {
|
||||
return new PrototypeModel[0];
|
||||
|
|
|
@ -9,10 +9,15 @@
|
|||
<range space="io"/>
|
||||
</global>
|
||||
<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"/>
|
||||
<segmentop space="ram" userop="segment" farpointer="yes">
|
||||
<pcode>
|
||||
<input name="inner" size="2"/>
|
||||
<input name="base" size="2"/>
|
||||
<output name="res" size="2"/>
|
||||
<body><![CDATA[
|
||||
res = (base << 12) + inner;
|
||||
]]></body>
|
||||
</pcode>
|
||||
<constresolve>
|
||||
<register name="rBBR"/>
|
||||
</constresolve>
|
||||
|
|
|
@ -27,6 +27,7 @@ data/languages/rdseed.sinc||GHIDRA||||END|
|
|||
data/languages/sgx.sinc||GHIDRA||||END|
|
||||
data/languages/sha.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.pspec||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.pspec||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.ldefs||GHIDRA||||END|
|
||||
data/languages/x86.opinion||GHIDRA||||END|
|
||||
|
|
|
@ -251,7 +251,7 @@ define context contextreg
|
|||
opsize=(2,3) # =0 16-bit operands =1 32-bit operands =2 64-bit operands
|
||||
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
|
||||
# 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
|
||||
repprefx=(9,9) # 0xf3 REP prefix
|
||||
|
@ -1056,6 +1056,8 @@ 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; }
|
||||
@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: CS: is segover=1 & CS { 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; }
|
||||
|
||||
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: DS: is segover=3 & DS { export DS; }
|
||||
seg16: ES: is segover=4 & ES { export ES; }
|
||||
|
@ -1387,10 +1389,8 @@ check_Rmr32_dest: is epsilon { }
|
|||
check_rm32_dest: is epsilon { }
|
||||
check_EAX_dest: is epsilon { }
|
||||
|
||||
# The far addresses listed here actually specify the CS segment to use
|
||||
# but we do not model changing the CS segment in protected mode
|
||||
# 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; }
|
||||
ptr1616: reloc is protectedMode=0 & imm16; j16 [ reloc = j16*0x10 + imm16; ] { CS = j16; export *[ram]:4 reloc; }
|
||||
ptr1616: reloc is protectedMode=1 & imm16; j16 [ reloc = j16*0x10000 + imm16; ] { CS = j16; export *[ram]:4 reloc; }
|
||||
ptr1632: j16":"imm32 is imm32; j16 { CS = j16; export *:4 imm32; }
|
||||
|
||||
|
||||
|
@ -2711,7 +2711,7 @@ Suffix3D: imm8 is imm8 [ suffix3D=imm8; ] { }
|
|||
@ifdef IA64
|
||||
:CALL rel32 is vexMode=0 & addrsize=2 & (opsize=1 | opsize=2) & byte=0xe8; simm32=0 & rel32 { push88(&:8 inst_next); goto rel32; }
|
||||
@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]; }
|
||||
@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]; }
|
||||
|
@ -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 rel32 is vexMode=0 & opsize=1 & 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 rm32 is vexMode=0 & addrsize=1 & opsize=1 & byte=0xff; rm32 & reg_opcode=4 ... { goto [rm32]; }
|
||||
@ifdef IA64
|
||||
|
|
33
Ghidra/Processors/x86/data/languages/x86-16-real.pspec
Normal file
33
Ghidra/Processors/x86/data/languages/x86-16-real.pspec
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Set up x86 16-bit in real mode -->
|
||||
<processor_spec>
|
||||
<properties>
|
||||
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
|
||||
</properties>
|
||||
<programcounter register="EIP"/>
|
||||
<segmented_address space="ram" type="real" />
|
||||
<segmentop space="ram" userop="segment" farpointer="yes">
|
||||
<pcode>
|
||||
<input name="inner" size="2"/>
|
||||
<input name="base" size="2"/>
|
||||
<output name="res" size="4"/>
|
||||
<body><![CDATA[
|
||||
res = (zext(base) << 4) + zext(inner);
|
||||
]]></body>
|
||||
</pcode>
|
||||
<constresolve>
|
||||
<register name="DS"/>
|
||||
</constresolve>
|
||||
</segmentop>
|
||||
<context_data>
|
||||
<context_set space="ram">
|
||||
<set name="addrsize" val="0"/>
|
||||
<set name="opsize" val="0"/>
|
||||
<set name="protectedMode" val="0"/>
|
||||
</context_set>
|
||||
<tracked_set space="ram">
|
||||
<set name="DF" val="0"/>
|
||||
</tracked_set>
|
||||
</context_data>
|
||||
</processor_spec>
|
|
@ -31,14 +31,6 @@
|
|||
<range space="ram"/>
|
||||
</global>
|
||||
<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>
|
||||
<prototype name="__stdcall16near" extrapop="unknown" stackshift="2">
|
||||
<input>
|
||||
|
@ -93,7 +85,7 @@
|
|||
<register name="DF"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
<prototype name="__stdcall16far" extrapop="unknown" stackshift="2">
|
||||
<prototype name="__stdcall16far" extrapop="unknown" stackshift="4">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="500" align="2">
|
||||
<addr offset="4" space="stack"/>
|
||||
|
@ -119,7 +111,7 @@
|
|||
<register name="DF"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
<prototype name="__cdecl16far" extrapop="4" stackshift="2">
|
||||
<prototype name="__cdecl16far" extrapop="4" stackshift="4">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="500" align="2">
|
||||
<addr offset="4" space="stack"/>
|
||||
|
|
|
@ -1,15 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Set up x86 16-bit in protected mode -->
|
||||
|
||||
<processor_spec>
|
||||
<properties>
|
||||
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
|
||||
</properties>
|
||||
<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_set space="ram">
|
||||
<set name="addrsize" val="0"/>
|
||||
<set name="opsize" val="0"/>
|
||||
<set name="protectedMode" val="1"/>
|
||||
</context_set>
|
||||
<tracked_set space="ram">
|
||||
<set name="DF" val="0"/>
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<compiler_spec>
|
||||
<global>
|
||||
<range space="ram"/>
|
||||
</global>
|
||||
<stackpointer register="SP" space="ram"/>
|
||||
<segmentop space="ram"
|
||||
userop="segment"
|
||||
baseinsize="2"
|
||||
innerinsize="2"
|
||||
farpointer="yes"
|
||||
force="false">
|
||||
<baseop code="INT_ZEXT"/>
|
||||
<baseop code="INT_LEFT" value="16"/>
|
||||
<innerop code="INT_ZEXT"/>
|
||||
</segmentop>
|
||||
<default_proto>
|
||||
<prototype name="__stdcall16near" extrapop="unknown" stackshift="2">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="500" align="2">
|
||||
<addr offset="2" space="stack"/>
|
||||
</pentry>
|
||||
</input>
|
||||
<output>
|
||||
<pentry minsize="1" maxsize="2">
|
||||
<register name="AX"/>
|
||||
</pentry>
|
||||
</output>
|
||||
<unaffected>
|
||||
<register name="SP"/>
|
||||
<register name="BP"/>
|
||||
<register name="SI"/>
|
||||
<register name="DI"/>
|
||||
<register name="DS"/>
|
||||
<register name="CS"/>
|
||||
<register name="ES"/>
|
||||
<register name="SS"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
</default_proto>
|
||||
<prototype name="__cdecl16near" extrapop="2" stackshift="2">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="500" align="2">
|
||||
<addr offset="2" space="stack"/>
|
||||
</pentry>
|
||||
</input>
|
||||
<output>
|
||||
<pentry minsize="1" maxsize="2">
|
||||
<register name="AX"/>
|
||||
</pentry>
|
||||
</output>
|
||||
<unaffected>
|
||||
<register name="SP"/>
|
||||
<register name="BP"/>
|
||||
<register name="SI"/>
|
||||
<register name="DI"/>
|
||||
<register name="DS"/>
|
||||
<register name="CS"/>
|
||||
<register name="ES"/>
|
||||
<register name="SS"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
<prototype name="__stdcall16far" extrapop="unknown" stackshift="2">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="500" align="2">
|
||||
<addr offset="4" space="stack"/>
|
||||
</pentry>
|
||||
</input>
|
||||
<output>
|
||||
<pentry minsize="1" maxsize="2">
|
||||
<register name="AX"/>
|
||||
</pentry>
|
||||
</output>
|
||||
<unaffected>
|
||||
<register name="SP"/>
|
||||
<register name="BP"/>
|
||||
<register name="SI"/>
|
||||
<register name="DI"/>
|
||||
<register name="DS"/>
|
||||
<register name="CS"/>
|
||||
<register name="ES"/>
|
||||
<register name="SS"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
<prototype name="__cdecl16far" extrapop="4" stackshift="2">
|
||||
<input>
|
||||
<pentry minsize="1" maxsize="500" align="2">
|
||||
<addr offset="4" space="stack"/>
|
||||
</pentry>
|
||||
</input>
|
||||
<output>
|
||||
<pentry minsize="1" maxsize="2">
|
||||
<register name="AX"/>
|
||||
</pentry>
|
||||
</output>
|
||||
<unaffected>
|
||||
<register name="SP"/>
|
||||
<register name="BP"/>
|
||||
<register name="SI"/>
|
||||
<register name="DI"/>
|
||||
<register name="DS"/>
|
||||
<register name="CS"/>
|
||||
<register name="ES"/>
|
||||
<register name="SS"/>
|
||||
</unaffected>
|
||||
</prototype>
|
||||
</compiler_spec>
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<processor_spec>
|
||||
<properties>
|
||||
<property key="useOperandReferenceAnalyzerSwitchTables" value="true"/>
|
||||
</properties>
|
||||
<context_data>
|
||||
<context_set space="ram">
|
||||
<set name="addrsize" val="0"/>
|
||||
<set name="opsize" val="0"/>
|
||||
</context_set>
|
||||
</context_data>
|
||||
</processor_spec>
|
|
@ -34,11 +34,11 @@
|
|||
variant="System Management Mode"
|
||||
version="2.8"
|
||||
slafile="x86.sla"
|
||||
processorspec="x86-smm.pspec"
|
||||
processorspec="x86-16.pspec"
|
||||
manualindexfile="../manuals/x86.idx"
|
||||
id="x86:LE:32:System Management Mode">
|
||||
<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"/>
|
||||
</language>
|
||||
<language processor="x86"
|
||||
|
@ -47,19 +47,31 @@
|
|||
variant="Real Mode"
|
||||
version="2.8"
|
||||
slafile="x86.sla"
|
||||
processorspec="x86-16.pspec"
|
||||
processorspec="x86-16-real.pspec"
|
||||
manualindexfile="../manuals/x86.idx"
|
||||
id="x86:LE:16:Real Mode">
|
||||
<description>Intel/AMD 16-bit x86 Real Mode</description>
|
||||
<compiler name="default" spec="x86-16.cspec" id="default"/>
|
||||
<external_name tool="IDA-PRO" name="8086"/>
|
||||
<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="80486r"/>
|
||||
<external_name tool="IDA-PRO" name="80586r"/>
|
||||
<external_name tool="IDA-PRO" name="metapc"/>
|
||||
</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"
|
||||
endian="little"
|
||||
size="64"
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<constraint primary="23117" processor="x86" endian="little" size="16" variant="Real Mode"/>
|
||||
</constraint>
|
||||
<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 loader="Mac OS X Mach-O" compilerSpecID="gcc">
|
||||
<constraint primary="7" processor="x86" endian="little" size="32" />
|
||||
|
|
|
@ -29,4 +29,9 @@
|
|||
</compiler>
|
||||
</language>
|
||||
|
||||
<language id="x86:LE:16:Protected Mode">
|
||||
<compiler id="default">
|
||||
<patternfile>x86-16_default_patterns.xml</patternfile>
|
||||
</compiler>
|
||||
</language>
|
||||
</patternconstraints>
|
||||
|
|
|
@ -6,14 +6,17 @@
|
|||
<data>0x4dcb</data> <!-- DEC(BP) 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 0x90</data> <!-- RET(constant) NOP -->
|
||||
<data>0xc390</data> <!-- RET NOP -->
|
||||
<data>0xcb90</data>
|
||||
<data>0xc3</data>
|
||||
</prepatterns>
|
||||
<postpatterns>
|
||||
<data>0x558bec</data> <!-- PUSH(BP) MOV(BP,SP) -->
|
||||
<data>0x5589e5</data> <!-- PUSH(BP) MOV(BP,SP) -->
|
||||
<data>0xc8 000....0 0x0000</data> <!-- ENTER (constant, 0x0) -->
|
||||
<data>0x8cd89045</data> <!-- MOV(AX,DS) NOP INC(BP) -->
|
||||
<data>0x8cd055</data> <!-- MOV(AX,SS) PUSH(BP) -->
|
||||
<funcstart/>
|
||||
</postpatterns>
|
||||
</patternpairs>
|
||||
|
|
|
@ -11,14 +11,6 @@
|
|||
<range space="io"/>
|
||||
</global>
|
||||
<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>
|
||||
<prototype name="__asmA" extrapop="2" stackshift="2" strategy="register">
|
||||
<input>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue