Plan 9 from Bell Labs’s /usr/web/sources/contrib/de0u/root/sys/src/cmd/squeak/Cross/plugins/GdbARMPlugin/sqGdbARMPlugin.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#define COG 1
#define FOR_COG_PLUGIN 1

#include "GdbARMPlugin.h"
//disassembler
#include <gdbconfig.h> /*  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 <bfd.h>
#include <dis-asm.h>

#include <stdarg.h>

//emulator
#include <armdefs.h>
#include <armemu.h>

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);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.