1 //===-- NativeProcessDarwin.cpp ---------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "NativeProcessDarwin.h"
13 #include <mach/mach_init.h>
14 #include <mach/mach_traps.h>
15 #include <sys/ptrace.h>
17 #include <sys/sysctl.h>
18 #include <sys/types.h>
22 #include "lldb/Core/Log.h"
23 #include "lldb/Core/State.h"
24 #include "lldb/Core/StreamString.h"
25 #include "lldb/Target/ProcessLaunchInfo.h"
26 #include "lldb/Utility/PseudoTerminal.h"
30 #include "DarwinProcessLauncher.h"
32 #include "MachException.h"
35 using namespace lldb_private;
36 using namespace lldb_private::process_darwin;
37 using namespace lldb_private::darwin_process_launcher;
39 // -----------------------------------------------------------------------------
41 // -----------------------------------------------------------------------------
44 struct hack_task_dyld_info {
45 mach_vm_address_t all_image_info_addr;
46 mach_vm_size_t all_image_info_size;
50 // -----------------------------------------------------------------------------
51 // Public Static Methods
52 // -----------------------------------------------------------------------------
54 Error NativeProcessProtocol::Launch(
55 ProcessLaunchInfo &launch_info,
56 NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop,
57 NativeProcessProtocolSP &native_process_sp) {
58 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
62 // Verify the working directory is valid if one was specified.
63 FileSpec working_dir(launch_info.GetWorkingDirectory());
65 (!working_dir.ResolvePath() ||
66 working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) {
67 error.SetErrorStringWithFormat("No such file or directory: %s",
68 working_dir.GetCString());
72 // Launch the inferior.
73 int pty_master_fd = -1;
74 LaunchFlavor launch_flavor = LaunchFlavor::Default;
76 error = LaunchInferior(launch_info, &pty_master_fd, &launch_flavor);
78 // Handle launch failure.
79 if (!error.Success()) {
81 log->Printf("NativeProcessDarwin::%s() failed to launch process: "
83 __FUNCTION__, error.AsCString());
87 // Handle failure to return a pid.
88 if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) {
90 log->Printf("NativeProcessDarwin::%s() launch succeeded but no "
91 "pid was returned! Aborting.",
96 // Create the Darwin native process impl.
97 std::shared_ptr<NativeProcessDarwin> np_darwin_sp(
98 new NativeProcessDarwin(launch_info.GetProcessID(), pty_master_fd));
99 if (!np_darwin_sp->RegisterNativeDelegate(native_delegate)) {
100 native_process_sp.reset();
101 error.SetErrorStringWithFormat("failed to register the native delegate");
105 // Finalize the processing needed to debug the launched process with
106 // a NativeProcessDarwin instance.
107 error = np_darwin_sp->FinalizeLaunch(launch_flavor, mainloop);
108 if (!error.Success()) {
110 log->Printf("NativeProcessDarwin::%s() aborting, failed to finalize"
111 " the launching of the process: %s",
112 __FUNCTION__, error.AsCString());
116 // Return the process and process id to the caller through the launch args.
117 native_process_sp = np_darwin_sp;
121 Error NativeProcessProtocol::Attach(
122 lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
123 MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) {
124 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
126 log->Printf("NativeProcessDarwin::%s(pid = %" PRIi64 ")", __FUNCTION__,
129 // Retrieve the architecture for the running process.
130 ArchSpec process_arch;
131 Error error = ResolveProcessArchitecture(pid, process_arch);
132 if (!error.Success())
135 // TODO get attach to return this value.
136 const int pty_master_fd = -1;
137 std::shared_ptr<NativeProcessDarwin> native_process_darwin_sp(
138 new NativeProcessDarwin(pid, pty_master_fd));
140 if (!native_process_darwin_sp->RegisterNativeDelegate(native_delegate)) {
141 error.SetErrorStringWithFormat("failed to register the native "
146 native_process_darwin_sp->AttachToInferior(mainloop, pid, error);
147 if (!error.Success())
150 native_process_sp = native_process_darwin_sp;
154 // -----------------------------------------------------------------------------
156 // -----------------------------------------------------------------------------
158 NativeProcessDarwin::NativeProcessDarwin(lldb::pid_t pid, int pty_master_fd)
159 : NativeProcessProtocol(pid), m_task(TASK_NULL), m_did_exec(false),
160 m_cpu_type(0), m_exception_port(MACH_PORT_NULL), m_exc_port_info(),
161 m_exception_thread(nullptr), m_exception_messages_mutex(),
162 m_sent_interrupt_signo(0), m_auto_resume_signo(0), m_thread_list(),
163 m_thread_actions(), m_waitpid_pipe(), m_waitpid_thread(nullptr),
164 m_waitpid_reader_handle() {
165 // TODO add this to the NativeProcessProtocol constructor.
166 m_terminal_fd = pty_master_fd;
169 NativeProcessDarwin::~NativeProcessDarwin() {}
171 // -----------------------------------------------------------------------------
173 // -----------------------------------------------------------------------------
175 Error NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor,
176 MainLoop &main_loop) {
178 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
184 for (i=0; (arg = argv[i]) != NULL; i++)
185 m_args.push_back(arg);
188 error = StartExceptionThread();
189 if (!error.Success()) {
191 log->Printf("NativeProcessDarwin::%s(): failure starting the "
192 "mach exception port monitor thread: %s",
193 __FUNCTION__, error.AsCString());
195 // Terminate the inferior process. There's nothing meaningful we can
196 // do if we can't receive signals and exceptions. Since we launched
197 // the process, it's fair game for us to kill it.
198 ::ptrace(PT_KILL, m_pid, 0, 0);
199 SetState(eStateExited);
206 if (launch_flavor == LaunchFlavor::PosixSpawn) {
207 SetState(eStateAttaching);
209 int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0);
211 // m_flags |= eMachProcessFlagsAttached;
213 log->Printf("NativeProcessDarwin::%s(): successfully spawned "
214 "process with pid %" PRIu64,
215 __FUNCTION__, m_pid);
217 error.SetErrorToErrno();
218 SetState(eStateExited);
220 log->Printf("NativeProcessDarwin::%s(): error: failed to "
221 "attach to spawned pid %" PRIu64 " (error=%d (%s))",
222 __FUNCTION__, m_pid, (int)error.GetError(),
229 log->Printf("NativeProcessDarwin::%s(): new pid is %" PRIu64 "...",
230 __FUNCTION__, m_pid);
232 // Spawn a thread to reap our child inferior process...
233 error = StartWaitpidThread(main_loop);
236 log->Printf("NativeProcessDarwin::%s(): failed to start waitpid() "
238 __FUNCTION__, error.AsCString());
239 kill(SIGKILL, static_cast<::pid_t>(m_pid));
243 if (TaskPortForProcessID(error) == TASK_NULL) {
244 // We failed to get the task for our process ID which is bad.
245 // Kill our process; otherwise, it will be stopped at the entry
246 // point and get reparented to someone else and never go away.
248 log->Printf("NativeProcessDarwin::%s(): could not get task port "
249 "for process, sending SIGKILL and exiting: %s",
250 __FUNCTION__, error.AsCString());
251 kill(SIGKILL, static_cast<::pid_t>(m_pid));
255 // Indicate that we're stopped, as we always launch suspended.
256 SetState(eStateStopped);
262 Error NativeProcessDarwin::SaveExceptionPortInfo() {
263 return m_exc_port_info.Save(m_task);
266 bool NativeProcessDarwin::ProcessUsingSpringBoard() const {
267 // TODO implement flags
268 // return (m_flags & eMachProcessFlagsUsingSBS) != 0;
272 bool NativeProcessDarwin::ProcessUsingBackBoard() const {
273 // TODO implement flags
274 // return (m_flags & eMachProcessFlagsUsingBKS) != 0;
278 // Called by the exception thread when an exception has been received from
279 // our process. The exception message is completely filled and the exception
280 // data has already been copied.
281 void NativeProcessDarwin::ExceptionMessageReceived(
282 const MachException::Message &message) {
283 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
285 std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex);
286 if (m_exception_messages.empty()) {
287 // Suspend the task the moment we receive our first exception message.
291 // Use a locker to automatically unlock our mutex in case of exceptions
292 // Add the exception to our internal exception stack
293 m_exception_messages.push_back(message);
296 log->Printf("NativeProcessDarwin::%s(): new queued message count: %lu",
297 __FUNCTION__, m_exception_messages.size());
300 void *NativeProcessDarwin::ExceptionThread(void *arg) {
301 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
304 log->Printf("NativeProcessDarwin::%s(): cannot run mach exception "
305 "thread, mandatory process arg was null",
310 return reinterpret_cast<NativeProcessDarwin *>(arg)->DoExceptionThread();
313 void *NativeProcessDarwin::DoExceptionThread() {
314 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
317 log->Printf("NativeProcessDarwin::%s(arg=%p) starting thread...",
320 pthread_setname_np("exception monitoring thread");
322 // Ensure we don't get CPU starved.
323 MaybeRaiseThreadPriority();
325 // We keep a count of the number of consecutive exceptions received so
326 // we know to grab all exceptions without a timeout. We do this to get a
327 // bunch of related exceptions on our exception port so we can process
328 // then together. When we have multiple threads, we can get an exception
329 // per thread and they will come in consecutively. The main loop in this
330 // thread can stop periodically if needed to service things related to this
333 // [did we lose some words here?]
335 // flag set in the options, so we will wait forever for an exception on
336 // 0 our exception port. After we get one exception, we then will use the
337 // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
338 // exceptions for our process. After we have received the last pending
339 // exception, we will get a timeout which enables us to then notify
340 // our main thread that we have an exception bundle available. We then wait
341 // for the main thread to tell this exception thread to start trying to get
342 // exceptions messages again and we start again with a mach_msg read with
345 // We choose to park a thread on this, rather than polling, because the
346 // polling is expensive. On devices, we need to minimize overhead caused
347 // by the process monitor.
348 uint32_t num_exceptions_received = 0;
350 task_t task = m_task;
351 mach_msg_timeout_t periodic_timeout = 0;
353 #if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS)
354 mach_msg_timeout_t watchdog_elapsed = 0;
355 mach_msg_timeout_t watchdog_timeout = 60 * 1000;
356 ::pid_t pid = (::pid_t)process->GetID();
357 CFReleaser<SBSWatchdogAssertionRef> watchdog;
359 if (process->ProcessUsingSpringBoard()) {
360 // Request a renewal for every 60 seconds if we attached using
362 watchdog.reset(::SBSWatchdogAssertionCreateForPID(nullptr, pid, 60));
364 log->Printf("::SBSWatchdogAssertionCreateForPID(NULL, %4.4x, 60) "
366 pid, watchdog.get());
368 if (watchdog.get()) {
369 ::SBSWatchdogAssertionRenew(watchdog.get());
371 CFTimeInterval watchdogRenewalInterval =
372 ::SBSWatchdogAssertionGetRenewalInterval(watchdog.get());
374 log->Printf("::SBSWatchdogAssertionGetRenewalInterval(%p) => "
376 watchdog.get(), watchdogRenewalInterval);
377 if (watchdogRenewalInterval > 0.0) {
378 watchdog_timeout = (mach_msg_timeout_t)watchdogRenewalInterval * 1000;
379 if (watchdog_timeout > 3000) {
380 // Give us a second to renew our timeout.
381 watchdog_timeout -= 1000;
382 } else if (watchdog_timeout > 1000) {
383 // Give us a quarter of a second to renew our timeout.
384 watchdog_timeout -= 250;
388 if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout)
389 periodic_timeout = watchdog_timeout;
391 #endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS)
394 CFReleaser<BKSWatchdogAssertionRef> watchdog;
395 if (process->ProcessUsingBackBoard()) {
396 ::pid_t pid = process->GetID();
397 CFAllocatorRef alloc = kCFAllocatorDefault;
398 watchdog.reset(::BKSWatchdogAssertionCreateForPID(alloc, pid));
400 #endif // #ifdef WITH_BKS
402 // Do we want to use a weak pointer to the NativeProcessDarwin here, in
403 // which case we can guarantee we don't whack the process monitor if we
404 // race between this thread and the main one on shutdown?
405 while (IsExceptionPortValid()) {
406 ::pthread_testcancel();
408 MachException::Message exception_message;
410 if (num_exceptions_received > 0) {
411 // We don't want a timeout here, just receive as many exceptions as
412 // we can since we already have one. We want to get all currently
413 // available exceptions for this task at once.
414 error = exception_message.Receive(
416 MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0);
417 } else if (periodic_timeout > 0) {
418 // We need to stop periodically in this loop, so try and get a mach
419 // message with a valid timeout (ms).
420 error = exception_message.Receive(GetExceptionPort(),
421 MACH_RCV_MSG | MACH_RCV_INTERRUPT |
425 // We don't need to parse all current exceptions or stop
426 // periodically, just wait for an exception forever.
427 error = exception_message.Receive(GetExceptionPort(),
428 MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0);
431 if (error.Success()) {
432 // We successfully received an exception.
433 if (exception_message.CatchExceptionRaise(task)) {
434 ++num_exceptions_received;
435 ExceptionMessageReceived(exception_message);
438 if (error.GetError() == MACH_RCV_INTERRUPTED) {
439 // We were interrupted.
441 // If we have no task port we should exit this thread, as it implies
442 // the inferior went down.
443 if (!IsExceptionPortValid()) {
445 log->Printf("NativeProcessDarwin::%s(): the inferior "
446 "exception port is no longer valid, "
447 "canceling exception thread...",
449 // Should we be setting a process state here?
453 // Make sure the inferior task is still valid.
457 log->Printf("NativeProcessDarwin::%s(): interrupted, but "
458 "the inferior task iss till valid, "
463 // The inferior task is no longer valid. Time to exit as
464 // the process has gone away.
466 log->Printf("NativeProcessDarwin::%s(): the inferior task "
467 "has exited, and so will we...",
469 // Does this race at all with our waitpid()?
470 SetState(eStateExited);
473 } else if (error.GetError() == MACH_RCV_TIMED_OUT) {
474 // We timed out when waiting for exceptions.
476 if (num_exceptions_received > 0) {
477 // We were receiving all current exceptions with a timeout of
478 // zero. It is time to go back to our normal looping mode.
479 num_exceptions_received = 0;
481 // Notify our main thread we have a complete exception message
482 // bundle available. Get the possibly updated task port back
483 // from the process in case we exec'ed and our task port
485 task = ExceptionMessageBundleComplete();
487 // In case we use a timeout value when getting exceptions,
488 // make sure our task is still valid.
489 if (IsTaskValid(task)) {
492 log->Printf("NativeProcessDarwin::%s(): got a timeout, "
497 // The inferior task is no longer valid. Time to exit as
498 // the process has gone away.
500 log->Printf("NativeProcessDarwin::%s(): the inferior "
501 "task has exited, and so will we...",
503 // Does this race at all with our waitpid()?
504 SetState(eStateExited);
509 #if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS)
510 if (watchdog.get()) {
511 watchdog_elapsed += periodic_timeout;
512 if (watchdog_elapsed >= watchdog_timeout) {
514 log->Printf("SBSWatchdogAssertionRenew(%p)", watchdog.get());
515 ::SBSWatchdogAssertionRenew(watchdog.get());
516 watchdog_elapsed = 0;
522 log->Printf("NativeProcessDarwin::%s(): continuing after "
523 "receiving an unexpected error: %u (%s)",
524 __FUNCTION__, error.GetError(), error.AsCString());
525 // TODO: notify of error?
530 #if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS)
531 if (watchdog.get()) {
532 // TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel
534 // all are up and running on systems that support it. The SBS framework has
536 // that will forward SBSWatchdogAssertionRelease to
537 // SBSWatchdogAssertionCancel for now
538 // so it should still build either way.
539 DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionRelease(%p)",
541 ::SBSWatchdogAssertionRelease(watchdog.get());
543 #endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS)
546 log->Printf("NativeProcessDarwin::%s(%p): thread exiting...", __FUNCTION__,
551 Error NativeProcessDarwin::StartExceptionThread() {
553 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
555 log->Printf("NativeProcessDarwin::%s() called", __FUNCTION__);
557 // Make sure we've looked up the inferior port.
558 TaskPortForProcessID(error);
560 // Ensure the inferior task is valid.
561 if (!IsTaskValid()) {
562 error.SetErrorStringWithFormat("cannot start exception thread: "
563 "task 0x%4.4x is not valid",
568 // Get the mach port for the process monitor.
569 mach_port_t task_self = mach_task_self();
571 // Allocate an exception port that we will use to track our child process
572 auto mach_err = ::mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE,
574 error.SetError(mach_err, eErrorTypeMachKernel);
577 log->Printf("NativeProcessDarwin::%s(): mach_port_allocate("
578 "task_self=0x%4.4x, MACH_PORT_RIGHT_RECEIVE, "
579 "&m_exception_port) failed: %u (%s)",
580 __FUNCTION__, task_self, error.GetError(), error.AsCString());
584 // Add the ability to send messages on the new exception port
585 mach_err = ::mach_port_insert_right(
586 task_self, m_exception_port, m_exception_port, MACH_MSG_TYPE_MAKE_SEND);
587 error.SetError(mach_err, eErrorTypeMachKernel);
590 log->Printf("NativeProcessDarwin::%s(): mach_port_insert_right("
591 "task_self=0x%4.4x, m_exception_port=0x%4.4x, "
592 "m_exception_port=0x%4.4x, MACH_MSG_TYPE_MAKE_SEND) "
594 __FUNCTION__, task_self, m_exception_port, m_exception_port,
595 error.GetError(), error.AsCString());
599 // Save the original state of the exception ports for our child process.
600 error = SaveExceptionPortInfo();
601 if (error.Fail() || (m_exc_port_info.mask == 0)) {
603 log->Printf("NativeProcessDarwin::%s(): SaveExceptionPortInfo() "
604 "failed, cannot install exception handler: %s",
605 __FUNCTION__, error.AsCString());
609 // Set the ability to get all exceptions on this port.
610 mach_err = ::task_set_exception_ports(
611 m_task, m_exc_port_info.mask, m_exception_port,
612 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
613 error.SetError(mach_err, eErrorTypeMachKernel);
616 log->Printf("::task_set_exception_ports (task = 0x%4.4x, "
617 "exception_mask = 0x%8.8x, new_port = 0x%4.4x, "
618 "behavior = 0x%8.8x, new_flavor = 0x%8.8x) failed: "
620 m_task, m_exc_port_info.mask, m_exception_port,
621 (EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES), THREAD_STATE_NONE,
622 error.GetError(), error.AsCString());
626 // Create the exception thread.
628 ::pthread_create(&m_exception_thread, nullptr, ExceptionThread, this);
629 error.SetError(pthread_err, eErrorTypePOSIX);
632 log->Printf("NativeProcessDarwin::%s(): failed to create Mach "
633 "exception-handling thread: %u (%s)",
634 __FUNCTION__, error.GetError(), error.AsCString());
641 NativeProcessDarwin::GetDYLDAllImageInfosAddress(Error &error) const {
644 struct hack_task_dyld_info dyld_info;
645 mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
646 // Make sure that COUNT isn't bigger than our hacked up struct
647 // hack_task_dyld_info. If it is, then make COUNT smaller to match.
648 if (count > (sizeof(struct hack_task_dyld_info) / sizeof(natural_t))) {
649 count = (sizeof(struct hack_task_dyld_info) / sizeof(natural_t));
652 TaskPortForProcessID(error);
654 return LLDB_INVALID_ADDRESS;
657 ::task_info(m_task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
658 error.SetError(mach_err, eErrorTypeMachKernel);
659 if (error.Success()) {
660 // We now have the address of the all image infos structure.
661 return dyld_info.all_image_info_addr;
665 return LLDB_INVALID_ADDRESS;
668 uint32_t NativeProcessDarwin::GetCPUTypeForLocalProcess(::pid_t pid) {
669 int mib[CTL_MAXNAME] = {
672 size_t len = CTL_MAXNAME;
674 if (::sysctlnametomib("sysctl.proc_cputype", mib, &len))
681 size_t cpu_len = sizeof(cpu);
682 if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0))
687 uint32_t NativeProcessDarwin::GetCPUType() const {
688 if (m_cpu_type == 0 && m_pid != 0)
689 m_cpu_type = GetCPUTypeForLocalProcess(m_pid);
693 task_t NativeProcessDarwin::ExceptionMessageBundleComplete() {
694 // We have a complete bundle of exceptions for our child process.
696 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
698 std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex);
700 log->Printf("NativeProcessDarwin::%s(): processing %lu exception "
702 __FUNCTION__, m_exception_messages.size());
704 if (m_exception_messages.empty()) {
705 // Not particularly useful...
709 bool auto_resume = false;
712 // First check for any SIGTRAP and make sure we didn't exec
713 const task_t task = m_task;
716 bool received_interrupt = false;
717 uint32_t num_task_exceptions = 0;
718 for (i = 0; i < m_exception_messages.size(); ++i) {
719 if (m_exception_messages[i].state.task_port != task) {
720 // This is an exception that is not for our inferior, ignore.
724 // This is an exception for the inferior.
725 ++num_task_exceptions;
726 const int signo = m_exception_messages[i].state.SoftSignal();
727 if (signo == SIGTRAP) {
728 // SIGTRAP could mean that we exec'ed. We need to check the
729 // dyld all_image_infos.infoArray to see if it is NULL and if
730 // so, say that we exec'ed.
731 const addr_t aii_addr = GetDYLDAllImageInfosAddress(error);
732 if (aii_addr == LLDB_INVALID_ADDRESS)
735 const addr_t info_array_count_addr = aii_addr + 4;
736 uint32_t info_array_count = 0;
737 size_t bytes_read = 0;
739 read_error = ReadMemory(info_array_count_addr, // source addr
740 &info_array_count, // dest addr
742 bytes_read); // #bytes read
743 if (read_error.Success() && (bytes_read == 4)) {
744 if (info_array_count == 0) {
745 // We got the all infos address, and there are zero
746 // entries. We think we exec'd.
749 // Force the task port to update itself in case the
750 // task port changed after exec
751 const task_t old_task = m_task;
752 const bool force_update = true;
753 const task_t new_task = TaskPortForProcessID(error, force_update);
754 if (old_task != new_task) {
756 log->Printf("exec: inferior task port changed "
757 "from 0x%4.4x to 0x%4.4x",
763 log->Printf("NativeProcessDarwin::%s() warning: "
764 "failed to read all_image_infos."
765 "infoArrayCount from 0x%8.8llx",
766 __FUNCTION__, info_array_count_addr);
768 } else if ((m_sent_interrupt_signo != 0) &&
769 (signo == m_sent_interrupt_signo)) {
770 // We just received the interrupt that we sent to ourselves.
771 received_interrupt = true;
776 cpu_type_t process_cpu_type = GetCPUTypeForLocalProcess(m_pid);
777 if (m_cpu_type != process_cpu_type) {
779 log->Printf("NativeProcessDarwin::%s(): arch changed from "
780 "0x%8.8x to 0x%8.8x",
781 __FUNCTION__, m_cpu_type, process_cpu_type);
782 m_cpu_type = process_cpu_type;
783 // TODO figure out if we need to do something here.
784 // DNBArchProtocol::SetArchitecture (process_cpu_type);
786 m_thread_list.Clear();
788 // TODO hook up breakpoints.
789 // m_breakpoints.DisableAll();
792 if (m_sent_interrupt_signo != 0) {
793 if (received_interrupt) {
795 log->Printf("NativeProcessDarwin::%s(): process "
796 "successfully interrupted with signal %i",
797 __FUNCTION__, m_sent_interrupt_signo);
799 // Mark that we received the interrupt signal
800 m_sent_interrupt_signo = 0;
801 // Now check if we had a case where:
802 // 1 - We called NativeProcessDarwin::Interrupt() but we stopped
803 // for another reason.
804 // 2 - We called NativeProcessDarwin::Resume() (but still
805 // haven't gotten the interrupt signal).
806 // 3 - We are now incorrectly stopped because we are handling
807 // the interrupt signal we missed.
808 // 4 - We might need to resume if we stopped only with the
809 // interrupt signal that we never handled.
810 if (m_auto_resume_signo != 0) {
811 // Only auto_resume if we stopped with _only_ the interrupt
813 if (num_task_exceptions == 1) {
816 log->Printf("NativeProcessDarwin::%s(): auto "
817 "resuming due to unhandled interrupt "
819 __FUNCTION__, m_auto_resume_signo);
821 m_auto_resume_signo = 0;
825 log->Printf("NativeProcessDarwin::%s(): didn't get signal "
826 "%i after MachProcess::Interrupt()",
827 __FUNCTION__, m_sent_interrupt_signo);
832 // Let all threads recover from stopping and do any clean up based
833 // on the previous thread state (if any).
834 m_thread_list.ProcessDidStop(*this);
836 // Let each thread know of any exceptions
837 for (i = 0; i < m_exception_messages.size(); ++i) {
838 // Let the thread list forward all exceptions on down to each thread.
839 if (m_exception_messages[i].state.task_port == task) {
840 // This exception is for our inferior.
841 m_thread_list.NotifyException(m_exception_messages[i].state);
846 m_exception_messages[i].Dump(stream);
848 log->PutCString(stream.GetString().c_str());
854 m_thread_list.Dump(stream);
856 log->PutCString(stream.GetString().c_str());
859 bool step_more = false;
860 if (m_thread_list.ShouldStop(step_more) && (auto_resume == false)) {
861 // TODO - need to hook up event system here. !!!!
863 // Wait for the eEventProcessRunningStateChanged event to be reset
864 // before changing state to stopped to avoid race condition with
865 // very fast start/stops.
866 struct timespec timeout;
868 //DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 ms
869 DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms
870 m_events.WaitForEventsToReset(eEventProcessRunningStateChanged,
873 SetState(eStateStopped);
875 // Resume without checking our current state.
882 void NativeProcessDarwin::StartSTDIOThread() {
886 Error NativeProcessDarwin::StartWaitpidThread(MainLoop &main_loop) {
888 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
890 // Strategy: create a thread that sits on waitpid(), waiting for the
891 // inferior process to die, reaping it in the process. Arrange for
892 // the thread to have a pipe file descriptor that it can send a byte
893 // over when the waitpid completes. Have the main loop have a read
894 // object for the other side of the pipe, and have the callback for
895 // the read do the process termination message sending.
897 // Create a single-direction communication channel.
898 const bool child_inherits = false;
899 error = m_waitpid_pipe.CreateNew(child_inherits);
902 log->Printf("NativeProcessDarwin::%s(): failed to create waitpid "
903 "communication pipe: %s",
904 __FUNCTION__, error.AsCString());
908 // Hook up the waitpid reader callback.
910 // TODO make PipePOSIX derive from IOObject. This is goofy here.
911 const bool transfer_ownership = false;
912 auto io_sp = IOObjectSP(
913 new File(m_waitpid_pipe.GetReadFileDescriptor(), transfer_ownership));
914 m_waitpid_reader_handle = main_loop.RegisterReadObject(
915 io_sp, [this](MainLoopBase &) { HandleWaitpidResult(); }, error);
917 // Create the thread.
919 ::pthread_create(&m_waitpid_thread, nullptr, WaitpidThread, this);
920 error.SetError(pthread_err, eErrorTypePOSIX);
923 log->Printf("NativeProcessDarwin::%s(): failed to create waitpid "
924 "handling thread: %u (%s)",
925 __FUNCTION__, error.GetError(), error.AsCString());
932 void *NativeProcessDarwin::WaitpidThread(void *arg) {
933 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
936 log->Printf("NativeProcessDarwin::%s(): cannot run waitpid "
937 "thread, mandatory process arg was null",
942 return reinterpret_cast<NativeProcessDarwin *>(arg)->DoWaitpidThread();
945 void NativeProcessDarwin::MaybeRaiseThreadPriority() {
946 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
947 struct sched_param thread_param;
948 int thread_sched_policy;
949 if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
950 &thread_param) == 0) {
951 thread_param.sched_priority = 47;
952 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
957 void *NativeProcessDarwin::DoWaitpidThread() {
958 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
960 if (m_pid == LLDB_INVALID_PROCESS_ID) {
962 log->Printf("NativeProcessDarwin::%s(): inferior process ID is "
963 "not set, cannot waitpid on it",
969 pthread_setname_np("waitpid thread");
971 // Ensure we don't get CPU starved.
972 MaybeRaiseThreadPriority();
979 ::pid_t child_pid = ::waitpid(m_pid, &status, 0);
981 error.SetErrorToErrno();
983 if (error.GetError() == EINTR) {
984 // This is okay, we can keep going.
986 log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64
987 ", &status, 0) interrupted, continuing",
988 __FUNCTION__, m_pid);
992 // This error is not okay, abort.
994 log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64
995 ", &status, 0) aborting due to error: %u (%s)",
996 __FUNCTION__, m_pid, error.GetError(), error.AsCString());
1000 // Log the successful result.
1002 log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64
1003 ", &status, 0) => %i, status = %i",
1004 __FUNCTION__, m_pid, child_pid, status);
1006 // Handle the result.
1007 if (WIFSTOPPED(status)) {
1009 log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64
1010 ") received a stop, continuing waitpid() loop",
1011 __FUNCTION__, m_pid);
1013 } else // if (WIFEXITED(status) || WIFSIGNALED(status))
1016 log->Printf("NativeProcessDarwin::%s(pid = %" PRIu64 "): "
1017 "waitpid thread is setting exit status for pid = "
1019 __FUNCTION__, m_pid, child_pid, status);
1021 error = SendInferiorExitStatusToMainLoop(child_pid, status);
1026 // We should never exit as long as our child process is alive. If we
1027 // get here, something completely unexpected went wrong and we should exit.
1030 "NativeProcessDarwin::%s(): internal error: waitpid thread "
1031 "exited out of its main loop in an unexpected way. pid = %" PRIu64
1032 ". Sending exit status of -1.",
1033 __FUNCTION__, m_pid);
1035 error = SendInferiorExitStatusToMainLoop((::pid_t)m_pid, -1);
1039 Error NativeProcessDarwin::SendInferiorExitStatusToMainLoop(::pid_t pid,
1042 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1044 size_t bytes_written = 0;
1047 error = m_waitpid_pipe.Write(&pid, sizeof(pid), bytes_written);
1048 if (error.Fail() || (bytes_written < sizeof(pid))) {
1050 log->Printf("NativeProcessDarwin::%s() - failed to write "
1051 "waitpid exiting pid to the pipe. Client will not "
1052 "hear about inferior exit status!",
1059 error = m_waitpid_pipe.Write(&status, sizeof(status), bytes_written);
1060 if (error.Fail() || (bytes_written < sizeof(status))) {
1062 log->Printf("NativeProcessDarwin::%s() - failed to write "
1063 "waitpid exit result to the pipe. Client will not "
1064 "hear about inferior exit status!",
1070 Error NativeProcessDarwin::HandleWaitpidResult() {
1072 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1075 const bool notify_status = true;
1078 size_t bytes_read = 0;
1079 error = m_waitpid_pipe.Read(&pid, sizeof(pid), bytes_read);
1080 if (error.Fail() || (bytes_read < sizeof(pid))) {
1082 log->Printf("NativeProcessDarwin::%s() - failed to read "
1083 "waitpid exiting pid from the pipe. Will notify "
1084 "as if parent process died with exit status -1.",
1086 SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result",
1093 error = m_waitpid_pipe.Read(&status, sizeof(status), bytes_read);
1094 if (error.Fail() || (bytes_read < sizeof(status))) {
1096 log->Printf("NativeProcessDarwin::%s() - failed to read "
1097 "waitpid exit status from the pipe. Will notify "
1098 "as if parent process died with exit status -1.",
1100 SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result",
1105 // Notify the monitor that our state has changed.
1107 log->Printf("NativeProcessDarwin::%s(): main loop received waitpid "
1108 "exit status info: pid=%i (%s), status=%i",
1110 (pid == m_pid) ? "the inferior" : "not the inferior", status);
1112 ExitType exit_type = eExitTypeInvalid;
1113 int exit_status = -1;
1115 if (WIFEXITED(status)) {
1116 exit_type = eExitTypeExit;
1117 exit_status = WEXITSTATUS(status);
1118 } else if (WIFSIGNALED(status)) {
1119 exit_type = eExitTypeSignal;
1120 exit_status = WTERMSIG(status);
1123 SetExitStatus(exit_type, exit_status, nullptr, notify_status);
1127 task_t NativeProcessDarwin::TaskPortForProcessID(Error &error,
1129 if ((m_task == TASK_NULL) || force) {
1130 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1131 if (m_pid == LLDB_INVALID_PROCESS_ID) {
1133 log->Printf("NativeProcessDarwin::%s(): cannot get task due "
1139 const uint32_t num_retries = 10;
1140 const uint32_t usec_interval = 10000;
1142 mach_port_t task_self = mach_task_self();
1143 task_t task = TASK_NULL;
1145 for (uint32_t i = 0; i < num_retries; i++) {
1146 kern_return_t err = ::task_for_pid(task_self, m_pid, &task);
1148 // Succeeded. Save and return it.
1151 log->Printf("NativeProcessDarwin::%s(): ::task_for_pid("
1152 "stub_port = 0x%4.4x, pid = %llu, &task) "
1153 "succeeded: inferior task port = 0x%4.4x",
1154 __FUNCTION__, task_self, m_pid, m_task);
1157 // Failed to get the task for the inferior process.
1158 error.SetError(err, eErrorTypeMachKernel);
1160 log->Printf("NativeProcessDarwin::%s(): ::task_for_pid("
1161 "stub_port = 0x%4.4x, pid = %llu, &task) "
1162 "failed, err = 0x%8.8x (%s)",
1163 __FUNCTION__, task_self, m_pid, err, error.AsCString());
1167 // Sleep a bit and try again
1168 ::usleep(usec_interval);
1171 // We failed to get the task for the inferior process.
1172 // Ensure that it is cleared out.
1178 void NativeProcessDarwin::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid,
1180 error.SetErrorString("TODO: implement");
1183 Error NativeProcessDarwin::PrivateResume() {
1185 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1187 std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex);
1188 m_auto_resume_signo = m_sent_interrupt_signo;
1191 if (m_auto_resume_signo)
1192 log->Printf("NativeProcessDarwin::%s(): task 0x%x resuming (with "
1193 "unhandled interrupt signal %i)...",
1194 __FUNCTION__, m_task, m_auto_resume_signo);
1196 log->Printf("NativeProcessDarwin::%s(): task 0x%x resuming...",
1197 __FUNCTION__, m_task);
1200 error = ReplyToAllExceptions();
1203 log->Printf("NativeProcessDarwin::%s(): aborting, failed to "
1204 "reply to exceptions: %s",
1205 __FUNCTION__, error.AsCString());
1208 // bool stepOverBreakInstruction = step;
1210 // Let the thread prepare to resume and see if any threads want us to
1211 // step over a breakpoint instruction (ProcessWillResume will modify
1212 // the value of stepOverBreakInstruction).
1213 m_thread_list.ProcessWillResume(*this, m_thread_actions);
1215 // Set our state accordingly
1216 if (m_thread_actions.NumActionsWithState(eStateStepping))
1217 SetState(eStateStepping);
1219 SetState(eStateRunning);
1221 // Now resume our task.
1222 error = ResumeTask();
1226 Error NativeProcessDarwin::ReplyToAllExceptions() {
1228 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
1230 TaskPortForProcessID(error);
1233 log->Printf("NativeProcessDarwin::%s(): no task port, aborting",
1238 std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex);
1239 if (m_exception_messages.empty()) {
1245 for (auto &message : m_exception_messages) {
1247 log->Printf("NativeProcessDarwin::%s(): replying to exception "
1249 __FUNCTION__, index++);
1252 int thread_reply_signal = 0;
1255 m_thread_list.GetThreadIDByMachPortNumber(message.state.thread_port);
1256 const ResumeAction *action = nullptr;
1257 if (tid != LLDB_INVALID_THREAD_ID)
1258 action = m_thread_actions.GetActionForThread(tid, false);
1261 thread_reply_signal = action->signal;
1262 if (thread_reply_signal)
1263 m_thread_actions.SetSignalHandledForThread(tid);
1266 error = message.Reply(m_pid, m_task, thread_reply_signal);
1267 if (error.Fail() && log) {
1268 // We log any error here, but we don't stop the exception
1269 // response handling.
1270 log->Printf("NativeProcessDarwin::%s(): failed to reply to "
1272 __FUNCTION__, error.AsCString());
1277 // Erase all exception message as we should have used and replied
1278 // to them all already.
1279 m_exception_messages.clear();
1283 Error NativeProcessDarwin::ResumeTask() {
1285 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1287 TaskPortForProcessID(error);
1290 log->Printf("NativeProcessDarwin::%s(): failed to get task port "
1291 "for process when attempting to resume: %s",
1292 __FUNCTION__, error.AsCString());
1295 if (m_task == TASK_NULL) {
1296 error.SetErrorString("task port retrieval succeeded but task port is "
1297 "null when attempting to resume the task");
1302 log->Printf("NativeProcessDarwin::%s(): requesting resume of task "
1304 __FUNCTION__, m_task);
1306 // Get the BasicInfo struct to verify that we're suspended before we try
1307 // to resume the task.
1308 struct task_basic_info task_info;
1309 error = GetTaskBasicInfo(m_task, &task_info);
1312 log->Printf("NativeProcessDarwin::%s(): failed to get task "
1313 "BasicInfo when attempting to resume: %s",
1314 __FUNCTION__, error.AsCString());
1318 // task_resume isn't counted like task_suspend calls are, so if the
1319 // task is not suspended, don't try and resume it since it is already
1321 if (task_info.suspend_count > 0) {
1322 auto mach_err = ::task_resume(m_task);
1323 error.SetError(mach_err, eErrorTypeMachKernel);
1325 if (error.Success())
1326 log->Printf("::task_resume(target_task = 0x%4.4x): success", m_task);
1328 log->Printf("::task_resume(target_task = 0x%4.4x) error: %s", m_task,
1333 log->Printf("::task_resume(target_task = 0x%4.4x): ignored, "
1341 bool NativeProcessDarwin::IsTaskValid() const {
1342 if (m_task == TASK_NULL)
1345 struct task_basic_info task_info;
1346 return GetTaskBasicInfo(m_task, &task_info).Success();
1349 bool NativeProcessDarwin::IsTaskValid(task_t task) const {
1350 if (task == TASK_NULL)
1353 struct task_basic_info task_info;
1354 return GetTaskBasicInfo(task, &task_info).Success();
1357 mach_port_t NativeProcessDarwin::GetExceptionPort() const {
1358 return m_exception_port;
1361 bool NativeProcessDarwin::IsExceptionPortValid() const {
1362 return MACH_PORT_VALID(m_exception_port);
1365 Error NativeProcessDarwin::GetTaskBasicInfo(
1366 task_t task, struct task_basic_info *info) const {
1368 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1372 error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): mandatory "
1378 // Grab the task if we don't already have it.
1379 if (task == TASK_NULL) {
1380 error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): given task "
1385 mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
1386 auto err = ::task_info(m_task, TASK_BASIC_INFO, (task_info_t)info, &count);
1387 error.SetError(err, eErrorTypeMachKernel);
1390 log->Printf("::task_info(target_task = 0x%4.4x, "
1391 "flavor = TASK_BASIC_INFO, task_info_out => %p, "
1392 "task_info_outCnt => %u) failed: %u (%s)",
1393 m_task, info, count, error.GetError(), error.AsCString());
1398 GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
1400 float user = (float)info->user_time.seconds +
1401 (float)info->user_time.microseconds / 1000000.0f;
1402 float system = (float)info->user_time.seconds +
1403 (float)info->user_time.microseconds / 1000000.0f;
1404 verbose_log->Printf("task_basic_info = { suspend_count = %i, "
1405 "virtual_size = 0x%8.8llx, resident_size = "
1406 "0x%8.8llx, user_time = %f, system_time = %f }",
1407 info->suspend_count, (uint64_t)info->virtual_size,
1408 (uint64_t)info->resident_size, user, system);
1413 Error NativeProcessDarwin::SuspendTask() {
1415 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1417 if (m_task == TASK_NULL) {
1418 error.SetErrorString("task port is null, cannot suspend task");
1420 log->Printf("NativeProcessDarwin::%s() failed: %s", __FUNCTION__,
1425 auto mach_err = ::task_suspend(m_task);
1426 error.SetError(mach_err, eErrorTypeMachKernel);
1427 if (error.Fail() && log)
1428 log->Printf("::task_suspend(target_task = 0x%4.4x)", m_task);
1433 Error NativeProcessDarwin::Resume(const ResumeActionList &resume_actions) {
1435 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1438 log->Printf("NativeProcessDarwin::%s() called", __FUNCTION__);
1441 m_thread_actions = resume_actions;
1442 error = PrivateResume();
1446 auto state = GetState();
1447 if (state == eStateRunning) {
1449 log->Printf("NativeProcessDarwin::%s(): task 0x%x is already "
1450 "running, ignoring...",
1451 __FUNCTION__, TaskPortForProcessID(error));
1455 // We can't resume from this state.
1456 error.SetErrorStringWithFormat("task 0x%x has state %s, can't resume",
1457 TaskPortForProcessID(error),
1458 StateAsCString(state));
1462 Error NativeProcessDarwin::Halt() {
1464 error.SetErrorString("TODO: implement");
1468 Error NativeProcessDarwin::Detach() {
1470 error.SetErrorString("TODO: implement");
1474 Error NativeProcessDarwin::Signal(int signo) {
1476 error.SetErrorString("TODO: implement");
1480 Error NativeProcessDarwin::Interrupt() {
1482 error.SetErrorString("TODO: implement");
1486 Error NativeProcessDarwin::Kill() {
1488 error.SetErrorString("TODO: implement");
1492 Error NativeProcessDarwin::GetMemoryRegionInfo(lldb::addr_t load_addr,
1493 MemoryRegionInfo &range_info) {
1495 error.SetErrorString("TODO: implement");
1499 Error NativeProcessDarwin::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
1500 size_t &bytes_read) {
1502 error.SetErrorString("TODO: implement");
1506 Error NativeProcessDarwin::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf,
1508 size_t &bytes_read) {
1510 error.SetErrorString("TODO: implement");
1514 Error NativeProcessDarwin::WriteMemory(lldb::addr_t addr, const void *buf,
1515 size_t size, size_t &bytes_written) {
1517 error.SetErrorString("TODO: implement");
1521 Error NativeProcessDarwin::AllocateMemory(size_t size, uint32_t permissions,
1522 lldb::addr_t &addr) {
1524 error.SetErrorString("TODO: implement");
1528 Error NativeProcessDarwin::DeallocateMemory(lldb::addr_t addr) {
1530 error.SetErrorString("TODO: implement");
1534 lldb::addr_t NativeProcessDarwin::GetSharedLibraryInfoAddress() {
1535 return LLDB_INVALID_ADDRESS;
1538 size_t NativeProcessDarwin::UpdateThreads() { return 0; }
1540 bool NativeProcessDarwin::GetArchitecture(ArchSpec &arch) const {
1544 Error NativeProcessDarwin::SetBreakpoint(lldb::addr_t addr, uint32_t size,
1547 error.SetErrorString("TODO: implement");
1551 void NativeProcessDarwin::DoStopIDBumped(uint32_t newBumpId) {}
1553 Error NativeProcessDarwin::GetLoadedModuleFileSpec(const char *module_path,
1554 FileSpec &file_spec) {
1556 error.SetErrorString("TODO: implement");
1560 Error NativeProcessDarwin::GetFileLoadAddress(const llvm::StringRef &file_name,
1561 lldb::addr_t &load_addr) {
1563 error.SetErrorString("TODO: implement");
1567 // -----------------------------------------------------------------
1568 // NativeProcessProtocol protected interface
1569 // -----------------------------------------------------------------
1570 Error NativeProcessDarwin::GetSoftwareBreakpointTrapOpcode(
1571 size_t trap_opcode_size_hint, size_t &actual_opcode_size,
1572 const uint8_t *&trap_opcode_bytes) {
1574 error.SetErrorString("TODO: implement");