mirror of
https://github.com/ringtailsoftware/uvm32.git
synced 2026-06-05 22:43:39 +00:00
Merge pull request #10 from hamid-rostami/gdbstub-support
gdbstub support
This commit is contained in:
commit
f7c11f30e0
6 changed files with 2009 additions and 0 deletions
7
hosts/host-gdbstub/Makefile
Normal file
7
hosts/host-gdbstub/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
TOPDIR=../..
|
||||||
|
|
||||||
|
all:
|
||||||
|
gcc -Wall -Werror -Wno-error=unused-function -pedantic -std=c99 -O2 -DUVM32_ERROR_STRINGS -DUVM32_MEMORY_SIZE=65536 -DGDBSTUB_ARCH_UVM32 -DGDBSTUB_IMPLEMENTATION -I${TOPDIR}/uvm32 -I${TOPDIR}/common -o host-gdbstub ${TOPDIR}/uvm32/uvm32.c host-gdbstub.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f host-gdbstub
|
||||||
29
hosts/host-gdbstub/README.md
Normal file
29
hosts/host-gdbstub/README.md
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Why?
|
||||||
|
|
||||||
|
To debug your guest application. GDB can attach to the host over TCP socket, stdio,
|
||||||
|
serial connection, etc. In the provided example, it communicate over stdio, however
|
||||||
|
using `socat` it can be redirected to a TCP socket.
|
||||||
|
|
||||||
|
# How to use it
|
||||||
|
|
||||||
|
1. Compile a guest application, for example from [apps](../../apps/) directory.
|
||||||
|
To have a better debugging experience, use `-O0` and `-g3`.
|
||||||
|
|
||||||
|
2. Run the host prividing the app binary file. Use the following command to
|
||||||
|
redirect stdio to a TCP socket:
|
||||||
|
|
||||||
|
```
|
||||||
|
socat -v -x
|
||||||
|
TCP-LISTEN:1234,reuseaddr \
|
||||||
|
EXEC:"./host-gdbstub ../../apps/maze/maze.bin"
|
||||||
|
```
|
||||||
|
|
||||||
|
`-v` and `-x` are used to see the traffic in hex.
|
||||||
|
|
||||||
|
3. Fire up a `riscv32-elf-gdb` (might be different name on your OS) and give
|
||||||
|
it the generated elf file from step 1:
|
||||||
|
|
||||||
|
`riscv32-elf-gdb -ex 'target remote :1234' -ex 'layout src' maze.elf`
|
||||||
|
|
||||||
|
4. Happy debugging. `s`, `si`, `n`, breakpoint, etc should be working :)
|
||||||
|
|
||||||
1887
hosts/host-gdbstub/gdbstub.h
Normal file
1887
hosts/host-gdbstub/gdbstub.h
Normal file
File diff suppressed because it is too large
Load diff
77
hosts/host-gdbstub/host-gdbstub.c
Normal file
77
hosts/host-gdbstub/host-gdbstub.c
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "uvm32.h"
|
||||||
|
#include "gdbstub.h"
|
||||||
|
|
||||||
|
static uint8_t *read_file(const char* filename, int *len) {
|
||||||
|
FILE* f = fopen(filename, "rb");
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
|
||||||
|
if (f == NULL) {
|
||||||
|
fprintf(stderr, "error: can't open file '%s'.\n", filename);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
size_t file_size = ftell(f);
|
||||||
|
rewind(f);
|
||||||
|
|
||||||
|
if (NULL == (buf = malloc(file_size))) {
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t result = fread(buf, sizeof(uint8_t), file_size, f);
|
||||||
|
if (result != file_size) {
|
||||||
|
fprintf(stderr, "error: while reading file '%s'\n", filename);
|
||||||
|
free(buf);
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
*len = file_size;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage(const char *name) {
|
||||||
|
fprintf(stderr, "%s filename.bin\n", name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
uvm32_state_t vmst;
|
||||||
|
const char *rom_filename = NULL;
|
||||||
|
int romlen = 0;
|
||||||
|
|
||||||
|
if (2 == argc) {
|
||||||
|
rom_filename = argv[1];
|
||||||
|
} else {
|
||||||
|
usage(argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *rom = read_file(rom_filename, &romlen);
|
||||||
|
if (NULL == rom) {
|
||||||
|
fprintf(stderr,"file read failed!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uvm32_init(&vmst);
|
||||||
|
|
||||||
|
if (!uvm32_load(&vmst, rom, romlen)) {
|
||||||
|
fprintf(stderr, "load failed!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attach gdbstub to vmst */
|
||||||
|
struct gdb_state state;
|
||||||
|
gdb_sys_init_state(&state, &vmst, NULL);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
gdb_main(&state);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(rom);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -309,6 +309,14 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
|
||||||
setStatusErr(vmst, UVM32_ERR_MEM_RD);
|
setStatusErr(vmst, UVM32_ERR_MEM_RD);
|
||||||
setup_err_evt(vmst, evt);
|
setup_err_evt(vmst, evt);
|
||||||
break;
|
break;
|
||||||
|
case 8:
|
||||||
|
setStatusErr(vmst, UVM32_ERR_MEM_WR);
|
||||||
|
setup_err_evt(vmst, evt);
|
||||||
|
break;
|
||||||
|
case 3: // ebreak
|
||||||
|
vmst->_ioevt.typ = UVM32_EVT_BREAK;
|
||||||
|
setStatus(vmst, UVM32_STATUS_PAUSED);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// unhandled exception
|
// unhandled exception
|
||||||
setStatusErr(vmst, UVM32_ERR_INTERNAL_CORE);
|
setStatusErr(vmst, UVM32_ERR_INTERNAL_CORE);
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ typedef enum {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UVM32_EVT_ERR, /*! Error has occurred, details in uvm32_evt_t data.err field */
|
UVM32_EVT_ERR, /*! Error has occurred, details in uvm32_evt_t data.err field */
|
||||||
UVM32_EVT_SYSCALL, /*! A syscall has been requested, details in uvm32__evt_t data.syscall field */
|
UVM32_EVT_SYSCALL, /*! A syscall has been requested, details in uvm32__evt_t data.syscall field */
|
||||||
|
UVM32_EVT_BREAK,
|
||||||
UVM32_EVT_END, /*! The program has ended by making a UVM32_SYSCALL_HALT */
|
UVM32_EVT_END, /*! The program has ended by making a UVM32_SYSCALL_HALT */
|
||||||
} uvm32_evt_typ_t;
|
} uvm32_evt_typ_t;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue