Merge branch 'feature/gdbstub_rt_multicore' into 'master'

Extension for GDBstub runtime component (multicore, breakpoints, steps etc...)

See merge request espressif/esp-idf!13896
This commit is contained in:
Ivan Grokhotkov 2022-03-17 19:59:29 +08:00
commit 2f9d47c708
22 changed files with 965 additions and 189 deletions

View File

@ -6,13 +6,14 @@ idf_component_register(SRCS "src/gdbstub.c" "src/packet.c"
PRIV_INCLUDE_DIRS "private_include"
LDFRAGMENTS "linker.lf"
REQUIRES "freertos"
PRIV_REQUIRES "soc" "esp_rom")
PRIV_REQUIRES "soc" "esp_rom" "esp_system")
endif()
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
target_include_directories(${COMPONENT_LIB} PUBLIC "xtensa" "${target}")
target_sources(${COMPONENT_LIB} PRIVATE "xtensa/gdbstub_xtensa.c"
"xtensa/gdbstub-entry.S"
"xtensa/xt_debugexception.S"
"esp_common/gdbstub_common.c")
elseif(CONFIG_IDF_TARGET_ARCH_RISCV)

View File

@ -1,22 +1,16 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/uart_periph.h"
#include "soc/gpio_periph.h"
#include "esp_gdbstub_common.h"
#include "sdkconfig.h"
#include "hal/uart_ll.h"
#include "freertos/FreeRTOS.h"
#include "xtensa/config/specreg.h"
#define UART_NUM CONFIG_ESP_CONSOLE_UART_NUM
@ -70,7 +64,10 @@ void esp_gdbstub_putchar(int c)
void esp_gdbstub_flush()
{
//not needed for uart
// wait until some data in transmition
while (false == uart_ll_is_tx_idle(gdb_uart))
{
}
}
int esp_gdbstub_getfifo()
@ -87,9 +84,6 @@ int esp_gdbstub_getfifo()
if (data == 0x3) {
doDebug = 1; //Check if any of the chars is Ctrl+C. Throw away rest.
}
if (data == '+') {
doDebug = 1; //Check if any of the chars is '+'. Throw away rest.
}
fifolen--;
}
uart_ll_clr_intsts_mask(gdb_uart, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT);

View File

@ -1,16 +1,8 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@ -20,6 +12,7 @@ extern "C" {
void esp_gdbstub_init(void);
void esp_gdbstub_panic_handler(void *frame);
void update_breakpoints(void);
#ifdef __cplusplus
}

View File

@ -1,16 +1,8 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@ -68,7 +60,7 @@ typedef struct {
#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
} esp_gdbstub_scratch_t;
extern esp_gdbstub_scratch_t s_scratch;
/**** Functions provided by the architecture specific part ****/
/**
@ -170,3 +162,19 @@ int esp_gdbstub_read_command(unsigned char **out_cmd, size_t *out_size);
/** Handle a command received from gdb */
int esp_gdbstub_handle_command(unsigned char *cmd, int len);
void esp_gdbstub_init_dports(void);
void esp_gdbstub_stall_other_cpus_start(void);
void esp_gdbstub_stall_other_cpus_end(void);
void esp_gdbstub_clear_step(void);
void esp_gdbstub_do_step(void);
void esp_gdbstub_trigger_cpu(void);
/**
* Write a value to register in frame
* @param frame gdbstub frame
* @param reg_index register index, depends on architecture
* @param value 32 bit data value
*/
void esp_gdbstub_set_register(esp_gdbstub_frame_t *frame, uint32_t reg_index, uint32_t value);

View File

@ -1,16 +1,8 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
@ -29,6 +21,17 @@ typedef struct {
uint32_t pc;
} esp_gdbstub_gdb_regfile_t;
// Amount of HW breakpoints used in GDB
#ifndef GDB_BP_SIZE
#define GDB_BP_SIZE 2
#endif // GDB_BP_SIZE
// Amount of HW watchpoints used in GDB
#ifndef GDB_WP_SIZE
#define GDB_WP_SIZE 2
#endif // GDB_WP_SIZE
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -47,10 +47,37 @@ void esp_gdbstub_tcb_to_regfile(TaskHandle_t tcb, esp_gdbstub_gdb_regfile_t *dst
int esp_gdbstub_get_signal(const esp_gdbstub_frame_t *frame)
{
return 5; // SIGTRAP, see IDF-2490
return 5; // SIGTRAP, see IDF-2490
}
void _xt_gdbstub_int(void * frame)
void _xt_gdbstub_int(void *frame)
{
}
void esp_gdbstub_init_dports()
{
}
void esp_gdbstub_stall_other_cpus_start()
{
}
void esp_gdbstub_stall_other_cpus_end()
{
}
void esp_gdbstub_clear_step()
{
}
void esp_gdbstub_do_step()
{
}
void esp_gdbstub_trigger_cpu(void)
{
}
void esp_gdbstub_set_register(esp_gdbstub_frame_t *frame, uint32_t reg_index, uint32_t value)
{
}

View File

@ -8,16 +8,17 @@
#include "esp_gdbstub.h"
#include "esp_gdbstub_common.h"
#include "sdkconfig.h"
#include <sys/param.h>
#include "soc/uart_reg.h"
#include "soc/periph_defs.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_intr_alloc.h"
#include "hal/wdt_hal.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
static inline int gdb_tid_to_task_index(int tid);
static inline int task_index_to_gdb_tid(int tid);
@ -28,10 +29,19 @@ static int handle_task_commands(unsigned char *cmd, int len);
static void esp_gdbstub_send_str_as_hex(const char *str);
#endif
static void send_reason(void);
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
static void handle_qSupported_command(const unsigned char *cmd, int len);
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
static esp_gdbstub_scratch_t s_scratch;
static esp_gdbstub_gdb_regfile_t *gdb_local_regfile = &s_scratch.regfile;
#if (CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME || CONFIG_ESP_GDBSTUB_SUPPORT_TASKS)
static bool command_name_matches(const char *pattern, const unsigned char *ucmd, int len);
#endif // (CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME || CONFIG_ESP_GDBSTUB_SUPPORT_TASKS)
static void send_reason(void);
static char gdb_packet(char *dest_buff, char *src_buff, int len);
esp_gdbstub_scratch_t s_scratch;
esp_gdbstub_gdb_regfile_t *gdb_local_regfile = &s_scratch.regfile;
/**
* @brief panic handler
@ -60,7 +70,7 @@ void esp_gdbstub_panic_handler(void *in_frame)
set_active_task(s_scratch.paniced_task_index);
}
}
#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
#endif /* CONFIG_ESP_GDBSTUB_SUPPORT_TASKS */
esp_gdbstub_target_init();
s_scratch.signal = esp_gdbstub_get_signal(frame);
@ -119,7 +129,7 @@ static inline void disable_all_wdts(void)
wdt1_context_enabled = wdt_hal_is_enabled(&wdt1_context);
rtc_wdt_ctx_enabled = wdt_hal_is_enabled(&rtc_wdt_ctx);
//Task WDT is the Main Watchdog Timer of Timer Group 0
/*Task WDT is the Main Watchdog Timer of Timer Group 0 */
if (true == wdt0_context_enabled) {
wdt_hal_write_protect_disable(&wdt0_context);
wdt_hal_disable(&wdt0_context);
@ -127,7 +137,7 @@ static inline void disable_all_wdts(void)
wdt_hal_write_protect_enable(&wdt0_context);
}
//Interupt WDT is the Main Watchdog Timer of Timer Group 1
/* Interupt WDT is the Main Watchdog Timer of Timer Group 1 */
if (true == wdt1_context_enabled) {
wdt_hal_write_protect_disable(&wdt1_context);
wdt_hal_disable(&wdt1_context);
@ -147,13 +157,13 @@ static inline void disable_all_wdts(void)
*/
static inline void enable_all_wdts(void)
{
//Task WDT is the Main Watchdog Timer of Timer Group 0
/* Task WDT is the Main Watchdog Timer of Timer Group 0 */
if (false == wdt0_context_enabled) {
wdt_hal_write_protect_disable(&wdt0_context);
wdt_hal_enable(&wdt0_context);
wdt_hal_write_protect_enable(&wdt0_context);
}
// Interupt WDT is the Main Watchdog Timer of Timer Group 1
/* Interupt WDT is the Main Watchdog Timer of Timer Group 1 */
if (false == wdt1_context_enabled) {
wdt_hal_write_protect_disable(&wdt1_context);
wdt_hal_enable(&wdt1_context);
@ -177,18 +187,50 @@ static inline void enable_all_wdts(void)
* @param curr_regs - actual registers frame
*
*/
static int bp_count = 0;
static int wp_count = 0;
static uint32_t bp_list[GDB_BP_SIZE] = {0};
static uint32_t wp_list[GDB_WP_SIZE] = {0};
static uint32_t wp_size[GDB_WP_SIZE] = {0};
static watchpoint_trigger_t wp_access[GDB_WP_SIZE] = {0};
static volatile bool step_in_progress = false;
static bool not_send_reason = false;
static bool process_gdb_kill = false;
static bool gdb_debug_int = false;
int getActiveTaskNum(void);
int __swrite(struct _reent *, void *, const char *, int);
int gdbstub__swrite(struct _reent *data1, void *data2, const char *buff, int len);
volatile esp_gdbstub_frame_t *temp_regs_frame;
void gdbstub_handle_uart_int(esp_gdbstub_frame_t *regs_frame)
{
// Disable all enabled WDT on enter
temp_regs_frame = regs_frame;
not_send_reason = step_in_progress;
if (step_in_progress == true) {
esp_gdbstub_send_str_packet("S05");
step_in_progress = false;
}
// process_gdb_kill = false;
bp_count = 0;
wp_count = 0;
/* Disable all enabled WDT on enter */
disable_all_wdts();
int doDebug = esp_gdbstub_getfifo();
s_scratch.signal = esp_gdbstub_get_signal(regs_frame);
if (doDebug) {
process_gdb_kill = false;
/* To enable console output in GDB, we replace the default stdout->_write function */
stdout->_write = gdbstub__swrite;
stderr->_write = gdbstub__swrite;
/* Stall other core until GDB exit */
esp_gdbstub_stall_other_cpus_start();
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
init_task_info();
#endif// CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
#endif/* CONFIG_ESP_GDBSTUB_SUPPORT_TASKS */
esp_gdbstub_frame_to_regfile(regs_frame, gdb_local_regfile);
send_reason();
while (true) {
@ -216,9 +258,92 @@ void gdbstub_handle_uart_int(esp_gdbstub_frame_t *regs_frame)
if (res == GDBSTUB_ST_CONT) {
break;
}
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
#endif /* CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME */
}
{
/* Resume other core */
if (step_in_progress == false) {
esp_gdbstub_stall_other_cpus_end();
}
}
}
esp_gdbstub_getfifo();
/* This is workaround for problem with 'next' command. */
if (process_gdb_kill == false) {
esp_gdbstub_send_str("OK");
} else {
/* We flush all data before exit from GDB.*/
esp_gdbstub_flush();
}
}
void gdbstub_handle_debug_int(esp_gdbstub_frame_t *regs_frame)
{
bp_count = 0;
wp_count = 0;
temp_regs_frame = regs_frame;
gdb_debug_int = true;
not_send_reason = step_in_progress;
if (step_in_progress == true) {
esp_gdbstub_clear_step();
esp_gdbstub_send_str_packet("S05");
step_in_progress = false;
}
int doDebug = esp_gdbstub_getfifo();
s_scratch.signal = 5; /* esp_gdbstub_get_db_signal(regs_frame); */
doDebug = 1;
if (doDebug) {
#if CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
s_scratch.current_task_index = getActiveTaskNum();
#endif
process_gdb_kill = false;
/* Stall other core until GDB exit */
esp_gdbstub_stall_other_cpus_start();
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
init_task_info();
#endif/* CONFIG_ESP_GDBSTUB_SUPPORT_TASKS */
esp_gdbstub_frame_to_regfile(regs_frame, gdb_local_regfile);
send_reason();
while (true) {
unsigned char *cmd;
size_t size;
int res = esp_gdbstub_read_command(&cmd, &size);
if (res == '-') {
send_reason();
continue;
}
if (res > 0) {
/* character received instead of a command */
continue;
}
if (res == -2) {
esp_gdbstub_send_str_packet("E01");
continue;
}
res = esp_gdbstub_handle_command(cmd, size);
if (res == -2) {
esp_gdbstub_send_str_packet(NULL);
}
if (res == GDBSTUB_ST_CONT) {
break;
}
}
{
/* Resume other core */
if (step_in_progress == false) {
esp_gdbstub_stall_other_cpus_end();
}
}
}
esp_gdbstub_getfifo();
if (process_gdb_kill == true) {
/* We flush all data before exit from GDB.*/
esp_gdbstub_flush();
}
gdb_debug_int = false;
}
intr_handle_t intr_handle_;
@ -231,8 +356,9 @@ extern void _xt_gdbstub_int(void * );
void esp_gdbstub_init(void)
{
esp_intr_alloc(ETS_UART0_INTR_SOURCE, 0, _xt_gdbstub_int, NULL, &intr_handle_);
esp_gdbstub_init_dports();
}
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
#endif /* CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME */
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
@ -291,9 +417,9 @@ static void handle_m_command(const unsigned char *cmd, int len)
static void handle_M_command(const unsigned char *cmd, int len)
{
intptr_t addr = (intptr_t) esp_gdbstub_gethex(&cmd, -1);
cmd++; // skip '.'
cmd++; /* skip '.' */
uint32_t size = esp_gdbstub_gethex(&cmd, -1);
cmd++; // skip ':'
cmd++; /* skip ':' */
if (esp_gdbstub_readmem(addr) < 0 || esp_gdbstub_readmem(addr + size - 1) < 0) {
esp_gdbstub_send_str_packet("E01");
@ -308,6 +434,210 @@ static void handle_M_command(const unsigned char *cmd, int len)
esp_gdbstub_send_end();
}
void update_breakpoints(void)
{
for (size_t i = 0; i < GDB_BP_SIZE; i++) {
if (bp_list[i] != 0) {
cpu_ll_set_breakpoint(i, (uint32_t)bp_list[i]);
} else {
cpu_hal_clear_breakpoint(i);
}
}
for (size_t i = 0; i < GDB_WP_SIZE; i++) {
if (wp_list[i] != 0) {
cpu_hal_set_watchpoint(i, (void *)wp_list[i], wp_size[i], wp_access[i]);
} else {
cpu_hal_clear_watchpoint(i);
}
}
}
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
/** Write breakpoint */
static void handle_Z0_command(const unsigned char *cmd, int len)
{
cmd++; /* skip 'Z' */
cmd++; /* skip '0' */
uint32_t addr = esp_gdbstub_gethex(&cmd, -1);
if (bp_count >= GDB_BP_SIZE) {
esp_gdbstub_send_str_packet("E02");
return;
}
bool add_bp = true;
/* Check if bp already exist */
for (size_t i = 0; i < GDB_BP_SIZE; i++) {
if (bp_list[i] == addr) {
add_bp = false;
break;
}
}
if (true == add_bp) {
for (size_t i = 0; i < GDB_BP_SIZE; i++) {
if (bp_list[i] == 0) {
bp_list[i] = (uint32_t)addr;
bp_count++;
break;
}
}
}
update_breakpoints();
esp_gdbstub_trigger_cpu();
esp_gdbstub_send_str_packet("OK");
}
/** Clear breakpoint */
static void handle_z0_command(const unsigned char *cmd, int len)
{
cmd++; /* skip 'z' */
cmd++; /* skip '0' */
uint32_t addr = esp_gdbstub_gethex(&cmd, -1);
for (size_t i = 0; i < GDB_BP_SIZE; i++) {
if (bp_list[i] == addr) {
bp_list[i] = 0;
bp_count--;
}
}
update_breakpoints();
esp_gdbstub_trigger_cpu();
esp_gdbstub_send_str_packet("OK");
}
/** Write watchpoints write*/
static void handle_Z2_command(const unsigned char *cmd, int len)
{
cmd++; /* skip 'Z' */
cmd++; /* skip '2' */
uint32_t addr = esp_gdbstub_gethex(&cmd, -1);
cmd++;
uint32_t size = esp_gdbstub_gethex(&cmd, -1);
if (wp_count >= GDB_WP_SIZE) {
esp_gdbstub_send_str_packet("E02");
return;
}
wp_access[wp_count] = WATCHPOINT_TRIGGER_ON_WO;
wp_size[wp_count] = size;
wp_list[wp_count++] = (uint32_t)addr;
update_breakpoints();
esp_gdbstub_trigger_cpu();
esp_gdbstub_send_str_packet("OK");
}
/** Write watchpoints read*/
static void handle_Z3_command(const unsigned char *cmd, int len)
{
cmd++; /* skip 'Z' */
cmd++; /* skip '3' */
uint32_t addr = esp_gdbstub_gethex(&cmd, -1);
cmd++;
uint32_t size = esp_gdbstub_gethex(&cmd, -1);
if (wp_count >= GDB_WP_SIZE) {
esp_gdbstub_send_str_packet("E02");
return;
}
wp_access[wp_count] = WATCHPOINT_TRIGGER_ON_RO;
wp_size[wp_count] = size;
wp_list[wp_count++] = (uint32_t)addr;
update_breakpoints();
esp_gdbstub_trigger_cpu();
esp_gdbstub_send_str_packet("OK");
}
/** Write watchpoints access*/
static void handle_Z4_command(const unsigned char *cmd, int len)
{
cmd++; /* skip 'Z' */
cmd++; /* skip '4' */
uint32_t addr = esp_gdbstub_gethex(&cmd, -1);
cmd++;
uint32_t size = esp_gdbstub_gethex(&cmd, -1);
if (wp_count >= GDB_WP_SIZE) {
esp_gdbstub_send_str_packet("E02");
return;
}
wp_access[wp_count] = WATCHPOINT_TRIGGER_ON_RW;
wp_size[wp_count] = size;
wp_list[wp_count++] = (uint32_t)addr;
update_breakpoints();
esp_gdbstub_trigger_cpu();
esp_gdbstub_send_str_packet("OK");
}
/** Clear watchpoint */
static void handle_zx_command(const unsigned char *cmd, int len)
{
cmd++; /* skip 'z' */
cmd++; /* skip 'x' */
uint32_t addr = esp_gdbstub_gethex(&cmd, -1);
for (size_t i = 0; i < GDB_WP_SIZE; i++) {
if (wp_list[i] == addr) {
wp_access[i] = 0;
wp_list[i] = 0;
}
}
update_breakpoints();
esp_gdbstub_trigger_cpu();
esp_gdbstub_send_str_packet("OK");
}
/** Step ... */
static void handle_S_command(const unsigned char *cmd, int len)
{
esp_gdbstub_send_str_packet("S05");
}
/** Step ... */
static void handle_s_command(const unsigned char *cmd, int len)
{
step_in_progress = true;
esp_gdbstub_do_step();
}
/** Step ... */
static void handle_C_command(const unsigned char *cmd, int len)
{
esp_gdbstub_send_str_packet("OK");
}
/** Set Register ... */
static void handle_P_command(const unsigned char *cmd, int len)
{
uint32_t reg_index = 0;
if (cmd[1] == '=') {
reg_index = esp_gdbstub_gethex(&cmd, 4);
cmd++;
} else if (cmd[2] == '=') {
reg_index = esp_gdbstub_gethex(&cmd, 8);
cmd++;
cmd++;
} else {
esp_gdbstub_send_str_packet("E02");
return;
}
uint32_t addr = esp_gdbstub_gethex(&cmd, -1);
/* The address comes with inverted byte order.*/
uint8_t *addr_ptr = (uint8_t *)&addr;
uint32_t p_address = 0;
uint8_t *p_addr_ptr = (uint8_t *)&p_address;
p_addr_ptr[3] = addr_ptr[0];
p_addr_ptr[2] = addr_ptr[1];
p_addr_ptr[1] = addr_ptr[2];
p_addr_ptr[0] = addr_ptr[3];
esp_gdbstub_set_register((esp_gdbstub_frame_t *)temp_regs_frame, reg_index, p_address);
/* Convert current regioster file to GDB*/
esp_gdbstub_frame_to_regfile((esp_gdbstub_frame_t *)temp_regs_frame, gdb_local_regfile);
/* Sen OK response*/
esp_gdbstub_send_str_packet("OK");
}
/** qSupported requests the communication with GUI
*/
static void handle_qSupported_command(const unsigned char *cmd, int len)
{
esp_gdbstub_send_start();
esp_gdbstub_send_str("qSupported:multiprocess+;swbreak-;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+");
esp_gdbstub_send_end();
}
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
/** Handle a command received from gdb */
int esp_gdbstub_handle_command(unsigned char *cmd, int len)
{
@ -326,21 +656,148 @@ int esp_gdbstub_handle_command(unsigned char *cmd, int len)
} else if (cmd[0] == '?') {
/* Reply with stop reason */
send_reason();
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
} else if (cmd[0] == 'Z') {
if (cmd[1] == '0') {
/* Write breakpoint */
handle_Z0_command(data, len - 1);
}
if (cmd[1] == '2') {
/* Write breakpoint */
handle_Z2_command(data, len - 1);
}
if (cmd[1] == '3') {
/* Write breakpoint */
handle_Z3_command(data, len - 1);
}
if (cmd[1] == '4') {
/* Write breakpoint */
handle_Z4_command(data, len - 1);
}
} else if (cmd[0] == 'z') {
/* Clear breakpoint*/
if (cmd[1] == '0') {
handle_z0_command(data, len - 1);
}
/* Clear breakpoint*/
if ((cmd[1] == '2') || (cmd[1] == '3') || (cmd[1] == '4')) {
handle_zx_command(data, len - 1);
}
} else if (cmd[0] == 'S') {
/* Step */
handle_S_command(data, len - 1);
} else if (cmd[0] == 'k') {
/* Kill GDB and continue without */
/* By exit from GDB we have to replcae stdout->_write back */
stdout->_write = __swrite;
stderr->_write = __swrite;
process_gdb_kill = true;
return GDBSTUB_ST_CONT;
} else if (cmd[0] == 's') {
/* Step and continue*/
handle_s_command(data, len - 1);
return GDBSTUB_ST_CONT;
} else if (cmd[0] == 'C') {
/* Just continue*/
handle_C_command(data, len - 1);
size_t size;
esp_gdbstub_read_command(&cmd, &size);
return GDBSTUB_ST_CONT;
} else if (cmd[0] == 'P') {
handle_P_command(data, len - 1);
} else if (cmd[0] == 'c') { //continue execution
return GDBSTUB_ST_CONT;
} else if (command_name_matches("qSupported", cmd, 10)) {
handle_qSupported_command(cmd, len);
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
#if CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
} else if (s_scratch.state != GDBSTUB_TASK_SUPPORT_DISABLED) {
return handle_task_commands(cmd, len);
#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
} else if (strncmp((char *)cmd, "vCont;c", 7) == 0 || cmd[0] == 'c') { //continue execution
return GDBSTUB_ST_CONT;
} else {
/* Unrecognized command */
return GDBSTUB_ST_ERR;
}
return GDBSTUB_ST_OK;
}
/**
* Replace standard __swrite function for GDB
*/
/* const int buff_len = 16; */
/* static char log_buffer[16*2 + 7]; */
int gdbstub__swrite(struct _reent *data1, void *data2, const char *buff, int len)
{
const int buff_len = 16;
char log_buffer[buff_len * 2 + 7];
char s_chsum = 'O';
char *sent_data = (char *)buff;
size_t remaining = len;
size_t send_pos = 0;
while (remaining > 0) {
size_t will_send = MIN(remaining, buff_len);
remaining -= will_send;
/* prepare and set 'will_send' number of bytes */
if (will_send > 0) {
log_buffer[0] = '$';
log_buffer[1] = 'O';
s_chsum = 'O';
s_chsum += gdb_packet(&log_buffer[2], &sent_data[send_pos], will_send);
sprintf(&log_buffer[will_send * 2 + 2], "#%2.2x\n", s_chsum);
__swrite(data1, data2, log_buffer, will_send * 2 + 6);
send_pos += buff_len;
}
}
return len;
}
/** @brief Convert to ASCI
* Function convert byte value to two ASCI carecters
*/
void gdb_get_asci_char(unsigned char data, char *buff)
{
const char *hex_chars = "0123456789abcdef";
buff[0] = hex_chars[(data >> 4) & 0x0f];
buff[1] = hex_chars[(data) & 0x0f];
}
/* Everything below is related to the support for listing FreeRTOS tasks as threads in GDB */
/** @brief Prepare GDB packet
* Function build GDB asci packet and return checksum
*
* Return checksum
*/
char gdb_packet(char *dest_buff, char *src_buff, int len)
{
char s_chsum = 0;
for (size_t i = 0; i < len; i++) {
gdb_get_asci_char(src_buff[i], &dest_buff[i * 2 + 0]);
}
for (size_t i = 0; i < len * 2; i++) {
s_chsum += dest_buff[i];
}
return s_chsum;
}
#if (CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME || CONFIG_ESP_GDBSTUB_SUPPORT_TASKS)
static bool command_name_matches(const char *pattern, const unsigned char *ucmd, int len)
{
const char *cmd = (const char *) ucmd;
const char *end = cmd + len;
for (; *pattern && cmd < end; ++cmd, ++pattern) {
if (*pattern == '?') {
continue;
}
if (*pattern != *cmd) {
return false;
}
}
return *pattern == 0 && (cmd == end || *cmd == ',');
}
#endif // (CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME || CONFIG_ESP_GDBSTUB_SUPPORT_TASKS)
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
/* Some terminology related to task/thread indices:
@ -386,6 +843,25 @@ static bool get_task_handle(size_t index, TaskHandle_t *handle)
return true;
}
static eTaskState get_task_state(size_t index)
{
eTaskState result = eReady;
TaskHandle_t handle;
get_task_handle(index, &handle);
if (gdb_debug_int == false) {
result = eTaskGetState(handle);
}
return result;
}
static int get_task_cpu_id(size_t index)
{
TaskHandle_t handle;
get_task_handle(index, &handle);
BaseType_t core_id = xTaskGetAffinity(handle);
return (int)core_id;
}
/** Get the index of the task running on the current CPU, and save the result */
static void find_paniced_task_index(void)
{
@ -455,6 +931,19 @@ static void handle_qC_command(const unsigned char *cmd, int len)
esp_gdbstub_send_end();
}
int getActiveTaskNum(void)
{
for (size_t i = 0; i < s_scratch.task_count; i++) {
{
eTaskState state = get_task_state(task_index_to_gdb_tid(i));
if (state == eRunning) {
return i;
}
}
}
return s_scratch.task_count;
}
/** T command checks if the task is alive.
* Since GDB isn't going to ask about the tasks which haven't been listed by q*ThreadInfo,
* and the state of tasks can not change (no stepping allowed), simply return "OK" here.
@ -510,27 +999,34 @@ static void handle_qThreadExtraInfo_command(const unsigned char *cmd, int len)
esp_gdbstub_send_str_as_hex((const char *)pcTaskGetName(handle));
esp_gdbstub_send_hex(' ', 8);
// Current version report only Suspended state
esp_gdbstub_send_str_as_hex("State: Suspended");
eTaskState state = get_task_state(task_index);
/* esp_gdbstub_send_str_as_hex("State: Suspended"); */
switch (state) {
case eRunning:
esp_gdbstub_send_str_as_hex("State: Running ");
esp_gdbstub_send_str_as_hex("@CPU - ");
esp_gdbstub_send_hex(get_task_cpu_id(task_index) + '0', 8);
break;
case eReady:
esp_gdbstub_send_str_as_hex("State: Ready");
break;
case eBlocked:
esp_gdbstub_send_str_as_hex("State: Blocked");
break;
case eSuspended:
esp_gdbstub_send_str_as_hex("State: Suspended");
break;
case eDeleted:
esp_gdbstub_send_str_as_hex("State: Deleted");
break;
default:
esp_gdbstub_send_str_as_hex("State: Invalid");
break;
}
esp_gdbstub_send_end();
}
bool command_name_matches(const char *pattern, const unsigned char *ucmd, int len)
{
const char *cmd = (const char *) ucmd;
const char *end = cmd + len;
for (; *pattern && cmd < end; ++cmd, ++pattern) {
if (*pattern == '?') {
continue;
}
if (*pattern != *cmd) {
return false;
}
}
return *pattern == 0 && (cmd == end || *cmd == ',');
}
/** Handle all the thread-related commands */
static int handle_task_commands(unsigned char *cmd, int len)
{
@ -553,7 +1049,7 @@ static int handle_task_commands(unsigned char *cmd, int len)
/* Unrecognized command */
return GDBSTUB_ST_ERR;
}
} else if (strncmp((char *)cmd, "vCont;c", 7) == 0 || cmd[0] == 'c') { //continue execution
} else if (strncmp((char *)cmd, "vCont;c", 7) == 0 || cmd[0] == 'c') { /*continue execution */
return GDBSTUB_ST_CONT;
} else {
/* Unrecognized command */
@ -562,4 +1058,4 @@ static int handle_task_commands(unsigned char *cmd, int len)
return GDBSTUB_ST_OK;
}
#endif // CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
#endif /* CONFIG_ESP_GDBSTUB_SUPPORT_TASKS */

View File

@ -1,16 +1,8 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
@ -86,6 +78,16 @@ typedef struct {
} esp_gdbstub_gdb_regfile_t;
// Amount of HW breakpoints used in GDB
#ifndef GDB_BP_SIZE
#define GDB_BP_SIZE 2
#endif // GDB_BP_SIZE
// Amount of HW watchpoints used in GDB
#ifndef GDB_WP_SIZE
#define GDB_WP_SIZE 2
#endif // GDB_WP_SIZE
#ifdef __cplusplus
}
#endif

View File

@ -1,18 +1,25 @@
#include "freertos/xtensa_rtos.h"
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// ------------------------------------------------
.section .iram1,"ax"
#include "freertos/xtensa_rtos.h"
.global gdbstub_handle_uart_int
.global _xt_gdbstub_int
.align 4
.section .iram1, "ax"
.global gdbstub_handle_uart_int
.global _xt_gdbstub_int
.align 4
_xt_gdbstub_int:
/* Allocate exception frame and save minimal context. */
mov a0, sp
addi sp, sp, -XT_STK_FRMSZ
s32i a0, sp, XT_STK_A1
s32i a0, sp, XT_STK_EXIT
s32i a0, sp, XT_STK_A0
#if XCHAL_HAVE_WINDOWED
s32e a0, sp, -12 /* for debug backtrace */
#endif
@ -20,8 +27,6 @@ _xt_gdbstub_int:
s32i a0, sp, XT_STK_PS
rsr a0, EPC_1 /* save interruptee's PC */
s32i a0, sp, XT_STK_PC
rsr a0, EXCSAVE_1 /* save interruptee's a0 */
s32i a0, sp, XT_STK_A0
#if XCHAL_HAVE_WINDOWED
s32e a0, sp, -16 /* for debug backtrace */
#endif
@ -34,7 +39,20 @@ _xt_gdbstub_int:
rsr a0, EXCVADDR
s32i a0, sp, XT_STK_EXCVADDR
mov a6,sp
/* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
rsr a0, EXCSAVE_1 /* save interruptee's a0 */
s32i a0, sp, XT_STK_A0
/* Save context pointer as input parameter */
rsr a6, excsave1
rsr a3, EPS
s32i a3, sp, XT_STK_PS // store PS to the ps place
movi a3, gdbstub_handle_uart_int
callx0 a3
l32i a0, sp, XT_STK_EXIT
addi sp, sp, XT_STK_FRMSZ
ret

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -10,6 +10,8 @@
#include "soc/soc_memory_layout.h"
#include "xtensa/config/specreg.h"
#include "sdkconfig.h"
#include "esp_ipc_isr.h"
#include "esp_private/crosscore_int.h"
#if !XCHAL_HAVE_WINDOWED
#warning "gdbstub_xtensa: revisit the implementation for Call0 ABI"
@ -122,3 +124,96 @@ int esp_gdbstub_get_signal(const esp_gdbstub_frame_t *frame)
}
return (int) exccause_to_signal[frame->exccause];
}
/** @brief Init dport for GDB
* Init dport for iterprocessor communications
* */
void esp_gdbstub_init_dports(void)
{
}
#if CONFIG_IDF_TARGET_ARCH_XTENSA && (!CONFIG_FREERTOS_UNICORE) && CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
static bool stall_started = false;
#endif
/** @brief GDB stall other CPU
* GDB stall other CPU
* */
void esp_gdbstub_stall_other_cpus_start()
{
#if CONFIG_IDF_TARGET_ARCH_XTENSA && (!CONFIG_FREERTOS_UNICORE) && CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
if (stall_started == false) {
esp_ipc_isr_stall_other_cpu();
stall_started = true;
}
#endif
}
/** @brief GDB end stall other CPU
* GDB end stall other CPU
* */
void esp_gdbstub_stall_other_cpus_end()
{
#if CONFIG_IDF_TARGET_ARCH_XTENSA && (!CONFIG_FREERTOS_UNICORE) && CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
if (stall_started == true) {
esp_ipc_isr_release_other_cpu();
stall_started = false;
}
#endif
}
/** @brief GDB clear step
* GDB clear step registers
* */
void esp_gdbstub_clear_step(void)
{
WSR(ICOUNT, 0);
WSR(ICOUNTLEVEL, 0);
}
/** @brief GDB do step
* GDB do one step
* */
void esp_gdbstub_do_step(void)
{
// We have gdbstub uart interrupt, and if we will call step, with ICOUNTLEVEL=2 or higher, from uart interrupt, the
// application will hang because it will try to step uart interrupt. That's why we have to set ICOUNTLEVEL=1
// If we will stop by the breakpoint inside interrupt, we will handle this interrupt with ICOUNTLEVEL=ps.intlevel+1
uint32_t level = s_scratch.regfile.ps;
level &= 0x7;
level += 1;
WSR(ICOUNTLEVEL, level);
WSR(ICOUNT, -2);
}
/** @brief GDB trigger other CPU
* GDB trigger other CPU
* */
void esp_gdbstub_trigger_cpu(void)
{
#if !CONFIG_FREERTOS_UNICORE
if (0 == cpu_hal_get_core_id()) {
esp_crosscore_int_send_gdb_call(1);
} else {
esp_crosscore_int_send_gdb_call(0);
}
#endif
}
/** @brief GDB set register in frame
* Set register in frame with address to value
*
* */
void esp_gdbstub_set_register(esp_gdbstub_frame_t *frame, uint32_t reg_index, uint32_t value)
{
switch (reg_index) {
case 0:
frame->pc = value;
break;
default:
(&frame->a0)[reg_index - 1] = value;
break;
}
}

View File

@ -0,0 +1,64 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <xtensa/coreasm.h>
#include <xtensa/corebits.h>
#include <xtensa/config/system.h>
#include "freertos/xtensa_context.h"
.section .iram1,"ax"
.global _xt_panic_gdbstub
.type _xt_panic_gdbstub,@function
.align 4
.literal_position
.align 4
_xt_panic_gdbstub:
/* Allocate exception frame and save minimal context. */
addi sp, sp, -XT_STK_FRMSZ
s32i a0, sp, XT_STK_EXIT
s32i a0, sp, XT_STK_A0
rsr a0, PS /* save interruptee's PS */
s32i a0, sp, XT_STK_PS
rsr a0, EPC_1 /* save interruptee's PC */
s32i a0, sp, XT_STK_PC
call0 _xt_context_save /* Save full context*/
addi a7, sp, XT_STK_FRMSZ
s32i a7, sp, XT_STK_A1
s32i a12, sp, XT_STK_A12
s32i a13, sp, XT_STK_A13
/* Save exc cause and vaddr into exception frame */
rsr a0, EXCCAUSE
s32i a0, sp, XT_STK_EXCCAUSE
rsr a0, EXCVADDR
s32i a0, sp, XT_STK_EXCVADDR
/* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
rsr a0, EXCSAVE_1 /* save interruptee's a0 */
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
wsr a0, PS
//Call gdbstub handler
rsr a0,(EPC + XCHAL_DEBUGLEVEL)
s32i a0, sp, XT_STK_PC
mov a6, sp
rsr a9, EPS_6
s32i a9, sp, XT_STK_PS // store PS to the ps place
movi a11, gdbstub_handle_debug_int
callx4 a11 /* Call interrupt handler */
l32i a0, sp, XT_STK_PC
wsr a0,(EPC + XCHAL_DEBUGLEVEL)
call0 _xt_context_restore /* Restore full context*/
l32i a12, sp, XT_STK_A12
l32i a13, sp, XT_STK_A13
l32i a0, sp, XT_STK_EXIT /* Restore return point*/
addi sp, sp, XT_STK_FRMSZ /* Restore SP*/
rfi 6 // Return from high-level interrupt

View File

@ -90,6 +90,4 @@ endif()
# [refactor-todo] requirement from the panic handler,
# need to introduce panic "event" concept to remove this dependency (IDF-2194)
if(CONFIG_ESP_SYSTEM_PANIC_GDBSTUB)
idf_component_optional_requires(PRIVATE esp_gdbstub)
endif()
idf_component_optional_requires(PRIVATE esp_gdbstub)

View File

@ -34,11 +34,10 @@ menu "ESP System Settings"
config ESP_SYSTEM_GDBSTUB_RUNTIME
bool "GDBStub at runtime"
select FREERTOS_UNICORE
select ESP_GDBSTUB_ENABLED
depends on !IDF_TARGET_ESP32C2
help
Invoke gdbstub on the serial port, allowing for gdb to attach to it and to do a debug on runtime.
This feature will switch system to single core mode.
endchoice
config ESP_SYSTEM_SINGLE_CORE_MODE

View File

@ -14,6 +14,10 @@
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h"
#if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
#include "esp_gdbstub.h"
#endif
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#include "soc/dport_reg.h"
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2
@ -22,6 +26,7 @@
#define REASON_YIELD BIT(0)
#define REASON_FREQ_SWITCH BIT(1)
#define REASON_GDB_CALL BIT(3)
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2 && !IDF_TARGET_ESP32C2
#define REASON_PRINT_BACKTRACE BIT(2)
@ -79,6 +84,11 @@ static void IRAM_ATTR esp_crosscore_isr(void *arg) {
* to allow DFS features without the extra latency of the ISR hook.
*/
}
#if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
if (my_reason_val & REASON_GDB_CALL) {
update_breakpoints();
}
#endif // !CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C2 // IDF-2986
if (my_reason_val & REASON_PRINT_BACKTRACE) {
esp_backtrace_print(100);
@ -141,6 +151,11 @@ void IRAM_ATTR esp_crosscore_int_send_freq_switch(int core_id)
esp_crosscore_int_send(core_id, REASON_FREQ_SWITCH);
}
void IRAM_ATTR esp_crosscore_int_send_gdb_call(int core_id)
{
esp_crosscore_int_send(core_id, REASON_GDB_CALL);
}
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2 && !IDF_TARGET_ESP32C2
void IRAM_ATTR esp_crosscore_int_send_print_backtrace(int core_id)
{

View File

@ -48,6 +48,7 @@ void esp_crosscore_int_send_yield(int core_id);
*/
void esp_crosscore_int_send_freq_switch(int core_id);
void esp_crosscore_int_send_gdb_call(int core_id);
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2 && !CONFIG_IDF_TARGET_ESP32C2
/**

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -68,7 +68,7 @@ void esp_startup_start_app_common(void)
esp_crosscore_int_init();
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
#if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME && !CONFIG_IDF_TARGET_ESP8684
esp_gdbstub_init();
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME

View File

@ -25,6 +25,8 @@ The default behaviour is to just exit the interrupt or call the panic handler on
_xt_debugexception:
#if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
s32i a0, sp, XT_STK_EXIT
#define XT_DEBUGCAUSE_DI (5)
getcoreid a0
#if (CONFIG_BTDM_CTRL_PINNED_TO_CORE == PRO_CPU_NUM)
@ -48,7 +50,11 @@ _xt_debugexception:
wsr a0,EPC_1
rsr a0,(EXCSAVE + XCHAL_DEBUGLEVEL)
wsr a0,EXCSAVE_1
#if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
J _xt_panic_gdbstub /* For gdbstub we make jump */
#else
call0 _xt_panic /* does not return */
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
rfi XCHAL_DEBUGLEVEL
#if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)

View File

@ -443,7 +443,7 @@ Debug Exception.
.global xt_debugexception
_DebugExceptionVector:
wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* preserve a0 */
call0 xt_debugexception /* load exception handler */
J xt_debugexception /* load exception handler */
.end literal_prefix

View File

@ -2,13 +2,14 @@
This example shows how to use gdbstub and it's functionality at runtime to debug an application with GDB.
With the gdbstub component it is possible to run GDB from IDF Monitor by pressing Ctrl+C and debug
the application using GDB. It is also possible to read/modify memory values, interrupt and continue the application.
the application using GDB. It is also possible to read/modify memory values, interrupt and continue
the application, set breakpoints, make steps and so on.
Upon exit from GDB, the application will continue to work in IDF Monitor as before.
## How to use example
### Hardware Required
he example can run on any commonly available ESP32 development board.
The example can run on any commonly available ESP32 development board.
There are two possible ways to execute gdbstub with GDB: from IDF Monitor and as standalone application.
gdbstub support ESP32, ESP32-S2 and ESP32-S3 chips.
@ -25,9 +26,6 @@ This selection switches gdbstub to runtime mode.
Depending on the project, following settings could be used:
-> Component Config -> GDB Stub -> ...
The user can enable or disable task list handling and define a maximum amount of tasks.
Note that gdbstub can now only be used when FreeRTOS is run on the first core only.
This setting is located here:
-> Component Config -> FreeRTOS -> Run FreeRTOS only on first core.
### Build and Flash
@ -56,15 +54,27 @@ The user can continue running the application in GDB by entering "continue" and
The user can check again that the application has worked by checking variable "print call_count".
The user can exit from GDB to continue seeing the trace from IDF Monitor by pressing "quit" and then "y".
The user will see in IDF Monitor that call_count and logging level have changed.
The user can add breakpoint to the label test_point2 by entering "break test_point2" and then enter "continue" or "c". The application will break at this line.
If user will continue again, the application will break at this line again.
Also, user can try to step application by entering "si".
A typical console output for such a scenario is shown below:
```
I (300) cpu_start: Starting scheduler on PRO CPU.
I (312) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
Hello GDB example!
I (307) gdbstub_example: INFO mode enabled. Call - 0. To enter GDB please press "Ctrl+C"
W (317) gdbstub_example: WARN mode enabled. Call - 0. To enter GDB please press "Ctrl+C"
I (1317) gdbstub_example: INFO mode enabled. Call - 1. To enter GDB please press "Ctrl+C"
W (1317) gdbstub_example: WARN mode enabled. Call - 1. To enter GDB please press "Ctrl+C"
To exit from the idf.py please use "Ctrl+]"
CPU 0: To enter GDB please press "Ctrl+C"
I (4317) gdbstub_example: INFO mode enabled. Task 0, Core ID 0, Call - 0.
W (4317) gdbstub_example: WARN mode enabled. Task 0, Core ID 0, Call - 0.
CPU 1: To enter GDB please press "Ctrl+C"
I (4327) gdbstub_example: INFO mode enabled. Task 1, Core ID 1, Call - 0.
W (4337) gdbstub_example: WARN mode enabled. Task 1, Core ID 1, Call - 0.
CPU 0: To enter GDB please press "Ctrl+C"
I (5137) gdbstub_example: INFO mode enabled. Task 0, Core ID 0, Call - 1.
W (5137) gdbstub_example: WARN mode enabled. Task 0, Core ID 0, Call - 1.
CPU 1: To enter GDB please press "Ctrl+C"
I (5157) gdbstub_example: INFO mode enabled. Task 1, Core ID 1, Call - 1.
W (5157) gdbstub_example: WARN mode enabled. Task 1, Core ID 1, Call - 1.
To exit from IDF monitor please use "Ctrl+]"
$T02#b6GNU gdb (crosstool-NG esp-2020r3) 8.1.0.20180627-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
@ -80,37 +90,71 @@ Find the GDB manual and other documentation resources online at:
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from c:\esp-idf\examples\system\gdbstub\build\gdbstub.elf...done.
Remote debugging using \\.\COM15
0x400dff0a in esp_pm_impl_waiti () at C:/esp-idf/components/esp_pm/pm_impl.c:533
533 asm("waiti 0");
(gdb) print call_count
Remote debugging using \\.\COM16
task4test (param=0x0) at ../main/gdbstub_main.c:41
41 asm(" nop;");
(gdb) print call_counts[0]
$1 = 2
(gdb) set call_count = 100
(gdb) print call_count
$2 = 100
(gdb) print call_counts[1]
$2 = 2
(gdb) set call_counts[0] = 100
(gdb) set call_counts[0] = 100(gdb) print call_counts[0]
$3 = 100
(gdb) print update_log_level
$3 = ESP_LOG_DEBUG
$4 = ESP_LOG_DEBUG
(gdb) set update_log_level = ESP_LOG_WARN
(gdb) print update_log_level
$4 = ESP_LOG_WARN
$5 = ESP_LOG_WARN
(gdb) c
Continuing.
CPU 0: To enter GDB please press "Ctrl+C"
W (5927) gdbstub_example: WARN mode enabled. Task 0, Core ID 0, Call - 100.
CPU 1: To enter GDB please press "Ctrl+C"
W (5927) gdbstub_example: WARN mode enabled. Task 1, Core ID 1, Call - 2.
CPU 0: To enter GDB please press "Ctrl+C"
W (5927) gdbstub_example: WARN mode enabled. Task 0, Core ID 0, Call - 101.
CPU 1: To enter GDB please press "Ctrl+C"
W (5927) gdbstub_example: WARN mode enabled. Task 1, Core ID 1, Call - 3.
CPU 0: To enter GDB please press "Ctrl+C"
W (5927) gdbstub_example: WARN mode enabled. Task 0, Core ID 0, Call - 102.
CPU 1: To enter GDB please press "Ctrl+C"
W (5927) gdbstub_example: WARN mode enabled. Task 1, Core ID 1, Call - 4.
Thread 1 received signal SIGINT, Interrupt.
task4test (param=0x0) at ../main/gdbstub_main.c:38
38 for (int i=0 ; i< 10000000; i++)
(gdb) break test_point2
Breakpoint 1 at 0x400d511d: file ../main/gdbstub_main.c, line 40.
(gdb) c
Continuing.
Thread 1 hit Breakpoint 1, task4test (param=0x1) at ../main/gdbstub_main.c:40
40 asm("test_point2: nop;");
(gdb) si
41 asm(" nop;");
(gdb) si
42 asm(" nop;");
(gdb) c
Continuing.
Thread 1 hit Breakpoint 1, task4test (param=0x1) at ../main/gdbstub_main.c:40
40 asm("test_point2: nop;");
(gdb) delete 1
(gdb) c
Continuing.
CPU 0: To enter GDB please press "Ctrl+C"
W (36077) gdbstub_example: WARN mode enabled. Task 0, Core ID 0, Call - 103.
CPU 1: To enter GDB please press "Ctrl+C"
W (36107) gdbstub_example: WARN mode enabled. Task 1, Core ID 1, Call - 5.
CPU 0: To enter GDB please press "Ctrl+C"
W (36917) gdbstub_example: WARN mode enabled. Task 0, Core ID 0, Call - 104.
CPU 1: To enter GDB please press "Ctrl+C"
W (36947) gdbstub_example: WARN mode enabled. Task 1, Core ID 1, Call - 6.
Thread 1 received signal SIGINT, Interrupt.
0x400dff0a in esp_pm_impl_waiti () at C:/esp-idf/components/esp_pm/pm_impl.c:533
533 asm("waiti 0");
(gdb) print call_count
$6 = 108
(gdb) quit
A debugging session is active.
Inferior 1 [Remote target] will be killed.
Quit anyway? (y or n) y
W (13977) gdbstub_example: WARN mode enabled. Call - 108. To enter GDB please press "Ctrl+C"
W (14977) gdbstub_example: WARN mode enabled. Call - 109. To enter GDB please press "Ctrl+C"
W (15977) gdbstub_example: WARN mode enabled. Call - 110. To enter GDB please press "Ctrl+C"
W (16977) gdbstub_example: WARN mode enabled. Call - 111. To enter GDB please press "Ctrl+C"
task4test (param=0x0) at ../main/gdbstub_main.c:38
38 for (int i=0 ; i< 10000000; i++)
(gdb)
```
To reproduce this scenario run the application by: idf.py -P PORT flash monitor
@ -121,7 +165,13 @@ Then:
4. Continue the application by typing in GDB command line "continue"
5. Interrupt application by pressing Ctrl+C
6. Check the value by typing in GDB command line "print call_count" or "print update_log_level"
7. Exit GDB by typing "quit" and then "y"
7. Continue the application by typing in GDB command line "continue"
8. Interrupt the application by pressing Ctrl+C
9. Add breakpoint by typing in GDB command line "break test_point2" or break 40 (break at line 40).
10. Continue the application by typing in GDB command line "continue"
11. After application stop at label "test_point2".
12. Make stepping by typing "si"
13. To exit from GDB to monitor type "exit" and press "y"
To exit from monitor please use Ctrl+]

View File

@ -14,26 +14,41 @@
#include "esp_log.h"
int call_count = 0;
static const char *TAG = "gdbstub_example";
esp_log_level_t log_level = ESP_LOG_DEBUG;
esp_log_level_t update_log_level = ESP_LOG_DEBUG;
int call_counts[4] = {0};
void task4test(void *param)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
int task_num = (int)param;
volatile int core = xPortGetCoreID();
while (1) {
core = xPortGetCoreID();
printf("CPU %i: To enter GDB please press \"Ctrl+C\"\n", core);
ESP_LOGD(TAG, "DEBUG mode enabled. Task %i, Core ID %i, Call - %i.", task_num, core, call_counts[task_num]);
ESP_LOGI(TAG, "INFO mode enabled. Task %i, Core ID %i, Call - %i.", task_num, core, call_counts[task_num]);
ESP_LOGW(TAG, "WARN mode enabled. Task %i, Core ID %i, Call - %i.", task_num, core, call_counts[task_num]++);
asm("test_point1: nop;");
for (int i = 0 ; i < 10000000; i++) {
asm("test_point2: nop;");
asm(" nop;");
asm(" nop;");
asm(" nop;");
}
log_level = update_log_level;
esp_log_level_set(TAG, log_level);
}
}
void app_main(void)
{
printf("Hello GDB example!\n");
call_count = 0;
vTaskDelay(1000 / portTICK_PERIOD_MS);
for (;;) {
ESP_LOGD(TAG, "DEBUG mode enabled. Call - %i. To enter GDB please press \"Ctrl+C\"", call_count);
ESP_LOGI(TAG, "INFO mode enabled. Call - %i. To enter GDB please press \"Ctrl+C\"", call_count);
ESP_LOGW(TAG, "WARN mode enabled. Call - %i. To enter GDB please press \"Ctrl+C\"", call_count++);
if (update_log_level != log_level) {
log_level = update_log_level;
esp_log_level_set(TAG, log_level);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
xTaskCreatePinnedToCore(task4test, "task 3", 4096, (void *)0, 10, NULL, 0);
xTaskCreatePinnedToCore(task4test, "task 4", 4096, (void *)1, 10, NULL, 1);
}

View File

@ -6,11 +6,6 @@ CONFIG_ESP_GDBSTUB_SUPPORT_TASKS=y
CONFIG_ESP_GDBSTUB_MAX_TASKS=32
# end of GDB Stub
#
# FreeRTOS
#
CONFIG_FREERTOS_UNICORE=y
#
# ESP System Settings
#
@ -18,5 +13,6 @@ CONFIG_FREERTOS_UNICORE=y
# CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT is not set
# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME=y
CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y
# CONFIG_ESP_INT_WDT is not set
# CONFIG_ESP_TASK_WDT is not set
# end of ESP System Settings

View File

@ -445,12 +445,7 @@ components/esp_gdbstub/esp32c3/gdbstub_target_config.h
components/esp_gdbstub/esp32h2/gdbstub_target_config.h
components/esp_gdbstub/esp32s2/gdbstub_target_config.h
components/esp_gdbstub/esp32s3/gdbstub_target_config.h
components/esp_gdbstub/esp_common/gdbstub_common.c
components/esp_gdbstub/include/esp_gdbstub.h
components/esp_gdbstub/private_include/esp_gdbstub_common.h
components/esp_gdbstub/riscv/esp_gdbstub_arch.h
components/esp_gdbstub/src/packet.c
components/esp_gdbstub/xtensa/esp_gdbstub_arch.h
components/esp_hid/include/esp_hid_common.h
components/esp_hid/include/esp_hidd.h
components/esp_hid/include/esp_hidd_gatts.h