ROSE 0.11.145.147
|
Insert new code in place of existing instructions.
Definition at line 26 of file CodeInserter.h.
#include <Rose/BinaryAnalysis/CodeInserter.h>
Classes | |
struct | InstructionInfo |
Information about an instruction within the basic block being modified. More... | |
struct | Relocation |
Relocation record. More... | |
Public Types | |
enum | AggregationDirection { AGGREGATE_PREDECESSORS = 0x00000001 , AGGREGATE_SUCCESSORS = 0x00000002 } |
What other instructions can be moved to make room. More... | |
enum | NopPadding { PAD_NOP_BACK , PAD_NOP_FRONT , PAD_RANDOM_BACK } |
How to pad with no-ops. More... | |
enum | RelocType { RELOC_INDEX_ABS_LE32 , RELOC_INDEX_ABS_LE32HI , RELOC_INDEX_ABS_BE32 , RELOC_ADDR_REL_LE32 , RELOC_ADDR_REL_BE32 , RELOC_INSN_ABS_LE32 , RELOC_INSN_REL_LE32 , RELOC_INSN_REL_BE32 } |
Type of relocation to perform. More... | |
typedef Sawyer::Container::Map< int, InstructionInfo > | InstructionInfoMap |
Information about instructions within the basic block being modified. | |
Public Member Functions | |
CodeInserter (const Partitioner2::PartitionerConstPtr &) | |
const AddressIntervalSet & | allocatedChunks () const |
Returns the parts of the virtual address space that were allocated for new instructions. | |
virtual bool | replaceBlockInsns (const Partitioner2::BasicBlockPtr &, size_t startIdx, size_t nInsns, std::vector< uint8_t > replacement, const std::vector< Relocation > &relocations=std::vector< Relocation >()) |
Replace instructions in basic block. | |
bool | replaceInsnsAtFront (const Partitioner2::BasicBlockPtr &, size_t nInsns, const std::vector< uint8_t > &replacement, const std::vector< Relocation > &relocations=std::vector< Relocation >()) |
Replace instructions at front of basic block. | |
virtual bool | replaceInsnsAtBack (const Partitioner2::BasicBlockPtr &, size_t nInsns, const std::vector< uint8_t > &replacement, const std::vector< Relocation > &relocations=std::vector< Relocation >()) |
Replace instructions at back of basic block. | |
virtual bool | prependInsns (const Partitioner2::BasicBlockPtr &, const std::vector< uint8_t > &replacement, const std::vector< Relocation > &relocations=std::vector< Relocation >()) |
Prepend code to a basic block. | |
virtual bool | appendInsns (const Partitioner2::BasicBlockPtr &, const std::vector< uint8_t > &replacement, const std::vector< Relocation > &relocations=std::vector< Relocation >()) |
Append code to a basic block. | |
virtual bool | replaceInsns (const std::vector< SgAsmInstruction * > &toReplace, const std::vector< uint8_t > &replacement, const std::vector< Relocation > &relocations=std::vector< Relocation >()) |
Replace exactly the specified instructions with some other encoding. | |
virtual void | fillWithNops (const AddressIntervalSet &where) |
Fill the specified memory with no-op instructions. | |
virtual void | fillWithRandom (const AddressIntervalSet &where) |
Fill the specified memory with random data. | |
virtual std::vector< uint8_t > | encodeJump (rose_addr_t srcVa, rose_addr_t tgtVa) |
Encode an unconditional branch. | |
virtual std::vector< uint8_t > | applyRelocations (rose_addr_t startVa, std::vector< uint8_t > replacement, const std::vector< Relocation > &relocations, size_t relocStart, const InstructionInfoMap &insnInfoMap) |
Apply relocations to create a new encoding. | |
virtual AddressInterval | allocateMemory (size_t nBytes, rose_addr_t jmpTargetVa, Commit::Boolean commit=Commit::YES) |
Allocate virtual memory in the partitioner memory map. | |
void | commitAllocation (const AddressInterval &where, Commit::Boolean commit=Commit::YES) |
Commit previous allocation. | |
AddressIntervalSet | instructionLocations (const std::vector< SgAsmInstruction * > &) |
Given a list of functions, return all addresses that the instructions occupy. | |
virtual bool | replaceByOverwrite (const AddressIntervalSet &toReplaceVas, const AddressInterval &entryInterval, const std::vector< uint8_t > &replacement, const std::vector< Relocation > &relocations, size_t relocStart, const InstructionInfoMap &insnInfoMap) |
Insert new code by overwriting existing instructions. | |
virtual bool | replaceByTransfer (const AddressIntervalSet &toReplaceVas, const AddressInterval &entryInterval, const std::vector< SgAsmInstruction * > &toReplace, const std::vector< uint8_t > &replacement, const std::vector< Relocation > &relocations, size_t relocStart, const InstructionInfoMap &insnInfoMap) |
Insert new code in allocated area. | |
InstructionInfoMap | computeInstructionInfoMap (const Partitioner2::BasicBlockPtr &, size_t startIdx, size_t nDeleted) |
Obtain info about instructions for the basic block being modified. | |
const AddressInterval & | chunkAllocationRegion () const |
Property: Where chunks are allocated. | |
void | chunkAllocationRegion (const AddressInterval &i) |
Property: Where chunks are allocated. | |
const AddressIntervalSet & | mappedFreeSpace () const |
Property: Mapped free-space chunks. | |
AddressIntervalSet & | mappedFreeSpace () |
Property: Mapped free-space chunks. | |
void | mappedFreeSpace (const AddressIntervalSet &x) |
Property: Mapped free-space chunks. | |
size_t | minChunkAllocationSize () const |
Property: Minimum size of allocated chunks. | |
void | minChunkAllocationSize (size_t n) |
Property: Minimum size of allocated chunks. | |
size_t | chunkAllocationAlignment () const |
Property: Alignment for large allocated chunks. | |
void | chunkAllocationAlignment (size_t n) |
Property: Alignment for large allocated chunks. | |
const std::string & | chunkAllocationName () const |
Property: Name for newly allocated regions of memory. | |
void | chunkAllocationName (const std::string &s) |
Property: Name for newly allocated regions of memory. | |
unsigned | aggregationDirection () const |
Property: Whether additional instructions can be moved. | |
void | aggregationDirection (unsigned d) |
Property: Whether additional instructions can be moved. | |
NopPadding | nopPadding () const |
Property: Where to add no-ops when padding. | |
void | nopPadding (NopPadding p) |
Property: Where to add no-ops when padding. | |
Static Public Member Functions | |
static void | initDiagnostics () |
Initialize diagnostic streams. | |
Static Public Attributes | |
static Sawyer::Message::Facility | mlog |
Facility for emitting diagnostics. | |
Protected Attributes | |
Partitioner2::PartitionerConstPtr | partitioner_ |
AddressInterval | chunkAllocationRegion_ |
size_t | minChunkAllocationSize_ |
size_t | chunkAllocationAlignment_ |
std::string | chunkAllocationName_ |
AddressIntervalSet | allocatedChunks_ |
AddressIntervalSet | freeSpace_ |
unsigned | aggregationDirection_ |
NopPadding | nopPadding_ |
typedef Sawyer::Container::Map<int, InstructionInfo> Rose::BinaryAnalysis::CodeInserter::InstructionInfoMap |
Information about instructions within the basic block being modified.
The instructions are numbered relative to their position with the insertion point and deleted instructions. Negative keys refer to instructions that appear before the insertion point, and non-negative keys refer to instructions starting one past the last deleted instruction or, if no instructions are deleted, the instruction originally at the insertion point.
Definition at line 145 of file CodeInserter.h.
What other instructions can be moved to make room.
These are bit flags.
Enumerator | |
---|---|
AGGREGATE_PREDECESSORS | Move preceding instructions in CFG. |
AGGREGATE_SUCCESSORS | Move succeeding instructions in CFG. |
Definition at line 29 of file CodeInserter.h.
How to pad with no-ops.
Enumerator | |
---|---|
PAD_NOP_BACK | Add no-ops to the end of replacements. |
PAD_NOP_FRONT | Add no-ops to the front of replacements. |
PAD_RANDOM_BACK | Add random data to the end of replacements. |
Definition at line 35 of file CodeInserter.h.
Type of relocation to perform.
Each enum constant identifies a function whose description is given below. In those descriptions, the following variables are used:
input
is a vector of bytes that was specified by the user as the new code to be inserted.reloc_value
is the value data member of the relocation record. It has various interpretations depending on the relocation function.The last word of the function name specifies the format used to write the computed value back to the output:
LE32
writes the low-order 32 bits of the computed value as a 32-bit integer in little-endian order.LE32HI
writes the high-order 32 bits of the computed value as a 32-bit integer in little-endian order. Definition at line 59 of file CodeInserter.h.
|
static |
Initialize diagnostic streams.
This is called automatically by Rose::Diagnostics::initialize.
|
inline |
Property: Where chunks are allocated.
This region defines the part of the memory map where new free space chunks will be mapped in order to hold replacement code that doesn't fit into the same space as the instructions its replacing. The default is the part of the address space immediately after the last mapped address in the partitioner passed to the constructor.
Definition at line 178 of file CodeInserter.h.
|
inline |
Property: Where chunks are allocated.
This region defines the part of the memory map where new free space chunks will be mapped in order to hold replacement code that doesn't fit into the same space as the instructions its replacing. The default is the part of the address space immediately after the last mapped address in the partitioner passed to the constructor.
Definition at line 179 of file CodeInserter.h.
|
inline |
Property: Mapped free-space chunks.
This is the set of mapped regions that are considered to be free space. The allocator will prefer to obtain memory from these already mapped regions before it tries to map additional free chunks within the chunkAllocationRegion.
Definition at line 188 of file CodeInserter.h.
|
inline |
Property: Mapped free-space chunks.
This is the set of mapped regions that are considered to be free space. The allocator will prefer to obtain memory from these already mapped regions before it tries to map additional free chunks within the chunkAllocationRegion.
Definition at line 189 of file CodeInserter.h.
|
inline |
Property: Mapped free-space chunks.
This is the set of mapped regions that are considered to be free space. The allocator will prefer to obtain memory from these already mapped regions before it tries to map additional free chunks within the chunkAllocationRegion.
Definition at line 190 of file CodeInserter.h.
|
inline |
Returns the parts of the virtual address space that were allocated for new instructions.
The returned value will be a subset of the chunkAllocationRegion. The return value indicates where large chunks of memory were allocated, but not what bytes within that memory were actually used for new instructions.
Definition at line 196 of file CodeInserter.h.
|
inline |
Property: Minimum size of allocated chunks.
When allocating space for replacement code, never allocate less than this many bytes at a time. Note that multiple replacement codes can be written to a single chunk since we maintain a free list within chunks.
Definition at line 204 of file CodeInserter.h.
|
inline |
Property: Minimum size of allocated chunks.
When allocating space for replacement code, never allocate less than this many bytes at a time. Note that multiple replacement codes can be written to a single chunk since we maintain a free list within chunks.
Definition at line 205 of file CodeInserter.h.
|
inline |
Property: Alignment for large allocated chunks.
Definition at line 211 of file CodeInserter.h.
|
inline |
Property: Name for newly allocated regions of memory.
Definition at line 218 of file CodeInserter.h.
|
inline |
Property: Name for newly allocated regions of memory.
Definition at line 219 of file CodeInserter.h.
|
inline |
Property: Whether additional instructions can be moved.
This property controls which additional instructions can be moved by the replaceBlockInsns method in order to make room for the replacement. It is a bit vector of AggregationDirection bits and defaults to both successors and predecessors. When both are present, successors are added first (all the way to the end of the block) and then predecessors are also added (all the way to the beginning of the block).
Definition at line 230 of file CodeInserter.h.
|
inline |
Property: Whether additional instructions can be moved.
This property controls which additional instructions can be moved by the replaceBlockInsns method in order to make room for the replacement. It is a bit vector of AggregationDirection bits and defaults to both successors and predecessors. When both are present, successors are added first (all the way to the end of the block) and then predecessors are also added (all the way to the beginning of the block).
Definition at line 231 of file CodeInserter.h.
|
inline |
Property: Where to add no-ops when padding.
When to-be-replaced instructions are overwritten with a replacement and the replacement is smaller than the replaced instructions, then the replacement is padded with no-op instructions according to this property.
Definition at line 240 of file CodeInserter.h.
|
inline |
Property: Where to add no-ops when padding.
When to-be-replaced instructions are overwritten with a replacement and the replacement is smaller than the replaced instructions, then the replacement is padded with no-op instructions according to this property.
Definition at line 241 of file CodeInserter.h.
|
virtual |
Replace instructions in basic block.
This replaces nInsns
instructions in the basic block starting at instruction number startIdx
. The nInsns
may be zero, in which case the replacement is inserted before the startIdx
instruction. The new code is inserted either by overwriting the to-be-replaced instructions with the replacement
padded at the end by no-ops if necessary (so called "overwrite" mode), or the replacement is written to some other part of the address space and unconditional branches are inserted to branch to the replacement and then back again (so called "branch-aside" mode).
If the neither the replacement (in overwrite mode) nor the unconditional branch (in branch-aside mode) fit in the area vacated by the to-be-replaced instructions, then the to-be-replaced instructions are extended by moving a neighboring instruction into the replacement
. The aggregationDirection property controls which instructions can be joined. This often works for branch-aside mode, but can even sometimes work for overwrite mode if the basic block instructions are not executed in address order. The overwrite situation can work when a subsequent or earlier instruction fills in a hole in the to-be-replaced address set.
This method assumes that the replacement
is entered at the first byte and exits to one past the last byte. Since some instruction encodings depend on the location of the replacement in virtual memory, the relocations
can be used to patch the replacement as it's written to memory.
Inserting code in this manner is not without risk. For instance, enlarging the to-be-replaced set might mean that additional instructions are moved to a different address without changing their encoding. Examples are moving instructions that reference global variables relative to the instruction's address, branches that span the branch-aside gap, etc.
Returns true if successful, false otherwise.
bool Rose::BinaryAnalysis::CodeInserter::replaceInsnsAtFront | ( | const Partitioner2::BasicBlockPtr & | , |
size_t | nInsns, | ||
const std::vector< uint8_t > & | replacement, | ||
const std::vector< Relocation > & | relocations = std::vector< Relocation >() |
||
) |
Replace instructions at front of basic block.
This is just a convenience for replaceBlockInsns that replaces nInsns
instructions at the beginning of the specified basic block. If nInsns
is zero, then the replacement
is inserted at the front of the basic block without removing any instructions.
|
virtual |
Replace instructions at back of basic block.
This is just a convenience for replaceBlockInsns that replaces nInsns
instructions at the end of the specified basic block. If nInsns
is zero, then the replacement
is appended to the end of the basic block without removing any instructions.
|
virtual |
Prepend code to a basic block.
This is a convenience for replaceInsnsAtFront. It inserts the replacement
at the front of the basic block by writing the replacement
followed by the first instruction(s) of the block to some other area of memory, overwriting the first part of the basic block with an unconditional branch to the replacement, and following the replacement with an unconditional branch back to the rest of the basic block.
|
virtual |
Append code to a basic block.
This is a convenience for replaceInsnsAtBack. It appends the replacement
to the end of the basic block by moving the last instruction(s) of the block to some other memory followed by the replacement. The original final instructions are overwritten with an unconditional branch to that other memory, which is followed by a branch back to the rest of the basic block.
|
virtual |
Replace exactly the specified instructions with some other encoding.
The replacement
instructions either overwrite the toReplace
instructions or the replacement
is written to a newly allocated area and unconditional branches connect it to the main control flow. The assumption is that control flow enters at the beginning of toReplace
and the replacement will exit to the first address after the last instruction in toReplace
. Likewise, control enters at the beginning of replacement
and exits to the first address after the end of the replacement
.
If relocations
are specified, then parts of the replacement
are rewritten based on its final address. Relocation records that refer to instructions rather than bytes are not permitted since this function doesn't have access to the basic block in which the replacement is occuring.
Returns true if the replacement could be inserted, false otherwise. The only time this returns false is when the addresses of the original instructions starting with the first instruction do not occupy a contiguous region of memory large enough to hold either the replacement or a jump to the relocated replacement. This algorithm correctly handles the general case when the toReplace
instructions are not in address order or are not contiguous.
|
virtual |
Encode an unconditional branch.
This encodes an unconditional branch instruction at srcVa
that causes control to flow to tgtVa
. The caller should not assume that a particular size encoding will be returned. E.g., on x86, jumps to targets that are further away require more bytes to encode than jumps to nearby targets.
|
virtual |
Apply relocations to create a new encoding.
The relocations
are applied to the replacement
bytes which are assumed to be mapped in virtual memory starting at startVa
. The relocStart
is a byte offset for all the relocations; i.e., the actual offset in the replacement
where the relocation is applied is the relocation's offset plus the relocStart
value.
|
virtual |
Allocate virtual memory in the partitioner memory map.
The second argument is the target address of an unconditional jump that will be added to the end of the allocated memory but which is not included in the nBytes
argument (it is however included in the return value).
If the third argument is yes, then memory is actually allocated and removed from the free list. If no, then all steps are completed except removing it from the free list. The commitAllocation function can be called later to remove it from the free list. If you don't remove it from the free list, a subsequent allocation request might return the same addresses.
void Rose::BinaryAnalysis::CodeInserter::commitAllocation | ( | const AddressInterval & | where, |
Commit::Boolean | commit = Commit::YES |
||
) |
Commit previous allocation.
This commits the allocation returned by allocateMemory by removing it from the free list (if the commit
argument is true). We do this as a separate step from the allocation so that we don't have to deallocate in all the error handling locations. Failing to commit an allocation will be easier to spot than failing to release an unused block because the former case causes nonsense disassembly whereas the latter looks like either unreachable code or static data.
|
virtual |
Insert new code by overwriting existing instructions.
The toReplaceVas
are the addresses occupied by the to-be-replaced instructions. Since the to-be-replaced instructions are not necessarily in address order or contiguous, the entryInterval
describes the largest contiguous subset of toReplaceVas
starting at the entry address. Since the replacement
is assumed to be entered at its first byte, the replacement
will be written into the entryInterval
(if it fits). The replacement
is padded if necessary according to the nopPadding property. All other addresses in toReplaceVas
are filled with no-op instructions.
|
virtual |
Insert new code in allocated area.
This inserts the replacement
code in a newly allocated area (by calling allocateMemory). The toReplaceVas
are the addresses of all the instruction bytes that are to be replaced. Note that this is all addresses of the instructions, not just the first addresses. The entryInterval
is a contiguous subset of toReplaceVas
and represents the entry point of toReplaceVas
and as many subsequent contiguous addresses as possible. This function writes an unconditional branch in the entryInterval
(padding it with no-ops according to nopPadding
) that jumps to the replacement code. It appends an unconditional branch to the end of the replacement that jumps to the first address after the end of the toReplaceVas
. All other bytes of toReplaceVas
are overwritten with no-ops.
InstructionInfoMap Rose::BinaryAnalysis::CodeInserter::computeInstructionInfoMap | ( | const Partitioner2::BasicBlockPtr & | , |
size_t | startIdx, | ||
size_t | nDeleted | ||
) |
Obtain info about instructions for the basic block being modified.
Given a basic block, an insertion point, and the number of instructions that will be deleted starting at that insertion point, return information about the remaining instructions. See documentation for InstructionInfoMap for details about how the instructions are indexed in this map.
|
protected |
Definition at line 148 of file CodeInserter.h.
|
protected |
Definition at line 149 of file CodeInserter.h.
|
protected |
Definition at line 150 of file CodeInserter.h.
|
protected |
Definition at line 151 of file CodeInserter.h.
|
protected |
Definition at line 152 of file CodeInserter.h.
|
protected |
Definition at line 153 of file CodeInserter.h.
|
protected |
Definition at line 154 of file CodeInserter.h.
|
protected |
Definition at line 155 of file CodeInserter.h.
|
protected |
Definition at line 156 of file CodeInserter.h.
|
static |
Facility for emitting diagnostics.
Definition at line 160 of file CodeInserter.h.