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 <inttypes.h> 6#include <link.h> 7#include <stdbool.h> 8#include <stdlib.h> 9#include <string.h> 10 11#include <fbl/algorithm.h> 12#include <launchpad/launchpad.h> 13#include <launchpad/vmo.h> 14#include <test-utils/test-utils.h> 15#include <unittest/unittest.h> 16#include <zircon/compiler.h> 17#include <zircon/process.h> 18#include <zircon/processargs.h> 19#include <zircon/syscalls.h> 20#include <zircon/syscalls/debug.h> 21#include <zircon/syscalls/object.h> 22#include <zircon/syscalls/port.h> 23 24#include "utils.h" 25 26// argv[0] 27const char* program_path; 28 29static const uint64_t exception_port_key = 0x6b6579; // "key" 30 31uint32_t get_uint32(char* buf) { 32 uint32_t value = 0; 33 memcpy(&value, buf, sizeof(value)); 34 return value; 35} 36 37uint64_t get_uint64(char* buf) { 38 uint64_t value = 0; 39 memcpy(&value, buf, sizeof(value)); 40 return value; 41} 42 43void set_uint64(char* buf, uint64_t value) { 44 memcpy(buf, &value, sizeof(value)); 45} 46 47uint32_t get_uint32_property(zx_handle_t handle, uint32_t prop) { 48 uint32_t value; 49 zx_status_t status = zx_object_get_property(handle, prop, &value, sizeof(value)); 50 if (status != ZX_OK) 51 tu_fatal("zx_object_get_property failed", status); 52 return value; 53} 54 55void send_msg(zx_handle_t handle, message msg) { 56 uint64_t data = msg; 57 unittest_printf("sending message %d on handle %u\n", msg, handle); 58 tu_channel_write(handle, 0, &data, sizeof(data), NULL, 0); 59} 60 61// This returns "bool" because it uses ASSERT_*. 62 63bool recv_msg(zx_handle_t handle, message* msg) { 64 BEGIN_HELPER; 65 66 uint64_t data; 67 uint32_t num_bytes = sizeof(data); 68 69 unittest_printf("waiting for message on handle %u\n", handle); 70 71 ASSERT_TRUE(tu_channel_wait_readable(handle), "peer closed while trying to read message"); 72 73 tu_channel_read(handle, 0, &data, &num_bytes, NULL, 0); 74 ASSERT_EQ(num_bytes, sizeof(data), "unexpected message size"); 75 76 *msg = static_cast<message>(data); 77 unittest_printf("received message %d\n", *msg); 78 79 END_HELPER; 80} 81 82void dump_gregs(zx_handle_t thread_handle, const zx_thread_state_general_regs_t* regs) { 83 unittest_printf("Registers for thread %d\n", thread_handle); 84 85#define DUMP_NAMED_REG(name) \ 86 unittest_printf(" %8s %24ld 0x%lx\n", #name, (long)regs->name, (long)regs->name) 87 88#if defined(__x86_64__) 89 90 DUMP_NAMED_REG(rax); 91 DUMP_NAMED_REG(rbx); 92 DUMP_NAMED_REG(rcx); 93 DUMP_NAMED_REG(rdx); 94 DUMP_NAMED_REG(rsi); 95 DUMP_NAMED_REG(rdi); 96 DUMP_NAMED_REG(rbp); 97 DUMP_NAMED_REG(rsp); 98 DUMP_NAMED_REG(r8); 99 DUMP_NAMED_REG(r9); 100 DUMP_NAMED_REG(r10); 101 DUMP_NAMED_REG(r11); 102 DUMP_NAMED_REG(r12); 103 DUMP_NAMED_REG(r13); 104 DUMP_NAMED_REG(r14); 105 DUMP_NAMED_REG(r15); 106 DUMP_NAMED_REG(rip); 107 DUMP_NAMED_REG(rflags); 108 109#elif defined(__aarch64__) 110 111 for (int i = 0; i < 30; i++) { 112 unittest_printf(" r[%2d] %24ld 0x%lx\n", i, (long)regs->r[i], (long)regs->r[i]); 113 } 114 DUMP_NAMED_REG(lr); 115 DUMP_NAMED_REG(sp); 116 DUMP_NAMED_REG(pc); 117 DUMP_NAMED_REG(cpsr); 118 119#endif 120 121#undef DUMP_NAMED_REG 122} 123 124void dump_inferior_regs(zx_handle_t thread) { 125 zx_thread_state_general_regs_t regs; 126 read_inferior_gregs(thread, ®s); 127 dump_gregs(thread, ®s); 128} 129 130// N.B. It is assumed |buf_size| is large enough. 131 132void read_inferior_gregs(zx_handle_t thread, zx_thread_state_general_regs_t* in) { 133 zx_status_t status = zx_thread_read_state( 134 thread, ZX_THREAD_STATE_GENERAL_REGS, in, sizeof(zx_thread_state_general_regs_t)); 135 // It's easier to just terminate if this fails. 136 if (status != ZX_OK) 137 tu_fatal("read_inferior_gregs: zx_thread_read_state", status); 138} 139 140void write_inferior_gregs(zx_handle_t thread, const zx_thread_state_general_regs_t* out) { 141 zx_status_t status = zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, out, 142 sizeof(zx_thread_state_general_regs_t)); 143 // It's easier to just terminate if this fails. 144 if (status != ZX_OK) 145 tu_fatal("write_inferior_gregs: zx_thread_write_state", status); 146} 147 148size_t read_inferior_memory(zx_handle_t proc, uintptr_t vaddr, void* buf, size_t len) { 149 zx_status_t status = zx_process_read_memory(proc, vaddr, buf, len, &len); 150 if (status < 0) 151 tu_fatal("read_inferior_memory", status); 152 return len; 153} 154 155size_t write_inferior_memory(zx_handle_t proc, uintptr_t vaddr, const void* buf, size_t len) { 156 zx_status_t status = zx_process_write_memory(proc, vaddr, buf, len, &len); 157 if (status < 0) 158 tu_fatal("write_inferior_memory", status); 159 return len; 160} 161 162// This does everything that launchpad_launch_fdio_etc does except 163// start the inferior. We want to attach to it first. 164// TODO(dje): Are there other uses of such a wrapper? Move to launchpad? 165// Plus there's a fair bit of code here. IWBN to not have to update it as 166// launchpad_launch_fdio_etc changes. 167 168zx_status_t create_inferior(const char* name, int argc, const char* const* argv, 169 const char* const* envp, size_t hnds_count, zx_handle_t* handles, 170 uint32_t* ids, launchpad_t** out_launchpad) { 171 launchpad_t* lp = NULL; 172 173 const char* filename = argv[0]; 174 if (name == NULL) 175 name = filename; 176 177 zx_status_t status; 178 launchpad_create(0u, name, &lp); 179 launchpad_load_from_file(lp, filename); 180 launchpad_set_args(lp, argc, argv); 181 launchpad_set_environ(lp, envp); 182 launchpad_clone(lp, LP_CLONE_FDIO_ALL); 183 status = launchpad_add_handles(lp, hnds_count, handles, ids); 184 185 if (status < 0) { 186 launchpad_destroy(lp); 187 } else { 188 *out_launchpad = lp; 189 } 190 return status; 191} 192 193bool setup_inferior(const char* name, launchpad_t** out_lp, zx_handle_t* out_inferior, 194 zx_handle_t* out_channel) { 195 BEGIN_HELPER; 196 197 zx_status_t status; 198 zx_handle_t channel1, channel2; 199 tu_channel_create(&channel1, &channel2); 200 201 const char verbosity_string[] = {'v', '=', static_cast<char>(utest_verbosity_level + '0'), 202 '\0'}; 203 const char* test_child_path = program_path; 204 const char* const argv[] = {test_child_path, name, verbosity_string}; 205 zx_handle_t handles[1] = {channel2}; 206 uint32_t handle_ids[1] = {PA_USER0}; 207 208 launchpad_t* lp; 209 unittest_printf("Creating process \"%s\"\n", name); 210 status = create_inferior(name, fbl::count_of(argv), argv, NULL, fbl::count_of(handles), 211 handles, handle_ids, &lp); 212 ASSERT_EQ(status, ZX_OK, "failed to create inferior"); 213 214 // Note: |inferior| is a borrowed handle here. 215 zx_handle_t inferior = launchpad_get_process_handle(lp); 216 ASSERT_NE(inferior, ZX_HANDLE_INVALID, "can't get launchpad process handle"); 217 218 zx_info_handle_basic_t process_info; 219 tu_handle_get_basic_info(inferior, &process_info); 220 unittest_printf("Inferior pid = %llu\n", (long long)process_info.koid); 221 222 // |inferior| is given to the child by launchpad_go. 223 // We need our own copy, and launchpad_go will give us one, but we need 224 // it before we call launchpad_go in order to attach to the debugging 225 // exception port. We could leave this to our caller to do, but since every 226 // caller needs this for convenience sake we do this here. 227 status = zx_handle_duplicate(inferior, ZX_RIGHT_SAME_RIGHTS, &inferior); 228 ASSERT_EQ(status, ZX_OK, "zx_handle_duplicate failed"); 229 230 *out_lp = lp; 231 *out_inferior = inferior; 232 *out_channel = channel1; 233 234 END_HELPER; 235} 236 237// While this should perhaps take a launchpad_t* argument instead of the 238// inferior's handle, we later want to test attaching to an already running 239// inferior. 240// |max_threads| is the maximum number of threads the process is expected 241// to have in its lifetime. A real debugger would be more flexible of course. 242// N.B. |inferior| cannot be the result of launchpad_get_process_handle(). 243// That handle is passed to the inferior when started and thus is lost to us. 244// Returns a boolean indicating success. 245 246inferior_data_t* attach_inferior(zx_handle_t inferior, zx_handle_t eport, size_t max_threads) { 247 // Fetch all current threads and attach async-waiters to them. 248 // N.B. We assume threads aren't being created as we're running. 249 // This is just a testcase so we can assume that. A real debugger 250 // would not have this assumption. 251 zx_koid_t* thread_koids = static_cast<zx_koid_t*>(tu_malloc(max_threads * sizeof(zx_koid_t))); 252 size_t num_threads = tu_process_get_threads(inferior, thread_koids, max_threads); 253 // For now require |max_threads| to be big enough. 254 if (num_threads > max_threads) 255 tu_fatal(__func__, ZX_ERR_BUFFER_TOO_SMALL); 256 257 tu_set_exception_port(inferior, eport, exception_port_key, ZX_EXCEPTION_PORT_DEBUGGER); 258 tu_object_wait_async(inferior, eport, ZX_PROCESS_TERMINATED); 259 260 inferior_data_t* data = static_cast<inferior_data_t*>(tu_malloc(sizeof(*data))); 261 data->threads = static_cast<thread_data_t*>(tu_calloc(max_threads, sizeof(data->threads[0]))); 262 data->inferior = inferior; 263 data->eport = eport; 264 data->max_num_threads = max_threads; 265 266 // Notification of thread termination and suspension is delivered by 267 // signals. So that we can continue to only have to wait on |eport| 268 // for inferior status change notification, install async-waiters 269 // for each thread. 270 size_t j = 0; 271 zx_signals_t thread_signals = ZX_THREAD_TERMINATED | ZX_THREAD_RUNNING | ZX_THREAD_SUSPENDED; 272 for (size_t i = 0; i < num_threads; ++i) { 273 zx_handle_t thread = tu_process_get_thread(inferior, thread_koids[i]); 274 if (thread != ZX_HANDLE_INVALID) { 275 data->threads[j].tid = thread_koids[i]; 276 data->threads[j].handle = thread; 277 tu_object_wait_async(thread, eport, thread_signals); 278 ++j; 279 } 280 } 281 free(thread_koids); 282 283 unittest_printf("Attached to inferior\n"); 284 return data; 285} 286 287void detach_inferior(inferior_data_t* data, bool unbind_eport) { 288 if (unbind_eport) { 289 tu_set_exception_port(data->inferior, ZX_HANDLE_INVALID, exception_port_key, 290 ZX_EXCEPTION_PORT_DEBUGGER); 291 } 292 for (size_t i = 0; i < data->max_num_threads; ++i) { 293 if (data->threads[i].handle != ZX_HANDLE_INVALID) 294 tu_handle_close(data->threads[i].handle); 295 } 296 free(data->threads); 297 free(data); 298} 299 300bool start_inferior(launchpad_t* lp) { 301 zx_handle_t dup_inferior = tu_launch_fdio_fini(lp); 302 unittest_printf("Inferior started\n"); 303 // launchpad_go returns a dup of |inferior|. The original inferior 304 // handle is given to the child. However we don't need it, we already 305 // created one so that we could attach to the inferior before starting it. 306 tu_handle_close(dup_inferior); 307 return true; 308} 309 310bool verify_inferior_running(zx_handle_t channel) { 311 BEGIN_HELPER; 312 313 enum message msg; 314 send_msg(channel, MSG_PING); 315 if (!recv_msg(channel, &msg)) 316 return false; 317 EXPECT_EQ(msg, MSG_PONG, "unexpected response from ping"); 318 319 END_HELPER; 320} 321 322static bool recv_msg_handle(zx_handle_t channel, message expected_msg, zx_handle_t* handle) { 323 BEGIN_HELPER; 324 325 unittest_printf("waiting for message on channel %u\n", channel); 326 ASSERT_TRUE(tu_channel_wait_readable(channel), "peer closed while trying to read message"); 327 328 uint64_t data; 329 uint32_t num_bytes = sizeof(data); 330 uint32_t num_handles = 1; 331 tu_channel_read(channel, 0, &data, &num_bytes, handle, &num_handles); 332 ASSERT_EQ(num_bytes, sizeof(data)); 333 ASSERT_EQ(num_handles, 1u); 334 335 message msg = static_cast<message>(data); 336 ASSERT_EQ(msg, expected_msg); 337 338 unittest_printf("received handle %d\n", *handle); 339 340 END_HELPER; 341} 342 343bool get_inferior_thread_handle(zx_handle_t channel, zx_handle_t* thread) { 344 BEGIN_HELPER; 345 346 send_msg(channel, MSG_GET_THREAD_HANDLE); 347 ASSERT_TRUE(recv_msg_handle(channel, MSG_THREAD_HANDLE, thread)); 348 349 END_HELPER; 350} 351 352bool resume_inferior(zx_handle_t inferior, zx_koid_t tid) { 353 BEGIN_HELPER; 354 355 zx_handle_t thread; 356 zx_status_t status = zx_object_get_child(inferior, tid, ZX_RIGHT_SAME_RIGHTS, &thread); 357 if (status == ZX_ERR_NOT_FOUND) { 358 // If the process has exited then the kernel may have reaped the 359 // thread already. Check. 360 if (tu_process_has_exited(inferior)) 361 return true; 362 } 363 ASSERT_EQ(status, ZX_OK, "zx_object_get_child failed"); 364 365 unittest_printf("Resuming inferior ...\n"); 366 status = zx_task_resume(thread, ZX_RESUME_EXCEPTION); 367 if (status == ZX_ERR_BAD_STATE) { 368 // If the process has exited then the thread may have exited 369 // ExceptionHandlerExchange already. Check. 370 if (tu_thread_is_dying_or_dead(thread)) { 371 tu_handle_close(thread); 372 return true; 373 } 374 } 375 tu_handle_close(thread); 376 ASSERT_EQ(status, ZX_OK, "zx_task_resume failed"); 377 378 END_HELPER; 379} 380 381bool shutdown_inferior(zx_handle_t channel, zx_handle_t inferior) { 382 BEGIN_HELPER; 383 384 unittest_printf("Shutting down inferior\n"); 385 386 send_msg(channel, MSG_DONE); 387 388 tu_process_wait_signaled(inferior); 389 EXPECT_EQ(tu_process_get_return_code(inferior), 1234, "unexpected inferior return code"); 390 391 END_HELPER; 392} 393 394// Wait for and read an exception/signal on |eport|. 395 396bool read_exception(zx_handle_t eport, zx_port_packet_t* packet) { 397 BEGIN_HELPER; 398 399 unittest_printf("Waiting for exception/signal on eport %d\n", eport); 400 ASSERT_EQ(zx_port_wait(eport, ZX_TIME_INFINITE, packet), ZX_OK, "zx_port_wait failed"); 401 402 if (ZX_PKT_IS_EXCEPTION(packet->type)) 403 ASSERT_EQ(packet->key, exception_port_key); 404 405 unittest_printf("read_exception: got exception/signal %d\n", packet->type); 406 407 END_HELPER; 408} 409 410// Wait for the thread to suspend 411// We could get a thread exit report from a previous test, so 412// we need to handle that, but no other exceptions are expected. 413// 414// The thread is assumed to be wait-async'd on |eport|. While we could just 415// wait on the |thread| for the appropriate signal, the signal will also be 416// sent to |eport| which our caller would then have to deal with. Keep things 417// simpler by doing all waiting via |eport|. It also makes us exercise doing 418// things this way, which is generally what debuggers will do. 419 420bool wait_thread_suspended(zx_handle_t proc, zx_handle_t thread, zx_handle_t eport) { 421 BEGIN_HELPER; 422 423 zx_koid_t tid = tu_get_koid(thread); 424 425 while (true) { 426 zx_port_packet_t packet; 427 zx_status_t status = zx_port_wait(eport, zx_deadline_after(ZX_SEC(1)), &packet); 428 if (status == ZX_ERR_TIMED_OUT) { 429 // This shouldn't really happen unless the system is really loaded. 430 // Just flag it and try again. The watchdog will catch failures. 431 unittest_printf("%s: timed out???\n", __func__); 432 continue; 433 } 434 ASSERT_EQ(status, ZX_OK); 435 if (ZX_PKT_IS_SIGNAL_REP(packet.type)) { 436 ASSERT_EQ(packet.key, tid); 437 if (packet.signal.observed & ZX_THREAD_SUSPENDED) 438 break; 439 ASSERT_TRUE(packet.signal.observed & ZX_THREAD_RUNNING); 440 } else { 441 ASSERT_TRUE(ZX_PKT_IS_EXCEPTION(packet.type)); 442 zx_koid_t report_tid = packet.exception.tid; 443 ASSERT_NE(report_tid, tid); 444 ASSERT_EQ(packet.type, (uint32_t)ZX_EXCP_THREAD_EXITING); 445 // Note the thread may be completely gone by now. 446 zx_handle_t other_thread; 447 zx_status_t status = 448 zx_object_get_child(proc, report_tid, ZX_RIGHT_SAME_RIGHTS, &other_thread); 449 if (status == ZX_OK) { 450 // And even if it's not gone it may be dead now. 451 status = zx_task_resume(other_thread, ZX_RESUME_EXCEPTION); 452 if (status == ZX_ERR_BAD_STATE) 453 ASSERT_TRUE(tu_thread_is_dying_or_dead(other_thread)); 454 else 455 ASSERT_EQ(status, ZX_OK); 456 tu_handle_close(other_thread); 457 } 458 } 459 } 460 461 // Verify thread is suspended 462 zx_info_thread_t info = tu_thread_get_info(thread); 463 ASSERT_EQ(info.state, ZX_THREAD_STATE_SUSPENDED); 464 ASSERT_EQ(info.wait_exception_port_type, ZX_EXCEPTION_PORT_TYPE_NONE); 465 466 END_HELPER; 467} 468 469static int phdr_info_callback(dl_phdr_info* info, size_t size, void* data) { 470 dl_phdr_info* key = static_cast<dl_phdr_info*>(data); 471 if (info->dlpi_addr == key->dlpi_addr) { 472 *key = *info; 473 return 1; 474 } 475 return 0; 476} 477 478// Fetch the [inclusive] range of the executable segment of the vdso. 479 480bool get_vdso_exec_range(uintptr_t* start, uintptr_t* end) { 481 BEGIN_HELPER; 482 483 char msg[128]; 484 485 uintptr_t prop_vdso_base; 486 zx_status_t status = 487 zx_object_get_property(zx_process_self(), ZX_PROP_PROCESS_VDSO_BASE_ADDRESS, 488 &prop_vdso_base, sizeof(prop_vdso_base)); 489 snprintf(msg, sizeof(msg), "zx_object_get_property failed: %d", status); 490 ASSERT_EQ(status, 0, msg); 491 492 dl_phdr_info info; 493 info.dlpi_addr = prop_vdso_base; 494 int ret = dl_iterate_phdr(&phdr_info_callback, &info); 495 ASSERT_EQ(ret, 1, "dl_iterate_phdr didn't see vDSO?"); 496 497 uintptr_t vdso_code_start = 0; 498 size_t vdso_code_len = 0; 499 for (unsigned i = 0; i < info.dlpi_phnum; ++i) { 500 if (info.dlpi_phdr[i].p_type == PT_LOAD && (info.dlpi_phdr[i].p_flags & PF_X)) { 501 vdso_code_start = info.dlpi_addr + info.dlpi_phdr[i].p_vaddr; 502 vdso_code_len = info.dlpi_phdr[i].p_memsz; 503 break; 504 } 505 } 506 ASSERT_NE(vdso_code_start, 0u, "vDSO has no code segment?"); 507 ASSERT_NE(vdso_code_len, 0u, "vDSO has no code segment?"); 508 509 *start = vdso_code_start; 510 *end = vdso_code_start + vdso_code_len - 1; 511 512 END_HELPER; 513} 514