1 /*
2 * Copyright (c) 2020 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <kernel_internal.h>
9 #include <toolchain.h>
10 #include <debug/coredump.h>
11 #include <sys/byteorder.h>
12 #include <sys/util.h>
13
14 #include "coredump_internal.h"
15
16 #if defined(CONFIG_DEBUG_COREDUMP_BACKEND_LOGGING)
17 extern struct coredump_backend_api coredump_backend_logging;
18 static struct coredump_backend_api
19 *backend_api = &coredump_backend_logging;
20 #elif defined(CONFIG_DEBUG_COREDUMP_BACKEND_FLASH_PARTITION)
21 extern struct coredump_backend_api coredump_backend_flash_partition;
22 static struct coredump_backend_api
23 *backend_api = &coredump_backend_flash_partition;
24 #elif defined(CONFIG_DEBUG_COREDUMP_BACKEND_OTHER)
25 extern struct coredump_backend_api coredump_backend_other;
26 static struct coredump_backend_api
27 *backend_api = &coredump_backend_other;
28 #else
29 #error "Need to select a coredump backend"
30 #endif
31
dump_header(unsigned int reason)32 static void dump_header(unsigned int reason)
33 {
34 struct coredump_hdr_t hdr = {
35 .id = {'Z', 'E'},
36 .hdr_version = COREDUMP_HDR_VER,
37 .reason = sys_cpu_to_le16(reason),
38 };
39
40 if (sizeof(uintptr_t) == 8) {
41 hdr.ptr_size_bits = 6; /* 2^6 = 64 */
42 } else if (sizeof(uintptr_t) == 4) {
43 hdr.ptr_size_bits = 5; /* 2^5 = 32 */
44 } else {
45 hdr.ptr_size_bits = 0; /* Unknown */
46 }
47
48 hdr.tgt_code = sys_cpu_to_le16(arch_coredump_tgt_code_get());
49
50 backend_api->buffer_output((uint8_t *)&hdr, sizeof(hdr));
51 }
52
dump_thread(struct k_thread * thread)53 static void dump_thread(struct k_thread *thread)
54 {
55 #ifdef CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN
56 uintptr_t end_addr;
57
58 /*
59 * When dumping minimum information,
60 * the current thread struct and stack need to
61 * to be dumped so debugger can examine them.
62 */
63
64 if (thread == NULL) {
65 return;
66 }
67
68 end_addr = POINTER_TO_UINT(thread) + sizeof(*thread);
69
70 coredump_memory_dump(POINTER_TO_UINT(thread), end_addr);
71
72 end_addr = thread->stack_info.start + thread->stack_info.size;
73
74 coredump_memory_dump(thread->stack_info.start, end_addr);
75 #endif
76 }
77
process_memory_region_list(void)78 void process_memory_region_list(void)
79 {
80 #ifdef CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_LINKER_RAM
81 unsigned int idx = 0;
82
83 while (true) {
84 struct z_coredump_memory_region_t *r =
85 &z_coredump_memory_regions[idx];
86
87 if (r->end == POINTER_TO_UINT(NULL)) {
88 break;
89 }
90
91 coredump_memory_dump(r->start, r->end);
92
93 idx++;
94 }
95 #endif
96 }
97
coredump(unsigned int reason,const z_arch_esf_t * esf,struct k_thread * thread)98 void coredump(unsigned int reason, const z_arch_esf_t *esf,
99 struct k_thread *thread)
100 {
101 z_coredump_start();
102
103 dump_header(reason);
104
105 if (esf != NULL) {
106 arch_coredump_info_dump(esf);
107 }
108
109 if (thread != NULL) {
110 dump_thread(thread);
111 }
112
113 process_memory_region_list();
114
115 z_coredump_end();
116 }
117
z_coredump_start(void)118 void z_coredump_start(void)
119 {
120 backend_api->start();
121 }
122
z_coredump_end(void)123 void z_coredump_end(void)
124 {
125 backend_api->end();
126 }
127
coredump_buffer_output(uint8_t * buf,size_t buflen)128 void coredump_buffer_output(uint8_t *buf, size_t buflen)
129 {
130 if ((buf == NULL) || (buflen == 0)) {
131 /* Invalid buffer, skip */
132 return;
133 }
134
135 backend_api->buffer_output(buf, buflen);
136 }
137
coredump_memory_dump(uintptr_t start_addr,uintptr_t end_addr)138 void coredump_memory_dump(uintptr_t start_addr, uintptr_t end_addr)
139 {
140 struct coredump_mem_hdr_t m;
141 size_t len;
142
143 if ((start_addr == POINTER_TO_UINT(NULL)) ||
144 (end_addr == POINTER_TO_UINT(NULL))) {
145 return;
146 }
147
148 if (start_addr >= end_addr) {
149 return;
150 }
151
152 len = end_addr - start_addr;
153
154 m.id = COREDUMP_MEM_HDR_ID;
155 m.hdr_version = COREDUMP_MEM_HDR_VER;
156
157 if (sizeof(uintptr_t) == 8) {
158 m.start = sys_cpu_to_le64(start_addr);
159 m.end = sys_cpu_to_le64(end_addr);
160 } else if (sizeof(uintptr_t) == 4) {
161 m.start = sys_cpu_to_le32(start_addr);
162 m.end = sys_cpu_to_le32(end_addr);
163 }
164
165 coredump_buffer_output((uint8_t *)&m, sizeof(m));
166
167 coredump_buffer_output((uint8_t *)start_addr, len);
168 }
169
coredump_query(enum coredump_query_id query_id,void * arg)170 int coredump_query(enum coredump_query_id query_id, void *arg)
171 {
172 int ret;
173
174 if (backend_api->query == NULL) {
175 ret = -ENOTSUP;
176 } else {
177 ret = backend_api->query(query_id, arg);
178 }
179
180 return ret;
181 }
182
coredump_cmd(enum coredump_cmd_id cmd_id,void * arg)183 int coredump_cmd(enum coredump_cmd_id cmd_id, void *arg)
184 {
185 int ret;
186
187 if (backend_api->cmd == NULL) {
188 ret = -ENOTSUP;
189 } else {
190 ret = backend_api->cmd(cmd_id, arg);
191 }
192
193 return ret;
194 }
195