java.lang.Object | |
↳ | com.pnfsoftware.jeb.core.units.code.asm.decompiler.AbstractConverter<InsnType extends com.pnfsoftware.jeb.core.units.code.IInstruction> |
A skeleton for code converters. TODO: documentation + examples.
Fields | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
protected IERoutineContext | ctx | Per-routine data - works because convert() is not re-entrant (same found in X86ConvXxx helper classes). | |||||||||
protected boolean | doNotGenerateNops | ||||||||||
protected IEGlobalContext | gCtx | ||||||||||
protected int | methodConversionCountFailure | ||||||||||
protected int | methodConversionCountSuccess | ||||||||||
protected INativeContext | nctx | ||||||||||
protected Set<Long> | parameterRegistersForAllCC | ||||||||||
protected IProcessor<InsnType extends IInstruction> | proc | ||||||||||
protected int | regNormalBitsize | ||||||||||
protected Set<Long> | spoiledRegistersForAllCC |
Protected Constructors | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
AbstractConverter(IProcessor<InsnType> proc) | |||||||||||
AbstractConverter(IProcessor<InsnType> proc, int registerBitsize) | |||||||||||
AbstractConverter(IProcessor<InsnType> proc, int registerBitsize, int addressBitsize) | |||||||||||
AbstractConverter(INativeContext nctx) |
Public Methods | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
final boolean | autoConvert(ConverterInstructionEntry<InsnType> e, ACS acs) | ||||||||||
IWildcardPrototype |
buildFailsafePrototype(IERoutineContext ctx, IEStatement stm)
The default implementation provides a no-arg/no-return prototype: "void __defaultCC ()".
| ||||||||||
boolean |
canCreateCalls()
The default implementation returns true.
| ||||||||||
final IERoutineContext |
convert(INativeMethodItem routine)
Convert a routine.
| ||||||||||
IERoutineContext |
convert(INativeMethodItem routine, boolean delayBuild)
Convert the blocks of the native routine's CFG after the other.
| ||||||||||
final List<IEStatement> |
convertBlockForTest(BasicBlock<InsnType> b)
Reserved for testing.
| ||||||||||
void | convertInstruction(ConverterInstructionEntry<InsnType> e) | ||||||||||
List<IEGeneric> |
convertParameterExpressions(IERoutineContext ctx, IWildcardPrototype prototype, INativeMethodItem targetRoutine, List<IWildcardType> varArgTypes)
Given a prototype, determine the list of IR expressions representing the input expressions
(would also contain implicitly read registers).
| ||||||||||
List<IEGeneric> |
convertReturnExpressions(IERoutineContext ctx, IWildcardPrototype prototype, INativeMethodItem targetRoutine, List<IWildcardType> varArgTypes, List<IEGeneric> outSpoiled)
Given a prototype, determine the list of IR expressions representing the output expressions.
| ||||||||||
IEGeneric |
convertReturnLocation(IERoutineContext ctx, IWildcardPrototype prototype)
Given a prototype, determine the IR expression representing the return address
location of a call to a method of said prototype.
| ||||||||||
IEMem |
createStackMemoryAccess(IEGeneric address, int bitsize)
The default implementation assumes a segment-less memory model.
| ||||||||||
void |
customInitStateRegisters(EState state, Long optionalNativeProgramCounter)
The default implementation does nothing.
| ||||||||||
int |
defaultPCConversion(IERoutineContext ctx)
Convert PC-assignment to
IEJumpFar statements. | ||||||||||
Integer |
determineStackBytesUsedByCall(IWildcardPrototype prototype, List<IWildcardType> varArgTypes)
Determine the amount of bytes that were pushed on the stack before calling the routine with
the provided prototype and optional additional slots.
| ||||||||||
Integer |
determineStackPointerDeltaAfterIRCall(IWildcardPrototype prototype, List<IWildcardType> varArgTypes)
Determine the stack pointer delta (in bytes) after the
IECall executed and
returned. | ||||||||||
Integer |
determineStackPointerDeltaFromSimulation(SimulationPointInformation simuinfo)
The default implementation returns null.
| ||||||||||
IEImm |
evaluateUntranslatedIR(IEUntranslatedInstruction insn, IERoutineContext ectx, EState state)
The default implementation returns null.
| ||||||||||
String |
formatStatistics()
The default implementation formats basic details about the number of converted methods.
| ||||||||||
ICStatement |
generateASTForUntranslatedIR(IEUntranslatedInstruction insn, IERoutineContext ectx, ICMethod cctx)
The default implementation returns null.
| ||||||||||
int |
getAddressBitsize()
The default implementation returns the size of the program counter.
| ||||||||||
IDecompilerManager |
getDecompiler()
Retrieve a reference to the decompiler managing this converter.
| ||||||||||
IEBranchDetails |
getDefaultBranchToRoutineSideEffects(INativeMethodItem optionalRoutine)
The default implementation returns a basic branch detail object specifying nothing (no def,
no use, no spoils, etc.).
| ||||||||||
IEVar | getFPRegister(int index) | ||||||||||
IEVar | getGPRegister(int index) | ||||||||||
IEGlobalContext |
getGlobalContext()
Retrieve the global program context.
| ||||||||||
IEVar |
getInputVariableByIndex(IERoutineContext ctx, int i)
The default implementation returns null.
| ||||||||||
INativeContext |
getNativeContext()
Retrieve the native code context that this converter should use.
| ||||||||||
long |
getNativeRegisterIdFromRegisterVariable(IEVar regVar, boolean shortForm)
The default implementation attempts to resolve the register variable by querying the
associated processor's register bank layout.
| ||||||||||
final long | getNativeRegisterIdFromRegisterVariable(IEVar regVar) | ||||||||||
IEVar |
getOutputVariableByIndex(IERoutineContext ctx, int i)
The default implementation returns null.
| ||||||||||
IEPrototypeHandler |
getPrototypeHandler(IERoutineContext ctx)
Create an instance of a prototype handler.
| ||||||||||
IEGeneric |
getRegister(String name, ELocation loc)
The default implementation forwards to
getVariableByName(String) . | ||||||||||
final IEGeneric | getRegister(String name) | ||||||||||
int |
getRegisterBitsize()
The default implementation returns the address bitsize.
| ||||||||||
IEGeneric |
getRegisterVariableFromNativeRegisterId(long nativeRegId, ELocation loc)
The default implementation attempts to resolve the native register id or number by querying
the associated processor's register bank layout.
| ||||||||||
final IEGeneric | getRegisterVariableFromNativeRegisterId(long nativeRegId) | ||||||||||
IEVar |
getReturnAddressRegister()
The default implementation considers that there is no specific Return Address Register.
| ||||||||||
String |
getSlicedRegisterName(String registerName, int bitstart, int bitend)
Get the name of the slice of a physical register.
| ||||||||||
int |
getStackSlotSize()
Get the size of standard slot on the stack, in bytes.
| ||||||||||
int |
getStateProcessorMode(EState state)
Retrieve the current processor mode relative to the provided
EState . | ||||||||||
IEVar | getTempRegister(int index) | ||||||||||
IWildcardType.Group |
getWildcardTypeManagerDefaultResolutionGroup()
The default implementation returns
INTEGER . | ||||||||||
void |
initialize()
This method is called by the owner decompiler after the principal components of the
lower-level code unit have been initialized.
| ||||||||||
final void |
initializeStateRegisters(EState state, Long optionalNativeProgramCounter)
This method initializes and sets all physical registers declared by this converter to 0,
except for the ones possibly used as arguments that are kept undefined (see
#isPossibleParameterRegisterForProcessorCallingConventions(IEGeneric)).
| ||||||||||
int |
insertReturns(IERoutineContext ctx)
This method introduces
IEReturn statements into the IR. | ||||||||||
boolean | isDoNotGenerateNops() | ||||||||||
boolean |
isPossibleParameterRegisterForProcessorCallingConventions(long nativeRegId)
Check if a native register id corresponds to a register that can possibly be used as a
routine parameter on this processor.
| ||||||||||
boolean |
isPossibleSpoiledRegistersForProcessorCallingConventions(long nativeRegId)
Check if a native register id corresponds to a physical register that can possibly be spoiled
by a routine call on this processor.
| ||||||||||
Boolean |
isSegmentEMemReferencingPrimaryMemory(IEMem e)
The default implementation returns true: by default, all EMem are assumed to reference bytes
in the primary VM.
| ||||||||||
IEGeneric |
normalizeBranchingExpression(IDFA<IEStatement> dfa, BasicBlock<IEStatement> b, IEGeneric target, IEGeneric expectedTarget)
Normalize a branching expression.
| ||||||||||
boolean |
resolveCustomCalls(IERoutineContext ctx)
Implementations should be aggressive and fast: calls to this method should always be enclosed
in a try-catch.
| ||||||||||
long |
sanitizeNativeAddress(long address)
The default implementation truncates the provided value to accomodate
getAddressBitsize() . | ||||||||||
void |
setCurrentContext(IERoutineContext ctx)
setup the helper converter classes
| ||||||||||
void |
setDecompiler(IDecompilerManager decompiler)
Reserved.
| ||||||||||
void | setDoNotGenerateNops(boolean doNotGenerateNops) | ||||||||||
void | setNativeContext(INativeContext nctx) |
Protected Methods | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
boolean | attemptCallInliningByExtension(ConverterInstructionEntry<InsnType> e, long target) | ||||||||||
boolean | attemptConversionByExtension(ConverterInstructionEntry<InsnType> e) | ||||||||||
void |
convertBlock(BasicBlock<InsnType> b, List<IEStatement> interlist)
Convert a block.
| ||||||||||
boolean | convertInstructionFirstChance(ConverterInstructionEntry<InsnType> e, String mn, boolean allowRecurse) | ||||||||||
boolean | convertInstructionLastChance(ConverterInstructionEntry<InsnType> e) | ||||||||||
IEGeneric | convertOperand(long insnAddress, InsnType insn, int opndIndex) | ||||||||||
boolean |
insertOptionalEntryPointTrampoline(IERoutineContext ctx, List<IEStatement> irlist)
For native routines that have their entry point in-the-middle (ie, not at their lowest
address), insert a synthetic
IEJump as the first instruction of the converted method. | ||||||||||
final boolean |
isPCRightValueCompatibleReturnValue(IDFA<IEStatement> dfa, BasicBlock<IEStatement> b, IEGeneric PCRightVal, IEGeneric expectedReturnAddress)
Can be overridden by implementors when complex return expression matching is needed.
| ||||||||||
void |
postBlockConversion(CFG<InsnType> cfg, BasicBlock<InsnType> b, List<IEStatement> interlist, int cnt)
This method is called after
convertBlock(BasicBlock, List) is called. | ||||||||||
void |
postRoutineConversion(INativeMethodItem routine, IERoutineContext ctx)
Executed by
convert after converting the blocks. | ||||||||||
BasicBlock<InsnType> |
preBlockConversion(CFG<InsnType> cfg, BasicBlock<InsnType> b, List<IEStatement> interlist)
This method is called before
convertBlock(BasicBlock, List) is called. | ||||||||||
void |
preRoutineConversion(INativeMethodItem routine, IERoutineContext ctx, List<IEStatement> irlist)
Executed by
convert before converting the
blocks. |
[Expand]
Inherited Methods | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
![]() | |||||||||||
![]() |
Per-routine data - works because convert() is not re-entrant (same found in X86ConvXxx helper
classes).
Should be set before converting a routine, and reset to null after it's done.
The default implementation provides a no-arg/no-return prototype: "void __defaultCC ()".
Custom implementations may return something more suitable to a given architecture
ctx | routine for which a failsafe prototype is to be generated |
---|---|
stm | optional statement calling into the routine |
The default implementation returns true.
Convert a routine. Convenience method for convert(routine, false)
.
Convert the blocks of the native routine's CFG after the other. The blocks' edges are not considered.
routine | the routine to be converted; must have a data definition |
---|---|
delayBuild | if true, the IR validation and CFG building will not take place (in that
case, getCfg() would return false) |
Given a prototype, determine the list of IR expressions representing the input expressions (would also contain implicitly read registers).
Used by IECall
.
prototype | mandatory prototype |
---|---|
targetRoutine | optional |
varArgTypes | optional |
Given a prototype, determine the list of IR expressions representing the output expressions. Spoiled register expressions can also be returned.
Used by IECall
.
Given a prototype, determine the IR expression representing the return address location of a call to a method of said prototype.
Used by IECall
.
The default implementation assumes a segment-less memory model. (The EMem segment component is set to null.)
The default implementation does nothing.
Convert PC-assignment to IEJumpFar
statements. This method is a fail-safe converter
for PC-assignments, and should be called as late as possible in the IR conversion phases.
After executing this method, the CFG should no longer contain PC-assignments.
Determine the amount of bytes that were pushed on the stack before calling the routine with the provided prototype and optional additional slots. That should include all routine parameters pushed on the stack as well as the return address bytes as well, if it is located on the stack (per the provided calling convention).
Used by IECall
.
Determine the stack pointer delta (in bytes) after the IECall
executed and
returned.
Careful: "IR-Call" and the "native-call" may not have the same structure; it depends on how
the conversion of "native-call" is implemented, and therefore is converter-dependent. The SP
delta returned by this method is the one after an execution over IECall
.
Used by IECall
.
The default implementation returns null.
simuinfo | state of IR execution; PC is assumed to be on the target routine entry-point |
---|
The default implementation returns null.
The default implementation formats basic details about the number of converted methods.
The default implementation returns null.
The default implementation returns the size of the program counter.
Retrieve a reference to the decompiler managing this converter.
INativeDecompilerUnit
), or null
The default implementation returns a basic branch detail object specifying nothing (no def, no use, no spoils, etc.).
Converters should override this method.
optionalRoutine | the optional target routine; if provided, the implementation may use that information to provide more accurate results |
---|
Retrieve the global program context. There is a single global context per decompiler, common
to all routine contexts
.
The default implementation returns null.
Retrieve the native code context that this converter should use.
The default implementation attempts to resolve the register variable by querying the associated processor's register bank layout. It throws if the resolution fails.
regVar | a global EVar-register |
---|---|
shortForm | if true the value provided does not contain the converter-specific information present in the long form (used in particular by IInstructionOperandRegisterBased#getRegisterName(long)), otherwise it is the long form |
The default implementation returns null.
Create an instance of a prototype handler.
The default implementation forwards to getVariableByName(String)
.
name | register name |
---|
The default implementation returns the address bitsize.
The default implementation attempts to resolve the native register id or number by querying the associated processor's register bank layout. It throws if the resolution fails.
nativeRegId | a native register id, used by the IProcessor that this converter
is relying on; the id may be a full id, that is, one supported by
IInstructionOperandRegisterBased#getRegisterName(long), or a short-form of
it (eg, the default X86 Processor module uses short-form 0 for the eAX register,
that is the first GP register whose size matches the current processor mode). |
---|---|
loc | optional IR statement location at which the conversion is taking place |
See getRegisterVariableFromNativeRegisterId(long, ELocation)
. No location provided
The default implementation considers that there is no specific Return Address Register. Override if one exists.
Get the name of the slice of a physical register. The slice name may be an official name or a convenience name decided by the converter.
registerName | full name of a physical register |
---|
Get the size of standard slot on the stack, in bytes.
The default implementation returns INTEGER
.
This method is called by the owner decompiler after the principal components of the lower-level code unit have been initialized. Initialization requiring, e.g. access to the type manager, should be performed here instead of within the constructor.
This method initializes and sets all physical registers declared by this converter to 0,
except for the ones possibly used as arguments that are kept undefined (see
#isPossibleParameterRegisterForProcessorCallingConventions(IEGeneric)). After this is
done, customInitStateRegisters(EState, Long)
is invoked.
state | input state to be initialized |
---|---|
optionalNativeProgramCounter | optional current native PC |
This method introduces IEReturn
statements into the IR. Must be performed only after
prototype discovery is completed.
Data chains: not used, may be invalidated; in the latter case, this method is responsible for recalculating them.
ctx | the routine context |
---|
Check if a native register id corresponds to a register that can possibly be used as a routine parameter on this processor.
To do so, the given id is compared against all input registers for all known calling conventions for the current processor. In particular, this method does not rely on the routine prototype and calling convention being defined, and can therefore be used early on during decompilation.
Check if a native register id corresponds to a physical register that can possibly be spoiled by a routine call on this processor.
To do so, the given id is compared against all spoiled registers for all known calling conventions for the current processor. In particular, this method does not rely on the routine prototype and calling convention being defined, and can therefore be used early on during decompilation.
The default implementation returns true: by default, all EMem are assumed to reference bytes in the primary VM.
Normalize a branching expression.
dfa | a DFA object |
---|---|
b | basic block whose last instruction is a branching statement (e.g. EAssign to PC, ECall, EJumpFar, etc.) |
target | the callsite of the branching statement targeted by the basic block `b` |
expectedTarget | optional |
Implementations should be aggressive and fast: calls to this method should always be enclosed in a try-catch.
TODO: MOVE to the CBDU
The default implementation truncates the provided value to accomodate getAddressBitsize()
.
Convert a block.
b | block to be converted |
---|---|
interlist | output list of converted IR statements |
For native routines that have their entry point in-the-middle (ie, not at their lowest
address), insert a synthetic IEJump
as the first instruction of the converted method.
By using this trick, we ensure that native routines that have their entry-point in the middle of their code can be converted to IR routines with an entry-point always set to offset 0 (the beginning of the IR code). The reason is that this helps with graph manipulation passes that come later on, in the AST phases.
ctx | translation context |
---|---|
irlist | global list of converted IR-statements, should be empty when this method is called |
Can be overridden by implementors when complex return expression matching is needed.
dfa | current DFA |
---|---|
b | BasicBlock containing the PC assign instruction (last one of the block) |
PCRightVal | right Value of the PC assign instruction |
expectedReturnAddress | Expected IEVar as per current Calling Convention |
This method is called after convertBlock(BasicBlock, List)
is called. The default
implementation sanitizes fake calls, i.e. it switches call-to-sub-PC-assigns to regular
PC-assigns if the underlying analyzer detected that what looked like a call-to-sub is not.
cfg | the native CFG of the method being converted |
---|---|
b | the native basic block that was just converted |
interlist | the current list of IR statements for the routine (not only for the provided block!); the last IR statements in that list are those of the routine that was just converted |
cnt | the number of IR statements that correspond to the conversion of the provided native block |
Executed by convert
after converting the blocks.
The default implementation does nothing.
This method is called before convertBlock(BasicBlock, List)
is called. It can be
overridden. Sub-classes do not need to call the default implementation. The default
implementation returns the provided input block.
cfg | the CFG |
---|---|
b | block about to be converted |
Executed by convert
before converting the
blocks. The default implementation does nothing.