coredump: Add config for capturing thread data in core dump
Update core dump file format to support a new section which contains metadata about threads necessary for debugging. Define configs to capture that metadata and include it in the dumps when enabled. Update documentation to reflect the changes. Signed-off-by: Mark Holden <mholden@meta.com>
This commit is contained in:
parent
9bd0a3f05b
commit
45684a598d
4 changed files with 111 additions and 4 deletions
|
@ -30,6 +30,13 @@ Here are the choices regarding memory dump:
|
||||||
walking the stack in the debugger. Use this only if absolute minimum of data
|
walking the stack in the debugger. Use this only if absolute minimum of data
|
||||||
dump is desired.
|
dump is desired.
|
||||||
|
|
||||||
|
* ``DEBUG_COREDUMP_MEMORY_DUMP_THREADS``: Dumps the thread struct and stack of all
|
||||||
|
threads and all data required to debug threads.
|
||||||
|
|
||||||
|
* ``DEBUG_COREDUMP_MEMORY_DUMP_LINKER_RAM``: Dumps the memory region between
|
||||||
|
_image_ram_start[] and _image_ram_end[]. This includes at least data, noinit,
|
||||||
|
and BSS sections. This is the default.
|
||||||
|
|
||||||
Additional memory can be included in a dump (even with the "DEBUG_COREDUMP_MEMORY_DUMP_MIN"
|
Additional memory can be included in a dump (even with the "DEBUG_COREDUMP_MEMORY_DUMP_MIN"
|
||||||
config selected) through one or more :ref:`coredump devices <coredump_device_api>`
|
config selected) through one or more :ref:`coredump devices <coredump_device_api>`
|
||||||
|
|
||||||
|
@ -244,7 +251,8 @@ File Format
|
||||||
***********
|
***********
|
||||||
|
|
||||||
The core dump binary file consists of one file header, one
|
The core dump binary file consists of one file header, one
|
||||||
architecture-specific block, and multiple memory blocks. All numbers in
|
architecture-specific block, zero or one threads metadata block(s),
|
||||||
|
and multiple memory blocks. All numbers in
|
||||||
the headers below are little endian.
|
the headers below are little endian.
|
||||||
|
|
||||||
File Header
|
File Header
|
||||||
|
@ -315,6 +323,36 @@ to the target architecture (e.g. CPU registers)
|
||||||
- ``uint8_t[]``
|
- ``uint8_t[]``
|
||||||
- Contains target architecture specific data.
|
- Contains target architecture specific data.
|
||||||
|
|
||||||
|
Threads Metadata Block
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
The threads metadata block contains the byte stream of data necessary
|
||||||
|
for debugging threads.
|
||||||
|
|
||||||
|
.. list-table:: Threads Metadata Block
|
||||||
|
:widths: 2 1 7
|
||||||
|
:header-rows: 1
|
||||||
|
|
||||||
|
* - Field
|
||||||
|
- Data Type
|
||||||
|
- Description
|
||||||
|
* - ID
|
||||||
|
- ``char``
|
||||||
|
- ``T`` to indicate this is a threads metadata block.
|
||||||
|
* - Header version
|
||||||
|
- ``uint16_t``
|
||||||
|
- Identify the version of the header. This needs to be incremented
|
||||||
|
whenever the header struct is modified. This allows parser to
|
||||||
|
reject older header versions so it will not incorrectly parse
|
||||||
|
the header.
|
||||||
|
* - Number of bytes
|
||||||
|
- ``uint16_t``
|
||||||
|
- Number of bytes following the header which contains the byte stream
|
||||||
|
for target data.
|
||||||
|
* - Byte stream
|
||||||
|
- ``uint8_t[]``
|
||||||
|
- Contains data necessary for debugging threads.
|
||||||
|
|
||||||
Memory Block
|
Memory Block
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
|
@ -142,10 +142,13 @@ struct coredump_cmd_copy_arg {
|
||||||
#include <zephyr/arch/cpu.h>
|
#include <zephyr/arch/cpu.h>
|
||||||
#include <zephyr/sys/byteorder.h>
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
|
||||||
#define COREDUMP_HDR_VER 1
|
#define COREDUMP_HDR_VER 2
|
||||||
|
|
||||||
#define COREDUMP_ARCH_HDR_ID 'A'
|
#define COREDUMP_ARCH_HDR_ID 'A'
|
||||||
|
|
||||||
|
#define THREADS_META_HDR_ID 'T'
|
||||||
|
#define THREADS_META_HDR_VER 1
|
||||||
|
|
||||||
#define COREDUMP_MEM_HDR_ID 'M'
|
#define COREDUMP_MEM_HDR_ID 'M'
|
||||||
#define COREDUMP_MEM_HDR_VER 1
|
#define COREDUMP_MEM_HDR_VER 1
|
||||||
|
|
||||||
|
@ -192,6 +195,18 @@ struct coredump_arch_hdr_t {
|
||||||
uint16_t num_bytes;
|
uint16_t num_bytes;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/* Threads metadata header */
|
||||||
|
struct coredump_threads_meta_hdr_t {
|
||||||
|
/* THREADS_META_HDR_ID */
|
||||||
|
char id;
|
||||||
|
|
||||||
|
/* Header version */
|
||||||
|
uint16_t hdr_version;
|
||||||
|
|
||||||
|
/* Number of bytes in this block (excluding header) */
|
||||||
|
uint16_t num_bytes;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
/* Memory block header */
|
/* Memory block header */
|
||||||
struct coredump_mem_hdr_t {
|
struct coredump_mem_hdr_t {
|
||||||
/* COREDUMP_MEM_HDR_ID */
|
/* COREDUMP_MEM_HDR_ID */
|
||||||
|
|
|
@ -58,6 +58,15 @@ config DEBUG_COREDUMP_MEMORY_DUMP_MIN
|
||||||
Don't use this unless you want absolutely
|
Don't use this unless you want absolutely
|
||||||
minimum core dump.
|
minimum core dump.
|
||||||
|
|
||||||
|
config DEBUG_COREDUMP_MEMORY_DUMP_THREADS
|
||||||
|
bool "Threads"
|
||||||
|
select THREAD_STACK_INFO
|
||||||
|
select DEBUG_THREAD_INFO
|
||||||
|
select DEBUG_COREDUMP_THREADS_METADATA
|
||||||
|
help
|
||||||
|
Dumps the thread struct and stack of all
|
||||||
|
threads and all data required to debug threads.
|
||||||
|
|
||||||
config DEBUG_COREDUMP_MEMORY_DUMP_LINKER_RAM
|
config DEBUG_COREDUMP_MEMORY_DUMP_LINKER_RAM
|
||||||
bool "RAM defined by linker section"
|
bool "RAM defined by linker section"
|
||||||
help
|
help
|
||||||
|
@ -87,4 +96,11 @@ config DEBUG_COREDUMP_SHELL
|
||||||
help
|
help
|
||||||
This shell provides access to coredump and its backends.
|
This shell provides access to coredump and its backends.
|
||||||
|
|
||||||
|
config DEBUG_COREDUMP_THREADS_METADATA
|
||||||
|
bool "Threads metadata"
|
||||||
|
select DEBUG_THREAD_INFO
|
||||||
|
help
|
||||||
|
Core dump will contain the threads metadata section containing
|
||||||
|
any necessary data to enable debugging threads
|
||||||
|
|
||||||
endif # DEBUG_COREDUMP
|
endif # DEBUG_COREDUMP
|
||||||
|
|
|
@ -60,7 +60,6 @@ static void dump_header(unsigned int reason)
|
||||||
|
|
||||||
static void dump_thread(struct k_thread *thread)
|
static void dump_thread(struct k_thread *thread)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN
|
|
||||||
uintptr_t end_addr;
|
uintptr_t end_addr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -80,7 +79,6 @@ static void dump_thread(struct k_thread *thread)
|
||||||
end_addr = thread->stack_info.start + thread->stack_info.size;
|
end_addr = thread->stack_info.start + thread->stack_info.size;
|
||||||
|
|
||||||
coredump_memory_dump(thread->stack_info.start, end_addr);
|
coredump_memory_dump(thread->stack_info.start, end_addr);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_COREDUMP_DEVICE)
|
#if defined(CONFIG_COREDUMP_DEVICE)
|
||||||
|
@ -111,12 +109,46 @@ void process_memory_region_list(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_THREADS
|
||||||
|
/*
|
||||||
|
* Content of _kernel.threads not being modified during dump
|
||||||
|
* capture so no need to lock z_thread_monitor_lock.
|
||||||
|
*/
|
||||||
|
struct k_thread *current;
|
||||||
|
|
||||||
|
for (current = _kernel.threads; current; current = current->next_thread) {
|
||||||
|
dump_thread(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also add interrupt stack, in case error occurred in an interrupt */
|
||||||
|
char *irq_stack = _kernel.cpus[0].irq_stack;
|
||||||
|
uintptr_t start_addr = POINTER_TO_UINT(irq_stack) - CONFIG_ISR_STACK_SIZE;
|
||||||
|
|
||||||
|
coredump_memory_dump(start_addr, POINTER_TO_UINT(irq_stack));
|
||||||
|
#endif /* CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_THREADS */
|
||||||
|
|
||||||
#if defined(CONFIG_COREDUMP_DEVICE)
|
#if defined(CONFIG_COREDUMP_DEVICE)
|
||||||
#define MY_FN(inst) process_coredump_dev_memory(DEVICE_DT_INST_GET(inst));
|
#define MY_FN(inst) process_coredump_dev_memory(DEVICE_DT_INST_GET(inst));
|
||||||
DT_INST_FOREACH_STATUS_OKAY(MY_FN)
|
DT_INST_FOREACH_STATUS_OKAY(MY_FN)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_COREDUMP_THREADS_METADATA
|
||||||
|
static void dump_threads_metadata(void)
|
||||||
|
{
|
||||||
|
struct coredump_threads_meta_hdr_t hdr = {
|
||||||
|
.id = THREADS_META_HDR_ID,
|
||||||
|
.hdr_version = THREADS_META_HDR_VER,
|
||||||
|
.num_bytes = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
hdr.num_bytes += sizeof(_kernel);
|
||||||
|
|
||||||
|
coredump_buffer_output((uint8_t *)&hdr, sizeof(hdr));
|
||||||
|
coredump_buffer_output((uint8_t *)&_kernel, sizeof(_kernel));
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_DEBUG_COREDUMP_THREADS_METADATA */
|
||||||
|
|
||||||
void coredump(unsigned int reason, const struct arch_esf *esf,
|
void coredump(unsigned int reason, const struct arch_esf *esf,
|
||||||
struct k_thread *thread)
|
struct k_thread *thread)
|
||||||
{
|
{
|
||||||
|
@ -128,8 +160,14 @@ void coredump(unsigned int reason, const struct arch_esf *esf,
|
||||||
arch_coredump_info_dump(esf);
|
arch_coredump_info_dump(esf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_COREDUMP_THREADS_METADATA
|
||||||
|
dump_threads_metadata();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (thread != NULL) {
|
if (thread != NULL) {
|
||||||
|
#ifdef CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN
|
||||||
dump_thread(thread);
|
dump_thread(thread);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
process_memory_region_list();
|
process_memory_region_list();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue