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, &regs, 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, &regs);
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, &regs);
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, &regs);
295 }
296