1// Copyright 2018 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#include <lib/crashlog.h>
8
9#include <ctype.h>
10#include <inttypes.h>
11#include <kernel/thread.h>
12#include <lib/version.h>
13#include <platform.h>
14#include <printf.h>
15#include <string.h>
16
17crashlog_t crashlog = {};
18
19size_t crashlog_to_string(char* out, const size_t out_len) {
20    char* buf = out;
21    size_t remain = out_len;
22    size_t len;
23
24    buf[0] = '\0';
25
26    len = snprintf(buf, remain, "ZIRCON KERNEL PANIC\n\n");
27    if (len > remain) {
28        return out_len;
29    }
30    remain -= len;
31    buf += len;
32
33    len = snprintf(buf, remain, "UPTIME (ms)\n%" PRIi64 "\n\n", current_time() / ZX_MSEC(1));
34    if (len > remain) {
35        return out_len;
36    }
37    remain -= len;
38    buf += len;
39
40    // Keep the format and values in sync with the symbolizer.
41    // Print before the registers (KASLR offset).
42#if defined(__x86_64__)
43    const char* arch = "x86_64";
44#elif defined(__aarch64__)
45    const char* arch = "aarch64";
46#endif
47    len = snprintf(buf, remain, "VERSION\narch: %s\nbuild_id: %s\ndso: id=%s base=%#lx name=zircon.elf\n\n", arch, version.buildid, version.elf_build_id, crashlog.base_address);
48    if (len > remain) {
49        return out_len;
50    }
51    remain -= len;
52    buf += len;
53
54    if (crashlog.iframe) {
55#if defined(__aarch64__)
56        len = snprintf(buf, remain, "REGISTERS\n"
57                                    "  x0: %#18" PRIx64 "\n"
58                                    "  x1: %#18" PRIx64 "\n"
59                                    "  x2: %#18" PRIx64 "\n"
60                                    "  x3: %#18" PRIx64 "\n"
61                                    "  x4: %#18" PRIx64 "\n"
62                                    "  x5: %#18" PRIx64 "\n"
63                                    "  x6: %#18" PRIx64 "\n"
64                                    "  x7: %#18" PRIx64 "\n"
65                                    "  x8: %#18" PRIx64 "\n"
66                                    "  x9: %#18" PRIx64 "\n"
67                                    " x10: %#18" PRIx64 "\n"
68                                    " x11: %#18" PRIx64 "\n"
69                                    " x12: %#18" PRIx64 "\n"
70                                    " x13: %#18" PRIx64 "\n"
71                                    " x14: %#18" PRIx64 "\n"
72                                    " x15: %#18" PRIx64 "\n"
73                                    " x16: %#18" PRIx64 "\n"
74                                    " x17: %#18" PRIx64 "\n"
75                                    " x18: %#18" PRIx64 "\n"
76                                    " x19: %#18" PRIx64 "\n"
77                                    " x20: %#18" PRIx64 "\n"
78                                    " x21: %#18" PRIx64 "\n"
79                                    " x22: %#18" PRIx64 "\n"
80                                    " x23: %#18" PRIx64 "\n"
81                                    " x24: %#18" PRIx64 "\n"
82                                    " x25: %#18" PRIx64 "\n"
83                                    " x26: %#18" PRIx64 "\n"
84                                    " x27: %#18" PRIx64 "\n"
85                                    " x28: %#18" PRIx64 "\n"
86                                    " x29: %#18" PRIx64 "\n"
87                                    "  lr: %#18" PRIx64 "\n"
88                                    " usp: %#18" PRIx64 "\n"
89                                    " elr: %#18" PRIx64 "\n"
90                                    "spsr: %#18" PRIx64 "\n"
91                                    "\n",
92                       crashlog.iframe->r[0],
93                       crashlog.iframe->r[1],
94                       crashlog.iframe->r[2],
95                       crashlog.iframe->r[3],
96                       crashlog.iframe->r[4],
97                       crashlog.iframe->r[5],
98                       crashlog.iframe->r[6],
99                       crashlog.iframe->r[7],
100                       crashlog.iframe->r[8],
101                       crashlog.iframe->r[9],
102                       crashlog.iframe->r[10],
103                       crashlog.iframe->r[11],
104                       crashlog.iframe->r[12],
105                       crashlog.iframe->r[13],
106                       crashlog.iframe->r[14],
107                       crashlog.iframe->r[15],
108                       crashlog.iframe->r[16],
109                       crashlog.iframe->r[17],
110                       crashlog.iframe->r[18],
111                       crashlog.iframe->r[19],
112                       crashlog.iframe->r[20],
113                       crashlog.iframe->r[21],
114                       crashlog.iframe->r[22],
115                       crashlog.iframe->r[23],
116                       crashlog.iframe->r[24],
117                       crashlog.iframe->r[25],
118                       crashlog.iframe->r[26],
119                       crashlog.iframe->r[27],
120                       crashlog.iframe->r[28],
121                       crashlog.iframe->r[29],
122                       crashlog.iframe->lr,
123                       crashlog.iframe->usp,
124                       crashlog.iframe->elr,
125                       crashlog.iframe->spsr);
126        if (len > remain) {
127            return out_len;
128        }
129        remain -= len;
130        buf += len;
131#elif defined(__x86_64__)
132        len = snprintf(buf, remain, "REGISTERS\n"
133                                    "  CS: %#18" PRIx64 "\n"
134                                    " RIP: %#18" PRIx64 "\n"
135                                    " EFL: %#18" PRIx64 "\n"
136                                    " CR2: %#18lx\n"
137                                    " RAX: %#18" PRIx64 "\n"
138                                    " RBX: %#18" PRIx64 "\n"
139                                    " RCX: %#18" PRIx64 "\n"
140                                    " RDX: %#18" PRIx64 "\n"
141                                    " RSI: %#18" PRIx64 "\n"
142                                    " RDI: %#18" PRIx64 "\n"
143                                    " RBP: %#18" PRIx64 "\n"
144                                    " RSP: %#18" PRIx64 "\n"
145                                    "  R8: %#18" PRIx64 "\n"
146                                    "  R9: %#18" PRIx64 "\n"
147                                    " R10: %#18" PRIx64 "\n"
148                                    " R11: %#18" PRIx64 "\n"
149                                    " R12: %#18" PRIx64 "\n"
150                                    " R13: %#18" PRIx64 "\n"
151                                    " R14: %#18" PRIx64 "\n"
152                                    " R15: %#18" PRIx64 "\n"
153                                    "errc: %#18" PRIx64 "\n"
154                                    "\n",
155                       crashlog.iframe->cs,
156                       crashlog.iframe->ip,
157                       crashlog.iframe->flags,
158                       x86_get_cr2(),
159                       crashlog.iframe->rax,
160                       crashlog.iframe->rbx,
161                       crashlog.iframe->rcx,
162                       crashlog.iframe->rdx,
163                       crashlog.iframe->rsi,
164                       crashlog.iframe->rdi,
165                       crashlog.iframe->rbp,
166                       crashlog.iframe->user_sp,
167                       crashlog.iframe->r8,
168                       crashlog.iframe->r9,
169                       crashlog.iframe->r10,
170                       crashlog.iframe->r11,
171                       crashlog.iframe->r12,
172                       crashlog.iframe->r13,
173                       crashlog.iframe->r14,
174                       crashlog.iframe->r15,
175                       crashlog.iframe->err_code);
176        if (len > remain) {
177            return out_len;
178        }
179        remain -= len;
180        buf += len;
181#endif
182    }
183
184    len = snprintf(buf, remain, "BACKTRACE (up to 16 calls)\n");
185    if (len > remain) {
186        return out_len;
187    }
188    remain -= len;
189    buf += len;
190
191    len = thread_append_current_backtrace(buf, remain);
192    if (len > remain) {
193        return out_len;
194    }
195    remain -= len;
196    buf += len;
197
198    len = snprintf(buf, remain, "\n");
199    if (len > remain) {
200        return out_len;
201    }
202    remain -= len;
203    buf += len;
204
205    return out_len - remain;
206}
207