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 <assert.h> 6#include <inttypes.h> 7#include <link.h> 8#include <stdbool.h> 9#include <stdlib.h> 10#include <string.h> 11 12#include <fbl/atomic.h> 13#include <launchpad/launchpad.h> 14#include <launchpad/vmo.h> 15#include <lib/zircon-internal/crashlogger.h> 16#include <test-utils/test-utils.h> 17#include <unittest/unittest.h> 18#include <zircon/process.h> 19#include <zircon/processargs.h> 20#include <zircon/syscalls.h> 21#include <zircon/syscalls/debug.h> 22#include <zircon/syscalls/exception.h> 23#include <zircon/syscalls/object.h> 24#include <zircon/syscalls/port.h> 25#include <zircon/threads.h> 26 27#include "utils.h" 28 29namespace { 30 31typedef bool(wait_inferior_exception_handler_t)(zx_handle_t inferior, zx_handle_t port, 32 const zx_port_packet_t* packet, void* handler_arg); 33 34constexpr size_t kTestMemorySize = 8; 35constexpr uint8_t kTestDataAdjust = 0x10; 36 37// Do the segv recovery test a number of times to stress test the API. 38constexpr int kNumSegvTries = 4; 39 40constexpr int kNumExtraThreads = 4; 41 42// Produce a backtrace of sufficient size to be interesting but not excessive. 43constexpr int kTestSegfaultDepth = 4; 44 45const char test_inferior_child_name[] = "inferior"; 46// The segfault child is not used by the test. 47// It exists for debugging purposes. 48const char test_segfault_child_name[] = "segfault"; 49// Used for testing the s/w breakpoint insn. 50const char test_swbreak_child_name[] = "swbreak"; 51 52fbl::atomic<int> extra_thread_count; 53 54uint64_t extract_pc_reg(const zx_thread_state_general_regs_t* regs) { 55#if defined(__x86_64__) 56 return regs->rip; 57#elif defined(__aarch64__) 58 return regs->pc; 59#endif 60} 61 62uint64_t extract_sp_reg(const zx_thread_state_general_regs_t* regs) { 63#if defined(__x86_64__) 64 return regs->rsp; 65#elif defined(__aarch64__) 66 return regs->sp; 67#endif 68} 69 70void test_memory_ops(zx_handle_t inferior, zx_handle_t thread) { 71 uint64_t test_data_addr = 0; 72 uint8_t test_data[kTestMemorySize]; 73 74 zx_thread_state_general_regs_t regs; 75 read_inferior_gregs(thread, ®s); 76 77#if defined(__x86_64__) 78 test_data_addr = regs.r9; 79#elif defined(__aarch64__) 80 test_data_addr = regs.r[9]; 81#endif 82 83 size_t size = read_inferior_memory(inferior, test_data_addr, test_data, sizeof(test_data)); 84 EXPECT_EQ(size, sizeof(test_data), "read_inferior_memory: short read"); 85 86 for (unsigned i = 0; i < sizeof(test_data); ++i) { 87 EXPECT_EQ(test_data[i], i, "test_memory_ops"); 88 } 89 90 for (unsigned i = 0; i < sizeof(test_data); ++i) { 91 test_data[i] = static_cast<uint8_t>(test_data[i] + kTestDataAdjust); 92 } 93 94 size = write_inferior_memory(inferior, test_data_addr, test_data, sizeof(test_data)); 95 EXPECT_EQ(size, sizeof(test_data), "write_inferior_memory: short write"); 96 97 // Note: Verification of the write is done in the inferior. 98} 99 100void fix_inferior_segv(zx_handle_t thread) { 101 unittest_printf("Fixing inferior segv\n"); 102 103 // The segv was because r8 == 0, change it to a usable value. See test_prep_and_segv. 104 zx_thread_state_general_regs_t regs; 105 read_inferior_gregs(thread, ®s); 106#if defined(__x86_64__) 107 regs.r8 = regs.rsp; 108#elif defined(__aarch64__) 109 regs.r[8] = regs.sp; 110#endif 111 write_inferior_gregs(thread, ®s); 112} 113 114bool test_segv_pc(zx_handle_t thread) { 115 zx_thread_state_general_regs_t regs; 116 read_inferior_gregs(thread, ®s); 117 118#if defined(__x86_64__) 119 ASSERT_EQ(regs.rip, regs.r10, "fault PC does not match r10"); 120#elif defined(__aarch64__) 121 ASSERT_EQ(regs.pc, regs.r[10], "fault PC does not match x10"); 122#endif 123 return true; 124} 125 126// A simpler exception handler. 127// All exceptions are passed on to |handler|. 128// Returns false if a test fails. 129// Otherwise waits for the inferior to exit and returns true. 130 131bool wait_inferior_thread_worker(inferior_data_t* inferior_data, 132 wait_inferior_exception_handler_t* handler, void* handler_arg) { 133 zx_handle_t inferior = inferior_data->inferior; 134 zx_koid_t pid = tu_get_koid(inferior); 135 zx_handle_t eport = inferior_data->eport; 136 137 while (true) { 138 zx_port_packet_t packet; 139 if (!read_exception(eport, &packet)) 140 return false; 141 142 // Is the inferior gone? 143 if (ZX_PKT_IS_SIGNAL_REP(packet.type) && packet.key == pid && 144 (packet.signal.observed & ZX_PROCESS_TERMINATED)) { 145 unittest_printf("wait-inf: inferior gone\n"); 146 return true; 147 } 148 149 if (!handler(inferior, eport, &packet, handler_arg)) 150 return false; 151 } 152} 153 154struct wait_inf_args_t { 155 inferior_data_t* inferior_data; 156 wait_inferior_exception_handler_t* handler; 157 void* handler_arg; 158}; 159 160int wait_inferior_thread_func(void* arg) { 161 wait_inf_args_t* args = static_cast<wait_inf_args_t*>(arg); 162 inferior_data_t* inferior_data = args->inferior_data; 163 wait_inferior_exception_handler_t* handler = args->handler; 164 void* handler_arg = args->handler_arg; 165 free(args); 166 167 bool pass = wait_inferior_thread_worker(inferior_data, handler, handler_arg); 168 169 return pass ? 0 : -1; 170} 171 172thrd_t start_wait_inf_thread(inferior_data_t* inferior_data, 173 wait_inferior_exception_handler_t* handler, void* handler_arg) { 174 wait_inf_args_t* args = static_cast<wait_inf_args_t*>(tu_calloc(1, sizeof(*args))); 175 176 // The proc handle is loaned to the thread. 177 // The caller of this function owns and must close it. 178 args->inferior_data = inferior_data; 179 args->handler = handler; 180 args->handler_arg = handler_arg; 181 182 thrd_t wait_inferior_thread; 183 tu_thread_create_c11(&wait_inferior_thread, wait_inferior_thread_func, args, "wait-inf thread"); 184 return wait_inferior_thread; 185} 186 187void join_wait_inf_thread(thrd_t wait_inf_thread) { 188 unittest_printf("Waiting for wait-inf thread\n"); 189 int thread_rc; 190 int ret = thrd_join(wait_inf_thread, &thread_rc); 191 EXPECT_EQ(ret, thrd_success, "thrd_join failed"); 192 EXPECT_EQ(thread_rc, 0, "unexpected wait-inf return"); 193 unittest_printf("wait-inf thread done\n"); 194} 195 196bool expect_debugger_attached_eq(zx_handle_t inferior, bool expected, const char* msg) { 197 zx_info_process_t info; 198 // ZX_ASSERT returns false if the check fails. 199 ASSERT_EQ(zx_object_get_info(inferior, ZX_INFO_PROCESS, &info, sizeof(info), NULL, NULL), ZX_OK); 200 ASSERT_EQ(info.debugger_attached, expected, msg); 201 return true; 202} 203 204// This returns a bool as it's a unittest "helper" routine. 205// N.B. This runs on the wait-inferior thread. 206 207bool handle_thread_exiting(zx_handle_t inferior, const zx_port_packet_t* packet) { 208 BEGIN_HELPER; 209 210 zx_koid_t tid = packet->exception.tid; 211 zx_handle_t thread; 212 zx_status_t status = zx_object_get_child(inferior, tid, ZX_RIGHT_SAME_RIGHTS, &thread); 213 // If the process has exited then the kernel may have reaped the 214 // thread already. Check. 215 if (status == ZX_OK) { 216 zx_info_thread_t info = tu_thread_get_info(thread); 217 // The thread could still transition to DEAD here (if the 218 // process exits), so check for either DYING or DEAD. 219 EXPECT_TRUE(info.state == ZX_THREAD_STATE_DYING || info.state == ZX_THREAD_STATE_DEAD); 220 // If the state is DYING it would be nice to check that the 221 // value of |info.wait_exception_port_type| is DEBUGGER. Alas 222 // if the process has exited then the thread will get 223 // THREAD_SIGNAL_KILL which will cause 224 // UserThread::ExceptionHandlerExchange to exit before we've 225 // told the thread to "resume" from ZX_EXCP_THREAD_EXITING. 226 // The thread is still in the DYING state but it is no longer 227 // in an exception. Thus |info.wait_exception_port_type| can 228 // either be DEBUGGER or NONE. 229 EXPECT_TRUE(info.wait_exception_port_type == ZX_EXCEPTION_PORT_TYPE_NONE || 230 info.wait_exception_port_type == ZX_EXCEPTION_PORT_TYPE_DEBUGGER); 231 tu_handle_close(thread); 232 } else { 233 EXPECT_EQ(status, ZX_ERR_NOT_FOUND); 234 EXPECT_TRUE(tu_process_has_exited(inferior)); 235 } 236 unittest_printf("wait-inf: thread %" PRId64 " exited\n", tid); 237 // A thread is gone, but we only care about the process. 238 if (!resume_inferior(inferior, tid)) 239 return false; 240 241 END_HELPER; 242} 243 244// This returns a bool as it's a unittest "helper" routine. 245// N.B. This runs on the wait-inferior thread. 246 247bool handle_expected_page_fault(zx_handle_t inferior, 248 zx_handle_t port, 249 const zx_port_packet_t* packet, 250 fbl::atomic<int>* segv_count) { 251 BEGIN_HELPER; 252 253 unittest_printf("wait-inf: got page fault exception\n"); 254 255 zx_koid_t tid = packet->exception.tid; 256 zx_handle_t thread = tu_get_thread(inferior, tid); 257 258 dump_inferior_regs(thread); 259 260 // Verify that the fault is at the PC we expected. 261 if (!test_segv_pc(thread)) 262 return false; 263 264 // Do some tests that require a suspended inferior. 265 test_memory_ops(inferior, thread); 266 267 fix_inferior_segv(thread); 268 // Useful for debugging, otherwise a bit too verbose. 269 // dump_inferior_regs(thread); 270 271 // Increment this before resuming the inferior in case the inferior 272 // sends MSG_RECOVERED_FROM_CRASH and the testcase processes the message 273 // before we can increment it. 274 atomic_fetch_add(segv_count, 1); 275 276 zx_status_t status = zx_task_resume_from_exception(thread, port, 0); 277 tu_handle_close(thread); 278 ASSERT_EQ(status, ZX_OK); 279 280 END_HELPER; 281} 282 283// N.B. This runs on the wait-inferior thread. 284 285bool debugger_test_exception_handler(zx_handle_t inferior, zx_handle_t port, 286 const zx_port_packet_t* packet, 287 void* handler_arg) { 288 BEGIN_HELPER; 289 290 // Note: This may be NULL if the test is not expecting a page fault. 291 fbl::atomic<int>* segv_count = static_cast<fbl::atomic<int>*>(handler_arg); 292 293 zx_koid_t pid = tu_get_koid(inferior); 294 295 if (ZX_PKT_IS_SIGNAL_REP(packet->type)) { 296 ASSERT_TRUE(packet->key != pid); 297 // Must be a signal on one of the threads. 298 // Here we're only expecting TERMINATED. 299 ASSERT_TRUE(packet->signal.observed & ZX_THREAD_TERMINATED); 300 } else { 301 ASSERT_TRUE(ZX_PKT_IS_EXCEPTION(packet->type)); 302 303 zx_koid_t tid = packet->exception.tid; 304 305 switch (packet->type) { 306 case ZX_EXCP_THREAD_STARTING: 307 unittest_printf("wait-inf: inferior started\n"); 308 if (!resume_inferior(inferior, tid)) 309 return false; 310 break; 311 312 case ZX_EXCP_THREAD_EXITING: 313 // N.B. We could get thread exiting messages from previous 314 // tests. 315 EXPECT_TRUE(handle_thread_exiting(inferior, packet)); 316 break; 317 318 case ZX_EXCP_FATAL_PAGE_FAULT: 319 ASSERT_NONNULL(segv_count); 320 ASSERT_TRUE(handle_expected_page_fault(inferior, port, packet, segv_count)); 321 break; 322 323 default: { 324 char msg[128]; 325 snprintf(msg, sizeof(msg), "unexpected packet type: 0x%x", packet->type); 326 ASSERT_TRUE(false, msg); 327 __UNREACHABLE; 328 } 329 } 330 } 331 332 END_HELPER; 333} 334 335bool debugger_test() { 336 BEGIN_TEST; 337 338 launchpad_t* lp; 339 zx_handle_t inferior, channel; 340 if (!setup_inferior(test_inferior_child_name, &lp, &inferior, &channel)) 341 return false; 342 343 fbl::atomic<int> segv_count; 344 345 expect_debugger_attached_eq(inferior, false, "debugger should not appear attached"); 346 zx_handle_t eport = tu_io_port_create(); 347 size_t max_threads = 10; 348 inferior_data_t* inferior_data = attach_inferior(inferior, eport, max_threads); 349 thrd_t wait_inf_thread = 350 start_wait_inf_thread(inferior_data, debugger_test_exception_handler, &segv_count); 351 EXPECT_NE(eport, ZX_HANDLE_INVALID); 352 expect_debugger_attached_eq(inferior, true, "debugger should appear attached"); 353 354 if (!start_inferior(lp)) 355 return false; 356 if (!verify_inferior_running(channel)) 357 return false; 358 359 segv_count.store(0); 360 enum message msg; 361 send_msg(channel, MSG_CRASH_AND_RECOVER_TEST); 362 if (!recv_msg(channel, &msg)) 363 return false; 364 EXPECT_EQ(msg, MSG_RECOVERED_FROM_CRASH, "unexpected response from crash"); 365 EXPECT_EQ(segv_count.load(), kNumSegvTries, "segv tests terminated prematurely"); 366 367 if (!shutdown_inferior(channel, inferior)) 368 return false; 369 370 // Stop the waiter thread before closing the eport that it's waiting on. 371 join_wait_inf_thread(wait_inf_thread); 372 373 detach_inferior(inferior_data, false); 374 375 expect_debugger_attached_eq(inferior, true, "debugger should still appear attached"); 376 tu_handle_close(eport); 377 expect_debugger_attached_eq(inferior, false, "debugger should no longer appear attached"); 378 379 tu_handle_close(channel); 380 tu_handle_close(inferior); 381 382 END_TEST; 383} 384 385bool debugger_thread_list_test() { 386 BEGIN_TEST; 387 388 launchpad_t* lp; 389 zx_handle_t inferior, channel; 390 if (!setup_inferior(test_inferior_child_name, &lp, &inferior, &channel)) 391 return false; 392 393 zx_handle_t eport = tu_io_port_create(); 394 size_t max_threads = 10; 395 inferior_data_t* inferior_data = attach_inferior(inferior, eport, max_threads); 396 thrd_t wait_inf_thread = 397 start_wait_inf_thread(inferior_data, debugger_test_exception_handler, NULL); 398 EXPECT_NE(eport, ZX_HANDLE_INVALID); 399 400 if (!start_inferior(lp)) 401 return false; 402 if (!verify_inferior_running(channel)) 403 return false; 404 405 enum message msg; 406 send_msg(channel, MSG_START_EXTRA_THREADS); 407 if (!recv_msg(channel, &msg)) 408 return false; 409 EXPECT_EQ(msg, MSG_EXTRA_THREADS_STARTED, "unexpected response when starting extra threads"); 410 411 // This doesn't use tu_process_get_threads() because here we're testing 412 // various aspects of ZX_INFO_PROCESS_THREADS. 413 uint32_t buf_size = 100 * sizeof(zx_koid_t); 414 size_t num_threads; 415 zx_koid_t* threads = static_cast<zx_koid_t*>(tu_malloc(buf_size)); 416 zx_status_t status = zx_object_get_info(inferior, ZX_INFO_PROCESS_THREADS, threads, buf_size, 417 &num_threads, NULL); 418 ASSERT_EQ(status, ZX_OK); 419 420 // There should be at least 1+kNumExtraThreads threads in the result. 421 ASSERT_GE(num_threads, 1 + kNumExtraThreads, "zx_object_get_info failed"); 422 423 // Verify each entry is valid. 424 for (uint32_t i = 0; i < num_threads; ++i) { 425 zx_koid_t koid = threads[i]; 426 unittest_printf("Looking up thread %llu\n", (long long)koid); 427 zx_handle_t thread = tu_get_thread(inferior, koid); 428 zx_info_handle_basic_t info; 429 status = zx_object_get_info(thread, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), NULL, NULL); 430 EXPECT_EQ(status, ZX_OK, "zx_object_get_info failed"); 431 EXPECT_EQ(info.type, ZX_OBJ_TYPE_THREAD, "not a thread"); 432 } 433 434 if (!shutdown_inferior(channel, inferior)) 435 return false; 436 437 // Stop the waiter thread before closing the eport that it's waiting on. 438 join_wait_inf_thread(wait_inf_thread); 439 440 detach_inferior(inferior_data, true); 441 442 tu_handle_close(eport); 443 tu_handle_close(channel); 444 tu_handle_close(inferior); 445 446 END_TEST; 447} 448 449bool property_process_debug_addr_test() { 450 BEGIN_TEST; 451 452 zx_handle_t self = zx_process_self(); 453 454 // We shouldn't be able to set it. 455 uintptr_t debug_addr = 42; 456 zx_status_t status = 457 zx_object_set_property(self, ZX_PROP_PROCESS_DEBUG_ADDR, &debug_addr, sizeof(debug_addr)); 458 ASSERT_EQ(status, ZX_ERR_ACCESS_DENIED); 459 460 // Some minimal verification that the value is correct. 461 462 status = 463 zx_object_get_property(self, ZX_PROP_PROCESS_DEBUG_ADDR, &debug_addr, sizeof(debug_addr)); 464 ASSERT_EQ(status, ZX_OK); 465 466 // These are all dsos we link with. See rules.mk. 467 const char* launchpad_so = "liblaunchpad.so"; 468 bool found_launchpad = false; 469 const char* libc_so = "libc.so"; 470 bool found_libc = false; 471 const char* test_utils_so = "libtest-utils.so"; 472 bool found_test_utils = false; 473 const char* unittest_so = "libunittest.so"; 474 bool found_unittest = false; 475 476 const r_debug* debug = (r_debug*)debug_addr; 477 const link_map* lmap = debug->r_map; 478 479 EXPECT_EQ(debug->r_state, r_debug::RT_CONSISTENT); 480 481 while (lmap != NULL) { 482 if (strcmp(lmap->l_name, launchpad_so) == 0) 483 found_launchpad = true; 484 else if (strcmp(lmap->l_name, libc_so) == 0) 485 found_libc = true; 486 else if (strcmp(lmap->l_name, test_utils_so) == 0) 487 found_test_utils = true; 488 else if (strcmp(lmap->l_name, unittest_so) == 0) 489 found_unittest = true; 490 lmap = lmap->l_next; 491 } 492 493 EXPECT_TRUE(found_launchpad); 494 EXPECT_TRUE(found_libc); 495 EXPECT_TRUE(found_test_utils); 496 EXPECT_TRUE(found_unittest); 497 498 END_TEST; 499} 500 501int write_text_segment_helper() __ALIGNED(8); 502int write_text_segment_helper() { 503 /* This function needs to be at least two bytes in size as we set a 504 breakpoint, figuratively speaking, on write_text_segment_helper + 1 505 to ensure the address is not page aligned. Returning some random value 506 will ensure that. */ 507 return 42; 508} 509 510bool write_text_segment() { 511 BEGIN_TEST; 512 513 zx_handle_t self = zx_process_self(); 514 515 // Exercise ZX-739 516 // Pretend we're writing a s/w breakpoint to the start of this function. 517 518 // write_text_segment_helper is suitably aligned, add 1 to ensure the 519 // byte we write is not page aligned. 520 uintptr_t addr = (uintptr_t)write_text_segment_helper + 1; 521 uint8_t previous_byte; 522 size_t size = read_inferior_memory(self, addr, &previous_byte, sizeof(previous_byte)); 523 EXPECT_EQ(size, sizeof(previous_byte)); 524 525 uint8_t byte_to_write = 0; 526 size = write_inferior_memory(self, addr, &byte_to_write, sizeof(byte_to_write)); 527 EXPECT_EQ(size, sizeof(byte_to_write)); 528 529 size = write_inferior_memory(self, addr, &previous_byte, sizeof(previous_byte)); 530 EXPECT_EQ(size, sizeof(previous_byte)); 531 532 END_TEST; 533} 534 535// These are "call-saved" registers used in the test. 536#if defined(__x86_64__) 537#define REG_ACCESS_TEST_REG r15 538#define REG_ACCESS_TEST_REG_NAME "r15" 539#elif defined(__aarch64__) 540#define REG_ACCESS_TEST_REG r[28] 541#define REG_ACCESS_TEST_REG_NAME "x28" 542#endif 543 544// Note: Neither of these can be zero. 545const uint64_t reg_access_initial_value = 0xee112233445566eeull; 546const uint64_t reg_access_write_test_value = 0xee665544332211eeull; 547 548struct suspended_reg_access_arg { 549 zx_handle_t channel; 550 uint64_t initial_value; 551 uint64_t result; 552 uint64_t pc, sp; 553}; 554 555int reg_access_thread_func(void* arg_) { 556 suspended_reg_access_arg* arg = static_cast<suspended_reg_access_arg*>(arg_); 557 558 send_msg(arg->channel, MSG_PONG); 559 560 // The loop has to be written in assembler as we cannot control what 561 // the compiler does with our "reserved" registers outside of the asm; 562 // they're not really reserved in the way we need them to be: the compiler 563 // is free to do with them whatever it wants outside of the assembler. 564 // We do make the assumption that test_reg will not contain 565 // |reg_access_initial_value| until it is set by the assembler. 566 567 uint64_t initial_value = arg->initial_value; 568 uint64_t result = 0; 569 uint64_t pc = 0; 570 uint64_t sp = 0; 571 572// The maximum number of bytes in the assembly. 573// This doesn't have to be perfect. It's used to verify the value read for 574// $pc is within some reasonable range. 575#define REG_ACCESS_MAX_LOOP_SIZE 64 576 577#ifdef __x86_64__ 578 __asm__("\ 579 lea .(%%rip), %[pc]\n\ 580 mov %%rsp, %[sp]\n\ 581 mov %[initial_value], %%" REG_ACCESS_TEST_REG_NAME "\n\ 582 2:\n\ 583 pause\n\ 584 cmp %[initial_value], %%" REG_ACCESS_TEST_REG_NAME "\n\ 585 je 2b\n\ 586 mov %%" REG_ACCESS_TEST_REG_NAME ", %[result]" 587 : [result] "=r"(result), [pc] "=&r"(pc), [sp] "=&r"(sp) 588 : [initial_value] "r"(initial_value) 589 : REG_ACCESS_TEST_REG_NAME); 590#endif 591 592#ifdef __aarch64__ 593 __asm__("\ 594 adr %[pc], .\n\ 595 mov %[sp], sp\n\ 596 mov " REG_ACCESS_TEST_REG_NAME ", %[initial_value]\n\ 597 1:\n\ 598 yield\n\ 599 cmp %[initial_value], " REG_ACCESS_TEST_REG_NAME "\n\ 600 b.eq 1b\n\ 601 mov %[result], " REG_ACCESS_TEST_REG_NAME 602 : [result] "=r"(result), [pc] "=&r"(pc), [sp] "=&r"(sp) 603 : [initial_value] "r"(initial_value) 604 : REG_ACCESS_TEST_REG_NAME); 605#endif 606 607 arg->result = result; 608 arg->pc = pc; 609 arg->sp = sp; 610 611 tu_handle_close(arg->channel); 612 613 return 0; 614} 615 616bool suspended_reg_access_test() { 617 BEGIN_TEST; 618 619 zx_handle_t self_proc = zx_process_self(); 620 621 thrd_t thread_c11; 622 suspended_reg_access_arg arg = {}; 623 arg.initial_value = reg_access_initial_value; 624 zx_handle_t channel; 625 tu_channel_create(&channel, &arg.channel); 626 tu_thread_create_c11(&thread_c11, reg_access_thread_func, &arg, "reg-access thread"); 627 // Get our own copy of the thread handle to avoid lifetime issues of 628 // thrd's copy. 629 zx_handle_t thread = tu_handle_duplicate(thrd_get_zx_handle(thread_c11)); 630 631 // KISS: Don't attach until the thread is up and running so we don't see 632 // ZX_EXCP_THREAD_STARTING. 633 enum message msg; 634 recv_msg(channel, &msg); 635 // No need to send a ping. 636 ASSERT_EQ(msg, MSG_PONG); 637 638 // Set up waiting for the thread to suspend via a port (since this is 639 // what debuggers will typically do). 640 zx_handle_t eport = tu_io_port_create(); 641 zx_signals_t signals = ZX_THREAD_TERMINATED | ZX_THREAD_RUNNING | ZX_THREAD_SUSPENDED; 642 tu_object_wait_async(thread, eport, signals); 643 644 // Keep looping until we know the thread is stopped in the assembler. 645 // This is the only place we can guarantee particular registers have 646 // particular values. 647 zx_handle_t suspend_token = ZX_HANDLE_INVALID; 648 zx_thread_state_general_regs_t regs; 649 uint64_t test_reg = 0; 650 while (true) { 651 zx_nanosleep(zx_deadline_after(ZX_USEC(1))); 652 ASSERT_EQ(zx_task_suspend_token(thread, &suspend_token), ZX_OK); 653 ASSERT_TRUE(wait_thread_suspended(self_proc, thread, eport)); 654 655 read_inferior_gregs(thread, ®s); 656 test_reg = regs.REG_ACCESS_TEST_REG; 657 658 if (test_reg == reg_access_initial_value) 659 break; // Keep thread suspended. 660 661 // Resume and try again. 662 zx_handle_close(suspend_token); 663 } 664 665 uint64_t pc_value = extract_pc_reg(®s); 666 uint64_t sp_value = extract_sp_reg(®s); 667 regs.REG_ACCESS_TEST_REG = reg_access_write_test_value; 668 write_inferior_gregs(thread, ®s); 669 670 ASSERT_EQ(zx_handle_close(suspend_token), ZX_OK); 671 thrd_join(thread_c11, NULL); 672 tu_handle_close(thread); 673 674 // We can't test the pc value exactly as we don't know on which instruction 675 // the thread will be suspended. But we can verify it is within some 676 // minimal range. 677 EXPECT_GE(pc_value, arg.pc); 678 EXPECT_LE(pc_value, arg.pc + REG_ACCESS_MAX_LOOP_SIZE); 679 680 EXPECT_EQ(sp_value, arg.sp); 681 682 EXPECT_EQ(reg_access_write_test_value, arg.result); 683 684 tu_handle_close(channel); 685 tu_handle_close(eport); 686 END_TEST; 687} 688 689struct suspended_in_syscall_reg_access_arg { 690 bool do_channel_call; 691 zx_handle_t syscall_handle; 692 fbl::atomic<uintptr_t> sp; 693}; 694 695// "zx_channel_call treats the leading bytes of the payload as 696// a transaction id of type zx_txid_t" 697static_assert(sizeof(zx_txid_t) == sizeof(uint32_t), ""); 698#define CHANNEL_CALL_PACKET_SIZE (sizeof(zx_txid_t) + sizeof("x")) 699 700int suspended_in_syscall_reg_access_thread_func(void* arg_) { 701 suspended_in_syscall_reg_access_arg* arg = 702 static_cast<suspended_in_syscall_reg_access_arg*>(arg_); 703 704 uint64_t sp; 705#ifdef __x86_64__ 706 __asm__("\ 707 mov %%rsp, %[sp]" 708 : [sp] "=r"(sp)); 709#endif 710#ifdef __aarch64__ 711 __asm__("\ 712 mov %[sp], sp" 713 : [sp] "=r"(sp)); 714#endif 715 arg->sp.store(sp); 716 717 if (arg->do_channel_call) { 718 uint8_t send_buf[CHANNEL_CALL_PACKET_SIZE] = "TXIDx"; 719 uint8_t recv_buf[CHANNEL_CALL_PACKET_SIZE]; 720 uint32_t actual_bytes, actual_handles; 721 zx_channel_call_args_t call_args = { 722 .wr_bytes = send_buf, 723 .wr_handles = NULL, 724 .rd_bytes = recv_buf, 725 .rd_handles = NULL, 726 .wr_num_bytes = sizeof(send_buf), 727 .wr_num_handles = 0, 728 .rd_num_bytes = sizeof(recv_buf), 729 .rd_num_handles = 0, 730 }; 731 zx_status_t call_status = zx_channel_call(arg->syscall_handle, 0, ZX_TIME_INFINITE, 732 &call_args, &actual_bytes, &actual_handles); 733 ASSERT_EQ(call_status, ZX_OK); 734 EXPECT_EQ(actual_bytes, sizeof(recv_buf)); 735 EXPECT_EQ(memcmp(recv_buf + sizeof(zx_txid_t), "y", sizeof(recv_buf) - sizeof(zx_txid_t)), 0); 736 } else { 737 zx_signals_t pending; 738 zx_status_t status = 739 zx_object_wait_one(arg->syscall_handle, ZX_EVENT_SIGNALED, ZX_TIME_INFINITE, &pending); 740 ASSERT_EQ(status, ZX_OK); 741 EXPECT_NE(pending & ZX_EVENT_SIGNALED, 0u); 742 } 743 744 return 0; 745} 746 747// Channel calls are a little special in that they are a two part syscall, 748// with suspension possible in between the two parts. 749// If |do_channel_call| is true, test zx_channel_call. Otherwise test some 750// random syscall that can block, here we use zx_object_wait_one. 751// 752// The syscall entry point is the vdso, there's no bypassing this for test 753// purposes. Also, the kernel doesn't save userspace regs on entry, it only 754// saves them later if it needs to - at which point many don't necessarily 755// have any useful value. Putting these together means we can't easily test 756// random integer registers: there's no guarantee any value we set in the test 757// will be available when the syscall is suspended. All is not lost, we can 758// still at least test that reading $pc, $sp work. 759 760bool suspended_in_syscall_reg_access_worker(bool do_channel_call) { 761 zx_handle_t self_proc = zx_process_self(); 762 763 uintptr_t vdso_start = 0, vdso_end = 0; 764 EXPECT_TRUE(get_vdso_exec_range(&vdso_start, &vdso_end)); 765 766 suspended_in_syscall_reg_access_arg arg = {}; 767 arg.do_channel_call = do_channel_call; 768 769 zx_handle_t syscall_handle; 770 if (do_channel_call) { 771 tu_channel_create(&arg.syscall_handle, &syscall_handle); 772 } else { 773 ASSERT_EQ(zx_event_create(0u, &syscall_handle), ZX_OK); 774 arg.syscall_handle = syscall_handle; 775 } 776 777 thrd_t thread_c11; 778 tu_thread_create_c11(&thread_c11, suspended_in_syscall_reg_access_thread_func, &arg, 779 "reg-access thread"); 780 // Get our own copy of the thread handle to avoid lifetime issues of 781 // thrd's copy. 782 zx_handle_t thread = tu_handle_duplicate(thrd_get_zx_handle(thread_c11)); 783 784 // Busy-wait until thread is blocked inside the syscall. 785 zx_info_thread_t thread_info; 786 uint32_t expected_blocked_reason = 787 do_channel_call ? ZX_THREAD_STATE_BLOCKED_CHANNEL : ZX_THREAD_STATE_BLOCKED_WAIT_ONE; 788 do { 789 // Don't check too frequently here as it can blow up tracing output 790 // when debugging with kernel tracing turned on. 791 zx_nanosleep(zx_deadline_after(ZX_USEC(100))); 792 thread_info = tu_thread_get_info(thread); 793 } while (thread_info.state != expected_blocked_reason); 794 ASSERT_EQ(thread_info.wait_exception_port_type, ZX_EXCEPTION_PORT_TYPE_NONE); 795 796 // Extra sanity check for channels. 797 if (do_channel_call) { 798 EXPECT_TRUE(tu_channel_wait_readable(syscall_handle)); 799 } 800 801 // Set up waiting for the thread to suspend via a port (since this is 802 // what debuggers will typically do). 803 zx_handle_t eport = tu_io_port_create(); 804 zx_signals_t signals = ZX_THREAD_TERMINATED | ZX_THREAD_RUNNING | ZX_THREAD_SUSPENDED; 805 tu_object_wait_async(thread, eport, signals); 806 807 zx_handle_t token; 808 ASSERT_EQ(zx_task_suspend_token(thread, &token), ZX_OK); 809 810 ASSERT_TRUE(wait_thread_suspended(self_proc, thread, eport)); 811 812 zx_thread_state_general_regs_t regs; 813 read_inferior_gregs(thread, ®s); 814 815 // Verify the pc is somewhere within the vdso. 816 uint64_t pc_value = extract_pc_reg(®s); 817 EXPECT_GE(pc_value, vdso_start); 818 EXPECT_LE(pc_value, vdso_end); 819 820 // The stack pointer is somewhere within the syscall. 821 // Just verify the value we have is within range. 822 uint64_t sp_value = extract_sp_reg(®s); 823 uint64_t arg_sp = arg.sp.load(); 824 EXPECT_LE(sp_value, arg_sp); 825 EXPECT_GE(sp_value + 1024, arg_sp); 826 827 // wake the thread 828 if (do_channel_call) { 829 uint8_t buf[CHANNEL_CALL_PACKET_SIZE]; 830 uint32_t actual_bytes; 831 ASSERT_EQ( 832 zx_channel_read(syscall_handle, 0, buf, NULL, sizeof(buf), 0, &actual_bytes, NULL), 833 ZX_OK); 834 EXPECT_EQ(actual_bytes, sizeof(buf)); 835 EXPECT_EQ(memcmp(buf + sizeof(zx_txid_t), "x", sizeof(buf) - sizeof(zx_txid_t)), 0); 836 837 // write a reply 838 buf[sizeof(zx_txid_t)] = 'y'; 839 ASSERT_EQ(zx_channel_write(syscall_handle, 0, buf, sizeof(buf), NULL, 0), ZX_OK); 840 841 // Make sure the remote channel didn't get signaled 842 EXPECT_EQ(zx_object_wait_one(arg.syscall_handle, ZX_CHANNEL_READABLE, 0, NULL), 843 ZX_ERR_TIMED_OUT); 844 845 // Make sure we can't read from the remote channel (the message should have 846 // been reserved for the other thread, even though it is suspended). 847 EXPECT_EQ( 848 zx_channel_read(arg.syscall_handle, 0, buf, NULL, sizeof(buf), 0, &actual_bytes, NULL), 849 ZX_ERR_SHOULD_WAIT); 850 } else { 851 ASSERT_EQ(zx_object_signal(syscall_handle, 0u, ZX_EVENT_SIGNALED), ZX_OK); 852 } 853 854 ASSERT_EQ(zx_handle_close(token), ZX_OK); 855 thrd_join(thread_c11, NULL); 856 tu_handle_close(thread); 857 858 tu_handle_close(eport); 859 if (do_channel_call) { 860 tu_handle_close(arg.syscall_handle); 861 } 862 tu_handle_close(syscall_handle); 863 864 return true; 865} 866 867bool suspended_in_syscall_reg_access_test() { 868 BEGIN_TEST; 869 870 EXPECT_TRUE(suspended_in_syscall_reg_access_worker(false)); 871 872 END_TEST; 873} 874 875bool suspended_in_channel_call_reg_access_test() { 876 BEGIN_TEST; 877 878 EXPECT_TRUE(suspended_in_syscall_reg_access_worker(true)); 879 880 END_TEST; 881} 882 883struct suspend_in_exception_data { 884 fbl::atomic<int> segv_count; 885 fbl::atomic<int> suspend_count; 886 fbl::atomic<int> resume_count; 887 zx_handle_t thread_handle; 888 zx_koid_t process_id; 889 zx_koid_t thread_id; 890}; 891 892// N.B. This runs on the wait-inferior thread. 893 894bool suspended_in_exception_handler(zx_handle_t inferior, zx_handle_t port, 895 const zx_port_packet_t* packet, void* handler_arg) { 896 BEGIN_HELPER; 897 898 suspend_in_exception_data* data = static_cast<suspend_in_exception_data*>(handler_arg); 899 900 if (ZX_PKT_IS_SIGNAL_REP(packet->type)) { 901 // Must be a signal on one of the threads. 902 ASSERT_TRUE(packet->key != data->process_id); 903 zx_koid_t pkt_tid = packet->key; 904 905 // The following signals are expected here. Note that 906 // ZX_THREAD_RUNNING and ZX_THREAD_TERMINATED can be reported 907 // together in the same zx_port_packet_t. 908 if (packet->signal.observed & ZX_THREAD_TERMINATED) { 909 // Nothing to do. 910 } 911 if (packet->signal.observed & ZX_THREAD_RUNNING) { 912 ASSERT_EQ(pkt_tid, data->thread_id); 913 atomic_fetch_add(&data->resume_count, 1); 914 } 915 if (packet->signal.observed & ZX_THREAD_SUSPENDED) { 916 ASSERT_EQ(pkt_tid, data->thread_id); 917 atomic_fetch_add(&data->suspend_count, 1); 918 ASSERT_EQ(zx_task_resume(data->thread_handle, 0), ZX_OK); 919 // At this point we should get ZX_THREAD_RUNNING, we'll 920 // process it later. 921 } 922 } else { 923 ASSERT_TRUE(ZX_PKT_IS_EXCEPTION(packet->type)); 924 925 zx_koid_t pkt_tid = packet->exception.tid; 926 927 switch (packet->type) { 928 case ZX_EXCP_THREAD_EXITING: 929 // N.B. We could get thread exiting messages from previous 930 // tests. 931 EXPECT_TRUE(handle_thread_exiting(inferior, packet)); 932 break; 933 934 case ZX_EXCP_FATAL_PAGE_FAULT: { 935 unittest_printf("wait-inf: got page fault exception\n"); 936 937 ASSERT_EQ(pkt_tid, data->thread_id); 938 939 // Verify that the fault is at the PC we expected. 940 if (!test_segv_pc(data->thread_handle)) 941 return false; 942 943 // Suspend the thread before fixing the segv to verify register 944 // access works while the thread is in an exception and suspended. 945 zx_handle_t token; 946 ASSERT_EQ(zx_task_suspend_token(data->thread_handle, &token), ZX_OK); 947 948 // Waiting for the thread to suspend doesn't work here as the 949 // thread stays in the exception until we pass ZX_RESUME_EXCEPTION. 950 // Just give the scheduler a chance to run the thread and process 951 // the ZX_ERR_INTERNAL_INTR_RETRY in ExceptionHandlerExchange. 952 zx_nanosleep(zx_deadline_after(ZX_MSEC(1))); 953 954 // Do some tests that require a suspended inferior. 955 // This is required as the inferior does tests after it wakes up 956 // that assumes we've done this. 957 test_memory_ops(inferior, data->thread_handle); 958 959 // Now correct the issue and resume the inferior. 960 fix_inferior_segv(data->thread_handle); 961 962 atomic_fetch_add(&data->segv_count, 1); 963 964 ASSERT_EQ(zx_task_resume(data->thread_handle, ZX_RESUME_EXCEPTION), ZX_OK); 965 // At this point we should get ZX_THREAD_SUSPENDED, we'll 966 // process it later. 967 968 break; 969 } 970 971 default: { 972 char msg[128]; 973 snprintf(msg, sizeof(msg), "unexpected packet type: 0x%x", packet->type); 974 ASSERT_TRUE(false, msg); 975 __UNREACHABLE; 976 } 977 } 978 } 979 980 END_HELPER; 981} 982 983bool suspended_in_exception_reg_access_test() { 984 BEGIN_TEST; 985 986 launchpad_t* lp; 987 zx_handle_t inferior, channel; 988 if (!setup_inferior(test_inferior_child_name, &lp, &inferior, &channel)) 989 return false; 990 991 if (!start_inferior(lp)) 992 return false; 993 if (!verify_inferior_running(channel)) 994 return false; 995 996 suspend_in_exception_data data; 997 data.segv_count.store(0); 998 data.suspend_count.store(0); 999 data.resume_count.store(0); 1000 ASSERT_TRUE(get_inferior_thread_handle(channel, &data.thread_handle)); 1001 data.process_id = tu_get_koid(inferior); 1002 data.thread_id = tu_get_koid(data.thread_handle); 1003 1004 // Defer attaching until after the inferior is running to test 1005 // attach_inferior's recording of existing threads. If that fails 1006 // it won't see thread suspended/running messages from the thread. 1007 zx_handle_t eport = tu_io_port_create(); 1008 size_t max_threads = 10; 1009 inferior_data_t* inferior_data = attach_inferior(inferior, eport, max_threads); 1010 thrd_t wait_inf_thread = 1011 start_wait_inf_thread(inferior_data, suspended_in_exception_handler, &data); 1012 EXPECT_NE(eport, ZX_HANDLE_INVALID); 1013 1014 enum message msg; 1015 send_msg(channel, MSG_CRASH_AND_RECOVER_TEST); 1016 if (!recv_msg(channel, &msg)) { 1017 return false; 1018 } 1019 // wait_inf_thread will process the crash and resume the inferior. 1020 EXPECT_EQ(msg, MSG_RECOVERED_FROM_CRASH); 1021 1022 if (!shutdown_inferior(channel, inferior)) 1023 return false; 1024 1025 // Stop the waiter thread before closing the eport that it's waiting on. 1026 join_wait_inf_thread(wait_inf_thread); 1027 1028 detach_inferior(inferior_data, true); 1029 1030 // Don't check these until now to ensure the resume_count has been 1031 // updated (we're guaranteed that ZX_THREAD_RUNNING will be signalled 1032 // and processed before the waiter thread exits. 1033 EXPECT_EQ(data.segv_count.load(), kNumSegvTries); 1034 EXPECT_EQ(data.suspend_count.load(), kNumSegvTries); 1035 // There's an initial "RUNNING" signal that the handler will see. 1036 // That is why we add one here. 1037 EXPECT_EQ(data.resume_count.load(), kNumSegvTries + 1); 1038 1039 tu_handle_close(data.thread_handle); 1040 tu_handle_close(eport); 1041 tu_handle_close(channel); 1042 tu_handle_close(inferior); 1043 1044 END_TEST; 1045} 1046 1047// This function is marked as no-inline to avoid duplicate label in case the 1048// function call is being inlined. 1049__NO_INLINE static bool test_prep_and_segv() { 1050 uint8_t test_data[kTestMemorySize]; 1051 for (unsigned i = 0; i < sizeof(test_data); ++i) 1052 test_data[i] = static_cast<uint8_t>(i); 1053 1054#ifdef __x86_64__ 1055 void* segv_pc; 1056 // Note: Fuchsia is always PIC. 1057 __asm__("leaq .Lsegv_here(%%rip),%0" : "=r"(segv_pc)); 1058 unittest_printf("About to segv, pc %p\n", segv_pc); 1059 1060 // Set r9 to point to test_data so we can easily access it 1061 // from the parent process. Likewise set r10 to segv_pc 1062 // so the parent process can verify it matches the fault PC. 1063 __asm__("\ 1064 movq %[zero],%%r8\n\ 1065 movq %[test_data],%%r9\n\ 1066 movq %[pc],%%r10\n\ 1067.Lsegv_here:\n\ 1068 movq (%%r8),%%rax\ 1069" 1070 : 1071 : [zero] "g"(0), [test_data] "g"(&test_data[0]), [pc] "g"(segv_pc) 1072 : "rax", "r8", "r9", "r10"); 1073#endif 1074 1075#ifdef __aarch64__ 1076 void* segv_pc; 1077 // Note: Fuchsia is always PIC. 1078 __asm__("adrp %0, .Lsegv_here\n" 1079 "add %0, %0, :lo12:.Lsegv_here" 1080 : "=r"(segv_pc)); 1081 unittest_printf("About to segv, pc %p\n", segv_pc); 1082 1083 // Set r9 to point to test_data so we can easily access it 1084 // from the parent process. Likewise set r10 to segv_pc 1085 // so the parent process can verify it matches the fault PC. 1086 __asm__("\ 1087 mov x8,xzr\n\ 1088 mov x9,%[test_data]\n\ 1089 mov x10,%[pc]\n\ 1090.Lsegv_here:\n\ 1091 ldr x0,[x8]\ 1092" 1093 : 1094 : [test_data] "r"(&test_data[0]), [pc] "r"(segv_pc) 1095 : "x0", "x8", "x9", "x10"); 1096#endif 1097 1098 // On resumption test_data should have had kTestDataAdjust added to each element. 1099 // Note: This is the inferior process, it's not running under the test harness. 1100 for (unsigned i = 0; i < sizeof(test_data); ++i) { 1101 if (test_data[i] != i + kTestDataAdjust) { 1102 unittest_printf("test_prep_and_segv: bad data on resumption, test_data[%u] = 0x%x\n", i, 1103 test_data[i]); 1104 return false; 1105 } 1106 } 1107 1108 unittest_printf("Inferior successfully resumed!\n"); 1109 1110 return true; 1111} 1112 1113int extra_thread_func(void* arg) { 1114 atomic_fetch_add(&extra_thread_count, 1); 1115 unittest_printf("Extra thread started.\n"); 1116 while (true) 1117 zx_nanosleep(zx_deadline_after(ZX_SEC(1))); 1118 return 0; 1119} 1120 1121// This returns a bool as it's a unittest "helper" routine. 1122 1123bool msg_loop(zx_handle_t channel) { 1124 BEGIN_HELPER; // Don't stomp on the main thread's current_test_info. 1125 1126 bool my_done_tests = false; 1127 1128 while (!my_done_tests) { 1129 enum message msg; 1130 ASSERT_TRUE(recv_msg(channel, &msg), "Error while receiving msg"); 1131 switch (msg) { 1132 case MSG_DONE: 1133 my_done_tests = true; 1134 break; 1135 case MSG_PING: 1136 send_msg(channel, MSG_PONG); 1137 break; 1138 case MSG_CRASH_AND_RECOVER_TEST: 1139 for (int i = 0; i < kNumSegvTries; ++i) { 1140 if (!test_prep_and_segv()) 1141 exit(21); 1142 } 1143 send_msg(channel, MSG_RECOVERED_FROM_CRASH); 1144 break; 1145 case MSG_START_EXTRA_THREADS: 1146 for (int i = 0; i < kNumExtraThreads; ++i) { 1147 // For our purposes, we don't need to track the threads. 1148 // They'll be terminated when the process exits. 1149 thrd_t thread; 1150 tu_thread_create_c11(&thread, extra_thread_func, NULL, "extra-thread"); 1151 } 1152 // Wait for all threads to be started. 1153 // Each will require an ZX_EXCP_THREAD_STARTING exchange with the "debugger". 1154 while (extra_thread_count.load() < kNumExtraThreads) 1155 zx_nanosleep(zx_deadline_after(ZX_USEC(1))); 1156 send_msg(channel, MSG_EXTRA_THREADS_STARTED); 1157 break; 1158 case MSG_GET_THREAD_HANDLE: { 1159 zx_handle_t self = zx_thread_self(); 1160 zx_handle_t copy; 1161 zx_handle_duplicate(self, ZX_RIGHT_SAME_RIGHTS, ©); 1162 // Note: The handle is transferred to the receiver. 1163 uint64_t data = MSG_THREAD_HANDLE; 1164 unittest_printf("sending handle %d message on channel %u\n", copy, channel); 1165 tu_channel_write(channel, 0, &data, sizeof(data), ©, 1); 1166 break; 1167 } 1168 default: 1169 unittest_printf("unknown message received: %d\n", msg); 1170 break; 1171 } 1172 } 1173 1174 END_HELPER; 1175} 1176 1177void test_inferior() { 1178 zx_handle_t channel = zx_take_startup_handle(PA_USER0); 1179 unittest_printf("test_inferior: got handle %d\n", channel); 1180 1181 if (!msg_loop(channel)) 1182 exit(20); 1183 1184 unittest_printf("Inferior done\n"); 1185 exit(1234); 1186} 1187 1188// Compilers are getting too smart. 1189// These maintain the semantics we want even under optimization. 1190 1191volatile int* crashing_ptr = (int*)42; 1192volatile int crash_depth; 1193 1194// This is used to cause fp != sp when the crash happens on arm64. 1195int leaf_stack_size = 10; 1196 1197int __NO_INLINE test_segfault_doit2(int*); 1198 1199int __NO_INLINE test_segfault_leaf(int n, int* p) { 1200 volatile int x[n]; 1201 x[0] = *p; 1202 *crashing_ptr = x[0]; 1203 return 0; 1204} 1205 1206int __NO_INLINE test_segfault_doit1(int* p) { 1207 if (crash_depth > 0) { 1208 int n = crash_depth; 1209 int use_stack[n]; 1210 memset(use_stack, 0x99, n * sizeof(int)); 1211 --crash_depth; 1212 return test_segfault_doit2(use_stack) + 99; 1213 } 1214 return test_segfault_leaf(leaf_stack_size, p) + 99; 1215} 1216 1217int __NO_INLINE test_segfault_doit2(int* p) { 1218 return test_segfault_doit1(p) + *p; 1219} 1220 1221// Produce a crash with a moderately interesting backtrace. 1222int __NO_INLINE test_segfault() { 1223 crash_depth = kTestSegfaultDepth; 1224 int i = 0; 1225 return test_segfault_doit1(&i); 1226} 1227 1228// Invoke the s/w breakpoint insn using the crashlogger mechanism 1229// to request a backtrace but not terminate the process. 1230int __NO_INLINE test_swbreak() { 1231 unittest_printf("Invoking s/w breakpoint instruction\n"); 1232 zx_crashlogger_request_backtrace(); 1233 unittest_printf("Resumed after s/w breakpoint instruction\n"); 1234 return 0; 1235} 1236 1237void scan_argv(int argc, char** argv) { 1238 for (int i = 1; i < argc; ++i) { 1239 if (strncmp(argv[i], "v=", 2) == 0) { 1240 int verbosity = atoi(argv[i] + 2); 1241 unittest_set_verbosity_level(verbosity); 1242 } 1243 } 1244} 1245 1246} // namespace 1247 1248BEGIN_TEST_CASE(debugger_tests) 1249RUN_TEST(debugger_test) 1250RUN_TEST(debugger_thread_list_test) 1251RUN_TEST(property_process_debug_addr_test) 1252RUN_TEST(write_text_segment) 1253RUN_TEST(suspended_reg_access_test) 1254RUN_TEST(suspended_in_syscall_reg_access_test) 1255RUN_TEST(suspended_in_channel_call_reg_access_test) 1256RUN_TEST(suspended_in_exception_reg_access_test) 1257END_TEST_CASE(debugger_tests) 1258 1259int main(int argc, char** argv) { 1260 program_path = argv[0]; 1261 scan_argv(argc, argv); 1262 1263 if (argc >= 2 && strcmp(argv[1], test_inferior_child_name) == 0) { 1264 test_inferior(); 1265 return 0; 1266 } 1267 if (argc >= 2 && strcmp(argv[1], test_segfault_child_name) == 0) { 1268 return test_segfault(); 1269 } 1270 if (argc >= 2 && strcmp(argv[1], test_swbreak_child_name) == 0) { 1271 return test_swbreak(); 1272 } 1273 1274 bool success = unittest_run_all_tests(argc, argv); 1275 return success ? 0 : -1; 1276} 1277