#define COG 1 #define FOR_COG_PLUGIN 1 #include "GdbARMPlugin.h" //disassembler #include /* TPR - <---- this is actually a *link* to the gdb gdb-7.6/bfd/config.h because it otherwise clashes with the Squeak one also in the assorted include paths. Must be a proper way to handle this case; it must happen elsewhere */ #include #include #include //emulator #include #include ARMul_State* lastCPU = NULL; /* When compiling armulator, it generally sets NEED_UI_LOOP_HOOK, which makes the main emulation step require this symbol to be set. */ extern int (*deprecated_ui_loop_hook) (int) = NULL; // These two variables exist, in case there are library-functions which write to a stream. // In that case, we would write functions which print to that stream instead of stderr or similar #define LOGSIZE 4096 static char gdb_log[LOGSIZE+1]; static int gdblog_index = 0; ulong minReadAddress, minWriteAddress; // what is that for? void (*prevInterruptCheckChain)() = 0; void print_state(ARMul_State* state) { printf("NextInstr: %i\ttheMemory: 0x%p\tNumInstrs: 0x%p\tPC: 0x%p\tmode: %i\tEndCondition: %i\tEmulate: %i\n", state->NextInstr, state->MemDataPtr, state->NumInstrs, state->Reg[15], state->Mode, state->EndCondition, state->Emulate); } void* newCPU() { if(lastCPU == NULL) ARMul_EmulateInit(); lastCPU = ARMul_NewState(); ARMul_SelectProcessor (lastCPU, ARM_v5_Prop | ARM_v5e_Prop | ARM_XScale_Prop | ARM_v6_Prop); return lastCPU; } int resetCPU(void* cpu) { unsigned int i, j; ARMul_State* state = (ARMul_State*) cpu; // test whether the supplied instance is an ARMul type? gdblog_index = 0; // reset registers in all modes for (i = 0; i < 16; i++) { state->Reg[i] = 0; for (j = 0; j < 7; j++) state->RegBank[j][i] = 0; } for (i = 0; i < 7; i++) state->Spsr[i] = 0; ARMul_Reset(state); return 0; } int runOnCPU(void *cpu, void *memory, ulong byteSize, ulong minAddr, ulong minWriteMaxExecAddr, ARMword (*run)(ARMul_State*)) { ARMul_State* state = (ARMul_State*) cpu; lastCPU = state; // test whether the supplied instance is an ARMul type? state->MemDataPtr = (unsigned char*) memory; state->MemSize = byteSize; minReadAddress = minAddr; minWriteAddress = minWriteMaxExecAddr; gdblog_index = 0; state->EndCondition = NoError; state->NextInstr = RESUME; state->Reg[15] = run(state); // collect the PSR from their dedicated flags to have easy access from the image. ARMul_SetCPSR(state, ARMul_GetCPSR(state)); if(state->EndCondition != NoError){ return state->EndCondition; } return gdblog_index == 0 ? 0 : SomethingLoggedError; } int singleStepCPUInSizeMinAddressReadWrite(void *cpu, void *memory, ulong byteSize, ulong minAddr, ulong minWriteMaxExecAddr) { return runOnCPU(cpu, memory, byteSize, minAddr, minWriteMaxExecAddr, ARMul_DoInstr); } int runCPUInSizeMinAddressReadWrite(void *cpu, void *memory, ulong byteSize, ulong minAddr, ulong minWriteMaxExecAddr) { return runOnCPU(cpu, memory, byteSize, minAddr, minWriteMaxExecAddr, ARMul_DoProg); } /* * Currently a dummy for ARM Processor Alien. */ void flushICacheFromTo(void *cpu, ulong saddr, ulong eaddr) { #if 0 # error not yet implemented #endif } int gdb_log_printf(void* stream, const char * format, ...) { va_list arg; int n; va_start(arg,format); if(stream == NULL){ n = vsnprintf((char*) (&gdb_log) + gdblog_index, LOGSIZE-gdblog_index, format, arg); gdblog_index = gdblog_index + n; } else { vfprintf(stream, format, arg); } return 0; } int disassembleForAtInSize(void *cpu, ulong laddr, void *memory, ulong byteSize) { gdblog_index = 0; // ignore the cpu // start disassembling at laddr relative to memory // stop disassembling at memory+byteSize disassemble_info* dis = (disassemble_info*) calloc(1, sizeof(disassemble_info)); // void init_disassemble_info (struct disassemble_info *dinfo, void *stream, fprintf_ftype fprintf_func) init_disassemble_info ( dis, NULL, gdb_log_printf); dis->arch = bfd_arch_arm; dis->mach = bfd_mach_arm_unknown; // sets some fields in the structure dis to architecture specific values disassemble_init_for_target( dis ); dis->buffer_vma = 0; dis->buffer = memory; dis->buffer_length = byteSize; // first print the address gdb_log_printf( NULL, "%08lx: ", laddr); //other possible functions are listed in opcodes/dissassemble.c unsigned int size = print_insn_little_arm((bfd_vma) laddr, dis); free(dis); gdb_log[gdblog_index+1] = 0; return size; } void forceStopRunning() { lastCPU->Emulate = STOP; } int errorAcorn(void) { return 0; } char * getlog(long *len) { *len = gdblog_index; return gdb_log; } // adding custom Software Interrupts to the ARMulator unsigned __real_ARMul_OSHandleSWI(ARMul_State*, ARMword); unsigned __wrap_ARMul_OSHandleSWI (ARMul_State * state, ARMword number) { switch(number) { case 0x200000: // This is the SWI number which is returned by our memory interface // if there is an instruction fetch for an illegal address. state->Emulate = STOP; state->EndCondition = InstructionPrefetchError; // during execution, the pc points the next fetch address, which is 8 byte after the current instruction. gdb_log_printf(NULL, "Illegal Instruction fetch address (%#p).", state->Reg[15]-8); return TRUE; } return __real_ARMul_OSHandleSWI(state, number); }