kernel: Add OpenOCD support

In order for OpenOCD to have a high-level view of an RTOS, it uses the
GDB protocol to obtain symbols from the system.

The GDB protocol, however, does not allow obtaining fields from
structures directly, and hardcoding offsets is not only brittle (due to
possibly different architectures or changes in the code), it's also
infeasible considering Zephyr is highly-configurable and parts of key
structs can be compiled in or out.

Export an array with offsets for these key structs. Also add a version
element in that array to allow changes in those structs.

Change-Id: I83bcfa0a7bd57d85582e5ec6efe70e1cceb1fc51
Signed-off-by: Leandro Pereira <leandro.pereira@intel.com>
This commit is contained in:
Leandro Pereira 2017-02-01 10:21:21 -08:00 committed by Anas Nashif
commit 570634a259
9 changed files with 102 additions and 0 deletions

View file

@ -71,6 +71,8 @@ SECTIONS {
KEEP(*(.exc_vector_table))
KEEP(*(".exc_vector_table.*"))
KEEP(*(.openocd_dbg))
KEEP(*(".openocd_dbg.*"))
KEEP(*(IRQ_VECTOR_TABLE))

View file

@ -82,6 +82,9 @@ SECTIONS
KEEP(*(IRQ_VECTOR_TABLE))
KEEP(*(.openocd_dbg))
KEEP(*(".openocd_dbg.*"))
/* Kinetis has to write 16 bytes at 0x400 */
SKIP_TO_KINETIS_FLASH_CONFIG
KEEP(*(.kinetis_flash_config))

View file

@ -107,6 +107,8 @@ SECTIONS
*(.text)
*(".text.*")
*(.gnu.linkonce.t.*)
KEEP(*(.openocd_dbg))
KEEP(*(".openocd_dbg.*"))
} GROUP_LINK_IN(ROMABLE_REGION)
_image_text_end = .;

View file

@ -81,6 +81,9 @@ SECTIONS
/* sections for IRQ100-999 */
KEEP(*(SORT(.gnu.linkonce.isr_irq[0-9][0-9][0-9])))
KEEP(*(.openocd_debug))
KEEP(*(".openocd_debug.*"))
_image_text_start = .;
*(.text)
*(".text.*")

View file

@ -60,6 +60,9 @@ SECTIONS
{
. = ALIGN(4);
KEEP(*(.openocd_dbg))
KEEP(*(".openocd_dbg.*"))
_image_text_start = .;
*(.text)
*(".text.*")

View file

@ -76,6 +76,8 @@ SECTIONS
*(.init)
*(.fini)
*(.eini)
KEEP(*(.openocd_dbg))
KEEP(*(".openocd_dbg.*"))
KEXEC_PGALIGN_PAD(MMU_PAGE_SIZE)
} GROUP_LINK_IN(ROMABLE_REGION)

View file

@ -115,3 +115,17 @@ config GDB_SERVER_BOOTLOADER
depends on GDB_SERVER
help
This option enables the bootloader mode of the GDB Server.
#
# Miscellaneous debugging options
#
config OPENOCD_SUPPORT
bool
prompt "OpenOCD support [EXPERIMENTAL]"
default n
select THREAD_MONITOR
help
This option exports an array of offsets to kernel structs, used by
OpenOCD to determine the state of running threads. (This option
selects CONFIG_THREAD_MONITOR, so all of its caveats are implied.)

View file

@ -4,3 +4,9 @@ CFLAGS_gdb_server.o =-I$(srctree)/include/drivers
obj-y =
obj-$(CONFIG_MEM_SAFE_CHECK_BOUNDARIES) += mem_safe_check_boundaries.o
obj-$(CONFIG_GDB_SERVER) += gdb_server.o
ifeq ($(CONFIG_OPENOCD_SUPPORT),y)
lib-y += openocd.o
ldflags-y += --undefined=_kernel_openocd_size_t_size
ldflags-y += --undefined=_kernel_openocd_offsets
endif

67
subsys/debug/openocd.c Normal file
View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel_structs.h>
#if defined(CONFIG_OPENOCD_SUPPORT) && defined(CONFIG_THREAD_MONITOR)
enum {
OPENOCD_OFFSET_VERSION,
OPENOCD_OFFSET_K_CURR_THREAD,
OPENOCD_OFFSET_K_THREADS,
OPENOCD_OFFSET_T_ENTRY,
OPENOCD_OFFSET_T_NEXT_THREAD,
OPENOCD_OFFSET_T_STATE,
OPENOCD_OFFSET_T_USER_OPTIONS,
OPENOCD_OFFSET_T_PRIO,
OPENOCD_OFFSET_T_STACK_PTR,
};
/* Forward-compatibility notes: 1) Increment OPENOCD_OFFSET_VERSION element
* each time an offset is added to this table. 2) Only append items to this
* table; otherwise, OpenOCD versions that expects version 0 will read garbage
* values.
*/
__attribute__((used, section(".openocd_dbg")))
size_t _kernel_openocd_offsets[] = {
/* Version 0 starts */
[OPENOCD_OFFSET_VERSION] = 0,
[OPENOCD_OFFSET_K_CURR_THREAD] = offsetof(struct _kernel, current),
[OPENOCD_OFFSET_K_THREADS] = offsetof(struct _kernel, threads),
[OPENOCD_OFFSET_T_ENTRY] = offsetof(struct k_thread, entry),
[OPENOCD_OFFSET_T_NEXT_THREAD] = offsetof(struct k_thread, next_thread),
[OPENOCD_OFFSET_T_STATE] = offsetof(struct _thread_base, thread_state),
[OPENOCD_OFFSET_T_USER_OPTIONS] = offsetof(struct _thread_base,
user_options),
[OPENOCD_OFFSET_T_PRIO] = offsetof(struct _thread_base, prio),
#if defined(CONFIG_ARM)
[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
callee_saved.psp),
#elif defined(CONFIG_ARC)
[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
callee_saved.sp),
#elif defined(CONFIG_X86)
[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
callee_saved.esp),
#elif defined(CONFIG_NIOS2)
[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
callee_saved.sp),
#elif defined(CONFIG_RISCV32)
[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
callee_saved.sp),
#else
/* Use 0xffffffff as a special value so that OpenOCD knows that
* obtaining the stack pointer is not possible on this particular
* architecture.
*/
#warning Please define OPENOCD_OFFSET_T_STACK_PTR for this architecture
[OPENOCD_OFFSET_T_STACK_PTR] = 0xffffffff,
#endif
/* Version 0 ends */
};
__attribute__((used, section(".openocd_dbg")))
uint8_t _kernel_openocd_size_t_size = (uint8_t)sizeof(size_t);
#endif