Skip to content

Commit 94bb504

Browse files
authored
Merge pull request #46 from RinHizakura/gdbstub
Manage breakpoints with red-black tree
2 parents 9dbc693 + 761b61d commit 94bb504

File tree

8 files changed

+117
-30
lines changed

8 files changed

+117
-30
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ GDBSTUB_LIB := $(GDBSTUB_OUT)/libgdbstub.a
6565
$(GDBSTUB_LIB): mini-gdbstub/Makefile
6666
$(MAKE) -C $(dir $<) O=$(dir $@)
6767
$(OUT)/emulate.o: $(GDBSTUB_LIB)
68-
OBJS_EXT += gdbstub.o
68+
OBJS_EXT += gdbstub.o breakpoint.o
6969
CFLAGS += -D ENABLE_GDBSTUB -D'GDBSTUB_COMM="$(GDBSTUB_COMM)"'
7070
LDFLAGS += $(GDBSTUB_LIB)
7171
gdbstub-test: $(BIN)

breakpoint.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "breakpoint.h"
2+
#include <assert.h>
3+
4+
static inline int cmp(const void *arg0, const void *arg1)
5+
{
6+
riscv_word_t *a = (riscv_word_t *) arg0, *b = (riscv_word_t *) arg1;
7+
return (*a < *b) ? _CMP_LESS : (*a > *b) ? _CMP_GREATER : _CMP_EQUAL;
8+
}
9+
10+
breakpoint_map_t breakpoint_map_new()
11+
{
12+
return map_init(riscv_word_t, breakpoint_t, cmp);
13+
}
14+
15+
bool breakpoint_map_insert(breakpoint_map_t map, riscv_word_t addr)
16+
{
17+
breakpoint_t bp = (breakpoint_t){.addr = addr, .orig_insn = 0};
18+
map_iter_t it;
19+
map_find(map, &it, &addr);
20+
/* We don't expect to set breakpoint at duplicate address */
21+
if (!map_at_end(map, &it))
22+
return false;
23+
return map_insert(map, &addr, &bp);
24+
}
25+
26+
static bool breakpoint_map_find_it(breakpoint_map_t map,
27+
riscv_word_t addr,
28+
map_iter_t *it)
29+
{
30+
map_find(map, it, &addr);
31+
if (map_at_end(map, it)) {
32+
return false;
33+
}
34+
35+
return true;
36+
}
37+
38+
breakpoint_t *breakpoint_map_find(breakpoint_map_t map, riscv_word_t addr)
39+
{
40+
map_iter_t it;
41+
if (!breakpoint_map_find_it(map, addr, &it))
42+
return NULL;
43+
44+
return (breakpoint_t *) map_iter_value(&it, breakpoint_t *);
45+
}
46+
47+
bool breakpoint_map_del(breakpoint_map_t map, riscv_word_t addr)
48+
{
49+
map_iter_t it;
50+
if (!breakpoint_map_find_it(map, addr, &it))
51+
return false;
52+
53+
map_erase(map, &it);
54+
return true;
55+
}
56+
57+
void breakpoint_map_destroy(breakpoint_map_t map)
58+
{
59+
map_delete(map);
60+
}

breakpoint.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#pragma once
2+
3+
#include "map.h"
4+
#include "riscv.h"
5+
6+
typedef struct {
7+
riscv_word_t addr;
8+
uint32_t orig_insn;
9+
} breakpoint_t;
10+
11+
typedef map_t breakpoint_map_t;
12+
13+
breakpoint_map_t breakpoint_map_new();
14+
bool breakpoint_map_insert(breakpoint_map_t map, riscv_word_t addr);
15+
breakpoint_t *breakpoint_map_find(breakpoint_map_t map, riscv_word_t addr);
16+
bool breakpoint_map_del(breakpoint_map_t map, riscv_word_t addr);
17+
void breakpoint_map_destroy(breakpoint_map_t map);

emulate.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,10 +1688,13 @@ void rv_debug(struct riscv_t *rv)
16881688
GDBSTUB_COMM)) {
16891689
return;
16901690
}
1691+
rv->breakpoint_map = breakpoint_map_new();
16911692

16921693
if (!gdbstub_run(&rv->gdbstub, (void *) rv)) {
16931694
return;
16941695
}
1696+
1697+
breakpoint_map_destroy(rv->breakpoint_map);
16951698
gdbstub_close(&rv->gdbstub);
16961699
}
16971700

gdbstub.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <assert.h>
22
#include "mini-gdbstub/include/gdbstub.h"
33
#include "riscv_private.h"
4+
#include "breakpoint.h"
45

56
static size_t rv_read_reg(void *args, int regno)
67
{
@@ -31,7 +32,7 @@ static gdb_action_t rv_cont(void *args)
3132
const uint32_t cycles_per_step = 1;
3233

3334
for (; !rv_has_halted(rv);) {
34-
if (rv->breakpoint_specified && (rv_get_pc(rv) == rv->breakpoint_addr)) {
35+
if (breakpoint_map_find(rv->breakpoint_map, rv_get_pc(rv)) != NULL) {
3536
break;
3637
}
3738
rv_step(rv, cycles_per_step);
@@ -50,12 +51,10 @@ static gdb_action_t rv_stepi(void *args)
5051
static bool rv_set_bp(void *args, size_t addr, bp_type_t type)
5152
{
5253
struct riscv_t *rv = (struct riscv_t *) args;
53-
if (type != BP_SOFTWARE || rv->breakpoint_specified)
54+
if (type != BP_SOFTWARE)
5455
return false;
5556

56-
rv->breakpoint_specified = true;
57-
rv->breakpoint_addr = addr;
58-
return true;;
57+
return breakpoint_map_insert(rv->breakpoint_map, addr);
5958
}
6059

6160
static bool rv_del_bp(void *args, size_t addr, bp_type_t type)
@@ -64,11 +63,7 @@ static bool rv_del_bp(void *args, size_t addr, bp_type_t type)
6463
if (type != BP_SOFTWARE)
6564
return false;
6665
/* When there is no matched breakpoint, no further action is taken */
67-
if (!rv->breakpoint_specified || addr != rv->breakpoint_addr)
68-
return true;
69-
70-
rv->breakpoint_specified = false;
71-
rv->breakpoint_addr = 0;
66+
breakpoint_map_del(rv->breakpoint_map, addr);
7267
return true;
7368
}
7469

riscv_private.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <stdbool.h>
33

44
#ifdef ENABLE_GDBSTUB
5+
#include "breakpoint.h"
56
#include "mini-gdbstub/include/gdbstub.h"
67
#endif
78
#include "riscv.h"
@@ -146,8 +147,7 @@ struct riscv_t {
146147
gdbstub_t gdbstub;
147148

148149
/* GDB instruction breakpoint */
149-
bool breakpoint_specified;
150-
riscv_word_t breakpoint_addr;
150+
breakpoint_map_t breakpoint_map;
151151
#endif
152152

153153
#ifdef ENABLE_RV32F

tests/gdbstub.sh

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,36 @@ PID=$!
77
if ps -p $PID > /dev/null
88
then
99
tmpfile=/tmp/rv32emu-gdbstub.$PID
10-
riscv32-unknown-elf-gdb --batch \
11-
-ex "file build/puzzle.elf" \
12-
-ex "target remote :1234" \
13-
-ex "break *0x10700" \
14-
-ex "continue" \
15-
-ex "print \$pc" \
16-
-ex "del 1" \
17-
-ex "stepi" \
18-
-ex "stepi" \
19-
-ex "continue" > ${tmpfile}
10+
breakpoint_arr=(0x10700 0x10800 0x10900)
11+
GDB_COMMANDS="riscv32-unknown-elf-gdb --batch "
12+
GDB_COMMANDS+="-ex 'file build/puzzle.elf' "
13+
GDB_COMMANDS+="-ex 'target remote :1234' "
14+
for t in ${breakpoint_arr[@]}; do
15+
GDB_COMMANDS+="-ex 'break *$t' "
16+
done
17+
for i in {1..3}; do
18+
GDB_COMMANDS+="-ex 'continue' "
19+
GDB_COMMANDS+="-ex 'print \$pc' "
20+
done
21+
for i in {1..3}; do
22+
GDB_COMMANDS+="-ex 'del $i' "
23+
done
24+
GDB_COMMANDS+="-ex 'stepi' "
25+
GDB_COMMANDS+="-ex 'stepi' "
26+
GDB_COMMANDS+="-ex 'continue' "
27+
28+
eval ${GDB_COMMANDS} > ${tmpfile}
2029

2130
# check if we stop at the breakpoint
22-
expected=$(grep -rw "Breakpoint 1 at" ${tmpfile} | awk {'print $4'})
23-
ans=$(grep -r "$1 =" ${tmpfile} | awk {'print $5'})
24-
if [ "$expected" != "$ans" ]; then
25-
# Fail
26-
exit 1
27-
fi
31+
for i in {1..3}
32+
do
33+
expected=$(grep -rw "Breakpoint ${i} at" ${tmpfile} | awk {'print $4'})
34+
ans=$(grep -r "\$${i} =" ${tmpfile} | awk {'print $5'})
35+
if [ "$expected" != "$ans" ]; then
36+
# Fail
37+
exit 1
38+
fi
39+
done
2840
# Pass and wait
2941
exit 0
3042
wait $PID

0 commit comments

Comments
 (0)