Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sched/misc: add coredump support on assert #9369

Merged
merged 3 commits into from May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions boards/Kconfig
Expand Up @@ -4034,6 +4034,30 @@ config BOARD_CRASHDUMP
"machine state" in a place where on the next reset can write it
to more sophisticated storage in a sane operating environment.

config BOARD_COREDUMP
bool "Enable Core Dump after assert"
default n
depends on ELF_COREDUMP
---help---
Enable to support for the dump core information after assert.

if BOARD_COREDUMP

config BOARD_COREDUMP_FULL
bool "Core Dump all thread registers and stacks"
default y
---help---
Enable to support for the dump all task registers and stacks.

config BOARD_COREDUMP_COMPRESSION
bool "Enable Core Dump compression"
default y
select LIBC_LZF
---help---
Enable LZF compression algorithm for core dump content

endif # BOARD_COREDUMP

config BOARD_ENTROPY_POOL
bool "Enable Board level storing of entropy pool structure"
default n
Expand Down
70 changes: 70 additions & 0 deletions boards/arm/imx6/sabre-6quad/configs/coredump/defconfig
@@ -0,0 +1,70 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
CONFIG_ARCH="arm"
CONFIG_ARCH_BOARD="sabre-6quad"
CONFIG_ARCH_BOARD_SABRE_6QUAD=y
CONFIG_ARCH_BUTTONS=y
CONFIG_ARCH_CHIP="imx6"
CONFIG_ARCH_CHIP_IMX6=y
CONFIG_ARCH_CHIP_IMX6_6QUAD=y
CONFIG_ARCH_INTERRUPTSTACK=2048
CONFIG_ARCH_IRQBUTTONS=y
CONFIG_ARCH_LOWVECTORS=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARD_COREDUMP=y
CONFIG_BOARD_LOOPSPERMSEC=99369
CONFIG_BOOT_RUNFROMSDRAM=y
CONFIG_BUILTIN=y
CONFIG_DEBUG_ASSERTIONS=y
CONFIG_DEBUG_FEATURES=y
CONFIG_DEBUG_FULLOPT=y
CONFIG_DEBUG_SYMBOLS=y
CONFIG_DEV_ZERO=y
CONFIG_ELF=y
CONFIG_ELF_COREDUMP=y
CONFIG_EXAMPLES_HELLO=y
CONFIG_EXPERIMENTAL=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_IMX6_UART1=y
CONFIG_IMX_DDR_SIZE=1073741824
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=1073741824
CONFIG_RAM_START=0x10000000
CONFIG_RAM_VSTART=0x10000000
CONFIG_RAW_BINARY=y
CONFIG_READLINE_CMD_HISTORY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_HPWORKPRIORITY=192
CONFIG_SMP=y
CONFIG_STACK_COLORATION=y
CONFIG_START_MONTH=3
CONFIG_START_YEAR=2016
CONFIG_SYMTAB_ORDEREDBYNAME=y
CONFIG_SYSLOG_BUFFER=y
CONFIG_SYSLOG_CONSOLE=y
CONFIG_SYSLOG_INTBUFFER=y
CONFIG_SYSLOG_PROCESSID=y
CONFIG_SYSTEM_COREDUMP=y
CONFIG_SYSTEM_NSH=y
CONFIG_SYSTEM_SYSTEM=y
CONFIG_SYSTEM_TASKSET=y
CONFIG_TESTING_GETPRIME=y
CONFIG_TESTING_OSTEST=y
CONFIG_TESTING_OSTEST_FPUTESTDISABLE=y
CONFIG_TESTING_SMP=y
CONFIG_UART1_SERIAL_CONSOLE=y
66 changes: 66 additions & 0 deletions sched/misc/assert.c
Expand Up @@ -25,6 +25,7 @@
#include <nuttx/config.h>

#include <nuttx/arch.h>
#include <nuttx/binfmt/binfmt.h>
#include <nuttx/board.h>
#include <nuttx/irq.h>
#include <nuttx/tls.h>
Expand Down Expand Up @@ -71,6 +72,14 @@

static uint8_t g_last_regs[XCPTCONTEXT_SIZE];

#ifdef CONFIG_BOARD_COREDUMP
static struct lib_syslogstream_s g_syslogstream;
static struct lib_hexdumpstream_s g_hexstream;
# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
static struct lib_lzfoutstream_s g_lzfstream;
# endif
#endif

static FAR const char *g_policy[4] =
{
"FIFO", "RR", "SPORADIC"
Expand Down Expand Up @@ -459,6 +468,53 @@ static void show_tasks(void)
#endif
}

/****************************************************************************
* Name: dump_core
****************************************************************************/

#ifdef CONFIG_BOARD_COREDUMP
static void dump_core(pid_t pid)
{
FAR void *stream;
int logmask;

logmask = setlogmask(LOG_ALERT);

_alert("Start coredump:\n");

/* Initialize hex output stream */

lib_syslogstream(&g_syslogstream, LOG_EMERG);

stream = &g_syslogstream;

lib_hexdumpstream(&g_hexstream, stream);

stream = &g_hexstream;

# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION

/* Initialize LZF compression stream */

lib_lzfoutstream(&g_lzfstream, stream);
stream = &g_lzfstream;

# endif

/* Do core dump */

core_dump(NULL, stream, pid);

# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
_alert("Finish coredump (Compression Enabled).\n");
# else
_alert("Finish coredump.\n");
# endif

setlogmask(logmask);
}
#endif

/****************************************************************************
* Public Functions
****************************************************************************/
Expand Down Expand Up @@ -550,6 +606,16 @@ void _assert(FAR const char *filename, int linenum,

#ifdef CONFIG_BOARD_CRASHDUMP
board_crashdump(up_getsp(), rtcb, filename, linenum, msg);

#elif defined(CONFIG_BOARD_COREDUMP)
/* Dump core information */

# ifdef CONFIG_BOARD_COREDUMP_FULL
dump_core(INVALID_PROCESS_ID);
# else
dump_core(rtcb->pid);
# endif

#endif

/* Flush any buffered SYSLOG data */
Expand Down
118 changes: 118 additions & 0 deletions tools/coredump.py
@@ -0,0 +1,118 @@
#!/usr/bin/env python3
############################################################################
# tools/coredump.py
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you 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.
#
############################################################################

import argparse
import binascii
import os
import struct
import sys

import lzf


def decompress(lzffile, outfile):
chunk_number = 1

while True:
prefix = lzffile.read(2)

if len(prefix) == 0:
break
elif prefix != b"ZV":
break

typ = lzffile.read(1)
clen = struct.unpack(">H", lzffile.read(2))[0]

if typ == b"\x00":
chunk = lzffile.read(clen)
elif typ == b"\x01":
uncompressed_len = struct.unpack(">H", lzffile.read(2))[0]
cdata = lzffile.read(clen)
chunk = lzf.decompress(cdata, uncompressed_len)
else:
return

outfile.write(chunk)
chunk_number += 1


def unhexlify(infile, outfile):
for line in infile.readlines():
line = line.strip()
if line == "":
break
index = line.rfind(" ")
if index > 0:
line = line[index + 1 :]

outfile.write(binascii.unhexlify(line))


def parse_args():
global args
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
allow_abbrev=False,
)
parser.add_argument("input")
parser.add_argument("-o", "--output", help="Output file in hex.")
args = parser.parse_args()


def main():
parse_args()
if not os.path.isfile(args.input):
sys.exit(1)

tmp = os.path.splitext(args.input)[0] + ".tmp"

if args.output is None:
args.output = os.path.splitext(args.input)[0] + ".core"

infile = open(args.input, "r")
tmpfile = open(tmp, "wb+")

unhexlify(infile, tmpfile)

infile.close()

tmpfile.seek(0, 0)

lzfhdr = tmpfile.read(2)

if lzfhdr == b"ZV":
outfile = open(args.output, "wb")
tmpfile.seek(0, 0)
decompress(tmpfile, outfile)
tmpfile.close()
outfile.close()
os.unlink(tmp)
else:
tmpfile.rename(args.output)
tmpfile.close()

print("Core file conversion completed: " + args.output)


if __name__ == "__main__":
main()