Skip to content

Manage breakpoints with red-black tree #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ GDBSTUB_LIB := $(GDBSTUB_OUT)/libgdbstub.a
$(GDBSTUB_LIB): mini-gdbstub/Makefile
$(MAKE) -C $(dir $<) O=$(dir $@)
$(OUT)/emulate.o: $(GDBSTUB_LIB)
OBJS_EXT += gdbstub.o
OBJS_EXT += gdbstub.o breakpoint.o
CFLAGS += -D ENABLE_GDBSTUB -D'GDBSTUB_COMM="$(GDBSTUB_COMM)"'
LDFLAGS += $(GDBSTUB_LIB)
gdbstub-test: $(BIN)
Expand Down
60 changes: 60 additions & 0 deletions breakpoint.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "breakpoint.h"
#include <assert.h>

static inline int cmp(const void *arg0, const void *arg1)
{
riscv_word_t *a = (riscv_word_t *) arg0, *b = (riscv_word_t *) arg1;
return (*a < *b) ? _CMP_LESS : (*a > *b) ? _CMP_GREATER : _CMP_EQUAL;
}

breakpoint_map_t breakpoint_map_new()
{
return map_init(riscv_word_t, breakpoint_t, cmp);
}

bool breakpoint_map_insert(breakpoint_map_t map, riscv_word_t addr)
{
breakpoint_t bp = (breakpoint_t){.addr = addr, .orig_insn = 0};
map_iter_t it;
map_find(map, &it, &addr);
/* We don't expect to set breakpoint at duplicate address */
if (!map_at_end(map, &it))
return false;
return map_insert(map, &addr, &bp);
}

static bool breakpoint_map_find_it(breakpoint_map_t map,
riscv_word_t addr,
map_iter_t *it)
{
map_find(map, it, &addr);
if (map_at_end(map, it)) {
return false;
}

return true;
}

breakpoint_t *breakpoint_map_find(breakpoint_map_t map, riscv_word_t addr)
{
map_iter_t it;
if (!breakpoint_map_find_it(map, addr, &it))
return NULL;

return (breakpoint_t *) map_iter_value(&it, breakpoint_t *);
}

bool breakpoint_map_del(breakpoint_map_t map, riscv_word_t addr)
{
map_iter_t it;
if (!breakpoint_map_find_it(map, addr, &it))
return false;

map_erase(map, &it);
return true;
}

void breakpoint_map_destroy(breakpoint_map_t map)
{
map_delete(map);
}
17 changes: 17 additions & 0 deletions breakpoint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "map.h"
#include "riscv.h"

typedef struct {
riscv_word_t addr;
uint32_t orig_insn;
} breakpoint_t;

typedef map_t breakpoint_map_t;

breakpoint_map_t breakpoint_map_new();
bool breakpoint_map_insert(breakpoint_map_t map, riscv_word_t addr);
breakpoint_t *breakpoint_map_find(breakpoint_map_t map, riscv_word_t addr);
bool breakpoint_map_del(breakpoint_map_t map, riscv_word_t addr);
void breakpoint_map_destroy(breakpoint_map_t map);
3 changes: 3 additions & 0 deletions emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1688,10 +1688,13 @@ void rv_debug(struct riscv_t *rv)
GDBSTUB_COMM)) {
return;
}
rv->breakpoint_map = breakpoint_map_new();

if (!gdbstub_run(&rv->gdbstub, (void *) rv)) {
return;
}

breakpoint_map_destroy(rv->breakpoint_map);
gdbstub_close(&rv->gdbstub);
}

Expand Down
15 changes: 5 additions & 10 deletions gdbstub.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <assert.h>
#include "mini-gdbstub/include/gdbstub.h"
#include "riscv_private.h"
#include "breakpoint.h"

static size_t rv_read_reg(void *args, int regno)
{
Expand Down Expand Up @@ -31,7 +32,7 @@ static gdb_action_t rv_cont(void *args)
const uint32_t cycles_per_step = 1;

for (; !rv_has_halted(rv);) {
if (rv->breakpoint_specified && (rv_get_pc(rv) == rv->breakpoint_addr)) {
if (breakpoint_map_find(rv->breakpoint_map, rv_get_pc(rv)) != NULL) {
break;
}
rv_step(rv, cycles_per_step);
Expand All @@ -50,12 +51,10 @@ static gdb_action_t rv_stepi(void *args)
static bool rv_set_bp(void *args, size_t addr, bp_type_t type)
{
struct riscv_t *rv = (struct riscv_t *) args;
if (type != BP_SOFTWARE || rv->breakpoint_specified)
if (type != BP_SOFTWARE)
return false;

rv->breakpoint_specified = true;
rv->breakpoint_addr = addr;
return true;;
return breakpoint_map_insert(rv->breakpoint_map, addr);
}

static bool rv_del_bp(void *args, size_t addr, bp_type_t type)
Expand All @@ -64,11 +63,7 @@ static bool rv_del_bp(void *args, size_t addr, bp_type_t type)
if (type != BP_SOFTWARE)
return false;
/* When there is no matched breakpoint, no further action is taken */
if (!rv->breakpoint_specified || addr != rv->breakpoint_addr)
return true;

rv->breakpoint_specified = false;
rv->breakpoint_addr = 0;
breakpoint_map_del(rv->breakpoint_map, addr);
return true;
}

Expand Down
4 changes: 2 additions & 2 deletions riscv_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <stdbool.h>

#ifdef ENABLE_GDBSTUB
#include "breakpoint.h"
#include "mini-gdbstub/include/gdbstub.h"
#endif
#include "riscv.h"
Expand Down Expand Up @@ -146,8 +147,7 @@ struct riscv_t {
gdbstub_t gdbstub;

/* GDB instruction breakpoint */
bool breakpoint_specified;
riscv_word_t breakpoint_addr;
breakpoint_map_t breakpoint_map;
#endif

#ifdef ENABLE_RV32F
Expand Down
44 changes: 28 additions & 16 deletions tests/gdbstub.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,36 @@ PID=$!
if ps -p $PID > /dev/null
then
tmpfile=/tmp/rv32emu-gdbstub.$PID
riscv32-unknown-elf-gdb --batch \
-ex "file build/puzzle.elf" \
-ex "target remote :1234" \
-ex "break *0x10700" \
-ex "continue" \
-ex "print \$pc" \
-ex "del 1" \
-ex "stepi" \
-ex "stepi" \
-ex "continue" > ${tmpfile}
breakpoint_arr=(0x10700 0x10800 0x10900)
GDB_COMMANDS="riscv32-unknown-elf-gdb --batch "
GDB_COMMANDS+="-ex 'file build/puzzle.elf' "
GDB_COMMANDS+="-ex 'target remote :1234' "
for t in ${breakpoint_arr[@]}; do
GDB_COMMANDS+="-ex 'break *$t' "
done
for i in {1..3}; do
GDB_COMMANDS+="-ex 'continue' "
GDB_COMMANDS+="-ex 'print \$pc' "
done
for i in {1..3}; do
GDB_COMMANDS+="-ex 'del $i' "
done
GDB_COMMANDS+="-ex 'stepi' "
GDB_COMMANDS+="-ex 'stepi' "
GDB_COMMANDS+="-ex 'continue' "

eval ${GDB_COMMANDS} > ${tmpfile}

# check if we stop at the breakpoint
expected=$(grep -rw "Breakpoint 1 at" ${tmpfile} | awk {'print $4'})
ans=$(grep -r "$1 =" ${tmpfile} | awk {'print $5'})
if [ "$expected" != "$ans" ]; then
# Fail
exit 1
fi
for i in {1..3}
do
expected=$(grep -rw "Breakpoint ${i} at" ${tmpfile} | awk {'print $4'})
ans=$(grep -r "\$${i} =" ${tmpfile} | awk {'print $5'})
if [ "$expected" != "$ans" ]; then
# Fail
exit 1
fi
done
# Pass and wait
exit 0
wait $PID
Expand Down