1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "inspector/inspector.h"
6
7 #include <inttypes.h>
8 #include <string.h>
9
10 #include <lib/backtrace-request/backtrace-request.h>
11 #include <pretty/hexdump.h>
12 #include <zircon/assert.h>
13 #include <zircon/syscalls.h>
14 #include <zircon/syscalls/exception.h>
15 #include <zircon/types.h>
16
17 #include "utils-impl.h"
18
19 namespace inspector {
20
21 // If true then s/w breakpoint instructions do not kill the process.
22 // After the backtrace is printed the thread quietly resumes.
23 // TODO: The default is on for now for development purposes.
24 // Ultimately will want to switch this to off.
25 static bool swbreak_backtrace_enabled = true;
26
27 // Return true if the thread is to be resumed "successfully" (meaning the o/s
28 // won't kill it, and thus the kill process).
is_resumable_swbreak(zx_excp_type_t excp_type)29 static bool is_resumable_swbreak(zx_excp_type_t excp_type) {
30 if (excp_type == ZX_EXCP_SW_BREAKPOINT && swbreak_backtrace_enabled)
31 return true;
32 return false;
33 }
34
35 #if defined(__x86_64__)
36
have_swbreak_magic(const zx_thread_state_general_regs_t * regs)37 static int have_swbreak_magic(const zx_thread_state_general_regs_t* regs) {
38 return regs->rax == BACKTRACE_REQUEST_MAGIC;
39 }
40
41 #elif defined(__aarch64__)
42
have_swbreak_magic(const zx_thread_state_general_regs_t * regs)43 static int have_swbreak_magic(const zx_thread_state_general_regs_t* regs) {
44 return regs->r[0] == BACKTRACE_REQUEST_MAGIC;
45 }
46
47 #else
48
have_swbreak_magic(const zx_thread_state_general_regs_t * regs)49 static int have_swbreak_magic(const zx_thread_state_general_regs_t* regs) {
50 return 0;
51 }
52
53 #endif
54
excp_type_to_str(zx_excp_type_t type)55 static const char* excp_type_to_str(zx_excp_type_t type) {
56 switch (type) {
57 case ZX_EXCP_GENERAL:
58 return "general fault";
59 case ZX_EXCP_FATAL_PAGE_FAULT:
60 return "fatal page fault";
61 case ZX_EXCP_UNDEFINED_INSTRUCTION:
62 return "undefined instruction";
63 case ZX_EXCP_SW_BREAKPOINT:
64 return "sw breakpoint";
65 case ZX_EXCP_HW_BREAKPOINT:
66 return "hw breakpoint";
67 case ZX_EXCP_UNALIGNED_ACCESS:
68 return "alignment fault";
69 case ZX_EXCP_POLICY_ERROR:
70 return "policy error";
71 default:
72 // Note: To get a compilation failure when a new exception type has
73 // been added without having also updated this function, compile with
74 // -Wswitch-enum.
75 return "unknown fault";
76 }
77 }
78
79 // How much memory to dump, in bytes.
80 // Space for this is allocated on the stack, so this can't be too large.
81 static constexpr size_t kMemoryDumpSize = 256;
82
83 #if defined(__aarch64__)
write_general_regs(zx_handle_t thread,void * buf,size_t buf_size)84 static bool write_general_regs(zx_handle_t thread, void* buf, size_t buf_size) {
85 // The syscall takes a uint32_t.
86 auto to_xfer = static_cast<uint32_t>(buf_size);
87 auto status = zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, buf, to_xfer);
88 if (status != ZX_OK) {
89 print_zx_error("unable to access general regs", status);
90 return false;
91 }
92 return true;
93 }
94 #endif
95
dump_memory(zx_handle_t proc,uintptr_t start,size_t len)96 static void dump_memory(zx_handle_t proc, uintptr_t start, size_t len) {
97 // Make sure we're not allocating an excessive amount of stack.
98 ZX_DEBUG_ASSERT(len <= kMemoryDumpSize);
99
100 uint8_t buf[len];
101 auto res = zx_process_read_memory(proc, start, buf, len, &len);
102 if (res < 0) {
103 printf("failed reading %p memory; error : %d\n", (void*)start, res);
104 } else if (len != 0) {
105 hexdump_ex(buf, len, start);
106 }
107 }
108
resume_thread(zx_handle_t thread,zx_handle_t exception_port,bool handled)109 static void resume_thread(zx_handle_t thread, zx_handle_t exception_port, bool handled) {
110 uint32_t options = 0;
111 if (!handled)
112 options |= ZX_RESUME_TRY_NEXT;
113 auto status = zx_task_resume_from_exception(thread, exception_port, options);
114 if (status != ZX_OK) {
115 print_zx_error("unable to \"resume\" thread", status);
116 // This shouldn't happen (unless someone killed it already).
117 // The task is now effectively hung (until someone kills it).
118 // TODO: Try to forcefully kill it ourselves?
119 }
120 }
121
resume_thread_from_exception(zx_handle_t thread,zx_handle_t exception_port,zx_excp_type_t excp_type,const zx_thread_state_general_regs_t * gregs)122 static void resume_thread_from_exception(zx_handle_t thread, zx_handle_t exception_port,
123 zx_excp_type_t excp_type,
124 const zx_thread_state_general_regs_t* gregs) {
125 if (is_resumable_swbreak(excp_type) &&
126 gregs != nullptr && have_swbreak_magic(gregs)) {
127 #if defined(__x86_64__)
128 // On x86, the pc is left at one past the s/w break insn,
129 // so there's nothing more we need to do.
130 #elif defined(__aarch64__)
131 zx_thread_state_general_regs_t regs = *gregs;
132 // Skip past the brk instruction.
133 regs.pc += 4;
134 if (!write_general_regs(thread, ®s, sizeof(regs)))
135 goto Fail;
136 #else
137 goto Fail;
138 #endif
139 resume_thread(thread, exception_port, true);
140 return;
141 }
142
143 // For now, we turn policy exceptions into non-fatal warnings, by
144 // resuming the thread when these exceptions occur. TODO(ZX-922):
145 // Remove this and make these exceptions fatal after the system has
146 // received some amount of testing with ZX_POL_BAD_HANDLE enabled as a
147 // warning.
148 if (excp_type == ZX_EXCP_POLICY_ERROR) {
149 resume_thread(thread, exception_port, true);
150 return;
151 }
152
153 #if !defined(__x86_64__)
154 Fail:
155 #endif
156 // Tell the o/s to "resume" the thread by killing the process, the
157 // exception has not been handled.
158 resume_thread(thread, exception_port, false);
159 }
160
get_koid(zx_handle_t handle)161 static zx_koid_t get_koid(zx_handle_t handle) {
162 zx_info_handle_basic_t info;
163 zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), NULL, NULL);
164 if (status != ZX_OK) {
165 printf("failed to get koid\n");
166 return ZX_HANDLE_INVALID;
167 }
168 return info.koid;
169 }
170
print_debug_info(zx_handle_t process,zx_handle_t thread,zx_excp_type_t * type,zx_thread_state_general_regs_t * regs)171 static void print_debug_info(zx_handle_t process, zx_handle_t thread, zx_excp_type_t* type, zx_thread_state_general_regs_t* regs) {
172 zx_koid_t pid = get_koid(process);
173 zx_koid_t tid = get_koid(thread);
174
175 zx_exception_report_t report;
176 zx_status_t status = zx_object_get_info(thread, ZX_INFO_THREAD_EXCEPTION_REPORT,
177 &report, sizeof(report), NULL, NULL);
178 if (status != ZX_OK) {
179 printf("failed to get exception report for [%" PRIu64 ".%" PRIu64 "] : error %d\n", pid, tid, status);
180 return;
181 }
182
183 *type = report.header.type;
184
185 if (!ZX_EXCP_IS_ARCH(*type) && *type != ZX_EXCP_POLICY_ERROR) {
186 return;
187 }
188
189 auto context = report.context;
190
191 zx_vaddr_t pc = 0, sp = 0, fp = 0;
192 const char* arch = "unknown";
193 const char* fatal = "fatal ";
194
195 if (inspector_read_general_regs(thread, regs) != ZX_OK) {
196 return;
197 }
198
199 #if defined(__x86_64__)
200 arch = "x86_64";
201 pc = regs->rip;
202 sp = regs->rsp;
203 fp = regs->rbp;
204 #elif defined(__aarch64__)
205 arch = "aarch64";
206 pc = regs->pc;
207 sp = regs->sp;
208 fp = regs->r[29];
209 #else
210 #error unsupported architecture
211 #endif
212
213 // This won't print "fatal" in the case where this is a s/w bkpt but
214 // ZX_CRASHLOGGER_REQUEST_SELF_BT_MAGIC isn't set. Big deal.
215 if (is_resumable_swbreak(*type))
216 fatal = "";
217 // TODO(MA-922): Remove this and make policy exceptions fatal.
218 if (*type == ZX_EXCP_POLICY_ERROR)
219 fatal = "";
220
221 char process_name[ZX_MAX_NAME_LEN];
222 status = zx_object_get_property(process, ZX_PROP_NAME, process_name, sizeof(process_name));
223 if (status != ZX_OK) {
224 strlcpy(process_name, "unknown", sizeof(process_name));
225 }
226
227 char thread_name[ZX_MAX_NAME_LEN];
228 status = zx_object_get_property(thread, ZX_PROP_NAME, thread_name, sizeof(thread_name));
229 if (status != ZX_OK) {
230 strlcpy(thread_name, "unknown", sizeof(thread_name));
231 }
232
233 printf("<== %sexception: process %s[%" PRIu64 "] thread %s[%" PRIu64 "]\n", fatal,
234 process_name, pid, thread_name, tid);
235 printf("<== %s, PC at 0x%" PRIxPTR "\n", excp_type_to_str(report.header.type), pc);
236
237 #if defined(__x86_64__)
238 inspector_print_general_regs(stdout, regs, &context.arch.u.x86_64);
239 #elif defined(__aarch64__)
240 inspector_print_general_regs(stdout, regs, &context.arch.u.arm_64);
241
242 // Only output the Fault address register and ESR if there's a data fault.
243 if (ZX_EXCP_FATAL_PAGE_FAULT == report.header.type) {
244 printf(" far %#18" PRIx64 " esr %#18x\n",
245 context.arch.u.arm_64.far, context.arch.u.arm_64.esr);
246 }
247 #else
248 #error unsupported architecture
249 #endif
250
251 printf("bottom of user stack:\n");
252 dump_memory(process, sp, kMemoryDumpSize);
253
254 printf("arch: %s\n", arch);
255
256 {
257 // Whether to use libunwind or not.
258 // If not then we use a simple algorithm that assumes ABI-specific
259 // frame pointers are present.
260 const bool use_libunwind = true;
261
262 // TODO (jakehehrlich): Remove old dso format.
263 inspector_dsoinfo_t* dso_list = inspector_dso_fetch_list(process);
264 inspector_dso_print_list(stdout, dso_list);
265 inspector_print_markup_context(stdout, process);
266 // TODO (jakehehrlich): Remove the old backtrace format.
267 inspector_print_backtrace(stdout, process, thread, dso_list,
268 pc, sp, fp, use_libunwind);
269 inspector_print_backtrace_markup(stdout, process, thread, dso_list,
270 pc, sp, fp, use_libunwind);
271 }
272
273 // TODO(ZX-588): Print a backtrace of all other threads in the process.
274
275 if (verbosity_level >= 1)
276 printf("Done handling thread %" PRIu64 ".%" PRIu64 ".\n", pid, tid);
277 }
278
279 } // namespace inspector
280
inspector_print_debug_info(zx_handle_t process,zx_handle_t thread)281 void inspector_print_debug_info(zx_handle_t process, zx_handle_t thread) {
282 zx_excp_type_t type = 0;
283 zx_thread_state_general_regs_t regs;
284 inspector::print_debug_info(process, thread, &type, ®s);
285 }
286
inspector_print_debug_info_and_resume_thread(zx_handle_t process,zx_handle_t thread,zx_handle_t exception_port)287 void inspector_print_debug_info_and_resume_thread(zx_handle_t process, zx_handle_t thread, zx_handle_t exception_port) {
288 zx_excp_type_t type = 0;
289 zx_thread_state_general_regs_t regs;
290 inspector::print_debug_info(process, thread, &type, ®s);
291
292 // allow the thread (and then process) to die, unless the exception is
293 // to just trigger a backtrace (if enabled).
294 inspector::resume_thread_from_exception(thread, exception_port, type, ®s);
295 }
296