big update
34
Makefile
Normal file
@ -0,0 +1,34 @@
|
||||
ifeq ($(ANDROID_NDK_ROOT),)
|
||||
$(error Error : Set the env variable 'ANDROID_NDK_ROOT' with the path of the Android NDK (version 20))
|
||||
endif
|
||||
|
||||
CC := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android27-clang
|
||||
AR := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar
|
||||
OBJCOPY := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-objcopy
|
||||
LD := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ld.bfd
|
||||
|
||||
#ARM 32 bit
|
||||
CC_32 := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi27-clang
|
||||
AR_32 := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ar
|
||||
OBJCOPY_32 := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-objcopy
|
||||
LD_32 := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ld.bfd
|
||||
|
||||
#ARM thumb mode
|
||||
TOOLCHAIN_ARM_T := $(TOOLCHAINENV)/gcc-arm-none-eabi-10-2020-q4-major/bin/arm-none-eabi-
|
||||
CC_T = $(TOOLCHAIN_ARM_T)gcc
|
||||
AS_T = $(TOOLCHAIN_ARM_T)as
|
||||
OBJCOPY_T = $(TOOLCHAIN_ARM_T)objcopy
|
||||
LD_T = $(TOOLCHAIN_ARM_T)ld.bfd
|
||||
|
||||
CFLAGS := -Werror -Wno-unused-variable -Os
|
||||
LINKER := /system/bin/linker64
|
||||
DEBUG := -g
|
||||
|
||||
#Thumb cflags
|
||||
all: error
|
||||
|
||||
error:
|
||||
@echo "Please specify a target to build (-f devices/nvidia_shield_t)"
|
||||
|
||||
clean:
|
||||
rm -rf bin/*
|
109
README.md
Normal file
@ -0,0 +1,109 @@
|
||||
# Gupje
|
||||
Gupje is a bare metal architecture based stub debugger that helps in post-exploitation steps. Like booting a device after RCE has been achieved. Gupje is also capable of doing hardware-in-the-middle approaches as well as keeping control over a device while it is booting(Hijack trustzone etc.).
|
||||
|
||||
Gupje currently supporting the following architectures:
|
||||
* ARM64 (good support)
|
||||
* ARM (minimal)
|
||||
* ARM Thumb (decent support)
|
||||
|
||||
The goal is to add support to more targets while I work on them. Because I mainly work on phones this list will probably not grow a lot in the short term. But if you have an interesting target and preferably a way to get into it(RCE), let me know and I will look into it.
|
||||
|
||||
The only actual things the debugger can do is:
|
||||
* Send/Receive (needs to be implemented by the user)
|
||||
* Read/Write registers
|
||||
|
||||
These functions are enough for a processor to run properly. The code size of the debugger is currently smaller than 4096 bytes(depends a bit on user setup) but will probably grow to include 1 extra page to support custom functionality. Like dumping extra registers and more specific VBAR setups.
|
||||
|
||||
In the future it should also be possible to add fuzzing and same architecture rehosting. Once I find a project to implement this at least.
|
||||
|
||||
## Overview
|
||||
A simple overview of how Gupje is meant to be used can be seen below:
|
||||
|
||||
![Simple Gupje Target](simple_device.drawio.svg)
|
||||
|
||||
The user is responsible for gaining RCE and setting up Gupje. After this Gupje along with the ``Ghidra-Assistant`` can be used to interact with the device from within python and continue booting.
|
||||
|
||||
### Gupje Setup
|
||||
Because Gupje attempts to be a architecture based debugger the user only has to provide send/receive functionality to Gupje. Like sahara_tx/sahara_rx in Qualcomm based devices or a raw USB endpoint for the nvidia shield tablet.
|
||||
|
||||
```c
|
||||
|
||||
void send(void *buffer, uint32_t size, uint32_t *num_xfer){
|
||||
// TODO implement
|
||||
}
|
||||
|
||||
int recv(void *buffer, uint32_t size, uint32_t *num_xfer){
|
||||
// TODO implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
void recv_data(void *data, uint32_t len) {
|
||||
uint32_t rx_err_code;
|
||||
uint32_t xfer = 0;
|
||||
while(1) {
|
||||
recv(data, len, &xfer);
|
||||
if(xfer >= len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mystrlen(char *data) {
|
||||
int i=0;
|
||||
while(1) {
|
||||
if(data[i++] == '\0'){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i-1;
|
||||
}
|
||||
|
||||
void usb_log(char * msg, uint32_t * error){
|
||||
send(msg, mystrlen(msg), error);
|
||||
}
|
||||
|
||||
void concrete_main(uint32_t debugger){
|
||||
// TODO device specific code
|
||||
}
|
||||
```
|
||||
|
||||
Other protocols, like UART, are also possible. I will try to add more reference devices and implementations.
|
||||
|
||||
### Memory layout
|
||||
Overall 4 pages are always reserved for the debugger. I usually try to place them at the end of a memory region since the chance of the pages being corrupted/used by other functions is smaller. 3 pages are required at least for the debugger to function properly.
|
||||
|
||||
![debugger memory layout](simple_device_memory.drawio.svg)
|
||||
|
||||
## Documentation
|
||||
The full documentation is covered in the ``documentation`` folder. To build it, navigate to the folder and run:
|
||||
```bash
|
||||
make livehtml
|
||||
```
|
||||
Install the python dependencies if they are missing. (TODO add requirements)
|
||||
|
||||
This code works in combination with the ``Ghidra Assistant``, which is another personal project to make Ghidra more instrumentable.
|
||||
|
||||
## TODO
|
||||
* ARM assembly needs to be completely rewritten
|
||||
* Add code that allows the host to easily write and execute shellcode on the device. This will significantly decrease the size of the debugger. (extra page required)
|
||||
* Add a more *minimal* approach to the debugger. That does not store data but can just be used to read/write memory. Usefull for exploitation when there is a very limited constraint on shellcode size.
|
||||
* Implement code block stepping.
|
||||
* Build an emulator to explain the debugger
|
||||
|
||||
### ARM64
|
||||
* Allow restoring all registers by writing X15 to SP and jump to ELRn to create a *full* restored state. Figure out a way to branch without corrupting X15.
|
||||
|
||||
### Thumb
|
||||
* headless mode is not supported
|
||||
* Figure out VBAR to implement single step debugging
|
||||
|
||||
## Building
|
||||
Download an Android NDK and set it's root path:
|
||||
```bash
|
||||
$ export ANDROID_NDK_ROOT=$TOOLCHAINENV/android-ndk-r21_Linux
|
||||
```
|
||||
|
||||
Now you can build one of your targets:
|
||||
```bash
|
||||
$ make -f devices/pixel3a/Makefile
|
||||
```
|
43
arm64_glitch_stub.S
Normal file
@ -0,0 +1,43 @@
|
||||
.text
|
||||
.global glitch_registers_loop
|
||||
glitch_registers_loop:
|
||||
BL trigger_high
|
||||
BL trigger_low
|
||||
BL glitch_dump_registers
|
||||
RET
|
||||
|
||||
.text
|
||||
.global glitch_out_loop
|
||||
glitch_out_loop:
|
||||
BL trigger_high
|
||||
MOV X0, #0x1
|
||||
glitch_loop:
|
||||
MOV X1, #0x0
|
||||
CMP X1, X0
|
||||
b.ne glitch_loop
|
||||
BL trigger_low
|
||||
B debugger_main
|
||||
|
||||
.text
|
||||
.global glitch_dump_registers
|
||||
glitch_dump_registers:
|
||||
LDR X15, glitch_storage
|
||||
STP X0, X1, [X15, #0x0]
|
||||
STP X2, X3, [X15, #0x10]
|
||||
STP X4, X5, [X15, #0x20]
|
||||
STP X6, X7, [X15, #0x30]
|
||||
STP X8, X9, [X15, #0x40]
|
||||
STP X10, X11, [X15, #0x50]
|
||||
STP X12, X13, [X15, #0x60]
|
||||
STP X14, X15, [X15, #0x70]
|
||||
STP X16, X17, [X15, #0x80]
|
||||
STP X18, X19, [X15, #0x90]
|
||||
STP X20, X21, [X15, #0xa0]
|
||||
STP X22, X23, [X15, #0xb0]
|
||||
STP X24, X25, [X15, #0xc0]
|
||||
STP X26, X27, [X15, #0xd0]
|
||||
STP X28, X29, [X15, #0xe0]
|
||||
STP X30, X31, [X15, #0xf0]
|
||||
RET
|
||||
|
||||
glitch_storage: .quad glitch_storage
|
416
arm64_stub.S
Normal file
@ -0,0 +1,416 @@
|
||||
start:
|
||||
LDR X15, addr_debugger_storage
|
||||
|
||||
STR X0, [X15, #0]
|
||||
STR X1, [X15, #8]
|
||||
STR X2, [X15, #16]
|
||||
STR X3, [X15, #24]
|
||||
STR X4, [X15, #32]
|
||||
STR X5, [X15, #40]
|
||||
STR X6, [X15, #48]
|
||||
STR X7, [X15, #56]
|
||||
STR X8, [X15, #64]
|
||||
STR X9, [X15, #72]
|
||||
STR X10, [X15, #80]
|
||||
STR X11, [X15, #88]
|
||||
STR X12, [X15, #96]
|
||||
STR X13, [X15, #104]
|
||||
STR X14, [X15, #112]
|
||||
STR X15, [X15, #120]
|
||||
STR X16, [X15, #128]
|
||||
STR X17, [X15, #136]
|
||||
STR X18, [X15, #144]
|
||||
STR X19, [X15, #152]
|
||||
STR X20, [X15, #160]
|
||||
STR X21, [X15, #168]
|
||||
STR X22, [X15, #176]
|
||||
STR X23, [X15, #184]
|
||||
STR X24, [X15, #192]
|
||||
STR X25, [X15, #200]
|
||||
STR X26, [X15, #208]
|
||||
STR X27, [X15, #216]
|
||||
STR X28, [X15, #224]
|
||||
STR X29, [X15, #232]
|
||||
STR X30, [X15, #240]
|
||||
MOV X0, SP
|
||||
STR X0, [X15, #248]
|
||||
|
||||
// Does not override the SP etc. TODO ELHER make configurable in debugger (during setup)
|
||||
// B debugger_main
|
||||
|
||||
// Overwrite SP and FP with the debugger stack location
|
||||
LDR X0, addr_debugger_stack
|
||||
MOV SP, X0
|
||||
MOV FP, X0
|
||||
|
||||
// See if we need to disable the MMU on entry
|
||||
// LDR X0, [X15, #0xfd0]
|
||||
// CMP X0, #0x777 //Disable the MMU
|
||||
// BL disable_mmu
|
||||
|
||||
// Compare to see if we need to jump into the debugger or need to continue the 'normal' execution flow
|
||||
LDR X0, [X15, #4064]
|
||||
CMP X0, #0x777
|
||||
B.NE debugger_main
|
||||
|
||||
|
||||
# Continue 'normal' execution flow
|
||||
BL sync_processor_state
|
||||
|
||||
// Restore LR and FP
|
||||
LDR X30, [X15, #240]
|
||||
LDR X29, [X15, #232]
|
||||
|
||||
// Restore the stack pointer
|
||||
LDR X0, [X15, #248]
|
||||
MOV SP, X0
|
||||
|
||||
// Also restore X0
|
||||
LDR X0, [X15, #0]
|
||||
|
||||
LDR X15, [X15, #0xfd8]
|
||||
BR X15
|
||||
|
||||
.text
|
||||
.global disable_mmu
|
||||
disable_mmu:
|
||||
MRS X0, SCTLR_EL3
|
||||
AND X0, X0, #-0x2
|
||||
RET
|
||||
|
||||
.text
|
||||
.global enable_mmu
|
||||
enable_mmu:
|
||||
// TODO crashes on EL1?
|
||||
MRS X0, SCTLR_EL3
|
||||
ORR X0, X0, #0x1
|
||||
RET
|
||||
|
||||
.text
|
||||
.global restore_and_jump
|
||||
restore_and_jump:
|
||||
BL sync_processor_state
|
||||
|
||||
//See if we need to enable the MMU
|
||||
// LDR X0, [X15, #0xfd0]
|
||||
// CMP X0, #0x777 //Disable the MMU
|
||||
// BL enable_mmu
|
||||
|
||||
// Restore LR and FP
|
||||
LDR X30, [X15, #240]
|
||||
LDR X29, [X15, #232]
|
||||
|
||||
// Restore the stack pointer
|
||||
LDR X0, [X15, #248]
|
||||
MOV SP, X0
|
||||
|
||||
// Also restore X0
|
||||
LDR X0, [X15, #0]
|
||||
|
||||
// Load target address and branch to it without setting the LR
|
||||
// JUMP_ADDR
|
||||
LDR X15, [X15, #4088]
|
||||
BR X15
|
||||
|
||||
.text
|
||||
.global dump_special_el3
|
||||
dump_special_el3:
|
||||
MRS X0, TTBR0_EL3
|
||||
STR X0, [X15, #256]
|
||||
|
||||
MRS X0, SCTLR_EL3
|
||||
STR X0, [X15, #280]
|
||||
|
||||
MRS X0, VBAR_EL3
|
||||
STR X0, [X15, #304]
|
||||
|
||||
MRS X0, TCR_EL3
|
||||
STR X0, [X15, #328]
|
||||
|
||||
MRS X0, ELR_EL3
|
||||
STR X0, [X15, #352]
|
||||
|
||||
MRS X0, SPSR_EL3
|
||||
STR X0, [X15, #400]
|
||||
|
||||
MRS X0, MAIR_EL3
|
||||
STR X0, [X15, #424]
|
||||
|
||||
// Also dump el2, el1
|
||||
BL dump_special_el2
|
||||
BL dump_special_el1
|
||||
RET
|
||||
|
||||
.text
|
||||
.global dump_special_el2
|
||||
dump_special_el2:
|
||||
MRS X0, TTBR0_EL2
|
||||
STR X0, [X15, #264]
|
||||
|
||||
MRS X0, SCTLR_EL2
|
||||
STR X0, [X15, #288]
|
||||
|
||||
MRS X0, VBAR_EL2
|
||||
STR X0, [X15, #312]
|
||||
|
||||
MRS X0, TCR_EL2
|
||||
STR X0, [X15, #336]
|
||||
|
||||
MRS X0, ELR_EL2
|
||||
STR X0, [X15, #360]
|
||||
|
||||
MRS X0, SP_EL2
|
||||
STR X0, [X15, #376]
|
||||
|
||||
MRS X0, SPSR_EL2
|
||||
STR X0, [X15, #408]
|
||||
|
||||
MRS X0, MAIR_EL2
|
||||
STR X0, [X15, #432]
|
||||
|
||||
// also dump EL1
|
||||
BL dump_special_el1
|
||||
RET
|
||||
|
||||
.text
|
||||
.global dump_special_el1
|
||||
dump_special_el1:
|
||||
// EL1 registers dump
|
||||
MRS X0, TTBR0_EL1
|
||||
STR X0, [X15, #272]
|
||||
|
||||
MRS X0, SCTLR_EL1
|
||||
STR X0, [X15, #296]
|
||||
|
||||
MRS X0, VBAR_EL1
|
||||
STR X0, [X15, #320]
|
||||
|
||||
MRS X0, TCR_EL1
|
||||
STR X0, [X15, #344]
|
||||
|
||||
MRS X0, ELR_EL1
|
||||
STR X0, [X15, #368]
|
||||
|
||||
// see https://community.arm.com/support-forums/f/architectures-and-processors-forum/49184/difference-between-sp_el1-and-spsel-mov
|
||||
// TODO for dumping with interactive shellcode?
|
||||
// MRS X0, SP_EL1
|
||||
// STR X0, [X15, #384]
|
||||
|
||||
MRS X0, SPSR_EL1
|
||||
STR X0, [X15, #416]
|
||||
|
||||
MRS X0, MAIR_EL1
|
||||
STR X0, [X15, #440]
|
||||
RET
|
||||
|
||||
.text
|
||||
.global dump_special_regs
|
||||
dump_special_regs:
|
||||
LDR X15, addr_debugger_storage
|
||||
|
||||
MRS X0, CurrentEL
|
||||
STR X0, [X15, #448]
|
||||
|
||||
cmp X0, #0b1100 // EL3
|
||||
BEQ dump_special_el3
|
||||
|
||||
cmp X0, #0b1000 // EL2
|
||||
BEQ dump_special_el2
|
||||
|
||||
cmp X0, #0b0100 // EL1
|
||||
BEQ dump_special_el1
|
||||
|
||||
// EL0 registers
|
||||
MRS X0, SP_EL0
|
||||
STR X0, [X15, #392]
|
||||
|
||||
RET
|
||||
|
||||
.text
|
||||
.global write_special_el3
|
||||
write_special_el3:
|
||||
LDR X0, [X15, #256]
|
||||
MSR TTBR0_EL3, X0
|
||||
|
||||
LDR X0, [X15, #280]
|
||||
MSR SCTLR_EL3, X0
|
||||
|
||||
LDR X0, [X15, #304]
|
||||
MSR VBAR_EL3, X0
|
||||
|
||||
LDR X0, [X15, #328]
|
||||
MSR TCR_EL3, X0
|
||||
|
||||
LDR X0, [X15, #352]
|
||||
MSR ELR_EL3, X0
|
||||
|
||||
LDR X0, [X15, #376]
|
||||
MSR SP_EL2, X0
|
||||
|
||||
LDR X0, [X15, #400]
|
||||
MSR SPSR_EL3, X0
|
||||
|
||||
LDR X0, [X15, #424]
|
||||
MSR MAIR_EL3, X0
|
||||
|
||||
BL write_special_el2
|
||||
BL write_special_el1
|
||||
|
||||
RET
|
||||
|
||||
.text
|
||||
.global write_special_el2
|
||||
write_special_el2:
|
||||
LDR X0, [X15, #264]
|
||||
MSR TTBR0_EL2, X0
|
||||
|
||||
LDR X0, [X15, #288]
|
||||
MSR SCTLR_EL2, X0
|
||||
|
||||
LDR X0, [X15, #312]
|
||||
MSR VBAR_EL2, X0
|
||||
|
||||
LDR X0, [X15, #336]
|
||||
MSR TCR_EL2, X0
|
||||
|
||||
LDR X0, [X15, #360]
|
||||
MSR ELR_EL2, X0
|
||||
|
||||
LDR X0, [X15, #384]
|
||||
MSR SP_EL1, X0
|
||||
|
||||
LDR X0, [X15, #408]
|
||||
MSR SPSR_EL2, X0
|
||||
|
||||
LDR X0, [X15, #432]
|
||||
MSR MAIR_EL2, X0
|
||||
|
||||
BL write_special_el1
|
||||
|
||||
RET
|
||||
|
||||
.text
|
||||
.global write_special_el1
|
||||
write_special_el1:
|
||||
LDR X0, [X15, #272]
|
||||
MSR TTBR0_EL1, X0
|
||||
|
||||
LDR X0, [X15, #296]
|
||||
MSR SCTLR_EL1, X0
|
||||
|
||||
LDR X0, [X15, #320]
|
||||
MSR VBAR_EL1, X0
|
||||
|
||||
LDR X0, [X15, #344]
|
||||
MSR TCR_EL1, X0
|
||||
|
||||
LDR X0, [X15, #368]
|
||||
MSR ELR_EL1, X0
|
||||
|
||||
LDR X0, [X15, #392]
|
||||
MSR SP_EL0, X0
|
||||
|
||||
LDR X0, [X15, #416]
|
||||
MSR SPSR_EL1, X0
|
||||
|
||||
LDR X0, [X15, #440]
|
||||
MSR MAIR_EL1, X0
|
||||
RET
|
||||
|
||||
.text
|
||||
.global write_special_regs
|
||||
write_special_regs:
|
||||
LDR X15, addr_debugger_storage
|
||||
|
||||
MRS X0, CurrentEL
|
||||
STR X0, [X15, #448]
|
||||
|
||||
cmp X0, #0b1100 // EL3
|
||||
BEQ write_special_el3
|
||||
|
||||
cmp X0, #0b1000 // EL2
|
||||
BEQ write_special_el2
|
||||
|
||||
cmp X0, #0b0100 // EL1
|
||||
BEQ write_special_el1
|
||||
|
||||
RET
|
||||
|
||||
|
||||
.text
|
||||
.global debugger_sync_special_regs
|
||||
debugger_sync_special_regs:
|
||||
BL write_special_regs
|
||||
B debugger_main
|
||||
|
||||
.text
|
||||
.global debugger_dump_special_regs
|
||||
debugger_dump_special_regs:
|
||||
BL dump_special_regs
|
||||
B debugger_main
|
||||
|
||||
.text
|
||||
.global sync_processor_state
|
||||
sync_processor_state:
|
||||
//Corrupt X15 to use it to restore the rest of the state, except for the SP, LR and FP
|
||||
LDR X15, addr_debugger_storage
|
||||
|
||||
LDR X1, [X15, #8]
|
||||
LDR X2, [X15, #16]
|
||||
LDR X3, [X15, #24]
|
||||
LDR X4, [X15, #32]
|
||||
LDR X5, [X15, #40]
|
||||
LDR X6, [X15, #48]
|
||||
LDR X7, [X15, #56]
|
||||
LDR X8, [X15, #64]
|
||||
LDR X9, [X15, #72]
|
||||
LDR X10, [X15, #80]
|
||||
LDR X11, [X15, #88]
|
||||
LDR X12, [X15, #96]
|
||||
LDR X13, [X15, #104]
|
||||
LDR X14, [X15, #112]
|
||||
LDR X15, [X15, #120]
|
||||
LDR X16, [X15, #128]
|
||||
LDR X17, [X15, #136]
|
||||
LDR X18, [X15, #144]
|
||||
LDR X19, [X15, #152]
|
||||
LDR X20, [X15, #160]
|
||||
LDR X21, [X15, #168]
|
||||
LDR X22, [X15, #176]
|
||||
LDR X23, [X15, #184]
|
||||
LDR X24, [X15, #192]
|
||||
LDR X25, [X15, #200]
|
||||
LDR X26, [X15, #208]
|
||||
LDR X27, [X15, #216]
|
||||
LDR X28, [X15, #224]
|
||||
RET
|
||||
|
||||
.text
|
||||
.global restore_and_return
|
||||
restore_and_return:
|
||||
B sync_processor_state
|
||||
|
||||
// Restore LR and FP
|
||||
LDR X30, [X15, #240]
|
||||
LDR X29, [X15, #232]
|
||||
|
||||
// Restore the stack pointer
|
||||
LDR X0, [X15, #248]
|
||||
MOV SP, X0
|
||||
|
||||
// Also restore X0
|
||||
LDR X0, [X15, #0]
|
||||
|
||||
RET
|
||||
|
||||
.text
|
||||
.global sync_debugger
|
||||
sync_debugger:
|
||||
BL sync_processor_state
|
||||
B debugger_main
|
||||
|
||||
.align 3
|
||||
|
||||
|
||||
addr_debugger_storage: .quad debugger_storage
|
||||
addr_debugger_stack: .quad debugger_stack
|
187
armT_stub.S
Normal file
@ -0,0 +1,187 @@
|
||||
.align 1
|
||||
.thumb
|
||||
start:
|
||||
@ Store R0 to the stack
|
||||
push {r0}
|
||||
|
||||
LDR R0, addr_debugger_storage
|
||||
stmia r0, {r0-r7}
|
||||
|
||||
@ Also store r0 by using r1
|
||||
ldr r1, addr_debugger_storage
|
||||
pop {r0}
|
||||
str r0, [r1, #0]
|
||||
# Keep using r0
|
||||
LDR R0, addr_debugger_storage
|
||||
|
||||
@ Store R8 to R15, not available directly in thumb mode
|
||||
mov r1, r8
|
||||
str r1, [r0, #0x20]
|
||||
mov r1, r9
|
||||
str r1, [r0, #0x24]
|
||||
mov r1, r10
|
||||
str r1, [r0, #0x28]
|
||||
mov r1, r11
|
||||
str r1, [r0, #0x2c]
|
||||
mov r1, r12 //ip scratch
|
||||
str r1, [r0, #0x30]
|
||||
mov r1, sp //sp
|
||||
str r1, [r0, #0x34]
|
||||
mov r1, lr //lr
|
||||
str r1, [r0, #0x38]
|
||||
mov r1, pc //pc
|
||||
str r1, [r0, #0x3c]
|
||||
|
||||
// set debugger stack (r13 sp, r14 lr, r15 pc)
|
||||
ldr r0, addr_debugger_stack
|
||||
mov sp, r0
|
||||
|
||||
// Compare to see if we need to jump into the debugger or need to continue the 'normal' execution flow
|
||||
// Default is jump in debugger
|
||||
// CNT_EXEC 0x7f0
|
||||
ldr r1, addr_debugger_storage
|
||||
ldr r0, =0x700
|
||||
add r0, #0xf0
|
||||
add r0, r0, r1
|
||||
|
||||
CMP r0, #0x77
|
||||
beq start_normal
|
||||
|
||||
@ TODO, use r8, how can I clear it
|
||||
ldr r2, addr_debugger_main
|
||||
mov r12, r2
|
||||
bx r12
|
||||
|
||||
// Continue 'normal' execution flow
|
||||
start_normal:
|
||||
BL sync_processor_state
|
||||
|
||||
// Restore LR, TODO
|
||||
@ LDR LR, [r1, #240]
|
||||
|
||||
@ // Restore the stack pointer
|
||||
@ LDR R0, [r1, #248]
|
||||
@ MOV SP, R0
|
||||
|
||||
// Also restore X0
|
||||
LDR R0, [r1, #0]
|
||||
|
||||
// 0x7ec DBG_JUMP_TO
|
||||
@ LDR r1, [r1, #0x7ec]
|
||||
@ bx r1
|
||||
|
||||
|
||||
.text
|
||||
.global restore_and_jump
|
||||
restore_and_jump:
|
||||
// Restores all registers except for LR and SP
|
||||
BL sync_processor_state
|
||||
|
||||
// restore SP, LR
|
||||
ldr r0, addr_debugger_storage
|
||||
ldr r1, [r0, #0x34]
|
||||
mov sp, r1 //SP
|
||||
ldr r1, [r0, #0x38]
|
||||
mov lr, r1 //LR
|
||||
|
||||
@ Load JUMP_ADDR 0x7fc into r12
|
||||
ldr r0, addr_debugger_storage
|
||||
ldr r1, =0x7fc
|
||||
add r1, r1, r0
|
||||
ldr r1, [r1] @ JUMP_ADDR
|
||||
mov r12, r1
|
||||
|
||||
// Restore r0 and r1
|
||||
ldr r0, addr_debugger_storage
|
||||
ldr r1, [r0, #4]
|
||||
ldr r0, [r0]
|
||||
|
||||
@ At this point everything is restored except for r12, which contains the jump address
|
||||
bx r12
|
||||
|
||||
.text
|
||||
.global debugger_sync_special_regs
|
||||
debugger_sync_special_regs:
|
||||
@ mov r4, #0x77
|
||||
// TODO, what special regs??
|
||||
bx LR
|
||||
|
||||
.text
|
||||
.global dump_special_regs
|
||||
dump_special_regs:
|
||||
// TODO, what special regs??
|
||||
bx LR
|
||||
|
||||
|
||||
.text
|
||||
.global debugger_dump_special_regs
|
||||
debugger_dump_special_regs:
|
||||
BL dump_special_regs
|
||||
B debugger_main
|
||||
|
||||
|
||||
.text
|
||||
.global sync_processor_state
|
||||
sync_processor_state:
|
||||
@ Syncs general purpose registers back to the cpu and branches to the LR
|
||||
|
||||
@ Load r8-r12
|
||||
ldr r0, addr_debugger_storage
|
||||
ldr r1, [r0, #0x20]
|
||||
mov r8, r1
|
||||
ldr r1, [r0, #0x24]
|
||||
mov r9, r1
|
||||
ldr r1, [r0, #0x28]
|
||||
mov r10, r1
|
||||
ldr r1, [r0, #0x2c]
|
||||
mov r11, r1
|
||||
ldr r1, [r0, #0x30]
|
||||
mov r12, r1
|
||||
|
||||
@ Not restoring SP, LR and PC. Left here as reference
|
||||
@ ldr r1, [r0, #0x34]
|
||||
@ mov r13, r1 //sp
|
||||
@ ldr r1, [r0, #0x38]
|
||||
@ mov r14, r1 //lr
|
||||
@ ldr r1, [r0, #0x3c]
|
||||
@ mov r15, r1 //pc
|
||||
|
||||
@ load r0-r7
|
||||
ldr r0, addr_debugger_storage
|
||||
ldmia r0, {r0-r7}
|
||||
|
||||
bx lr
|
||||
|
||||
|
||||
.text
|
||||
.global restore_and_return
|
||||
restore_and_return:
|
||||
B sync_processor_state
|
||||
|
||||
// restore SP, LR
|
||||
ldr r0, addr_debugger_storage
|
||||
ldr r1, [r0, #0x30]
|
||||
mov r12, r1 //IP
|
||||
ldr r1, [r0, #0x34]
|
||||
mov sp, r1 //SP
|
||||
ldr r1, [r0, #0x38]
|
||||
mov lr, r1 //LR
|
||||
|
||||
// Restore r0 and r1
|
||||
@ ldr r0, addr_debugger_storage
|
||||
ldr r1, [r0, #4]
|
||||
ldr r0, [r0]
|
||||
|
||||
@ At this point everything is restored including the LR. Return to it
|
||||
BX LR
|
||||
|
||||
.text
|
||||
.global sync_debugger
|
||||
sync_debugger:
|
||||
BL sync_processor_state
|
||||
b debugger_main
|
||||
|
||||
.align 4
|
||||
addr_debugger_storage: .word debugger_storage
|
||||
addr_debugger_stack: .word debugger_stack
|
||||
addr_debugger_main: .word debugger_main
|
112
arm_stub.S
Normal file
@ -0,0 +1,112 @@
|
||||
start:
|
||||
// TODO there is an ARM instruction that pushes all values to the stack
|
||||
// LDR R15, addr_debugger_storage
|
||||
STR R0, [R15, #0]
|
||||
STR R1, [R15, #4]
|
||||
STR R2, [R15, #8]
|
||||
STR R3, [R15, #12]
|
||||
STR R4, [R15, #16]
|
||||
STR R5, [R15, #20]
|
||||
STR R6, [R15, #24]
|
||||
STR R7, [R15, #28]
|
||||
STR R8, [R15, #64]
|
||||
STR R9, [R15, #72]
|
||||
STR R10, [R15, #80]
|
||||
STR R11, [R15, #88]
|
||||
STR R12, [R15, #96]
|
||||
STR R13, [R15, #104]
|
||||
STR R14, [R15, #112]
|
||||
MOV R0, SP
|
||||
STR R0, [R15, #248]
|
||||
|
||||
// Overwrite SP and FP with the debugger stack location
|
||||
// LDR R0, addr_debugger_stack
|
||||
MOV SP, R0
|
||||
MOV FP, R0
|
||||
|
||||
B debugger_main
|
||||
|
||||
.text
|
||||
.global restore_and_jump
|
||||
restore_and_jump:
|
||||
BL sync_processor_state
|
||||
|
||||
// Restore the stack pointer
|
||||
LDR R0, [R15, #248]
|
||||
MOV SP, R0
|
||||
|
||||
// Also restore R0
|
||||
LDR R0, [R15, #0]
|
||||
|
||||
// Load target address and branch to it
|
||||
LDR R15, [R15, #4088]
|
||||
B debugger_main
|
||||
|
||||
.text
|
||||
.global dump_special_regs
|
||||
dump_special_regs:
|
||||
B debugger_main
|
||||
|
||||
.text
|
||||
.global write_special_regs
|
||||
write_special_regs:
|
||||
B debugger_main
|
||||
|
||||
|
||||
.text
|
||||
.global debugger_sync_special_regs
|
||||
debugger_sync_special_regs:
|
||||
BL write_special_regs
|
||||
B debugger_main
|
||||
|
||||
.text
|
||||
.global debugger_dump_special_regs
|
||||
debugger_dump_special_regs:
|
||||
BL dump_special_regs
|
||||
B debugger_main
|
||||
|
||||
.text
|
||||
.global sync_processor_state
|
||||
sync_processor_state:
|
||||
//Corrupt R15 to use it to restore the rest of the state, eRcept for the SP, LR and FP
|
||||
// R13 == SP, R14 == LR, R15 == PC (oops)
|
||||
// LDR R15, addr_debugger_storage
|
||||
|
||||
LDR R1, [R15, #8]
|
||||
LDR R2, [R15, #16]
|
||||
LDR R3, [R15, #24]
|
||||
LDR R4, [R15, #32]
|
||||
LDR R5, [R15, #40]
|
||||
LDR R6, [R15, #48]
|
||||
LDR R7, [R15, #56]
|
||||
LDR R8, [R15, #64]
|
||||
LDR R9, [R15, #72]
|
||||
LDR R10, [R15, #80]
|
||||
LDR R11, [R15, #88]
|
||||
LDR R12, [R15, #96]
|
||||
LDR R13, [R15, #104]
|
||||
LDR R14, [R15, #112]
|
||||
bx lr
|
||||
|
||||
.text
|
||||
.global restore_and_return
|
||||
restore_and_return:
|
||||
B sync_processor_state
|
||||
|
||||
// Restore the stack pointer
|
||||
LDR R0, [R15, #248]
|
||||
MOV SP, R0
|
||||
|
||||
// Also restore R0
|
||||
LDR R0, [R15, #0]
|
||||
|
||||
BX LR
|
||||
|
||||
.text
|
||||
.global sync_debugger
|
||||
sync_debugger:
|
||||
BL sync_processor_state
|
||||
B debugger_main
|
||||
|
||||
.align 3
|
||||
|
227
debugger.c
Normal file
@ -0,0 +1,227 @@
|
||||
#include <stdint.h>
|
||||
#include "device.h"
|
||||
|
||||
|
||||
// These functions must be included in your device.h and device.c files
|
||||
// extern void send(void*addr, uint32_t size, void *return_addr); //from device to host
|
||||
// extern int recv(void *data, uint32_t len, uint32_t max_len, uint32_t *err_code, uint32_t type); //from host to device
|
||||
// extern void recv_data(void *data, uint32_t len);
|
||||
// extern int mystrlen(char *data);
|
||||
// extern void usb_log(char * msg, uint32_t * error);
|
||||
|
||||
#ifdef __aarch64__
|
||||
#include "debugger_archs/ga_arm64.h"
|
||||
#elif __arm__
|
||||
#include "debugger_archs/ga_arm.h"
|
||||
#elif __thumb__
|
||||
#include "debugger_archs/ga_arm_thumb.h"
|
||||
#else
|
||||
#include "debugger_archs/ga_arm64.h"
|
||||
#endif
|
||||
|
||||
#ifdef GLITCH_ENABLE
|
||||
#include "glitch_handler.h"
|
||||
#endif
|
||||
|
||||
// Functions that are implemented in assembly, based on the architecture
|
||||
extern void restore_and_jump();
|
||||
extern void debugger_dump_special_regs();
|
||||
extern void sync_debugger();
|
||||
extern void debugger_sync_special_regs();
|
||||
extern void restore_and_return();
|
||||
|
||||
extern int debugger_storage;
|
||||
// uint64_t debugger_storage_values[] = &debugger_storage;
|
||||
#define GUPJE_BLOCK_SIZE 0x100
|
||||
|
||||
__attribute__((section(".init")))
|
||||
int debugger_main(void){
|
||||
#ifdef DEVICE_SETUP
|
||||
#ifdef __aarch64__
|
||||
uint64_t *val = (uint64_t *)((uint64_t)debugger_storage);
|
||||
|
||||
// 0xfc0
|
||||
if(val[504] == (uint64_t)0x77){
|
||||
void (*custom_func)() = (void*)val[505]; //0xfc8
|
||||
// custom_func();
|
||||
}
|
||||
else{
|
||||
device_setup();
|
||||
}
|
||||
#endif
|
||||
// TODO other architectures
|
||||
#endif
|
||||
|
||||
#ifdef __aarch64__
|
||||
uint64_t mem_off;
|
||||
#else
|
||||
uint32_t mem_off;
|
||||
#endif
|
||||
uint32_t tx_err_code;
|
||||
uint32_t mem_sz;
|
||||
uint32_t blk_sz;
|
||||
char cmd[12];
|
||||
char data[0x20];
|
||||
usb_log("GiAs", &tx_err_code);
|
||||
|
||||
while(1){
|
||||
recv_data(&data, 4);
|
||||
if(data[0] == 'P' && data[1] == 'I' && data[2] == 'N' && data[3] == 'G'){
|
||||
data[1] = 'O';
|
||||
send(&data, 4, &tx_err_code);
|
||||
}
|
||||
else if(data[0] == 'P' && data[1] == 'E' && data[2] == 'E' && data[3] == 'K') {
|
||||
// peek, dump memory
|
||||
recv_data(&data, 12); // Receive uint64_t size and and uint32_t offset
|
||||
#ifdef __aarch64__
|
||||
mem_off = *(uint64_t *)data;
|
||||
mem_sz = *(uint32_t *)(data+8);
|
||||
#else
|
||||
// For ARM and Thumb Mode
|
||||
// Receive uint32_t size and and uint32_t offset
|
||||
mem_off = *(uint32_t *)data;
|
||||
mem_sz = *(uint32_t *)(data+4);
|
||||
#endif
|
||||
|
||||
for(unsigned int i=0;i<=mem_sz;i+=GUPJE_BLOCK_SIZE) {
|
||||
if((mem_sz - i) < GUPJE_BLOCK_SIZE) {
|
||||
blk_sz = mem_sz - i;
|
||||
} else {
|
||||
blk_sz = GUPJE_BLOCK_SIZE;
|
||||
}
|
||||
send((void *)(mem_off+i), blk_sz, &tx_err_code);
|
||||
recv_data(&data, 4);
|
||||
if(!(data[0] == 'A' && data[1] == 'C' && data[2] == 'K')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(data[0] == 'H' && data[1] == 'W' && data[2] == 'I' && data[3] == 'O') {
|
||||
//HWIO, write byte by byte
|
||||
//
|
||||
recv_data(&data, 0x20);
|
||||
mem_off = *(uint32_t *)data;
|
||||
mem_sz = *(uint32_t *)(data+8);
|
||||
// Data is stored in the rest of the data buffer
|
||||
// No error checking on size, be carefull!
|
||||
for(unsigned int i=0;i<mem_sz;i++) {
|
||||
*((uint8_t *)(mem_off+i)) = data[12+i];
|
||||
}
|
||||
usb_log("OK", &tx_err_code);
|
||||
}
|
||||
else if(data[0] == 'P' && data[1] == 'O' && data[2] == 'K' && data[3] == 'E') {
|
||||
#ifdef __aarch64__
|
||||
recv_data(&data, 12); // Receive uint64_t size and and uint32_t offset
|
||||
mem_off = *(uint64_t *)data;
|
||||
mem_sz = *(uint32_t *)(data+8);
|
||||
#else
|
||||
// For ARM and Thumb mode
|
||||
recv_data(&data, 12); // Receive uint32_t size and and uint32_t offset
|
||||
mem_off = *(uint32_t *)data;
|
||||
mem_sz = *(uint32_t *)(data+4);
|
||||
#endif
|
||||
|
||||
for(unsigned int i=0;i < mem_sz; i += GUPJE_BLOCK_SIZE) {
|
||||
if((mem_sz - i) < GUPJE_BLOCK_SIZE) {
|
||||
blk_sz = mem_sz - i;
|
||||
} else {
|
||||
blk_sz = GUPJE_BLOCK_SIZE;
|
||||
}
|
||||
recv_data((void *) (mem_off + i), blk_sz);
|
||||
usb_log("OK", &tx_err_code);
|
||||
recv_data(&data, 4);
|
||||
|
||||
if(!(data[0] == 'A' && data[1] == 'C' && data[2] == 'K')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(data[0] == 'S' && data[1] == 'E' && data[2] == 'L' && data[3] == 'F') {
|
||||
#ifdef __aarch64__
|
||||
mem_off = (uint64_t) &debugger_main;
|
||||
#else
|
||||
mem_off = (uint32_t) &debugger_main;
|
||||
#endif
|
||||
send(&mem_off, sizeof(mem_off), &tx_err_code);
|
||||
}
|
||||
else if(data[0] == 'M' && data[1] == 'A' && data[2] == 'I' && data[3] == 'N') {
|
||||
#ifdef __aarch64__
|
||||
mem_off = (uint64_t) &debugger_main;
|
||||
#else
|
||||
mem_off = (uint32_t) &debugger_main;
|
||||
#endif
|
||||
concrete_main(mem_off);
|
||||
}
|
||||
else if(data[0] == 'F' && data[1] == 'L' && data[2] == 'S' && data[3] == 'H') {
|
||||
//FLSH cache flush
|
||||
#ifdef __aarch64__
|
||||
cache_flush();
|
||||
#else
|
||||
// Todo for ARM and Thumb
|
||||
#endif
|
||||
}
|
||||
else if(data[0] == 'J' && data[1] == 'U' && data[2] == 'M' && data[3] == 'P') {
|
||||
//JUMP == jump to function using provided pointer
|
||||
#ifdef __aarch64__
|
||||
recv_data(&data, 8);
|
||||
mem_off = *(uint64_t *)data;
|
||||
void (*custom_func)() = (void*)mem_off; //mem_off;
|
||||
custom_func();
|
||||
#else
|
||||
recv_data(&data, 4);
|
||||
mem_off = *(uint32_t *)data;
|
||||
void (*custom_func)() = (void*)mem_off; //mem_off;
|
||||
custom_func();
|
||||
#endif
|
||||
}
|
||||
else if(data[0] == 'S' && data[1] == 'Y' && data[2] == 'N' && data[3] == 'C') {
|
||||
//SYNC: Synchronize registers from memory with actual registers
|
||||
sync_debugger();
|
||||
}
|
||||
else if(data[0] == 'S' && data[1] == 'Y' && data[2] == 'N' && data[3] == 'S') {
|
||||
//SYNS: Synchronize special registers
|
||||
debugger_sync_special_regs();
|
||||
}
|
||||
else if(data[0] == 'S' && data[1] == 'P' && data[2] == 'E' && data[3] == 'C') {
|
||||
//SPEC dump special registers
|
||||
debugger_dump_special_regs();
|
||||
}
|
||||
else if(data[0] == 'E' && data[1] == 'R' && data[2] == 'E' && data[3] == 'T') {
|
||||
#ifdef __aarch64__
|
||||
__asm__ __volatile__("ERET\n\t");
|
||||
#endif
|
||||
}
|
||||
else if(data[0] == 'R' && data[1] == 'E' && data[2] == 'S' && data[3] == 'T') {
|
||||
//REST restore stack and jump
|
||||
restore_and_jump();
|
||||
}
|
||||
else if(data[0] == 'R' && data[1] == 'R' && data[2] == 'E' && data[3] == 'T') {
|
||||
// TODO Remove or change?
|
||||
restore_and_return();
|
||||
return 0;
|
||||
}
|
||||
else if(data[0] == 'T' && data[1] == 'E' && data[2] == 'S' && data[3] == 'T') {
|
||||
// Implement any test function here
|
||||
#ifdef __aarch64__
|
||||
__asm__ __volatile__("SVC 0x0\n\t");
|
||||
// disable_mmu();
|
||||
#endif
|
||||
}
|
||||
#ifdef GLITCH_ENABLE
|
||||
else if(data[0] == 'G' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') {
|
||||
#ifdef __aarch64__
|
||||
mem_off = (uint64_t) &debugger_main;
|
||||
#else
|
||||
mem_off = (uint32_t) &debugger_main;
|
||||
#endif
|
||||
glitch_main(mem_off);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void){
|
||||
debugger_main();
|
||||
return 0;
|
||||
}
|
5
debugger_archs/ga_arm.h
Normal file
@ -0,0 +1,5 @@
|
||||
#include <unistd.h>
|
||||
|
||||
void dump_regs(uint32_t addr){
|
||||
|
||||
}
|
31
debugger_archs/ga_arm64.h
Normal file
@ -0,0 +1,31 @@
|
||||
#include <unistd.h>
|
||||
|
||||
void invalidate_tlb()
|
||||
{
|
||||
asm(
|
||||
"dsb sy\n"
|
||||
"tlbi alle3\n"
|
||||
"dsb sy\n"
|
||||
"isb\n"
|
||||
);
|
||||
}
|
||||
|
||||
void sync()
|
||||
{
|
||||
asm(
|
||||
"dsb sy\n"
|
||||
"isb\n"
|
||||
);
|
||||
}
|
||||
|
||||
void iciallu(void)
|
||||
{
|
||||
__asm__ __volatile__("ic iallu\n\t" : : :"memory");
|
||||
__asm__ __volatile__("ic ialluis\n\t" : : :"memory");
|
||||
}
|
||||
|
||||
void cache_flush(){
|
||||
// invalidate_tlb();
|
||||
sync();
|
||||
iciallu();
|
||||
}
|
5
debugger_archs/ga_arm_thumb.h
Normal file
@ -0,0 +1,5 @@
|
||||
#include <unistd.h>
|
||||
|
||||
void dump_regs(uint32_t addr){
|
||||
|
||||
}
|
1
documentation/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
build/
|
3
documentation/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"esbonio.sphinx.confDir": ""
|
||||
}
|
27
documentation/Makefile
Normal file
@ -0,0 +1,27 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SPHINXAUTOBUILD = sphinx-autobuild
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
confluence:
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" -E -a $(O)
|
||||
|
||||
livehtml:
|
||||
@$(SPHINXAUTOBUILD) -b html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) --port 34343
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
35
documentation/make.bat
Normal file
@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
@ -0,0 +1,59 @@
|
||||
********************************
|
||||
Debugger Storage Overview on ARM
|
||||
********************************
|
||||
|
||||
Overview of the storage setup on ARM Thumb for the debugger.
|
||||
To interact with this storage dump you can either dump the storage location and parse the entries or use the *utils/debugger/debugger_archs/armT_processor_state.py* processor state, which is also passed as an argument in **GA_arm_thumb_debugger**.
|
||||
|
||||
.. note:: All addresses below asume ``STORAGE_LOCATION`` + **Address**
|
||||
|
||||
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| Address | Function | Comment |
|
||||
+=========+=================+================================================================================+
|
||||
| 0x0 | R0 | Stores Register R0 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x4 | R1 | Stores Register R1 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x8 | R2 | Stores Register R2 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0xc | R3 | Stores Register R3 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x10 | R4 | Stores Register R4 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x14 | R5 | Stores Register R5 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x18 | R6 | Stores Register R6 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x1c | R7 | Stores Register R7 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x20 | R8 | Stores Register R8 (Indirect Function Call Target ``IFC``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x24 | R9 | Stores Register R9 (Platform Register ``P``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x28 | R10 | Stores Register R10 (Thread Pointer ``TP``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x2c | R11 | Stores Register R11 (Frame Pointer ``FP``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x30 | R12 | Stores Register R12 (Intra-Procedure-call-scratched-Register ``IP``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x34 | R13 | Stores Register R13 (Stack Pointer ``SP``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x38 | R14 | Stores Register R14 (Link Register ``LR``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x3c | R15 | Stores Register R15 (Program Counter ``PC``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| | | |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7d8 | DBG_MMU_DISABLE | **DISABLED** ``DEBUGGER`` Disable the MMU on entry and enable the MMU on leave |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7ec | DBG_JUMP_TO | ``DEBUGGER`` Address to jump to instead of the debugger |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7f0 | DBG_CONT_EXEC | ``DEBUGGER`` Do not jump in debugger but into |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7f4 | TEMP X0 | ``DEBUGGER`` Temporary storage for X0 value |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7f8 | Store X0 | ``DEBUGGER`` Stores exception id for the ``SMC`` call |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7fc | JUMP_ADDR | ``DEBUGGER`` Memory location that instructs the debugger where to jump to |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
5
documentation/source/architectures/arm/index.rst
Normal file
@ -0,0 +1,5 @@
|
||||
===
|
||||
ARM
|
||||
===
|
||||
|
||||
.. include:: debugger/arm_debugger_storage.rst
|
31
documentation/source/architectures/arm64/aarch64_mmu.rst
Normal file
@ -0,0 +1,31 @@
|
||||
******************************
|
||||
Memory Managment Unit on ARM64
|
||||
******************************
|
||||
This part describes the memory managment unit on ARM64 and how it is used by the debugger.
|
||||
|
||||
Single Level Pagetable at EL3
|
||||
=============================
|
||||
The documentation described here can also be found at the `official ARM documentation <https://developer.arm.com/documentation/102416/0100/Single-level-table-at-EL3>`_.
|
||||
|
||||
Translation Regime
|
||||
******************
|
||||
Register ``TCR_ELx`` is used to control the **Tranlation Regime** for the pagetables. The documentation for the ``TCR_EL3`` can be found in the `official ARM documentation <https://developer.arm.com/documentation/ddi0500/d/system-control/aarch64-register-descriptions/translation-control-register--el3>`_.
|
||||
|
||||
Translation Table
|
||||
*****************
|
||||
The location of the page table is located in register ``ttbr0_el3``. Depending of the configuration of ``TCR_EL3`` the bits for address selection can change.
|
||||
|
||||
More documentation can be found `here <https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/TTBR0-EL3--Translation-Table-Base-Register-0--EL3->`_
|
||||
|
||||
Pagetable Entry
|
||||
***************
|
||||
The following diagram shows the format of a stage 1 level 1 table entry on EL3.
|
||||
|
||||
.. image:: images/mmu/singlelevel_el3_pte.png
|
||||
|
||||
Automatic Paging
|
||||
================
|
||||
Automatic paging for page walking will be setup in the debugger.
|
||||
For this the ``ARM64_Concrete_State`` contains a mmu with class ``ARM64_MMU``.
|
||||
|
||||
|
58
documentation/source/architectures/arm64/aarch64_vbar.rst
Normal file
@ -0,0 +1,58 @@
|
||||
**********************
|
||||
Vector Tables in ARM64
|
||||
**********************
|
||||
A lot of this documentation can also be found in the `ARM SMC calling convention documentation <https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwitkfqjqNz5AhUJHuwKHZ3vAj4QFnoECBMQAQ&url=https%3A%2F%2Fdocumentation-service.arm.com%2Fstatic%2F5f8ea482f86e16515cdbe3c6%3Ftoken%3D&usg=AOvVaw3QI7Lwrcg6B3BmQ5syZV70>`_
|
||||
|
||||
Vector Exception Levels
|
||||
=======================
|
||||
|
||||
In ARM64 each there is a Vector table for each Exception level, except for EL0. So, in practice there is a Vector table for:
|
||||
|
||||
* EL3 ``Secure Monitor Call (SMC)``
|
||||
* EL2 ``Hyper Visor Call (HVC)``
|
||||
* EL1 ``Super Visor Call (SVC)``
|
||||
|
||||
Documentation about this can be found in `the ARM documentation <https://developer.arm.com/documentation/100933/0100/AArch64-exception-vector-table>`_
|
||||
|
||||
.. image:: images/vector_table/vector_table_arm64.png
|
||||
|
||||
This vector table can be allocated and filled for each of the vector tables described above.
|
||||
|
||||
Setting the Vector Base Address
|
||||
===============================
|
||||
To set the location of this vector table a call ``MSR`` call can be done to ``VBAR_ELX`` which will write an address to that register. When an execption call is executed, this address is fetched and execution will move to that page, with the corresponding Execption Level(EL)
|
||||
|
||||
ARM SMC Calling Convention
|
||||
==========================
|
||||
When doing an SMC call in arm64 a synchronous exception is generated that is handled by the secure monitor in EL3.
|
||||
The SMC call can be in both 32 and 64 bit mode, depending on various bits in the instruction.
|
||||
For most phones this will be in 64 bit mode.
|
||||
|
||||
When doing a SMC call, the register ``ELR_ELn`` is updated to show the location of where the call came from.
|
||||
This is the address after the call where the exception came from. When doing an ``ERET`` instruction this value is written to the ``PC``.
|
||||
|
||||
Stack Pointers
|
||||
**************
|
||||
Each Exception Level has its own stack pointers. The registers for these are:
|
||||
|
||||
* SP_EL0
|
||||
* SP_EL1
|
||||
* SP_EL2
|
||||
* SP_EL3
|
||||
|
||||
``SP_EL3`` is innacessible in EL3, to read it you need to read the ``SP``.
|
||||
|
||||
****************************
|
||||
Debugger VBAR Implementation
|
||||
****************************
|
||||
|
||||
The debugger uses a SMC call to insert a breakpoint at any address. When a SMC call is thrown the processor jumps to the address pointed to in the ``VBAR_EL3`` register.
|
||||
This register **has to ** point to the debugger.
|
||||
The debugger will first store all the registers in the storage location, overwrite the stack pointer and send the hello message ``b'GiAs'`` to the host.
|
||||
|
||||
An overview of what is happening when a SMC call is dan can be seen below:
|
||||
|
||||
.. image:: images/vector_table/smc_handling_arm64.jpg
|
||||
|
||||
.. warning:: Currently register X15 gets corrupted when an SMC call is handled.
|
||||
|
@ -0,0 +1,147 @@
|
||||
**********************************
|
||||
Debugger Storage Overview on ARM64
|
||||
**********************************
|
||||
Overview of the storage setup on ARM64 for the debugger. To interact with this storage dump you can either dump the storage location and parse the entries or use the *utils/debugger/debugger_archs/arm64_processor_state.py* processor state, which is also passed as an argument in **GA_arm64_debugger**.
|
||||
|
||||
.. note:: All addresses below asume ``STORAGE_LOCATION`` + **Address**
|
||||
|
||||
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| Address | Function | Comment |
|
||||
+=========+========================+========================================================================================+
|
||||
| 0x0 | X0 | Stores Register X0 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x8 | X1 | Stores Register X1 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x10 | X2 | Stores Register X2 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x18 | X3 | Stores Register X3 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x20 | X4 | Stores Register X4 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x28 | X5 | Stores Register X5 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x30 | X6 | Stores Register X6 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x38 | X7 | Stores Register X7 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x40 | X8 | Stores Register X8 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x48 | X9 | Stores Register X9 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x50 | X10 | Stores Register X10 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x58 | X11 | Stores Register X11 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x60 | X12 | Stores Register X12 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x68 | X13 | Stores Register X13 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x70 | X14 | Stores Register X14 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x78 | X15 | Stores Register X15 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x80 | X16 | Stores Register X16 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x88 | X17 | Stores Register X17 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x90 | X18 | Stores Register X18 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x98 | X19 | Stores Register X19 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xa0 | X20 | Stores Register X20 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xa8 | X21 | Stores Register X21 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xb0 | X22 | Stores Register X22 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xb8 | X23 | Stores Register X23 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xc0 | X24 | Stores Register X24 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xc8 | X25 | Stores Register X25 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xd0 | X26 | Stores Register X26 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xd8 | X27 | Stores Register X27 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xe0 | X28 | Stores Register X28 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xe8 | X29 | Stores the ``Frame Pointer`` |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xf0 | X30 | Stores the ``Link Register`` |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xf8 | SP | Stores the ``Stack Pointer`` |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x100 | TTBR0_EL3 | Stores ``TTBR0_EL3`` |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x108 | TTBR0_EL2 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x110 | TTBR0_EL1 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x118 | SCTLR_EL3 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x120 | SCTLR_EL2 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x128 | SCTLR_EL1 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x130 | VBAR_EL3 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x130 | VBAR_EL2 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x140 | VBAR_EL1 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x148 | TCR_EL3 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x150 | TCR_EL2 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x158 | TCR_EL1 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x160 | ELR_EL3 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x168 | ELR_EL2 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x170 | ELR_EL1 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x178 | SP_EL2 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x180 | SP_EL1 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x188 | SP_EL0 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x190 | SPSR_EL3 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x198 | SPSR_EL2 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x1a0 | SPSR_EL1 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x1a8 | MAIR_EL3 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x1b0 | MAIR_EL2 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x1b8 | MAIR_EL1 | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0x1c0 | CurrentEL | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| | | |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xfc0 | DBG_SETUP_JUMP | ``DEBUGGER`` Set to 0x77 to jump to ``DBG_SETUP_JUMP_ADDRESS`` and when DEVICE_SETUP=1 |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xfc8 | DBG_SETUP_JUMP_ADDRESS | ``DEBUGGER`` Address to jump to when ``DBG_SETUP_JUMP`` is set to *0x77* |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xfd0 | DBG_MMU_DISABLE | **DISABLED** ``DEBUGGER`` Disable the MMU on entry and enable the MMU on leave |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xfd8 | DBG_JUMP_TO | ``DEBUGGER`` Address to jump to instead of the debugger |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xfe0 | DBG_CONT_EXEC | ``DEBUGGER`` Do not jump in debugger but into |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xfe8 | TEMP X0 | ``DEBUGGER`` Temporary storage for X0 value |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xff0 | Store X0 | ``DEBUGGER`` Stores exception id for the ``SMC`` call |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
| 0xff8 | JUMP_ADDR | ``DEBUGGER`` Memory location that instructs the debugger where to jump to |
|
||||
+---------+------------------------+----------------------------------------------------------------------------------------+
|
||||
|
||||
.. note:: This memory segment is still being updated to add registers
|
||||
|
||||
When ``DBG_CONT_EXEC`` is set to **0x777** the debugger will not enter the debugger_main address, but instead restore the original processor state and jump into ``DBG_JUMP_TO``. This allows the debugger to be run without user interaction.
|
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 93 KiB |
After Width: | Height: | Size: 61 KiB |
9
documentation/source/architectures/arm64/index.rst
Normal file
@ -0,0 +1,9 @@
|
||||
=====
|
||||
ARM64
|
||||
=====
|
||||
Documentation for the ARM64 architecture.
|
||||
|
||||
.. include:: aarch64_vbar.rst
|
||||
.. include:: aarch64_mmu.rst
|
||||
.. include:: system_configuration.rst
|
||||
.. include:: debugger/arm64_debugger_storage.rst
|
@ -0,0 +1,11 @@
|
||||
********************
|
||||
System Configuration
|
||||
********************
|
||||
|
||||
Configuration for the processor can be set in the System Control Register for different exception levels. These registers are:
|
||||
|
||||
* SCTLR_EL3
|
||||
* SCTLR_EL2
|
||||
* SCTLR_EL1
|
||||
|
||||
More information about the configuration settings can be found in the `ARM documentation <https://developer.arm.com/documentation/ddi0601/2020-12/AArch64-Registers/SCTLR-EL3--System-Control-Register--EL3->`_
|
@ -0,0 +1,95 @@
|
||||
***************************************
|
||||
Debugger Storage Overview on ARM(Thumb)
|
||||
***************************************
|
||||
|
||||
Overview of the storage setup on ARM Thumb for the debugger.
|
||||
To interact with this storage dump you can either dump the storage location and parse the entries or use the *utils/debugger/debugger_archs/armT_processor_state.py* processor state, which is also passed as an argument in **GA_arm_thumb_debugger**.
|
||||
|
||||
.. note:: All addresses below asume ``STORAGE_LOCATION`` + **Address**
|
||||
|
||||
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| Address | Function | Comment |
|
||||
+=========+=================+================================================================================+
|
||||
| 0x0 | R0 | Stores Register R0 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x4 | R1 | Stores Register R1 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x8 | R2 | Stores Register R2 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0xc | R3 | Stores Register R3 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x10 | R4 | Stores Register R4 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x14 | R5 | Stores Register R5 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x18 | R6 | Stores Register R6 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x1c | R7 | Stores Register R7 |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x20 | R8 | Stores Register R8 (Indirect Function Call Target ``IFC``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x24 | R9 | Stores Register R9 (Platform Register ``P``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x28 | R10 | Stores Register R10 (Thread Pointer ``TP``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x2c | R11 | Stores Register R11 (Frame Pointer ``FP``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x30 | R12 | Stores Register R12 (Intra-Procedure-call-scratched-Register ``IP``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x34 | R13 | Stores Register R13 (Stack Pointer ``SP``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x38 | R14 | Stores Register R14 (Link Register ``LR``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x3c | R15 | Stores Register R15 (Program Counter ``PC``) |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| | | |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7d8 | DBG_MMU_DISABLE | **DISABLED** ``DEBUGGER`` Disable the MMU on entry and enable the MMU on leave |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7ec | DBG_JUMP_TO | ``DEBUGGER`` Address to jump to instead of the debugger |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7f0 | DBG_CONT_EXEC | ``DEBUGGER`` Do not jump in debugger but into |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7f4 | TEMP X0 | ``DEBUGGER`` Temporary storage for X0 value |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7f8 | Store X0 | ``DEBUGGER`` Stores exception id for the ``SMC`` call |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
| 0x7fc | JUMP_ADDR | ``DEBUGGER`` Memory location that instructs the debugger where to jump to |
|
||||
+---------+-----------------+--------------------------------------------------------------------------------+
|
||||
|
||||
.. note:: This memory segment is still being updated to add registers
|
||||
|
||||
When ``DBG_CONT_EXEC`` is set to **0x77** the debugger will not enter the debugger_main address, but instead restore the original processor state and jump into ``DBG_JUMP_TO``.
|
||||
This allows the debugger to be run without user interaction.
|
||||
|
||||
.. note::
|
||||
|
||||
By default `register r12 <https://developer.arm.com/documentation/dui0056/d/using-the-procedure-call-standard/register-roles-and-names/register-roles>`_ is corrupted for debugger usage(usually the high registers are not used in thumb mode)
|
||||
|
||||
Low/high registers
|
||||
------------------
|
||||
ARM in thumb mode has low and high registers. The low registers are R0-R7 and the high registers are R8-R15.
|
||||
The high registers can not be directly accessed in thumb mode. The ``LDR`` and ``STR`` can not be used for accessing the high registers.
|
||||
The ``MOV`` register however can be used to access these registers, which is enough for the debugger to use these registers.
|
||||
|
||||
.. code-block:: assembly
|
||||
:caption: Accessing high registers in thumb mode and branch to it.
|
||||
|
||||
ldr r2, =addr_debugger_main
|
||||
mov r12, r2
|
||||
bx r12
|
||||
|
||||
addr_debugger_main: .word 0x100000
|
||||
|
||||
Instructions
|
||||
============
|
||||
Some notes on instructions in ``ARM Thumb``.
|
||||
|
||||
Branch Exchange
|
||||
---------------
|
||||
The ``BX`` instruction is used to branch to a new address and exchange the instruction set if required(ARM/Thumb).
|
||||
The ``BX`` instruction does **not** set the LR.
|
||||
|
||||
|
||||
|
6
documentation/source/architectures/arm_thumb/index.rst
Normal file
@ -0,0 +1,6 @@
|
||||
==============
|
||||
ARM Thumb Mode
|
||||
==============
|
||||
Documentation for the ARM architecture in ``Thumb`` Mode.
|
||||
|
||||
.. include:: debugger/armT_debugger_storage.rst
|
32
documentation/source/conf.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# For the full list of built-in configuration values, see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||
|
||||
project = 'gupje'
|
||||
copyright = '2024, Eljakim'
|
||||
author = 'Eljakim'
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
||||
extensions = [ 'myst_parser',
|
||||
'sphinx_rtd_theme',
|
||||
'sphinx.ext.todo',
|
||||
'sphinxcontrib.confluencebuilder',
|
||||
"sphinxcontrib.drawio",
|
||||
]
|
||||
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = []
|
||||
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_static_path = ['_static']
|
1
documentation/source/images/debugger_flow.drawio.svg
Normal file
After Width: | Height: | Size: 11 KiB |
1
documentation/source/images/gupje_overview.drawio.svg
Normal file
After Width: | Height: | Size: 7.0 KiB |
23
documentation/source/index.rst
Normal file
@ -0,0 +1,23 @@
|
||||
.. gupje documentation master file, created by
|
||||
sphinx-quickstart on Thu Mar 28 15:26:50 2024.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Gupje Architecture based debugger
|
||||
=================================
|
||||
This is the documentation for the Gupje debugger.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Setup:
|
||||
|
||||
overview.rst
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Architectures:
|
||||
|
||||
architectures/arm64/index.rst
|
||||
architectures/arm/index.rst
|
||||
architectures/arm_thumb/index.rst
|
91
documentation/source/overview.rst
Normal file
@ -0,0 +1,91 @@
|
||||
==============
|
||||
Gupje overview
|
||||
==============
|
||||
Gupje is a stub debugger that is designed to be minimal and requires 3 pages(0x1000) of data to be loaded on a target system.
|
||||
A high level overview of how the memory mapping for this works is shown below.
|
||||
|
||||
.. figure:: images/gupje_overview.drawio.svg
|
||||
|
||||
.. note::
|
||||
|
||||
In the future the debugger will probably grow to 4 pages, to include an extra page for the debugger to use in custom functionality.
|
||||
|
||||
Features
|
||||
========
|
||||
In a typical usecase the flow of the debugger wuuld look as something like this:
|
||||
|
||||
.. figure:: images/debugger_flow.drawio.svg
|
||||
|
||||
State saving
|
||||
------------
|
||||
Function: ``On enter``
|
||||
|
||||
The first thing the debugger does when it enters is save it's state into it's storage page.
|
||||
The state being all the General Purpose registers and some special register, like the stack pointer and link register.
|
||||
The stack pointer is overwritten to the debugger stack, in order to not taint the original stack.
|
||||
This is architecture dependent and written in Assembly.
|
||||
See the documentation in each architecture on how this is performed and if data is lost.
|
||||
|
||||
Memory Read(Peek)
|
||||
-----------------
|
||||
Read an address in memory to the host.
|
||||
|
||||
Memory Write(Poke)
|
||||
------------------
|
||||
Write a buffer to an address in memory.
|
||||
|
||||
Get debugger main(SELF)
|
||||
-----------------------
|
||||
Get the main entry point of the debugger. This is used to jump to only the debugger without setting up the stack and registers again.
|
||||
This taints the device but is very usefull for debugging and showing where the debugger is in memory.
|
||||
|
||||
Concrete main(MAIN)
|
||||
-------------------
|
||||
Execute the ``concrete_main`` function. This function is fully user customizable and can be used to implement custom functionality.
|
||||
Like executing boot stages in a Qualcomm bootROM.
|
||||
|
||||
Flush Cache(FLSH)
|
||||
-----------------
|
||||
Execute architecture specific instructions in order to flush the cache.
|
||||
|
||||
.. note::
|
||||
|
||||
Only arm64 is supported for this function. The support is there for arm and thumb but not implemented.
|
||||
|
||||
Jump to address(JUMP)
|
||||
---------------------
|
||||
Simple function that will just jump to an address without restoring the stack or registers. Usefull for testing the debugger or relocating it.
|
||||
|
||||
Dump special registers(SPEC)
|
||||
----------------------------
|
||||
Will dump the special registers to the host. This is architecture dependent and will only dump the registers that are supported. For ARM64 checks for each exception level are implemented.
|
||||
|
||||
Synchronize State(SYNC)
|
||||
-----------------------
|
||||
This function can be called from the debugger and will force write the registers from the saved state into the processor.
|
||||
|
||||
Sync Special(SYNS)
|
||||
------------------
|
||||
Will force write the special registers from the saved state into the processor. Usefull for overwriting the ``VBAR_ELN`` and others.
|
||||
Not all registers are supported here and in the future this will probably be changed to be code pushed from the host to save space and support all special registers.
|
||||
|
||||
.. note::
|
||||
|
||||
This function is currently only properly implemented for ARM64.
|
||||
|
||||
Restore and Jump(REST)
|
||||
----------------------
|
||||
This function restores the state of the processor from it's internal storage and jump's to the address defined in ``DEBUGGER_JUMP``.
|
||||
|
||||
.. caution::
|
||||
|
||||
Currently there is always a register corrupted on the jump function(we need to branch to a register). I have not found a good method to mitigate this(maybe ldr pc in arm/thumb but wont work for arm64)
|
||||
|
||||
Restore and Return(RRET)
|
||||
------------------------
|
||||
Does the same as ``Restore and Jump`` but instead of jumping it returns to the address that called the debugger.
|
||||
|
||||
Glitching
|
||||
=========
|
||||
A debug flag is added for adding glitching to the debugger. The command ``GLIT`` will jump to the glitch function but this is not very well implemented yet.
|
||||
The goal is to add several testable glitch cases to the debugger for profiling.
|
36
glitch_handler.h
Normal file
@ -0,0 +1,36 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern void glitch_registers_loop();
|
||||
extern void glitch_out_loop();
|
||||
|
||||
int glitch_main(uintptr_t cmd_handler){
|
||||
uint32_t tx_err_code;
|
||||
char data[0x20];
|
||||
usb_log("GlAs", &tx_err_code); // Send glitcher magic
|
||||
|
||||
while(1){
|
||||
recv_data(&data, 4);
|
||||
if(data[0] == 'P' && data[1] == 'I' && data[2] == 'N' && data[3] == 'G'){
|
||||
//PING
|
||||
data[1] = 'O';
|
||||
send(&data, 4, &tx_err_code);
|
||||
}
|
||||
if(data[0] == 'D' && data[1] == 'E' && data[2] == 'B' && data[3] == 'G'){
|
||||
//DEBG: Jump to debugger
|
||||
void (*debg)() = ((void *) cmd_handler);
|
||||
debg();
|
||||
}
|
||||
if(data[0] == 'S' && data[1] == 'E' && data[2] == 'T' && data[3] == 'P'){
|
||||
//SETP setup triggers
|
||||
setup_trigger();
|
||||
}
|
||||
if(data[0] == 'G' && data[1] == 'L' && data[2] == 'I' && data[3] == '1'){
|
||||
glitch_registers_loop();
|
||||
}
|
||||
if(data[0] == 'G' && data[1] == 'L' && data[2] == 'I' && data[3] == '2'){
|
||||
glitch_out_loop();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
1
simple_device.drawio.svg
Normal file
After Width: | Height: | Size: 9.9 KiB |
1
simple_device_memory.drawio.svg
Normal file
After Width: | Height: | Size: 5.2 KiB |