1 /*
2  * Copyright (c) 2020 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <zephyr/sys/util.h>
9 
10 #include <zephyr/debug/coredump.h>
11 #include "coredump_internal.h"
12 
13 #include <zephyr/logging/log.h>
14 #include <zephyr/logging/log_ctrl.h>
15 LOG_MODULE_REGISTER(coredump, CONFIG_KERNEL_LOG_LEVEL);
16 
17 /* Length of buffer of printable size */
18 #define LOG_BUF_SZ		64
19 
20 /* Length of buffer of printable size plus null character */
21 #define LOG_BUF_SZ_RAW		(LOG_BUF_SZ + 1)
22 
23 /* Log Buffer */
24 static char log_buf[LOG_BUF_SZ_RAW];
25 
26 static int error;
27 
coredump_logging_backend_start(void)28 static void coredump_logging_backend_start(void)
29 {
30 	/* Reset error */
31 	error = 0;
32 
33 	while (LOG_PROCESS()) {
34 		;
35 	}
36 
37 	LOG_PANIC();
38 	LOG_ERR(COREDUMP_PREFIX_STR COREDUMP_BEGIN_STR);
39 }
40 
coredump_logging_backend_end(void)41 static void coredump_logging_backend_end(void)
42 {
43 	if (error != 0) {
44 		LOG_ERR(COREDUMP_PREFIX_STR COREDUMP_ERROR_STR);
45 	}
46 
47 	LOG_ERR(COREDUMP_PREFIX_STR COREDUMP_END_STR);
48 }
49 
coredump_logging_backend_buffer_output(uint8_t * buf,size_t buflen)50 static void coredump_logging_backend_buffer_output(uint8_t *buf, size_t buflen)
51 {
52 	uint8_t log_ptr = 0;
53 	size_t remaining = buflen;
54 	size_t i = 0;
55 
56 	if ((buf == NULL) || (buflen == 0)) {
57 		error = -EINVAL;
58 		remaining = 0;
59 	}
60 
61 	while (remaining > 0) {
62 		if (hex2char(buf[i] >> 4, &log_buf[log_ptr]) < 0) {
63 			error = -EINVAL;
64 			break;
65 		}
66 		log_ptr++;
67 
68 		if (hex2char(buf[i] & 0xf, &log_buf[log_ptr]) < 0) {
69 			error = -EINVAL;
70 			break;
71 		}
72 		log_ptr++;
73 
74 		i++;
75 		remaining--;
76 
77 		if ((log_ptr >= LOG_BUF_SZ) || (remaining == 0)) {
78 			log_buf[log_ptr] = '\0';
79 			LOG_ERR(COREDUMP_PREFIX_STR "%s", log_buf);
80 			log_ptr = 0;
81 		}
82 	}
83 }
84 
coredump_logging_backend_query(enum coredump_query_id query_id,void * arg)85 static int coredump_logging_backend_query(enum coredump_query_id query_id,
86 					  void *arg)
87 {
88 	int ret;
89 
90 	switch (query_id) {
91 	case COREDUMP_QUERY_GET_ERROR:
92 		ret = error;
93 		break;
94 	default:
95 		ret = -ENOTSUP;
96 		break;
97 	}
98 
99 	return ret;
100 }
101 
coredump_logging_backend_cmd(enum coredump_cmd_id cmd_id,void * arg)102 static int coredump_logging_backend_cmd(enum coredump_cmd_id cmd_id,
103 					void *arg)
104 {
105 	int ret;
106 
107 	switch (cmd_id) {
108 	case COREDUMP_CMD_CLEAR_ERROR:
109 		ret = 0;
110 		error = 0;
111 		break;
112 	default:
113 		ret = -ENOTSUP;
114 		break;
115 	}
116 
117 	return ret;
118 }
119 
120 
121 struct coredump_backend_api coredump_backend_logging = {
122 	.start = coredump_logging_backend_start,
123 	.end = coredump_logging_backend_end,
124 	.buffer_output = coredump_logging_backend_buffer_output,
125 	.query = coredump_logging_backend_query,
126 	.cmd = coredump_logging_backend_cmd,
127 };
128 
129 
130 #ifdef CONFIG_DEBUG_COREDUMP_SHELL
131 #include <zephyr/shell/shell.h>
132 
cmd_coredump_error_get(const struct shell * sh,size_t argc,char ** argv)133 static int cmd_coredump_error_get(const struct shell *sh,
134 				  size_t argc, char **argv)
135 {
136 	ARG_UNUSED(argc);
137 	ARG_UNUSED(argv);
138 
139 	if (error == 0) {
140 		shell_print(sh, "No error.");
141 	} else {
142 		shell_print(sh, "Error: %d", error);
143 	}
144 
145 	return 0;
146 }
147 
cmd_coredump_error_clear(const struct shell * sh,size_t argc,char ** argv)148 static int cmd_coredump_error_clear(const struct shell *sh,
149 				    size_t argc, char **argv)
150 {
151 	error = 0;
152 
153 	shell_print(sh, "Error cleared.");
154 
155 	return 0;
156 }
157 
158 SHELL_STATIC_SUBCMD_SET_CREATE(sub_coredump_error,
159 	SHELL_CMD(get, NULL, "Get Coredump error", cmd_coredump_error_get),
160 	SHELL_CMD(clear, NULL, "Clear Coredump error",
161 		  cmd_coredump_error_clear),
162 	SHELL_SUBCMD_SET_END /* Array terminated. */
163 );
164 
165 SHELL_STATIC_SUBCMD_SET_CREATE(sub_coredump,
166 	SHELL_CMD(error, &sub_coredump_error,
167 		  "Get/clear backend error.", NULL),
168 	SHELL_SUBCMD_SET_END /* Array terminated. */
169 );
170 
171 SHELL_CMD_REGISTER(coredump, &sub_coredump,
172 		   "Coredump commands (logging backend)", NULL);
173 
174 #endif /* CONFIG_DEBUG_COREDUMP_SHELL */
175