mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-03 03:31:41 +03:00
feat(esp_gdbstub): support watchpoint trigger reason
This commit is contained in:
@@ -169,6 +169,15 @@ void esp_gdbstub_clear_step(void);
|
|||||||
void esp_gdbstub_do_step(esp_gdbstub_frame_t *regs_frame);
|
void esp_gdbstub_do_step(esp_gdbstub_frame_t *regs_frame);
|
||||||
void esp_gdbstub_trigger_cpu(void);
|
void esp_gdbstub_trigger_cpu(void);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||||
|
/**
|
||||||
|
* Check if a watchpoint triggered the current debug exception.
|
||||||
|
* @param[out] addr Address of the triggered watchpoint (only valid if return is true)
|
||||||
|
* @return true if a watchpoint triggered, false otherwise (breakpoint/step/other)
|
||||||
|
*/
|
||||||
|
bool esp_gdbstub_get_watchpoint_trigger_addr(uint32_t *addr);
|
||||||
|
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a value to register in frame
|
* Write a value to register in frame
|
||||||
* @param frame gdbstub frame
|
* @param frame gdbstub frame
|
||||||
|
|||||||
@@ -28,6 +28,10 @@
|
|||||||
#define GDBSTUB_QXFER_SUPPORTED_STR ""
|
#define GDBSTUB_QXFER_SUPPORTED_STR ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||||
|
static void send_watchpoint_reason(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
|
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
|
||||||
static inline int gdb_tid_to_task_index(int tid);
|
static inline int gdb_tid_to_task_index(int tid);
|
||||||
static inline int task_index_to_gdb_tid(int tid);
|
static inline int task_index_to_gdb_tid(int tid);
|
||||||
@@ -110,6 +114,9 @@ static void send_reason(void)
|
|||||||
esp_gdbstub_send_start();
|
esp_gdbstub_send_start();
|
||||||
esp_gdbstub_send_char('T');
|
esp_gdbstub_send_char('T');
|
||||||
esp_gdbstub_send_hex(s_scratch.signal, 8);
|
esp_gdbstub_send_hex(s_scratch.signal, 8);
|
||||||
|
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||||
|
send_watchpoint_reason();
|
||||||
|
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||||
esp_gdbstub_send_end();
|
esp_gdbstub_send_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +222,35 @@ static bool not_send_reason = false;
|
|||||||
static bool process_gdb_kill = false;
|
static bool process_gdb_kill = false;
|
||||||
static bool gdb_debug_int = false;
|
static bool gdb_debug_int = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if a watchpoint triggered and append the corresponding
|
||||||
|
* GDB RSP stop-reply field (watch/rwatch/awatch) to the current packet.
|
||||||
|
*/
|
||||||
|
static void send_watchpoint_reason(void)
|
||||||
|
{
|
||||||
|
uint32_t wp_addr = 0;
|
||||||
|
if (!esp_gdbstub_get_watchpoint_trigger_addr(&wp_addr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *type_str = "watch";
|
||||||
|
for (size_t i = 0; i < SOC_CPU_WATCHPOINTS_NUM; i++) {
|
||||||
|
if (wp_list[i] == wp_addr) {
|
||||||
|
if (wp_access[i] == ESP_CPU_WATCHPOINT_LOAD) {
|
||||||
|
type_str = "rwatch";
|
||||||
|
} else if (wp_access[i] == ESP_CPU_WATCHPOINT_ACCESS) {
|
||||||
|
type_str = "awatch";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_gdbstub_send_str(type_str);
|
||||||
|
esp_gdbstub_send_char(':');
|
||||||
|
esp_gdbstub_send_hex(wp_addr, 32);
|
||||||
|
esp_gdbstub_send_char(';');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handle UART interrupt
|
* @brief Handle UART interrupt
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -250,6 +250,22 @@ void esp_gdbstub_init_dports(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool esp_gdbstub_get_watchpoint_trigger_addr(uint32_t *addr)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SOC_CPU_BREAKPOINTS_NUM; i++) {
|
||||||
|
RV_WRITE_CSR(tselect, i);
|
||||||
|
uint32_t tdata1 = RV_READ_CSR(tdata1);
|
||||||
|
bool is_load = tdata1 & TDATA1_LOAD;
|
||||||
|
bool is_store = tdata1 & TDATA1_STORE;
|
||||||
|
bool is_exec = tdata1 & TDATA1_EXECUTE;
|
||||||
|
if (!is_exec && (is_load || is_store)) {
|
||||||
|
*addr = RV_READ_CSR(tdata2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||||
|
|
||||||
#if (!CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE) && CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
#if (!CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE) && CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||||
|
|||||||
@@ -307,6 +307,23 @@ void esp_gdbstub_init_dports(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||||
|
bool esp_gdbstub_get_watchpoint_trigger_addr(uint32_t *addr)
|
||||||
|
{
|
||||||
|
uint32_t debugcause;
|
||||||
|
RSR(XT_REG_DEBUGCAUSE, debugcause);
|
||||||
|
if (debugcause & XCHAL_DEBUGCAUSE_DBREAK_MASK) {
|
||||||
|
if (debugcause & (1 << 8)) {
|
||||||
|
RSR(XT_REG_DBREAKA_1, *addr);
|
||||||
|
} else {
|
||||||
|
RSR(XT_REG_DBREAKA_0, *addr);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ARCH_XTENSA && (!CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE) && CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
#if CONFIG_IDF_TARGET_ARCH_XTENSA && (!CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE) && CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||||
static bool stall_started = false;
|
static bool stall_started = false;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -371,14 +371,11 @@ def test_gdbstub_runtime(dut: PanicTestDut) -> None:
|
|||||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||||
cmd = '-exec-continue'
|
cmd = '-exec-continue'
|
||||||
payload = run_and_break(dut, cmd)
|
payload = run_and_break(dut, cmd)
|
||||||
assert payload['reason'] == 'signal-received'
|
assert payload['reason'] == 'watchpoint-trigger'
|
||||||
|
assert int(payload['value']['new']) == int(payload['value']['old']) + 2
|
||||||
assert payload['frame']['func'] == 'foo'
|
assert payload['frame']['func'] == 'foo'
|
||||||
|
assert payload['frame']['line'] == str(get_line_number('var_2--;'))
|
||||||
assert payload['stopped-threads'] == 'all'
|
assert payload['stopped-threads'] == 'all'
|
||||||
# Uncomment this when implement send reason to gdb: GCC-313
|
|
||||||
#
|
|
||||||
# assert payload['reason'] == 'watchpoint-trigger'
|
|
||||||
# assert int(payload['value']['new']) == int(payload['value']['old']) + 1
|
|
||||||
# assert payload['frame']['line'] == '14'
|
|
||||||
|
|
||||||
cmd = '-break-delete 2'
|
cmd = '-break-delete 2'
|
||||||
responses = dut.gdb_write(cmd)
|
responses = dut.gdb_write(cmd)
|
||||||
|
|||||||
Reference in New Issue
Block a user