1 //===-- sanitizer_stoptheworld_linux_libcdep.cpp --------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // See sanitizer_stoptheworld.h for details. 10 // This implementation was inspired by Markus Gutschke's linuxthreads.cc. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_platform.h" 15 16 #if SANITIZER_LINUX && \ 17 (defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \ 18 defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \ 19 defined(__arm__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64) 20 21 #include "sanitizer_stoptheworld.h" 22 23 #include "sanitizer_platform_limits_posix.h" 24 #include "sanitizer_atomic.h" 25 26 #include <errno.h> 27 #include <sched.h> // for CLONE_* definitions 28 #include <stddef.h> 29 #include <sys/prctl.h> // for PR_* definitions 30 #include <sys/ptrace.h> // for PTRACE_* definitions 31 #include <sys/types.h> // for pid_t 32 #include <sys/uio.h> // for iovec 33 #include <elf.h> // for NT_PRSTATUS 34 #if (defined(__aarch64__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64) && \ 35 !SANITIZER_ANDROID 36 // GLIBC 2.20+ sys/user does not include asm/ptrace.h 37 # include <asm/ptrace.h> 38 #endif 39 #include <sys/user.h> // for user_regs_struct 40 #if SANITIZER_ANDROID && SANITIZER_MIPS 41 # include <asm/reg.h> // for mips SP register in sys/user.h 42 #endif 43 #include <sys/wait.h> // for signal-related stuff 44 45 #ifdef sa_handler 46 # undef sa_handler 47 #endif 48 49 #ifdef sa_sigaction 50 # undef sa_sigaction 51 #endif 52 53 #include "sanitizer_common.h" 54 #include "sanitizer_flags.h" 55 #include "sanitizer_libc.h" 56 #include "sanitizer_linux.h" 57 #include "sanitizer_mutex.h" 58 #include "sanitizer_placement_new.h" 59 60 // Sufficiently old kernel headers don't provide this value, but we can still 61 // call prctl with it. If the runtime kernel is new enough, the prctl call will 62 // have the desired effect; if the kernel is too old, the call will error and we 63 // can ignore said error. 64 #ifndef PR_SET_PTRACER 65 #define PR_SET_PTRACER 0x59616d61 66 #endif 67 68 // This module works by spawning a Linux task which then attaches to every 69 // thread in the caller process with ptrace. This suspends the threads, and 70 // PTRACE_GETREGS can then be used to obtain their register state. The callback 71 // supplied to StopTheWorld() is run in the tracer task while the threads are 72 // suspended. 73 // The tracer task must be placed in a different thread group for ptrace to 74 // work, so it cannot be spawned as a pthread. Instead, we use the low-level 75 // clone() interface (we want to share the address space with the caller 76 // process, so we prefer clone() over fork()). 77 // 78 // We don't use any libc functions, relying instead on direct syscalls. There 79 // are two reasons for this: 80 // 1. calling a library function while threads are suspended could cause a 81 // deadlock, if one of the treads happens to be holding a libc lock; 82 // 2. it's generally not safe to call libc functions from the tracer task, 83 // because clone() does not set up a thread-local storage for it. Any 84 // thread-local variables used by libc will be shared between the tracer task 85 // and the thread which spawned it. 86 87 namespace __sanitizer { 88 89 class SuspendedThreadsListLinux final : public SuspendedThreadsList { 90 public: 91 SuspendedThreadsListLinux() { thread_ids_.reserve(1024); } 92 93 tid_t GetThreadID(uptr index) const override; 94 uptr ThreadCount() const override; 95 bool ContainsTid(tid_t thread_id) const; 96 void Append(tid_t tid); 97 98 PtraceRegistersStatus GetRegistersAndSP(uptr index, 99 InternalMmapVector<uptr> *buffer, 100 uptr *sp) const override; 101 102 private: 103 InternalMmapVector<tid_t> thread_ids_; 104 }; 105 106 // Structure for passing arguments into the tracer thread. 107 struct TracerThreadArgument { 108 StopTheWorldCallback callback; 109 void *callback_argument; 110 // The tracer thread waits on this mutex while the parent finishes its 111 // preparations. 112 Mutex mutex; 113 // Tracer thread signals its completion by setting done. 114 atomic_uintptr_t done; 115 uptr parent_pid; 116 }; 117 118 // This class handles thread suspending/unsuspending in the tracer thread. 119 class ThreadSuspender { 120 public: 121 explicit ThreadSuspender(pid_t pid, TracerThreadArgument *arg) 122 : arg(arg) 123 , pid_(pid) { 124 CHECK_GE(pid, 0); 125 } 126 bool SuspendAllThreads(); 127 void ResumeAllThreads(); 128 void KillAllThreads(); 129 SuspendedThreadsListLinux &suspended_threads_list() { 130 return suspended_threads_list_; 131 } 132 TracerThreadArgument *arg; 133 private: 134 SuspendedThreadsListLinux suspended_threads_list_; 135 pid_t pid_; 136 bool SuspendThread(tid_t thread_id); 137 }; 138 139 bool ThreadSuspender::SuspendThread(tid_t tid) { 140 int pterrno; 141 if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr), 142 &pterrno)) { 143 // Either the thread is dead, or something prevented us from attaching. 144 // Log this event and move on. 145 VReport(1, "Could not attach to thread %zu (errno %d).\n", (uptr)tid, 146 pterrno); 147 return false; 148 } else { 149 VReport(2, "Attached to thread %zu.\n", (uptr)tid); 150 // The thread is not guaranteed to stop before ptrace returns, so we must 151 // wait on it. Note: if the thread receives a signal concurrently, 152 // we can get notification about the signal before notification about stop. 153 // In such case we need to forward the signal to the thread, otherwise 154 // the signal will be missed (as we do PTRACE_DETACH with arg=0) and 155 // any logic relying on signals will break. After forwarding we need to 156 // continue to wait for stopping, because the thread is not stopped yet. 157 // We do ignore delivery of SIGSTOP, because we want to make stop-the-world 158 // as invisible as possible. 159 for (;;) { 160 int status; 161 uptr waitpid_status; 162 HANDLE_EINTR(waitpid_status, internal_waitpid(tid, &status, __WALL)); 163 int wperrno; 164 if (internal_iserror(waitpid_status, &wperrno)) { 165 // Got a ECHILD error. I don't think this situation is possible, but it 166 // doesn't hurt to report it. 167 VReport(1, "Waiting on thread %zu failed, detaching (errno %d).\n", 168 (uptr)tid, wperrno); 169 internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr); 170 return false; 171 } 172 if (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) { 173 internal_ptrace(PTRACE_CONT, tid, nullptr, 174 (void*)(uptr)WSTOPSIG(status)); 175 continue; 176 } 177 break; 178 } 179 suspended_threads_list_.Append(tid); 180 return true; 181 } 182 } 183 184 void ThreadSuspender::ResumeAllThreads() { 185 for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) { 186 pid_t tid = suspended_threads_list_.GetThreadID(i); 187 int pterrno; 188 if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr), 189 &pterrno)) { 190 VReport(2, "Detached from thread %d.\n", tid); 191 } else { 192 // Either the thread is dead, or we are already detached. 193 // The latter case is possible, for instance, if this function was called 194 // from a signal handler. 195 VReport(1, "Could not detach from thread %d (errno %d).\n", tid, pterrno); 196 } 197 } 198 } 199 200 void ThreadSuspender::KillAllThreads() { 201 for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) 202 internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i), 203 nullptr, nullptr); 204 } 205 206 bool ThreadSuspender::SuspendAllThreads() { 207 ThreadLister thread_lister(pid_); 208 bool retry = true; 209 InternalMmapVector<tid_t> threads; 210 threads.reserve(128); 211 for (int i = 0; i < 30 && retry; ++i) { 212 retry = false; 213 switch (thread_lister.ListThreads(&threads)) { 214 case ThreadLister::Error: 215 ResumeAllThreads(); 216 VReport(1, "Failed to list threads\n"); 217 return false; 218 case ThreadLister::Incomplete: 219 VReport(1, "Incomplete list\n"); 220 retry = true; 221 break; 222 case ThreadLister::Ok: 223 break; 224 } 225 for (tid_t tid : threads) { 226 // Are we already attached to this thread? 227 // Currently this check takes linear time, however the number of threads 228 // is usually small. 229 if (suspended_threads_list_.ContainsTid(tid)) 230 continue; 231 if (SuspendThread(tid)) 232 retry = true; 233 else 234 VReport(2, "%llu/status: %s\n", tid, thread_lister.LoadStatus(tid)); 235 } 236 if (retry) 237 VReport(1, "SuspendAllThreads retry: %d\n", i); 238 } 239 return suspended_threads_list_.ThreadCount(); 240 } 241 242 // Pointer to the ThreadSuspender instance for use in signal handler. 243 static ThreadSuspender *thread_suspender_instance = nullptr; 244 245 // Synchronous signals that should not be blocked. 246 static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS, 247 SIGXCPU, SIGXFSZ }; 248 249 static void TracerThreadDieCallback() { 250 // Generally a call to Die() in the tracer thread should be fatal to the 251 // parent process as well, because they share the address space. 252 // This really only works correctly if all the threads are suspended at this 253 // point. So we correctly handle calls to Die() from within the callback, but 254 // not those that happen before or after the callback. Hopefully there aren't 255 // a lot of opportunities for that to happen... 256 ThreadSuspender *inst = thread_suspender_instance; 257 if (inst && stoptheworld_tracer_pid == internal_getpid()) { 258 inst->KillAllThreads(); 259 thread_suspender_instance = nullptr; 260 } 261 } 262 263 // Signal handler to wake up suspended threads when the tracer thread dies. 264 static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo, 265 void *uctx) { 266 SignalContext ctx(siginfo, uctx); 267 Printf("Tracer caught signal %d: addr=%p pc=%p sp=%p\n", signum, 268 (void *)ctx.addr, (void *)ctx.pc, (void *)ctx.sp); 269 ThreadSuspender *inst = thread_suspender_instance; 270 if (inst) { 271 if (signum == SIGABRT) 272 inst->KillAllThreads(); 273 else 274 inst->ResumeAllThreads(); 275 RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); 276 thread_suspender_instance = nullptr; 277 atomic_store(&inst->arg->done, 1, memory_order_relaxed); 278 } 279 internal__exit((signum == SIGABRT) ? 1 : 2); 280 } 281 282 // Size of alternative stack for signal handlers in the tracer thread. 283 static const int kHandlerStackSize = 8192; 284 285 // This function will be run as a cloned task. 286 static int TracerThread(void* argument) { 287 TracerThreadArgument *tracer_thread_argument = 288 (TracerThreadArgument *)argument; 289 290 internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); 291 // Check if parent is already dead. 292 if (internal_getppid() != tracer_thread_argument->parent_pid) 293 internal__exit(4); 294 295 // Wait for the parent thread to finish preparations. 296 tracer_thread_argument->mutex.Lock(); 297 tracer_thread_argument->mutex.Unlock(); 298 299 RAW_CHECK(AddDieCallback(TracerThreadDieCallback)); 300 301 ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument); 302 // Global pointer for the signal handler. 303 thread_suspender_instance = &thread_suspender; 304 305 // Alternate stack for signal handling. 306 InternalMmapVector<char> handler_stack_memory(kHandlerStackSize); 307 stack_t handler_stack; 308 internal_memset(&handler_stack, 0, sizeof(handler_stack)); 309 handler_stack.ss_sp = handler_stack_memory.data(); 310 handler_stack.ss_size = kHandlerStackSize; 311 internal_sigaltstack(&handler_stack, nullptr); 312 313 // Install our handler for synchronous signals. Other signals should be 314 // blocked by the mask we inherited from the parent thread. 315 for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) { 316 __sanitizer_sigaction act; 317 internal_memset(&act, 0, sizeof(act)); 318 act.sigaction = TracerThreadSignalHandler; 319 act.sa_flags = SA_ONSTACK | SA_SIGINFO; 320 internal_sigaction_norestorer(kSyncSignals[i], &act, 0); 321 } 322 323 int exit_code = 0; 324 if (!thread_suspender.SuspendAllThreads()) { 325 VReport(1, "Failed suspending threads.\n"); 326 exit_code = 3; 327 } else { 328 tracer_thread_argument->callback(thread_suspender.suspended_threads_list(), 329 tracer_thread_argument->callback_argument); 330 thread_suspender.ResumeAllThreads(); 331 exit_code = 0; 332 } 333 RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); 334 thread_suspender_instance = nullptr; 335 atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed); 336 return exit_code; 337 } 338 339 class ScopedStackSpaceWithGuard { 340 public: 341 explicit ScopedStackSpaceWithGuard(uptr stack_size) { 342 stack_size_ = stack_size; 343 guard_size_ = GetPageSizeCached(); 344 // FIXME: Omitting MAP_STACK here works in current kernels but might break 345 // in the future. 346 guard_start_ = (uptr)MmapOrDie(stack_size_ + guard_size_, 347 "ScopedStackWithGuard"); 348 CHECK(MprotectNoAccess((uptr)guard_start_, guard_size_)); 349 } 350 ~ScopedStackSpaceWithGuard() { 351 UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_); 352 } 353 void *Bottom() const { 354 return (void *)(guard_start_ + stack_size_ + guard_size_); 355 } 356 357 private: 358 uptr stack_size_; 359 uptr guard_size_; 360 uptr guard_start_; 361 }; 362 363 // We have a limitation on the stack frame size, so some stuff had to be moved 364 // into globals. 365 static __sanitizer_sigset_t blocked_sigset; 366 static __sanitizer_sigset_t old_sigset; 367 368 class StopTheWorldScope { 369 public: 370 StopTheWorldScope() { 371 // Make this process dumpable. Processes that are not dumpable cannot be 372 // attached to. 373 process_was_dumpable_ = internal_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); 374 if (!process_was_dumpable_) 375 internal_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); 376 } 377 378 ~StopTheWorldScope() { 379 // Restore the dumpable flag. 380 if (!process_was_dumpable_) 381 internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); 382 } 383 384 private: 385 int process_was_dumpable_; 386 }; 387 388 // When sanitizer output is being redirected to file (i.e. by using log_path), 389 // the tracer should write to the parent's log instead of trying to open a new 390 // file. Alert the logging code to the fact that we have a tracer. 391 struct ScopedSetTracerPID { 392 explicit ScopedSetTracerPID(uptr tracer_pid) { 393 stoptheworld_tracer_pid = tracer_pid; 394 stoptheworld_tracer_ppid = internal_getpid(); 395 } 396 ~ScopedSetTracerPID() { 397 stoptheworld_tracer_pid = 0; 398 stoptheworld_tracer_ppid = 0; 399 } 400 }; 401 402 void StopTheWorld(StopTheWorldCallback callback, void *argument) { 403 StopTheWorldScope in_stoptheworld; 404 // Prepare the arguments for TracerThread. 405 struct TracerThreadArgument tracer_thread_argument; 406 tracer_thread_argument.callback = callback; 407 tracer_thread_argument.callback_argument = argument; 408 tracer_thread_argument.parent_pid = internal_getpid(); 409 atomic_store(&tracer_thread_argument.done, 0, memory_order_relaxed); 410 const uptr kTracerStackSize = 2 * 1024 * 1024; 411 ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize); 412 // Block the execution of TracerThread until after we have set ptrace 413 // permissions. 414 tracer_thread_argument.mutex.Lock(); 415 // Signal handling story. 416 // We don't want async signals to be delivered to the tracer thread, 417 // so we block all async signals before creating the thread. An async signal 418 // handler can temporary modify errno, which is shared with this thread. 419 // We ought to use pthread_sigmask here, because sigprocmask has undefined 420 // behavior in multithreaded programs. However, on linux sigprocmask is 421 // equivalent to pthread_sigmask with the exception that pthread_sigmask 422 // does not allow to block some signals used internally in pthread 423 // implementation. We are fine with blocking them here, we are really not 424 // going to pthread_cancel the thread. 425 // The tracer thread should not raise any synchronous signals. But in case it 426 // does, we setup a special handler for sync signals that properly kills the 427 // parent as well. Note: we don't pass CLONE_SIGHAND to clone, so handlers 428 // in the tracer thread won't interfere with user program. Double note: if a 429 // user does something along the lines of 'kill -11 pid', that can kill the 430 // process even if user setup own handler for SEGV. 431 // Thing to watch out for: this code should not change behavior of user code 432 // in any observable way. In particular it should not override user signal 433 // handlers. 434 internal_sigfillset(&blocked_sigset); 435 for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) 436 internal_sigdelset(&blocked_sigset, kSyncSignals[i]); 437 int rv = internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset); 438 CHECK_EQ(rv, 0); 439 uptr tracer_pid = internal_clone( 440 TracerThread, tracer_stack.Bottom(), 441 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED, 442 &tracer_thread_argument, nullptr /* parent_tidptr */, 443 nullptr /* newtls */, nullptr /* child_tidptr */); 444 internal_sigprocmask(SIG_SETMASK, &old_sigset, 0); 445 int local_errno = 0; 446 if (internal_iserror(tracer_pid, &local_errno)) { 447 VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno); 448 tracer_thread_argument.mutex.Unlock(); 449 } else { 450 ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid); 451 // On some systems we have to explicitly declare that we want to be traced 452 // by the tracer thread. 453 internal_prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0); 454 // Allow the tracer thread to start. 455 tracer_thread_argument.mutex.Unlock(); 456 // NOTE: errno is shared between this thread and the tracer thread. 457 // internal_waitpid() may call syscall() which can access/spoil errno, 458 // so we can't call it now. Instead we for the tracer thread to finish using 459 // the spin loop below. Man page for sched_yield() says "In the Linux 460 // implementation, sched_yield() always succeeds", so let's hope it does not 461 // spoil errno. Note that this spin loop runs only for brief periods before 462 // the tracer thread has suspended us and when it starts unblocking threads. 463 while (atomic_load(&tracer_thread_argument.done, memory_order_relaxed) == 0) 464 sched_yield(); 465 // Now the tracer thread is about to exit and does not touch errno, 466 // wait for it. 467 for (;;) { 468 uptr waitpid_status = internal_waitpid(tracer_pid, nullptr, __WALL); 469 if (!internal_iserror(waitpid_status, &local_errno)) 470 break; 471 if (local_errno == EINTR) 472 continue; 473 VReport(1, "Waiting on the tracer thread failed (errno %d).\n", 474 local_errno); 475 break; 476 } 477 } 478 } 479 480 // Platform-specific methods from SuspendedThreadsList. 481 #if SANITIZER_ANDROID && defined(__arm__) 482 typedef pt_regs regs_struct; 483 #define REG_SP ARM_sp 484 485 #elif SANITIZER_LINUX && defined(__arm__) 486 typedef user_regs regs_struct; 487 #define REG_SP uregs[13] 488 489 #elif defined(__i386__) || defined(__x86_64__) 490 typedef user_regs_struct regs_struct; 491 #if defined(__i386__) 492 #define REG_SP esp 493 #else 494 #define REG_SP rsp 495 #endif 496 #define ARCH_IOVEC_FOR_GETREGSET 497 // Support ptrace extensions even when compiled without required kernel support 498 #ifndef NT_X86_XSTATE 499 #define NT_X86_XSTATE 0x202 500 #endif 501 #ifndef PTRACE_GETREGSET 502 #define PTRACE_GETREGSET 0x4204 503 #endif 504 // Compiler may use FP registers to store pointers. 505 static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET}; 506 507 #elif defined(__powerpc__) || defined(__powerpc64__) 508 typedef pt_regs regs_struct; 509 #define REG_SP gpr[PT_R1] 510 511 #elif defined(__mips__) 512 typedef struct user regs_struct; 513 # if SANITIZER_ANDROID 514 # define REG_SP regs[EF_R29] 515 # else 516 # define REG_SP regs[EF_REG29] 517 # endif 518 519 #elif defined(__aarch64__) 520 typedef struct user_pt_regs regs_struct; 521 #define REG_SP sp 522 static constexpr uptr kExtraRegs[] = {0}; 523 #define ARCH_IOVEC_FOR_GETREGSET 524 525 #elif defined(__loongarch__) 526 typedef struct user_pt_regs regs_struct; 527 #define REG_SP regs[3] 528 static constexpr uptr kExtraRegs[] = {0}; 529 #define ARCH_IOVEC_FOR_GETREGSET 530 531 #elif SANITIZER_RISCV64 532 typedef struct user_regs_struct regs_struct; 533 // sys/ucontext.h already defines REG_SP as 2. Undefine it first. 534 #undef REG_SP 535 #define REG_SP sp 536 static constexpr uptr kExtraRegs[] = {0}; 537 #define ARCH_IOVEC_FOR_GETREGSET 538 539 #elif defined(__s390__) 540 typedef _user_regs_struct regs_struct; 541 #define REG_SP gprs[15] 542 static constexpr uptr kExtraRegs[] = {0}; 543 #define ARCH_IOVEC_FOR_GETREGSET 544 545 #else 546 #error "Unsupported architecture" 547 #endif // SANITIZER_ANDROID && defined(__arm__) 548 549 tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const { 550 CHECK_LT(index, thread_ids_.size()); 551 return thread_ids_[index]; 552 } 553 554 uptr SuspendedThreadsListLinux::ThreadCount() const { 555 return thread_ids_.size(); 556 } 557 558 bool SuspendedThreadsListLinux::ContainsTid(tid_t thread_id) const { 559 for (uptr i = 0; i < thread_ids_.size(); i++) { 560 if (thread_ids_[i] == thread_id) return true; 561 } 562 return false; 563 } 564 565 void SuspendedThreadsListLinux::Append(tid_t tid) { 566 thread_ids_.push_back(tid); 567 } 568 569 PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP( 570 uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { 571 pid_t tid = GetThreadID(index); 572 constexpr uptr uptr_sz = sizeof(uptr); 573 int pterrno; 574 #ifdef ARCH_IOVEC_FOR_GETREGSET 575 auto AppendF = [&](uptr regset) { 576 uptr size = buffer->size(); 577 // NT_X86_XSTATE requires 64bit alignment. 578 uptr size_up = RoundUpTo(size, 8 / uptr_sz); 579 buffer->reserve(Max<uptr>(1024, size_up)); 580 struct iovec regset_io; 581 for (;; buffer->resize(buffer->capacity() * 2)) { 582 buffer->resize(buffer->capacity()); 583 uptr available_bytes = (buffer->size() - size_up) * uptr_sz; 584 regset_io.iov_base = buffer->data() + size_up; 585 regset_io.iov_len = available_bytes; 586 bool fail = 587 internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, 588 (void *)regset, (void *)®set_io), 589 &pterrno); 590 if (fail) { 591 VReport(1, "Could not get regset %p from thread %d (errno %d).\n", 592 (void *)regset, tid, pterrno); 593 buffer->resize(size); 594 return false; 595 } 596 597 // Far enough from the buffer size, no need to resize and repeat. 598 if (regset_io.iov_len + 64 < available_bytes) 599 break; 600 } 601 buffer->resize(size_up + RoundUpTo(regset_io.iov_len, uptr_sz) / uptr_sz); 602 return true; 603 }; 604 605 buffer->clear(); 606 bool fail = !AppendF(NT_PRSTATUS); 607 if (!fail) { 608 // Accept the first available and do not report errors. 609 for (uptr regs : kExtraRegs) 610 if (regs && AppendF(regs)) 611 break; 612 } 613 #else 614 buffer->resize(RoundUpTo(sizeof(regs_struct), uptr_sz) / uptr_sz); 615 bool fail = internal_iserror( 616 internal_ptrace(PTRACE_GETREGS, tid, nullptr, buffer->data()), &pterrno); 617 if (fail) 618 VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, 619 pterrno); 620 #endif 621 if (fail) { 622 // ESRCH means that the given thread is not suspended or already dead. 623 // Therefore it's unsafe to inspect its data (e.g. walk through stack) and 624 // we should notify caller about this. 625 return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL 626 : REGISTERS_UNAVAILABLE; 627 } 628 629 *sp = reinterpret_cast<regs_struct *>(buffer->data())[0].REG_SP; 630 return REGISTERS_AVAILABLE; 631 } 632 633 } // namespace __sanitizer 634 635 #endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) 636 // || defined(__aarch64__) || defined(__powerpc64__) 637 // || defined(__s390__) || defined(__i386__) || defined(__arm__) 638 // || SANITIZER_LOONGARCH64 639