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