For the T32 variant we have to evaluate the memory access instruction to find out, which memory address was accessed. Dissassmbly by OpenOCDs arm_disassembler.hpp/.cc: - fine for ARM / Thumb1 - needs fixes for Thumb2 :( (currently doing that..)
98 lines
3.6 KiB
C++
98 lines
3.6 KiB
C++
#include "ArmMemoryInstruction.hpp"
|
|
|
|
#include <iostream>
|
|
using namespace std;
|
|
|
|
namespace fail {
|
|
static ArmMemoryInstructionAnalyzer anal;
|
|
MemoryInstructionAnalyzer & meminstruction = anal;
|
|
|
|
address_t ArmMemoryInstructionAnalyzer::findPrevious(address_t address){
|
|
if(m_dis.hasInstructionAt(address-2)) {
|
|
return address - 2;
|
|
} else if (m_dis.hasInstructionAt(address - 4)) {
|
|
return address - 4;
|
|
} else {
|
|
return ADDR_INV;
|
|
}
|
|
}
|
|
|
|
void ArmMemoryInstructionAnalyzer::evaluate(arm_instruction & inst, MemoryInstruction& result){
|
|
cout << "Memory Access: " << inst.text << " - Size: " << inst.instruction_size << " Type " << inst.type << endl;
|
|
inst.info.load_store.evaluate();
|
|
result.setValue(inst.info.load_store.value);
|
|
result.setAddress(inst.info.load_store.address);
|
|
result.setWidth(4); // TODO;
|
|
result.setWriteAccess(inst.isStoreInstruction());
|
|
}
|
|
|
|
// The Cortex M3 Lauterbach is a pain in the ass, as a Memory Watchpoint does not stop
|
|
// at the accessing instruction, but 1 or 2 instructions later.
|
|
bool ArmMemoryInstructionAnalyzer::eval_cm3(address_t address, MemoryInstruction& result){
|
|
arm_instruction inst;
|
|
uint32_t opcode =0;
|
|
address = findPrevious(address); // Cortex M3: memory access is at the previous instruction
|
|
opcode = m_dis.disassemble(address).opcode;
|
|
|
|
// OpenOCDs thumb2_opcode evaluation is not complete yet. :(
|
|
thumb2_opcode(address, opcode, &inst);
|
|
|
|
if(inst.isMemoryAccess()){
|
|
evaluate(inst, result);
|
|
return true;
|
|
} else if(inst.isBranchInstruction()){
|
|
// The memory access took place within the function previously branched
|
|
int regop = inst.info.b_bl_bx_blx.reg_operand;
|
|
uint32_t addr = inst.info.b_bl_bx_blx.target_address;
|
|
//cout << " Reg:" << hex << regop << " address " << hex << addr << endl;
|
|
// Lets look into this function
|
|
if( regop == -1 ){
|
|
// address should be set..
|
|
const ElfSymbol & sym = m_elf.getSymbol(addr|1); // | 1 to set first bit -> thumbmode
|
|
addr += sym.getSize(); // Go to end of function.
|
|
// THIS IS DANGEROUS: The memory access can be anywhere within this function, one instruction before a ret.
|
|
// OR, the memory access itself can result in leaving the function :e.g., ldr pc, [r3]
|
|
// We cannot be sure :( Here we assume the first memory access from the back.
|
|
do { // go backwards until there is a memory instruction.
|
|
addr = findPrevious(addr); // find previous
|
|
thumb2_opcode(addr, m_dis.disassemble(addr).opcode, &inst);
|
|
} while( !inst.isMemoryAccess() );
|
|
evaluate(inst, result);
|
|
return true;
|
|
}
|
|
} else {
|
|
// There was a memory access before, but the previous instruction
|
|
// is neither an access nor a branch.
|
|
// This can happen if we came here from anywhere, e.g. by ldr pc, [r4]
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ArmMemoryInstructionAnalyzer::eval_ca9(address_t address, MemoryInstruction& result){
|
|
arm_instruction inst;
|
|
uint32_t opcode = m_dis.disassemble(address).opcode;
|
|
arm_evaluate_opcode(address, opcode, &inst);
|
|
if( inst.isMemoryAccess() ){
|
|
evaluate(inst, result);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#define CORTEXM3
|
|
|
|
bool ArmMemoryInstructionAnalyzer::eval(address_t address, MemoryInstruction & result){
|
|
#ifdef CORTEXM3
|
|
#warning "Memory Accesses cannot be evaluated completedly!"
|
|
return eval_cm3(address, result);
|
|
#elif defined CORTEXA9
|
|
return eval_ca9(address, result);
|
|
#else
|
|
#warning "Memory Accesses are not evaluated!"
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
|
|
};
|