blob: 4d787782c604f7998eb181fa954f30f9b3ed6e18 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- MachProcess.cpp -----------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Created by Greg Clayton on 6/15/07.
11//
12//===----------------------------------------------------------------------===//
13
14#include "DNB.h"
15#include <mach/mach.h>
Greg Clayton708c1ab2011-10-28 01:24:12 +000016#include <signal.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000017#include <spawn.h>
18#include <sys/fcntl.h>
19#include <sys/types.h>
20#include <sys/ptrace.h>
21#include <sys/stat.h>
Greg Clayton71337622011-02-24 22:24:29 +000022#include <sys/sysctl.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000023#include <unistd.h>
24#include "MacOSX/CFUtils.h"
25#include "SysSignal.h"
26
27#include <algorithm>
28#include <map>
29
30#include "DNBDataRef.h"
31#include "DNBLog.h"
32#include "DNBThreadResumeActions.h"
33#include "DNBTimer.h"
34#include "MachProcess.h"
35#include "PseudoTerminal.h"
36
37#include "CFBundle.h"
38#include "CFData.h"
39#include "CFString.h"
40
41static CFStringRef CopyBundleIDForPath (const char *app_buncle_path, DNBError &err_str);
42
Jason Molenda42999a42012-02-22 02:18:59 +000043#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +000044
45#include <CoreFoundation/CoreFoundation.h>
46#include <SpringBoardServices/SpringBoardServer.h>
47#include <SpringBoardServices/SBSWatchdogAssertion.h>
48
Chris Lattner30fdc8d2010-06-08 16:52:24 +000049static bool
50IsSBProcess (nub_process_t pid)
51{
52 bool opt_runningApps = true;
53 bool opt_debuggable = false;
54
55 CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
56 if (sbsAppIDs.get() != NULL)
57 {
58 CFIndex count = ::CFArrayGetCount (sbsAppIDs.get());
59 CFIndex i = 0;
60 for (i = 0; i < count; i++)
61 {
62 CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
63
64 // Get the process id for the app (if there is one)
65 pid_t sbs_pid = INVALID_NUB_PROCESS;
66 if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &sbs_pid) == TRUE)
67 {
68 if (sbs_pid == pid)
69 return true;
70 }
71 }
72 }
73 return false;
74}
75
Chris Lattner30fdc8d2010-06-08 16:52:24 +000076#endif
77
78#if 0
79#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__)
80#else
81#define DEBUG_LOG(fmt, ...)
82#endif
83
84#ifndef MACH_PROCESS_USE_POSIX_SPAWN
85#define MACH_PROCESS_USE_POSIX_SPAWN 1
86#endif
87
Greg Claytonf681b942010-08-31 18:35:14 +000088#ifndef _POSIX_SPAWN_DISABLE_ASLR
89#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
90#endif
Chris Lattner30fdc8d2010-06-08 16:52:24 +000091
92MachProcess::MachProcess() :
93 m_pid (0),
Greg Clayton71337622011-02-24 22:24:29 +000094 m_cpu_type (0),
Chris Lattner30fdc8d2010-06-08 16:52:24 +000095 m_child_stdin (-1),
96 m_child_stdout (-1),
97 m_child_stderr (-1),
98 m_path (),
99 m_args (),
100 m_task (this),
101 m_flags (eMachProcessFlagsNone),
102 m_stdio_thread (0),
103 m_stdio_mutex (PTHREAD_MUTEX_RECURSIVE),
104 m_stdout_data (),
Greg Claytonc4e411f2011-01-18 19:36:39 +0000105 m_thread_actions (),
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000106 m_thread_list (),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000107 m_exception_messages (),
108 m_exception_messages_mutex (PTHREAD_MUTEX_RECURSIVE),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000109 m_state (eStateUnloaded),
110 m_state_mutex (PTHREAD_MUTEX_RECURSIVE),
111 m_events (0, kAllEventsMask),
112 m_breakpoints (),
113 m_watchpoints (),
114 m_name_to_addr_callback(NULL),
115 m_name_to_addr_baton(NULL),
116 m_image_infos_callback(NULL),
117 m_image_infos_baton(NULL)
118{
119 DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__);
120}
121
122MachProcess::~MachProcess()
123{
124 DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__);
125 Clear();
126}
127
128pid_t
129MachProcess::SetProcessID(pid_t pid)
130{
131 // Free any previous process specific data or resources
132 Clear();
133 // Set the current PID appropriately
134 if (pid == 0)
Johnny Chenc0cd18d2010-09-28 16:34:56 +0000135 m_pid = ::getpid ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000136 else
137 m_pid = pid;
138 return m_pid; // Return actualy PID in case a zero pid was passed in
139}
140
141nub_state_t
142MachProcess::GetState()
143{
144 // If any other threads access this we will need a mutex for it
145 PTHREAD_MUTEX_LOCKER(locker, m_state_mutex);
146 return m_state;
147}
148
149const char *
150MachProcess::ThreadGetName(nub_thread_t tid)
151{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000152 return m_thread_list.GetName(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000153}
154
155nub_state_t
156MachProcess::ThreadGetState(nub_thread_t tid)
157{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000158 return m_thread_list.GetState(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000159}
160
161
162nub_size_t
163MachProcess::GetNumThreads () const
164{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000165 return m_thread_list.NumThreads();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000166}
167
168nub_thread_t
169MachProcess::GetThreadAtIndex (nub_size_t thread_idx) const
170{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000171 return m_thread_list.ThreadIDAtIndex(thread_idx);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000172}
173
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000174nub_thread_t
175MachProcess::GetCurrentThread ()
176{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000177 return m_thread_list.CurrentThreadID();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000178}
179
180nub_thread_t
181MachProcess::SetCurrentThread(nub_thread_t tid)
182{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000183 return m_thread_list.SetCurrentThread(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000184}
185
186bool
187MachProcess::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const
188{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000189 return m_thread_list.GetThreadStoppedReason(tid, stop_info);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000190}
191
192void
193MachProcess::DumpThreadStoppedReason(nub_thread_t tid) const
194{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000195 return m_thread_list.DumpThreadStoppedReason(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000196}
197
198const char *
199MachProcess::GetThreadInfo(nub_thread_t tid) const
200{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000201 return m_thread_list.GetThreadInfo(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000202}
203
Greg Clayton71337622011-02-24 22:24:29 +0000204uint32_t
205MachProcess::GetCPUType ()
206{
207 if (m_cpu_type == 0 && m_pid != 0)
208 m_cpu_type = MachProcess::GetCPUTypeForLocalProcess (m_pid);
209 return m_cpu_type;
210}
211
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000212const DNBRegisterSetInfo *
Greg Claytone2d4f0d2011-01-19 07:54:15 +0000213MachProcess::GetRegisterSetInfo (nub_thread_t tid, nub_size_t *num_reg_sets) const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000214{
Greg Claytone2d4f0d2011-01-19 07:54:15 +0000215 MachThreadSP thread_sp (m_thread_list.GetThreadByID (tid));
216 if (thread_sp)
Greg Clayton3af9ea52010-11-18 05:57:03 +0000217 {
Greg Claytone2d4f0d2011-01-19 07:54:15 +0000218 DNBArchProtocol *arch = thread_sp->GetArchProtocol();
Greg Clayton3af9ea52010-11-18 05:57:03 +0000219 if (arch)
220 return arch->GetRegisterSetInfo (num_reg_sets);
221 }
222 *num_reg_sets = 0;
223 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000224}
225
226bool
227MachProcess::GetRegisterValue ( nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value ) const
228{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000229 return m_thread_list.GetRegisterValue(tid, set, reg, value);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000230}
231
232bool
233MachProcess::SetRegisterValue ( nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value ) const
234{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000235 return m_thread_list.SetRegisterValue(tid, set, reg, value);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000236}
237
238void
239MachProcess::SetState(nub_state_t new_state)
240{
241 // If any other threads access this we will need a mutex for it
242 uint32_t event_mask = 0;
243
244 // Scope for mutex locker
245 {
246 PTHREAD_MUTEX_LOCKER(locker, m_state_mutex);
247 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::SetState ( %s )", DNBStateAsString(new_state));
248
249 const nub_state_t old_state = m_state;
250
251 if (old_state != new_state)
252 {
253 if (NUB_STATE_IS_STOPPED(new_state))
254 event_mask = eEventProcessStoppedStateChanged;
255 else
256 event_mask = eEventProcessRunningStateChanged;
257
258 m_state = new_state;
259 if (new_state == eStateStopped)
260 m_stop_count++;
261 }
262 }
263
264 if (event_mask != 0)
265 {
266 m_events.SetEvents (event_mask);
267
268 // Wait for the event bit to reset if a reset ACK is requested
269 m_events.WaitForResetAck(event_mask);
270 }
271
272}
273
274void
275MachProcess::Clear()
276{
277 // Clear any cached thread list while the pid and task are still valid
278
279 m_task.Clear();
280 // Now clear out all member variables
281 m_pid = INVALID_NUB_PROCESS;
282 CloseChildFileDescriptors();
283 m_path.clear();
284 m_args.clear();
285 SetState(eStateUnloaded);
286 m_flags = eMachProcessFlagsNone;
287 m_stop_count = 0;
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000288 m_thread_list.Clear();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000289 {
290 PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
291 m_exception_messages.clear();
292 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000293}
294
295
296bool
297MachProcess::StartSTDIOThread()
298{
299 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__);
300 // Create the thread that watches for the child STDIO
Greg Clayton3382c2c2010-07-30 23:14:42 +0000301 return ::pthread_create (&m_stdio_thread, NULL, MachProcess::STDIOThread, this) == 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000302}
303
304
305nub_addr_t
306MachProcess::LookupSymbol(const char *name, const char *shlib)
307{
308 if (m_name_to_addr_callback != NULL && name && name[0])
309 return m_name_to_addr_callback(ProcessID(), name, shlib, m_name_to_addr_baton);
310 return INVALID_NUB_ADDRESS;
311}
312
313bool
314MachProcess::Resume (const DNBThreadResumeActions& thread_actions)
315{
316 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Resume ()");
317 nub_state_t state = GetState();
318
319 if (CanResume(state))
320 {
Greg Claytonc4e411f2011-01-18 19:36:39 +0000321 m_thread_actions = thread_actions;
322 PrivateResume();
Greg Clayton3382c2c2010-07-30 23:14:42 +0000323 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000324 }
325 else if (state == eStateRunning)
326 {
327 DNBLogThreadedIf(LOG_PROCESS, "Resume() - task 0x%x is running, ignoring...", m_task.TaskPort());
Greg Clayton3382c2c2010-07-30 23:14:42 +0000328 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000329 }
Greg Clayton3382c2c2010-07-30 23:14:42 +0000330 DNBLogThreadedIf(LOG_PROCESS, "Resume() - task 0x%x can't continue, ignoring...", m_task.TaskPort());
331 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000332}
333
334bool
335MachProcess::Kill (const struct timespec *timeout_abstime)
336{
337 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill ()");
Jim Ingham5d2735e2012-04-25 17:45:26 +0000338 nub_state_t state = DoSIGSTOP(true, false, NULL);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000339 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() state = %s", DNBStateAsString(state));
340 errno = 0;
341 ::ptrace (PT_KILL, m_pid, 0, 0);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000342 DNBError err;
343 err.SetErrorToErrno();
Greg Clayton490fbbe2011-10-28 22:59:14 +0000344 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() ::ptrace (PT_KILL, pid=%u, 0, 0) => 0x%8.8x (%s)", m_pid, err.Error(), err.AsString());
Greg Claytonc4e411f2011-01-18 19:36:39 +0000345 m_thread_actions = DNBThreadResumeActions (eStateRunning, 0);
346 PrivateResume ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000347 return true;
348}
349
350bool
351MachProcess::Signal (int signal, const struct timespec *timeout_abstime)
352{
353 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p)", signal, timeout_abstime);
354 nub_state_t state = GetState();
355 if (::kill (ProcessID(), signal) == 0)
356 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000357 // If we were running and we have a timeout, wait for the signal to stop
358 if (IsRunning(state) && timeout_abstime)
359 {
360 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) waiting for signal to stop process...", signal, timeout_abstime);
361 m_events.WaitForSetEvents(eEventProcessStoppedStateChanged, timeout_abstime);
362 state = GetState();
363 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) state = %s", signal, timeout_abstime, DNBStateAsString(state));
364 return !IsRunning (state);
365 }
366 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) not waiting...", signal, timeout_abstime);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000367 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000368 }
Greg Clayton3382c2c2010-07-30 23:14:42 +0000369 DNBError err(errno, DNBError::POSIX);
370 err.LogThreadedIfError("kill (pid = %d, signo = %i)", ProcessID(), signal);
371 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000372
373}
374
375nub_state_t
Jim Ingham5d2735e2012-04-25 17:45:26 +0000376MachProcess::DoSIGSTOP (bool clear_bps_and_wps, bool allow_running, uint32_t *thread_idx_ptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000377{
378 nub_state_t state = GetState();
379 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s", DNBStateAsString (state));
380
381 if (!IsRunning(state))
382 {
383 if (clear_bps_and_wps)
384 {
385 DisableAllBreakpoints (true);
386 DisableAllWatchpoints (true);
387 clear_bps_and_wps = false;
388 }
389
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000390 // If we already have a thread stopped due to a SIGSTOP, we don't have
391 // to do anything...
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000392 uint32_t thread_idx = m_thread_list.GetThreadIndexForThreadStoppedWithSignal (SIGSTOP);
393 if (thread_idx_ptr)
394 *thread_idx_ptr = thread_idx;
395 if (thread_idx != UINT32_MAX)
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000396 return GetState();
397
398 // No threads were stopped with a SIGSTOP, we need to run and halt the
399 // process with a signal
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000400 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s -- resuming process", DNBStateAsString (state));
Jim Ingham5d2735e2012-04-25 17:45:26 +0000401 if (allow_running)
402 m_thread_actions = DNBThreadResumeActions (eStateRunning, 0);
403 else
404 m_thread_actions = DNBThreadResumeActions (eStateSuspended, 0);
405
Greg Claytonc4e411f2011-01-18 19:36:39 +0000406 PrivateResume ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000407
408 // Reset the event that says we were indeed running
409 m_events.ResetEvents(eEventProcessRunningStateChanged);
410 state = GetState();
411 }
412
413 // We need to be stopped in order to be able to detach, so we need
414 // to send ourselves a SIGSTOP
415
416 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s -- sending SIGSTOP", DNBStateAsString (state));
417 struct timespec sigstop_timeout;
418 DNBTimer::OffsetTimeOfDay(&sigstop_timeout, 2, 0);
419 Signal (SIGSTOP, &sigstop_timeout);
420 if (clear_bps_and_wps)
421 {
422 DisableAllBreakpoints (true);
423 DisableAllWatchpoints (true);
Johnny Chen119fd6c2011-08-10 23:19:32 +0000424 // The static analyzer complains about this, but just leave the following line in.
425 clear_bps_and_wps = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000426 }
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000427 uint32_t thread_idx = m_thread_list.GetThreadIndexForThreadStoppedWithSignal (SIGSTOP);
428 if (thread_idx_ptr)
429 *thread_idx_ptr = thread_idx;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000430 return GetState();
431}
432
433bool
434MachProcess::Detach()
435{
436 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach()");
437
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000438 uint32_t thread_idx = UINT32_MAX;
Jim Ingham5d2735e2012-04-25 17:45:26 +0000439 nub_state_t state = DoSIGSTOP(true, true, &thread_idx);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000440 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach() DoSIGSTOP() returned %s", DNBStateAsString(state));
441
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000442 {
Greg Claytonc4e411f2011-01-18 19:36:39 +0000443 m_thread_actions.Clear();
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000444 DNBThreadResumeAction thread_action;
445 thread_action.tid = m_thread_list.ThreadIDAtIndex (thread_idx);
446 thread_action.state = eStateRunning;
447 thread_action.signal = -1;
448 thread_action.addr = INVALID_NUB_ADDRESS;
449
Greg Claytonc4e411f2011-01-18 19:36:39 +0000450 m_thread_actions.Append (thread_action);
451 m_thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0);
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000452
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000453 PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000454
Greg Claytonc4e411f2011-01-18 19:36:39 +0000455 ReplyToAllExceptions ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000456
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000457 }
458
459 m_task.ShutDownExcecptionThread();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000460
461 // Detach from our process
462 errno = 0;
463 nub_process_t pid = m_pid;
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000464 int ret = ::ptrace (PT_DETACH, pid, (caddr_t)1, 0);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000465 DNBError err(errno, DNBError::POSIX);
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000466 if (DNBLogCheckLogBit(LOG_PROCESS) || err.Fail() || (ret != 0))
Greg Clayton3382c2c2010-07-30 23:14:42 +0000467 err.LogThreaded("::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000468
469 // Resume our task
470 m_task.Resume();
471
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000472 // NULL our task out as we have already retored all exception ports
473 m_task.Clear();
474
475 // Clear out any notion of the process we once were
476 Clear();
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000477
478 SetState(eStateDetached);
479
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000480 return true;
481}
482
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000483nub_size_t
484MachProcess::RemoveTrapsFromBuffer (nub_addr_t addr, nub_size_t size, uint8_t *buf) const
485{
486 nub_size_t bytes_removed = 0;
487 const DNBBreakpoint *bp;
488 nub_addr_t intersect_addr;
489 nub_size_t intersect_size;
490 nub_size_t opcode_offset;
491 nub_size_t idx;
492 for (idx = 0; (bp = m_breakpoints.GetByIndex(idx)) != NULL; ++idx)
493 {
494 if (bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset))
495 {
496 assert(addr <= intersect_addr && intersect_addr < addr + size);
497 assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size);
498 assert(opcode_offset + intersect_size <= bp->ByteSize());
499 nub_size_t buf_offset = intersect_addr - addr;
500 ::memcpy(buf + buf_offset, bp->SavedOpcodeBytes() + opcode_offset, intersect_size);
501 }
502 }
503 return bytes_removed;
504}
505
506//----------------------------------------------------------------------
507// ReadMemory from the MachProcess level will always remove any software
508// breakpoints from the memory buffer before returning. If you wish to
509// read memory and see those traps, read from the MachTask
510// (m_task.ReadMemory()) as that version will give you what is actually
511// in inferior memory.
512//----------------------------------------------------------------------
513nub_size_t
514MachProcess::ReadMemory (nub_addr_t addr, nub_size_t size, void *buf)
515{
516 // We need to remove any current software traps (enabled software
517 // breakpoints) that we may have placed in our tasks memory.
518
519 // First just read the memory as is
520 nub_size_t bytes_read = m_task.ReadMemory(addr, size, buf);
521
522 // Then place any opcodes that fall into this range back into the buffer
523 // before we return this to callers.
524 if (bytes_read > 0)
525 RemoveTrapsFromBuffer (addr, size, (uint8_t *)buf);
526 return bytes_read;
527}
528
529//----------------------------------------------------------------------
530// WriteMemory from the MachProcess level will always write memory around
531// any software breakpoints. Any software breakpoints will have their
532// opcodes modified if they are enabled. Any memory that doesn't overlap
533// with software breakpoints will be written to. If you wish to write to
534// inferior memory without this interference, then write to the MachTask
535// (m_task.WriteMemory()) as that version will always modify inferior
536// memory.
537//----------------------------------------------------------------------
538nub_size_t
539MachProcess::WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf)
540{
541 // We need to write any data that would go where any current software traps
542 // (enabled software breakpoints) any software traps (breakpoints) that we
543 // may have placed in our tasks memory.
544
545 std::map<nub_addr_t, DNBBreakpoint *> addr_to_bp_map;
546 DNBBreakpoint *bp;
547 nub_size_t idx;
548 for (idx = 0; (bp = m_breakpoints.GetByIndex(idx)) != NULL; ++idx)
549 {
550 if (bp->IntersectsRange(addr, size, NULL, NULL, NULL))
551 addr_to_bp_map[bp->Address()] = bp;
552 }
553
554 // If we don't have any software breakpoints that are in this buffer, then
555 // we can just write memory and be done with it.
556 if (addr_to_bp_map.empty())
557 return m_task.WriteMemory(addr, size, buf);
558
559 // If we make it here, we have some breakpoints that overlap and we need
560 // to work around them.
561
562 nub_size_t bytes_written = 0;
563 nub_addr_t intersect_addr;
564 nub_size_t intersect_size;
565 nub_size_t opcode_offset;
566 const uint8_t *ubuf = (const uint8_t *)buf;
567 std::map<nub_addr_t, DNBBreakpoint *>::iterator pos, end = addr_to_bp_map.end();
568 for (pos = addr_to_bp_map.begin(); pos != end; ++pos)
569 {
570 bp = pos->second;
571
572 assert(bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset));
573 assert(addr <= intersect_addr && intersect_addr < addr + size);
574 assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size);
575 assert(opcode_offset + intersect_size <= bp->ByteSize());
576
577 // Check for bytes before this breakpoint
578 const nub_addr_t curr_addr = addr + bytes_written;
579 if (intersect_addr > curr_addr)
580 {
581 // There are some bytes before this breakpoint that we need to
582 // just write to memory
583 nub_size_t curr_size = intersect_addr - curr_addr;
584 nub_size_t curr_bytes_written = m_task.WriteMemory(curr_addr, curr_size, ubuf + bytes_written);
585 bytes_written += curr_bytes_written;
586 if (curr_bytes_written != curr_size)
587 {
588 // We weren't able to write all of the requested bytes, we
589 // are done looping and will return the number of bytes that
590 // we have written so far.
591 break;
592 }
593 }
594
595 // Now write any bytes that would cover up any software breakpoints
596 // directly into the breakpoint opcode buffer
597 ::memcpy(bp->SavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, intersect_size);
598 bytes_written += intersect_size;
599 }
600
601 // Write any remaining bytes after the last breakpoint if we have any left
602 if (bytes_written < size)
603 bytes_written += m_task.WriteMemory(addr + bytes_written, size - bytes_written, ubuf + bytes_written);
604
605 return bytes_written;
606}
607
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000608void
Greg Claytonc4e411f2011-01-18 19:36:39 +0000609MachProcess::ReplyToAllExceptions ()
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000610{
611 PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
612 if (m_exception_messages.empty() == false)
613 {
614 MachException::Message::iterator pos;
615 MachException::Message::iterator begin = m_exception_messages.begin();
616 MachException::Message::iterator end = m_exception_messages.end();
617 for (pos = begin; pos != end; ++pos)
618 {
Greg Clayton490fbbe2011-10-28 22:59:14 +0000619 DNBLogThreadedIf(LOG_EXCEPTIONS, "Replying to exception %u...", (uint32_t)std::distance(begin, pos));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000620 int thread_reply_signal = 0;
621
Greg Claytonc4e411f2011-01-18 19:36:39 +0000622 const DNBThreadResumeAction *action = m_thread_actions.GetActionForThread (pos->state.thread_port, false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000623
624 if (action)
625 {
626 thread_reply_signal = action->signal;
627 if (thread_reply_signal)
Greg Claytonc4e411f2011-01-18 19:36:39 +0000628 m_thread_actions.SetSignalHandledForThread (pos->state.thread_port);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000629 }
630
Greg Clayton3382c2c2010-07-30 23:14:42 +0000631 DNBError err (pos->Reply(this, thread_reply_signal));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000632 if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
Greg Clayton3382c2c2010-07-30 23:14:42 +0000633 err.LogThreadedIfError("Error replying to exception");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000634 }
635
636 // Erase all exception message as we should have used and replied
637 // to them all already.
638 m_exception_messages.clear();
639 }
640}
641void
Greg Claytonc4e411f2011-01-18 19:36:39 +0000642MachProcess::PrivateResume ()
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000643{
644 PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
645
Greg Claytonc4e411f2011-01-18 19:36:39 +0000646 ReplyToAllExceptions ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000647// bool stepOverBreakInstruction = step;
648
649 // Let the thread prepare to resume and see if any threads want us to
650 // step over a breakpoint instruction (ProcessWillResume will modify
651 // the value of stepOverBreakInstruction).
Greg Claytonc4e411f2011-01-18 19:36:39 +0000652 m_thread_list.ProcessWillResume (this, m_thread_actions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000653
654 // Set our state accordingly
Greg Claytonc4e411f2011-01-18 19:36:39 +0000655 if (m_thread_actions.NumActionsWithState(eStateStepping))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000656 SetState (eStateStepping);
657 else
658 SetState (eStateRunning);
659
660 // Now resume our task.
Greg Clayton3382c2c2010-07-30 23:14:42 +0000661 m_task.Resume();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000662}
663
664nub_break_t
665MachProcess::CreateBreakpoint(nub_addr_t addr, nub_size_t length, bool hardware, thread_t tid)
666{
Greg Clayton490fbbe2011-10-28 22:59:14 +0000667 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = 0x%8.8llx, length = %zu, hardware = %i, tid = 0x%4.4x )", (uint64_t)addr, length, hardware, tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000668 if (hardware && tid == INVALID_NUB_THREAD)
669 tid = GetCurrentThread();
670
671 DNBBreakpoint bp(addr, length, tid, hardware);
672 nub_break_t breakID = m_breakpoints.Add(bp);
673 if (EnableBreakpoint(breakID))
674 {
Greg Clayton490fbbe2011-10-28 22:59:14 +0000675 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = 0x%8.8llx, length = %zu, tid = 0x%4.4x ) => %u", (uint64_t)addr, length, tid, breakID);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000676 return breakID;
677 }
678 else
679 {
680 m_breakpoints.Remove(breakID);
681 }
682 // We failed to enable the breakpoint
683 return INVALID_NUB_BREAK_ID;
684}
685
686nub_watch_t
687MachProcess::CreateWatchpoint(nub_addr_t addr, nub_size_t length, uint32_t watch_flags, bool hardware, thread_t tid)
688{
Greg Clayton490fbbe2011-10-28 22:59:14 +0000689 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %zu, flags = 0x%8.8x, hardware = %i, tid = 0x%4.4x )", (uint64_t)addr, length, watch_flags, hardware, tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000690 if (hardware && tid == INVALID_NUB_THREAD)
691 tid = GetCurrentThread();
692
693 DNBBreakpoint watch(addr, length, tid, hardware);
694 watch.SetIsWatchpoint(watch_flags);
695
696 nub_watch_t watchID = m_watchpoints.Add(watch);
697 if (EnableWatchpoint(watchID))
698 {
Greg Clayton490fbbe2011-10-28 22:59:14 +0000699 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %zu, tid = 0x%x) => %u", (uint64_t)addr, length, tid, watchID);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000700 return watchID;
701 }
702 else
703 {
Greg Clayton490fbbe2011-10-28 22:59:14 +0000704 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %zu, tid = 0x%x) => FAILED (%u)", (uint64_t)addr, length, tid, watchID);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000705 m_watchpoints.Remove(watchID);
706 }
707 // We failed to enable the watchpoint
708 return INVALID_NUB_BREAK_ID;
709}
710
711nub_size_t
712MachProcess::DisableAllBreakpoints(bool remove)
713{
714 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::%s (remove = %d )", __FUNCTION__, remove);
715 DNBBreakpoint *bp;
716 nub_size_t disabled_count = 0;
717 nub_size_t idx = 0;
718 while ((bp = m_breakpoints.GetByIndex(idx)) != NULL)
719 {
720 bool success = DisableBreakpoint(bp->GetID(), remove);
721
722 if (success)
723 disabled_count++;
724 // If we failed to disable the breakpoint or we aren't removing the breakpoint
725 // increment the breakpoint index. Otherwise DisableBreakpoint will have removed
726 // the breakpoint at this index and we don't need to change it.
727 if ((success == false) || (remove == false))
728 idx++;
729 }
730 return disabled_count;
731}
732
733nub_size_t
734MachProcess::DisableAllWatchpoints(bool remove)
735{
736 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::%s (remove = %d )", __FUNCTION__, remove);
737 DNBBreakpoint *wp;
738 nub_size_t disabled_count = 0;
739 nub_size_t idx = 0;
740 while ((wp = m_watchpoints.GetByIndex(idx)) != NULL)
741 {
742 bool success = DisableWatchpoint(wp->GetID(), remove);
743
744 if (success)
745 disabled_count++;
746 // If we failed to disable the watchpoint or we aren't removing the watchpoint
747 // increment the watchpoint index. Otherwise DisableWatchpoint will have removed
748 // the watchpoint at this index and we don't need to change it.
749 if ((success == false) || (remove == false))
750 idx++;
751 }
752 return disabled_count;
753}
754
755bool
756MachProcess::DisableBreakpoint(nub_break_t breakID, bool remove)
757{
758 DNBBreakpoint *bp = m_breakpoints.FindByID (breakID);
759 if (bp)
760 {
761 nub_addr_t addr = bp->Address();
762 DNBLogThreadedIf(LOG_BREAKPOINTS | LOG_VERBOSE, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx", breakID, remove, (uint64_t)addr);
763
764 if (bp->IsHardware())
765 {
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000766 bool hw_disable_result = m_thread_list.DisableHardwareBreakpoint (bp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000767
768 if (hw_disable_result == true)
769 {
770 bp->SetEnabled(false);
771 // Let the thread list know that a breakpoint has been modified
772 if (remove)
773 {
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000774 m_thread_list.NotifyBreakpointChanged(bp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000775 m_breakpoints.Remove(breakID);
776 }
777 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx (hardware) => success", breakID, remove, (uint64_t)addr);
778 return true;
779 }
780
781 return false;
782 }
783
784 const nub_size_t break_op_size = bp->ByteSize();
785 assert (break_op_size > 0);
Greg Clayton3af9ea52010-11-18 05:57:03 +0000786 const uint8_t * const break_op = DNBArchProtocol::GetBreakpointOpcode (bp->ByteSize());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000787 if (break_op_size > 0)
788 {
789 // Clear a software breakoint instruction
790 uint8_t curr_break_op[break_op_size];
791 bool break_op_found = false;
792
793 // Read the breakpoint opcode
794 if (m_task.ReadMemory(addr, break_op_size, curr_break_op) == break_op_size)
795 {
796 bool verify = false;
797 if (bp->IsEnabled())
798 {
799 // Make sure we have the a breakpoint opcode exists at this address
800 if (memcmp(curr_break_op, break_op, break_op_size) == 0)
801 {
802 break_op_found = true;
803 // We found a valid breakpoint opcode at this address, now restore
804 // the saved opcode.
805 if (m_task.WriteMemory(addr, break_op_size, bp->SavedOpcodeBytes()) == break_op_size)
806 {
807 verify = true;
808 }
809 else
810 {
811 DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx memory write failed when restoring original opcode", breakID, remove, (uint64_t)addr);
812 }
813 }
814 else
815 {
816 DNBLogWarning("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx expected a breakpoint opcode but didn't find one.", breakID, remove, (uint64_t)addr);
817 // Set verify to true and so we can check if the original opcode has already been restored
818 verify = true;
819 }
820 }
821 else
822 {
Greg Claytondce502e2011-11-04 03:34:56 +0000823 DNBLogThreadedIf(LOG_BREAKPOINTS | LOG_VERBOSE, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx is not enabled", breakID, remove, (uint64_t)addr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000824 // Set verify to true and so we can check if the original opcode is there
825 verify = true;
826 }
827
828 if (verify)
829 {
830 uint8_t verify_opcode[break_op_size];
831 // Verify that our original opcode made it back to the inferior
832 if (m_task.ReadMemory(addr, break_op_size, verify_opcode) == break_op_size)
833 {
834 // compare the memory we just read with the original opcode
835 if (memcmp(bp->SavedOpcodeBytes(), verify_opcode, break_op_size) == 0)
836 {
837 // SUCCESS
838 bp->SetEnabled(false);
839 // Let the thread list know that a breakpoint has been modified
840 if (remove)
841 {
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000842 m_thread_list.NotifyBreakpointChanged(bp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000843 m_breakpoints.Remove(breakID);
844 }
845 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx => success", breakID, remove, (uint64_t)addr);
846 return true;
847 }
848 else
849 {
850 if (break_op_found)
851 DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx: failed to restore original opcode", breakID, remove, (uint64_t)addr);
852 else
853 DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx: opcode changed", breakID, remove, (uint64_t)addr);
854 }
855 }
856 else
857 {
858 DNBLogWarning("MachProcess::DisableBreakpoint: unable to disable breakpoint 0x%8.8llx", (uint64_t)addr);
859 }
860 }
861 }
862 else
863 {
864 DNBLogWarning("MachProcess::DisableBreakpoint: unable to read memory at 0x%8.8llx", (uint64_t)addr);
865 }
866 }
867 }
868 else
869 {
870 DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) invalid breakpoint ID", breakID, remove);
871 }
872 return false;
873}
874
875bool
876MachProcess::DisableWatchpoint(nub_watch_t watchID, bool remove)
877{
878 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::%s(watchID = %d, remove = %d)", __FUNCTION__, watchID, remove);
879 DNBBreakpoint *wp = m_watchpoints.FindByID (watchID);
880 if (wp)
881 {
882 nub_addr_t addr = wp->Address();
883 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::DisableWatchpoint ( watchID = %d, remove = %d ) addr = 0x%8.8llx", watchID, remove, (uint64_t)addr);
884
885 if (wp->IsHardware())
886 {
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000887 bool hw_disable_result = m_thread_list.DisableHardwareWatchpoint (wp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000888
889 if (hw_disable_result == true)
890 {
891 wp->SetEnabled(false);
892 if (remove)
893 m_watchpoints.Remove(watchID);
894 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::Disablewatchpoint ( watchID = %d, remove = %d ) addr = 0x%8.8llx (hardware) => success", watchID, remove, (uint64_t)addr);
895 return true;
896 }
897 }
898
899 // TODO: clear software watchpoints if we implement them
900 }
901 else
902 {
903 DNBLogError("MachProcess::DisableWatchpoint ( watchID = %d, remove = %d ) invalid watchpoint ID", watchID, remove);
904 }
905 return false;
906}
907
908
909void
910MachProcess::DumpBreakpoint(nub_break_t breakID) const
911{
912 DNBLogThreaded("MachProcess::DumpBreakpoint(breakID = %d)", breakID);
913
914 if (NUB_BREAK_ID_IS_VALID(breakID))
915 {
916 const DNBBreakpoint *bp = m_breakpoints.FindByID(breakID);
917 if (bp)
918 bp->Dump();
919 else
920 DNBLog("MachProcess::DumpBreakpoint(breakID = %d): invalid breakID", breakID);
921 }
922 else
923 {
924 m_breakpoints.Dump();
925 }
926}
927
928void
929MachProcess::DumpWatchpoint(nub_watch_t watchID) const
930{
931 DNBLogThreaded("MachProcess::DumpWatchpoint(watchID = %d)", watchID);
932
933 if (NUB_BREAK_ID_IS_VALID(watchID))
934 {
935 const DNBBreakpoint *wp = m_watchpoints.FindByID(watchID);
936 if (wp)
937 wp->Dump();
938 else
939 DNBLog("MachProcess::DumpWatchpoint(watchID = %d): invalid watchID", watchID);
940 }
941 else
942 {
943 m_watchpoints.Dump();
944 }
945}
946
Johnny Chen64637202012-05-23 21:09:52 +0000947uint32_t
948MachProcess::GetNumSupportedHardwareWatchpoints () const
949{
950 return m_thread_list.NumSupportedHardwareWatchpoints();
951}
952
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000953bool
954MachProcess::EnableBreakpoint(nub_break_t breakID)
955{
956 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::EnableBreakpoint ( breakID = %d )", breakID);
957 DNBBreakpoint *bp = m_breakpoints.FindByID (breakID);
958 if (bp)
959 {
960 nub_addr_t addr = bp->Address();
961 if (bp->IsEnabled())
962 {
963 DNBLogWarning("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: breakpoint already enabled.", breakID, (uint64_t)addr);
964 return true;
965 }
966 else
967 {
968 if (bp->HardwarePreferred())
969 {
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000970 bp->SetHardwareIndex(m_thread_list.EnableHardwareBreakpoint(bp));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000971 if (bp->IsHardware())
972 {
973 bp->SetEnabled(true);
974 return true;
975 }
976 }
977
978 const nub_size_t break_op_size = bp->ByteSize();
979 assert (break_op_size != 0);
Greg Clayton3af9ea52010-11-18 05:57:03 +0000980 const uint8_t * const break_op = DNBArchProtocol::GetBreakpointOpcode (break_op_size);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000981 if (break_op_size > 0)
982 {
983 // Save the original opcode by reading it
984 if (m_task.ReadMemory(addr, break_op_size, bp->SavedOpcodeBytes()) == break_op_size)
985 {
986 // Write a software breakpoint in place of the original opcode
987 if (m_task.WriteMemory(addr, break_op_size, break_op) == break_op_size)
988 {
989 uint8_t verify_break_op[4];
990 if (m_task.ReadMemory(addr, break_op_size, verify_break_op) == break_op_size)
991 {
992 if (memcmp(break_op, verify_break_op, break_op_size) == 0)
993 {
994 bp->SetEnabled(true);
995 // Let the thread list know that a breakpoint has been modified
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000996 m_thread_list.NotifyBreakpointChanged(bp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000997 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: SUCCESS.", breakID, (uint64_t)addr);
998 return true;
999 }
1000 else
1001 {
1002 DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: breakpoint opcode verification failed.", breakID, (uint64_t)addr);
1003 }
1004 }
1005 else
1006 {
1007 DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: unable to read memory to verify breakpoint opcode.", breakID, (uint64_t)addr);
1008 }
1009 }
1010 else
1011 {
1012 DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: unable to write breakpoint opcode to memory.", breakID, (uint64_t)addr);
1013 }
1014 }
1015 else
1016 {
1017 DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: unable to read memory at breakpoint address.", breakID, (uint64_t)addr);
1018 }
1019 }
1020 else
1021 {
1022 DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) no software breakpoint opcode for current architecture.", breakID);
1023 }
1024 }
1025 }
1026 return false;
1027}
1028
1029bool
1030MachProcess::EnableWatchpoint(nub_watch_t watchID)
1031{
1032 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::EnableWatchpoint(watchID = %d)", watchID);
1033 DNBBreakpoint *wp = m_watchpoints.FindByID (watchID);
1034 if (wp)
1035 {
1036 nub_addr_t addr = wp->Address();
1037 if (wp->IsEnabled())
1038 {
1039 DNBLogWarning("MachProcess::EnableWatchpoint(watchID = %d) addr = 0x%8.8llx: watchpoint already enabled.", watchID, (uint64_t)addr);
1040 return true;
1041 }
1042 else
1043 {
1044 // Currently only try and set hardware watchpoints.
Greg Clayton58d1c9a2010-10-18 04:14:23 +00001045 wp->SetHardwareIndex(m_thread_list.EnableHardwareWatchpoint(wp));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001046 if (wp->IsHardware())
1047 {
1048 wp->SetEnabled(true);
1049 return true;
1050 }
1051 // TODO: Add software watchpoints by doing page protection tricks.
1052 }
1053 }
1054 return false;
1055}
1056
1057// Called by the exception thread when an exception has been received from
1058// our process. The exception message is completely filled and the exception
1059// data has already been copied.
1060void
1061MachProcess::ExceptionMessageReceived (const MachException::Message& exceptionMessage)
1062{
1063 PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
1064
1065 if (m_exception_messages.empty())
1066 m_task.Suspend();
1067
1068 DNBLogThreadedIf(LOG_EXCEPTIONS, "MachProcess::ExceptionMessageReceived ( )");
1069
1070 // Use a locker to automatically unlock our mutex in case of exceptions
1071 // Add the exception to our internal exception stack
1072 m_exception_messages.push_back(exceptionMessage);
1073}
1074
1075void
1076MachProcess::ExceptionMessageBundleComplete()
1077{
1078 // We have a complete bundle of exceptions for our child process.
1079 PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
Greg Clayton490fbbe2011-10-28 22:59:14 +00001080 DNBLogThreadedIf(LOG_EXCEPTIONS, "%s: %zu exception messages.", __PRETTY_FUNCTION__, m_exception_messages.size());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001081 if (!m_exception_messages.empty())
1082 {
1083 // Let all threads recover from stopping and do any clean up based
1084 // on the previous thread state (if any).
Greg Clayton58d1c9a2010-10-18 04:14:23 +00001085 m_thread_list.ProcessDidStop(this);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001086
1087 // Let each thread know of any exceptions
1088 task_t task = m_task.TaskPort();
1089 size_t i;
1090 for (i=0; i<m_exception_messages.size(); ++i)
1091 {
1092 // Let the thread list figure use the MachProcess to forward all exceptions
1093 // on down to each thread.
1094 if (m_exception_messages[i].state.task_port == task)
Greg Clayton58d1c9a2010-10-18 04:14:23 +00001095 m_thread_list.NotifyException(m_exception_messages[i].state);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001096 if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
1097 m_exception_messages[i].Dump();
1098 }
1099
1100 if (DNBLogCheckLogBit(LOG_THREAD))
Greg Clayton58d1c9a2010-10-18 04:14:23 +00001101 m_thread_list.Dump();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001102
1103 bool step_more = false;
Greg Clayton58d1c9a2010-10-18 04:14:23 +00001104 if (m_thread_list.ShouldStop(step_more))
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001105 {
1106 // Wait for the eEventProcessRunningStateChanged event to be reset
1107 // before changing state to stopped to avoid race condition with
1108 // very fast start/stops
1109 struct timespec timeout;
1110 //DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 ms
1111 DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms
1112 m_events.WaitForEventsToReset(eEventProcessRunningStateChanged, &timeout);
1113 SetState(eStateStopped);
1114 }
1115 else
1116 {
1117 // Resume without checking our current state.
Greg Claytonc4e411f2011-01-18 19:36:39 +00001118 PrivateResume ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001119 }
1120 }
1121 else
1122 {
Greg Claytondce502e2011-11-04 03:34:56 +00001123 DNBLogThreadedIf(LOG_EXCEPTIONS, "%s empty exception messages bundle (%zu exceptions).", __PRETTY_FUNCTION__, m_exception_messages.size());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001124 }
1125}
1126
1127nub_size_t
1128MachProcess::CopyImageInfos ( struct DNBExecutableImageInfo **image_infos, bool only_changed)
1129{
1130 if (m_image_infos_callback != NULL)
1131 return m_image_infos_callback(ProcessID(), image_infos, only_changed, m_image_infos_baton);
1132 return 0;
1133}
1134
1135void
1136MachProcess::SharedLibrariesUpdated ( )
1137{
1138 uint32_t event_bits = eEventSharedLibsStateChange;
1139 // Set the shared library event bit to let clients know of shared library
1140 // changes
1141 m_events.SetEvents(event_bits);
1142 // Wait for the event bit to reset if a reset ACK is requested
1143 m_events.WaitForResetAck(event_bits);
1144}
1145
1146void
1147MachProcess::AppendSTDOUT (char* s, size_t len)
1148{
Greg Clayton490fbbe2011-10-28 22:59:14 +00001149 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (<%zu> %s) ...", __FUNCTION__, len, s);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001150 PTHREAD_MUTEX_LOCKER (locker, m_stdio_mutex);
1151 m_stdout_data.append(s, len);
1152 m_events.SetEvents(eEventStdioAvailable);
1153
1154 // Wait for the event bit to reset if a reset ACK is requested
1155 m_events.WaitForResetAck(eEventStdioAvailable);
1156}
1157
1158size_t
1159MachProcess::GetAvailableSTDOUT (char *buf, size_t buf_size)
1160{
Greg Clayton490fbbe2011-10-28 22:59:14 +00001161 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (&%p[%zu]) ...", __FUNCTION__, buf, buf_size);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001162 PTHREAD_MUTEX_LOCKER (locker, m_stdio_mutex);
1163 size_t bytes_available = m_stdout_data.size();
1164 if (bytes_available > 0)
1165 {
1166 if (bytes_available > buf_size)
1167 {
1168 memcpy(buf, m_stdout_data.data(), buf_size);
1169 m_stdout_data.erase(0, buf_size);
1170 bytes_available = buf_size;
1171 }
1172 else
1173 {
1174 memcpy(buf, m_stdout_data.data(), bytes_available);
1175 m_stdout_data.clear();
1176 }
1177 }
1178 return bytes_available;
1179}
1180
1181nub_addr_t
1182MachProcess::GetDYLDAllImageInfosAddress ()
1183{
Greg Clayton3382c2c2010-07-30 23:14:42 +00001184 DNBError err;
1185 return m_task.GetDYLDAllImageInfosAddress(err);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001186}
1187
1188size_t
1189MachProcess::GetAvailableSTDERR (char *buf, size_t buf_size)
1190{
1191 return 0;
1192}
1193
1194void *
1195MachProcess::STDIOThread(void *arg)
1196{
1197 MachProcess *proc = (MachProcess*) arg;
1198 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( arg = %p ) thread starting...", __FUNCTION__, arg);
1199
1200 // We start use a base and more options so we can control if we
1201 // are currently using a timeout on the mach_msg. We do this to get a
1202 // bunch of related exceptions on our exception port so we can process
1203 // then together. When we have multiple threads, we can get an exception
1204 // per thread and they will come in consecutively. The main thread loop
1205 // will start by calling mach_msg to without having the MACH_RCV_TIMEOUT
1206 // flag set in the options, so we will wait forever for an exception on
1207 // our exception port. After we get one exception, we then will use the
1208 // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
1209 // exceptions for our process. After we have received the last pending
1210 // exception, we will get a timeout which enables us to then notify
1211 // our main thread that we have an exception bundle avaiable. We then wait
1212 // for the main thread to tell this exception thread to start trying to get
1213 // exceptions messages again and we start again with a mach_msg read with
1214 // infinite timeout.
1215 DNBError err;
1216 int stdout_fd = proc->GetStdoutFileDescriptor();
1217 int stderr_fd = proc->GetStderrFileDescriptor();
1218 if (stdout_fd == stderr_fd)
1219 stderr_fd = -1;
1220
1221 while (stdout_fd >= 0 || stderr_fd >= 0)
1222 {
1223 ::pthread_testcancel ();
1224
1225 fd_set read_fds;
1226 FD_ZERO (&read_fds);
1227 if (stdout_fd >= 0)
1228 FD_SET (stdout_fd, &read_fds);
1229 if (stderr_fd >= 0)
1230 FD_SET (stderr_fd, &read_fds);
1231 int nfds = std::max<int>(stdout_fd, stderr_fd) + 1;
1232
1233 int num_set_fds = select (nfds, &read_fds, NULL, NULL, NULL);
1234 DNBLogThreadedIf(LOG_PROCESS, "select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
1235
1236 if (num_set_fds < 0)
1237 {
1238 int select_errno = errno;
1239 if (DNBLogCheckLogBit(LOG_PROCESS))
1240 {
1241 err.SetError (select_errno, DNBError::POSIX);
1242 err.LogThreadedIfError("select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
1243 }
1244
1245 switch (select_errno)
1246 {
1247 case EAGAIN: // The kernel was (perhaps temporarily) unable to allocate the requested number of file descriptors, or we have non-blocking IO
1248 break;
1249 case EBADF: // One of the descriptor sets specified an invalid descriptor.
1250 return NULL;
1251 break;
1252 case EINTR: // A signal was delivered before the time limit expired and before any of the selected events occurred.
1253 case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
1254 default: // Other unknown error
1255 break;
1256 }
1257 }
1258 else if (num_set_fds == 0)
1259 {
1260 }
1261 else
1262 {
1263 char s[1024];
1264 s[sizeof(s)-1] = '\0'; // Ensure we have NULL termination
1265 int bytes_read = 0;
1266 if (stdout_fd >= 0 && FD_ISSET (stdout_fd, &read_fds))
1267 {
1268 do
1269 {
1270 bytes_read = ::read (stdout_fd, s, sizeof(s)-1);
1271 if (bytes_read < 0)
1272 {
1273 int read_errno = errno;
1274 DNBLogThreadedIf(LOG_PROCESS, "read (stdout_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
1275 }
1276 else if (bytes_read == 0)
1277 {
1278 // EOF...
1279 DNBLogThreadedIf(LOG_PROCESS, "read (stdout_fd, ) => %d (reached EOF for child STDOUT)", bytes_read);
1280 stdout_fd = -1;
1281 }
1282 else if (bytes_read > 0)
1283 {
1284 proc->AppendSTDOUT(s, bytes_read);
1285 }
1286
1287 } while (bytes_read > 0);
1288 }
1289
1290 if (stderr_fd >= 0 && FD_ISSET (stderr_fd, &read_fds))
1291 {
1292 do
1293 {
1294 bytes_read = ::read (stderr_fd, s, sizeof(s)-1);
1295 if (bytes_read < 0)
1296 {
1297 int read_errno = errno;
1298 DNBLogThreadedIf(LOG_PROCESS, "read (stderr_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
1299 }
1300 else if (bytes_read == 0)
1301 {
1302 // EOF...
1303 DNBLogThreadedIf(LOG_PROCESS, "read (stderr_fd, ) => %d (reached EOF for child STDERR)", bytes_read);
1304 stderr_fd = -1;
1305 }
1306 else if (bytes_read > 0)
1307 {
1308 proc->AppendSTDOUT(s, bytes_read);
1309 }
1310
1311 } while (bytes_read > 0);
1312 }
1313 }
1314 }
1315 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%p): thread exiting...", __FUNCTION__, arg);
1316 return NULL;
1317}
1318
1319pid_t
1320MachProcess::AttachForDebug (pid_t pid, char *err_str, size_t err_len)
1321{
1322 // Clear out and clean up from any current state
1323 Clear();
1324 if (pid != 0)
1325 {
Greg Clayton3382c2c2010-07-30 23:14:42 +00001326 DNBError err;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001327 // Make sure the process exists...
1328 if (::getpgid (pid) < 0)
1329 {
Greg Clayton3382c2c2010-07-30 23:14:42 +00001330 err.SetErrorToErrno();
1331 const char *err_cstr = err.AsString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001332 ::snprintf (err_str, err_len, "%s", err_cstr ? err_cstr : "No such process");
1333 return INVALID_NUB_PROCESS;
1334 }
1335
1336 SetState(eStateAttaching);
1337 m_pid = pid;
1338 // Let ourselves know we are going to be using SBS if the correct flag bit is set...
Jason Molenda42999a42012-02-22 02:18:59 +00001339#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001340 if (IsSBProcess(pid))
1341 m_flags |= eMachProcessFlagsUsingSBS;
1342#endif
Greg Clayton3382c2c2010-07-30 23:14:42 +00001343 if (!m_task.StartExceptionThread(err))
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001344 {
Greg Clayton3382c2c2010-07-30 23:14:42 +00001345 const char *err_cstr = err.AsString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001346 ::snprintf (err_str, err_len, "%s", err_cstr ? err_cstr : "unable to start the exception thread");
1347 DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid);
1348 m_pid = INVALID_NUB_PROCESS;
1349 return INVALID_NUB_PROCESS;
1350 }
1351
1352 errno = 0;
Greg Clayton3382c2c2010-07-30 23:14:42 +00001353 if (::ptrace (PT_ATTACHEXC, pid, 0, 0))
1354 err.SetError(errno);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001355 else
Greg Clayton3382c2c2010-07-30 23:14:42 +00001356 err.Clear();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001357
Greg Clayton3382c2c2010-07-30 23:14:42 +00001358 if (err.Success())
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001359 {
1360 m_flags |= eMachProcessFlagsAttached;
1361 // Sleep a bit to let the exception get received and set our process status
1362 // to stopped.
1363 ::usleep(250000);
1364 DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", pid);
1365 return m_pid;
1366 }
1367 else
1368 {
Greg Clayton3382c2c2010-07-30 23:14:42 +00001369 ::snprintf (err_str, err_len, "%s", err.AsString());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001370 DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid);
1371 }
1372 }
1373 return INVALID_NUB_PROCESS;
1374}
1375
1376// Do the process specific setup for attach. If this returns NULL, then there's no
1377// platform specific stuff to be done to wait for the attach. If you get non-null,
1378// pass that token to the CheckForProcess method, and then to CleanupAfterAttach.
1379
1380// Call PrepareForAttach before attaching to a process that has not yet launched
1381// This returns a token that can be passed to CheckForProcess, and to CleanupAfterAttach.
1382// You should call CleanupAfterAttach to free the token, and do whatever other
1383// cleanup seems good.
1384
1385const void *
1386MachProcess::PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &err_str)
1387{
Jason Molenda42999a42012-02-22 02:18:59 +00001388#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001389 // Tell SpringBoard to halt the next launch of this application on startup.
1390
1391 if (!waitfor)
1392 return NULL;
1393
1394 const char *app_ext = strstr(path, ".app");
1395 if (app_ext == NULL)
1396 {
Greg Claytondce502e2011-11-04 03:34:56 +00001397 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::PrepareForAttach(): path '%s' doesn't contain .app, we can't tell springboard to wait for launch...", path);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001398 return NULL;
1399 }
1400
1401 if (launch_flavor != eLaunchFlavorSpringBoard
1402 && launch_flavor != eLaunchFlavorDefault)
1403 return NULL;
1404
1405 std::string app_bundle_path(path, app_ext + strlen(".app"));
1406
1407 CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path.c_str (), err_str);
1408 std::string bundleIDStr;
1409 CFString::UTF8(bundleIDCFStr, bundleIDStr);
1410 DNBLogThreadedIf(LOG_PROCESS, "CopyBundleIDForPath (%s, err_str) returned @\"%s\"", app_bundle_path.c_str (), bundleIDStr.c_str());
1411
1412 if (bundleIDCFStr == NULL)
1413 {
1414 return NULL;
1415 }
1416
1417 SBSApplicationLaunchError sbs_error = 0;
1418
1419 const char *stdout_err = "/dev/null";
1420 CFString stdio_path;
1421 stdio_path.SetFileSystemRepresentation (stdout_err);
1422
1423 DNBLogThreadedIf(LOG_PROCESS, "SBSLaunchApplicationForDebugging ( @\"%s\" , NULL, NULL, NULL, @\"%s\", @\"%s\", SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger )", bundleIDStr.c_str(), stdout_err, stdout_err);
1424 sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
1425 (CFURLRef)NULL, // openURL
1426 NULL, // launch_argv.get(),
1427 NULL, // launch_envp.get(), // CFDictionaryRef environment
1428 stdio_path.get(),
1429 stdio_path.get(),
1430 SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger);
1431
1432 if (sbs_error != SBSApplicationLaunchErrorSuccess)
1433 {
1434 err_str.SetError(sbs_error, DNBError::SpringBoard);
1435 return NULL;
1436 }
1437
1438 DNBLogThreadedIf(LOG_PROCESS, "Successfully set DebugOnNextLaunch.");
1439 return bundleIDCFStr;
1440# else
1441 return NULL;
1442#endif
1443}
1444
1445// Pass in the token you got from PrepareForAttach. If there is a process
1446// for that token, then the pid will be returned, otherwise INVALID_NUB_PROCESS
1447// will be returned.
1448
1449nub_process_t
1450MachProcess::CheckForProcess (const void *attach_token)
1451{
1452 if (attach_token == NULL)
1453 return INVALID_NUB_PROCESS;
1454
Jason Molenda42999a42012-02-22 02:18:59 +00001455#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001456 CFStringRef bundleIDCFStr = (CFStringRef) attach_token;
1457 Boolean got_it;
1458 nub_process_t attach_pid;
1459 got_it = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &attach_pid);
1460 if (got_it)
1461 return attach_pid;
1462 else
1463 return INVALID_NUB_PROCESS;
1464#endif
1465 return INVALID_NUB_PROCESS;
1466}
1467
1468// Call this to clean up after you have either attached or given up on the attach.
1469// Pass true for success if you have attached, false if you have not.
1470// The token will also be freed at this point, so you can't use it after calling
1471// this method.
1472
1473void
1474MachProcess::CleanupAfterAttach (const void *attach_token, bool success, DNBError &err_str)
1475{
Jason Molenda42999a42012-02-22 02:18:59 +00001476#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001477 if (attach_token == NULL)
1478 return;
1479
1480 // Tell SpringBoard to cancel the debug on next launch of this application
1481 // if we failed to attach
1482 if (!success)
1483 {
1484 SBSApplicationLaunchError sbs_error = 0;
1485 CFStringRef bundleIDCFStr = (CFStringRef) attach_token;
1486
1487 sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
1488 (CFURLRef)NULL,
1489 NULL,
1490 NULL,
1491 NULL,
1492 NULL,
1493 SBSApplicationCancelDebugOnNextLaunch);
1494
1495 if (sbs_error != SBSApplicationLaunchErrorSuccess)
1496 {
1497 err_str.SetError(sbs_error, DNBError::SpringBoard);
1498 return;
1499 }
1500 }
1501
1502 CFRelease((CFStringRef) attach_token);
1503#endif
1504}
1505
1506pid_t
1507MachProcess::LaunchForDebug
1508(
1509 const char *path,
1510 char const *argv[],
1511 char const *envp[],
Greg Clayton6779606a2011-01-22 23:43:18 +00001512 const char *working_directory, // NULL => dont' change, non-NULL => set working directory for inferior to this
1513 const char *stdin_path,
1514 const char *stdout_path,
1515 const char *stderr_path,
Caroline Ticef8da8632010-12-03 18:46:09 +00001516 bool no_stdio,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001517 nub_launch_flavor_t launch_flavor,
Greg Claytonf681b942010-08-31 18:35:14 +00001518 int disable_aslr,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001519 DNBError &launch_err
1520)
1521{
1522 // Clear out and clean up from any current state
1523 Clear();
1524
Greg Claytonf681b942010-08-31 18:35:14 +00001525 DNBLogThreadedIf(LOG_PROCESS, "%s( path = '%s', argv = %p, envp = %p, launch_flavor = %u, disable_aslr = %d )", __FUNCTION__, path, argv, envp, launch_flavor, disable_aslr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001526
1527 // Fork a child process for debugging
1528 SetState(eStateLaunching);
1529
1530 switch (launch_flavor)
1531 {
1532 case eLaunchFlavorForkExec:
1533 m_pid = MachProcess::ForkChildForPTraceDebugging (path, argv, envp, this, launch_err);
1534 break;
1535
Johnny Chenbe4e2082012-06-11 21:05:26 +00001536#ifdef WITH_SPRINGBOARD
1537
1538 case eLaunchFlavorSpringBoard:
1539 {
1540 const char *app_ext = strstr(path, ".app");
1541 if (app_ext != NULL)
1542 {
1543 std::string app_bundle_path(path, app_ext + strlen(".app"));
1544 if (SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, launch_err) != 0)
1545 return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid.
1546 }
1547 }
1548 // In case the executable name has a ".app" fragment which confuses our debugserver,
1549 // let's do an intentional fallthrough here...
1550 launch_flavor = eLaunchFlavorPosixSpawn;
1551
1552#endif
1553
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001554 case eLaunchFlavorPosixSpawn:
Greg Clayton3af9ea52010-11-18 05:57:03 +00001555 m_pid = MachProcess::PosixSpawnChildForPTraceDebugging (path,
Greg Clayton3c144382010-12-01 22:45:40 +00001556 DNBArchProtocol::GetArchitecture (),
Greg Clayton3af9ea52010-11-18 05:57:03 +00001557 argv,
1558 envp,
Greg Clayton6779606a2011-01-22 23:43:18 +00001559 working_directory,
1560 stdin_path,
1561 stdout_path,
1562 stderr_path,
Caroline Ticef8da8632010-12-03 18:46:09 +00001563 no_stdio,
Greg Clayton3af9ea52010-11-18 05:57:03 +00001564 this,
1565 disable_aslr,
1566 launch_err);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001567 break;
1568
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001569 default:
1570 // Invalid launch
1571 launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic);
1572 return INVALID_NUB_PROCESS;
1573 }
1574
1575 if (m_pid == INVALID_NUB_PROCESS)
1576 {
1577 // If we don't have a valid process ID and no one has set the error,
1578 // then return a generic error
1579 if (launch_err.Success())
1580 launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic);
1581 }
1582 else
1583 {
1584 m_path = path;
1585 size_t i;
1586 char const *arg;
1587 for (i=0; (arg = argv[i]) != NULL; i++)
1588 m_args.push_back(arg);
1589
Greg Clayton3382c2c2010-07-30 23:14:42 +00001590 m_task.StartExceptionThread(launch_err);
1591 if (launch_err.Fail())
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001592 {
Greg Clayton3382c2c2010-07-30 23:14:42 +00001593 if (launch_err.AsString() == NULL)
1594 launch_err.SetErrorString("unable to start the exception thread");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001595 ::ptrace (PT_KILL, m_pid, 0, 0);
1596 m_pid = INVALID_NUB_PROCESS;
1597 return INVALID_NUB_PROCESS;
1598 }
1599
1600 StartSTDIOThread();
1601
1602 if (launch_flavor == eLaunchFlavorPosixSpawn)
1603 {
1604
1605 SetState (eStateAttaching);
1606 errno = 0;
Caroline Tice5d7be2e2010-11-02 16:16:53 +00001607 int err = ::ptrace (PT_ATTACHEXC, m_pid, 0, 0);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001608 if (err == 0)
1609 {
1610 m_flags |= eMachProcessFlagsAttached;
1611 DNBLogThreadedIf(LOG_PROCESS, "successfully spawned pid %d", m_pid);
1612 launch_err.Clear();
1613 }
1614 else
1615 {
1616 SetState (eStateExited);
1617 DNBError ptrace_err(errno, DNBError::POSIX);
1618 DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to spawned pid %d (err = %i, errno = %i (%s))", m_pid, err, ptrace_err.Error(), ptrace_err.AsString());
1619 launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic);
1620 }
1621 }
1622 else
1623 {
1624 launch_err.Clear();
1625 }
1626 }
1627 return m_pid;
1628}
1629
1630pid_t
1631MachProcess::PosixSpawnChildForPTraceDebugging
1632(
1633 const char *path,
Greg Clayton3af9ea52010-11-18 05:57:03 +00001634 cpu_type_t cpu_type,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001635 char const *argv[],
1636 char const *envp[],
Greg Clayton6779606a2011-01-22 23:43:18 +00001637 const char *working_directory,
1638 const char *stdin_path,
1639 const char *stdout_path,
1640 const char *stderr_path,
Caroline Ticef8da8632010-12-03 18:46:09 +00001641 bool no_stdio,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001642 MachProcess* process,
Greg Claytonf681b942010-08-31 18:35:14 +00001643 int disable_aslr,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001644 DNBError& err
1645)
1646{
1647 posix_spawnattr_t attr;
Greg Claytonf681b942010-08-31 18:35:14 +00001648 short flags;
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001649 DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv=%p, envp=%p, working_dir=%s, stdin=%s, stdout=%s stderr=%s, no-stdio=%i)",
1650 __FUNCTION__,
1651 path,
1652 argv,
1653 envp,
1654 working_directory,
1655 stdin_path,
1656 stdout_path,
1657 stderr_path,
1658 no_stdio);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001659
1660 err.SetError( ::posix_spawnattr_init (&attr), DNBError::POSIX);
1661 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1662 err.LogThreaded("::posix_spawnattr_init ( &attr )");
1663 if (err.Fail())
1664 return INVALID_NUB_PROCESS;
1665
Greg Clayton708c1ab2011-10-28 01:24:12 +00001666 flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
Greg Claytonf681b942010-08-31 18:35:14 +00001667 if (disable_aslr)
1668 flags |= _POSIX_SPAWN_DISABLE_ASLR;
Greg Clayton708c1ab2011-10-28 01:24:12 +00001669
1670 sigset_t no_signals;
1671 sigset_t all_signals;
1672 sigemptyset (&no_signals);
1673 sigfillset (&all_signals);
1674 ::posix_spawnattr_setsigmask(&attr, &no_signals);
1675 ::posix_spawnattr_setsigdefault(&attr, &all_signals);
1676
Greg Claytonf681b942010-08-31 18:35:14 +00001677 err.SetError( ::posix_spawnattr_setflags (&attr, flags), DNBError::POSIX);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001678 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
Greg Claytonf681b942010-08-31 18:35:14 +00001679 err.LogThreaded("::posix_spawnattr_setflags ( &attr, POSIX_SPAWN_START_SUSPENDED%s )", flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR" : "");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001680 if (err.Fail())
1681 return INVALID_NUB_PROCESS;
1682
1683 // Don't do this on SnowLeopard, _sometimes_ the TASK_BASIC_INFO will fail
1684 // and we will fail to continue with our process...
1685
1686 // On SnowLeopard we should set "DYLD_NO_PIE" in the inferior environment....
1687
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001688#if !defined(__arm__)
1689
1690 // We don't need to do this for ARM, and we really shouldn't now that we
1691 // have multiple CPU subtypes and no posix_spawnattr call that allows us
1692 // to set which CPU subtype to launch...
Greg Clayton71337622011-02-24 22:24:29 +00001693 if (cpu_type != 0)
1694 {
1695 size_t ocount = 0;
1696 err.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu_type, &ocount), DNBError::POSIX);
1697 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1698 err.LogThreaded("::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %zu )", cpu_type, ocount);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001699
Greg Clayton71337622011-02-24 22:24:29 +00001700 if (err.Fail() != 0 || ocount != 1)
1701 return INVALID_NUB_PROCESS;
1702 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001703#endif
1704
1705 PseudoTerminal pty;
1706
1707 posix_spawn_file_actions_t file_actions;
1708 err.SetError( ::posix_spawn_file_actions_init (&file_actions), DNBError::POSIX);
1709 int file_actions_valid = err.Success();
1710 if (!file_actions_valid || DNBLogCheckLogBit(LOG_PROCESS))
1711 err.LogThreaded("::posix_spawn_file_actions_init ( &file_actions )");
1712 int pty_error = -1;
1713 pid_t pid = INVALID_NUB_PROCESS;
1714 if (file_actions_valid)
1715 {
Greg Clayton6779606a2011-01-22 23:43:18 +00001716 if (stdin_path == NULL && stdout_path == NULL && stderr_path == NULL && !no_stdio)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001717 {
1718 pty_error = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY);
1719 if (pty_error == PseudoTerminal::success)
Greg Clayton6779606a2011-01-22 23:43:18 +00001720 {
1721 stdin_path = stdout_path = stderr_path = pty.SlaveName();
1722 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001723 }
1724
Greg Clayton701a6b42012-03-12 19:02:41 +00001725 // if no_stdio or std paths not supplied, then route to "/dev/null".
1726 if (no_stdio || stdin_path == NULL || stdin_path[0] == '\0')
1727 stdin_path = "/dev/null";
1728 if (no_stdio || stdout_path == NULL || stdout_path[0] == '\0')
1729 stdout_path = "/dev/null";
1730 if (no_stdio || stderr_path == NULL || stderr_path[0] == '\0')
1731 stderr_path = "/dev/null";
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001732
Greg Clayton701a6b42012-03-12 19:02:41 +00001733 err.SetError( ::posix_spawn_file_actions_addopen (&file_actions,
1734 STDIN_FILENO,
1735 stdin_path,
1736 O_RDONLY | O_NOCTTY,
1737 0),
1738 DNBError::POSIX);
1739 if (err.Fail() || DNBLogCheckLogBit (LOG_PROCESS))
1740 err.LogThreaded ("::posix_spawn_file_actions_addopen (&file_actions, filedes=STDIN_FILENO, path='%s')", stdin_path);
1741
1742 err.SetError( ::posix_spawn_file_actions_addopen (&file_actions,
1743 STDOUT_FILENO,
1744 stdout_path,
1745 O_WRONLY | O_NOCTTY | O_CREAT,
1746 0640),
1747 DNBError::POSIX);
1748 if (err.Fail() || DNBLogCheckLogBit (LOG_PROCESS))
1749 err.LogThreaded ("::posix_spawn_file_actions_addopen (&file_actions, filedes=STDOUT_FILENO, path='%s')", stdout_path);
1750
1751 err.SetError( ::posix_spawn_file_actions_addopen (&file_actions,
1752 STDERR_FILENO,
1753 stderr_path,
1754 O_WRONLY | O_NOCTTY | O_CREAT,
1755 0640),
1756 DNBError::POSIX);
1757 if (err.Fail() || DNBLogCheckLogBit (LOG_PROCESS))
1758 err.LogThreaded ("::posix_spawn_file_actions_addopen (&file_actions, filedes=STDERR_FILENO, path='%s')", stderr_path);
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001759
1760 // TODO: Verify if we can set the working directory back immediately
1761 // after the posix_spawnp call without creating a race condition???
1762 if (working_directory)
1763 ::chdir (working_directory);
1764
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001765 err.SetError( ::posix_spawnp (&pid, path, &file_actions, &attr, (char * const*)argv, (char * const*)envp), DNBError::POSIX);
1766 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1767 err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, &file_actions, &attr, argv, envp);
1768 }
1769 else
1770 {
Greg Claytonbd82a5d2011-01-23 05:56:20 +00001771 // TODO: Verify if we can set the working directory back immediately
1772 // after the posix_spawnp call without creating a race condition???
1773 if (working_directory)
1774 ::chdir (working_directory);
1775
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001776 err.SetError( ::posix_spawnp (&pid, path, NULL, &attr, (char * const*)argv, (char * const*)envp), DNBError::POSIX);
1777 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1778 err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, NULL, &attr, argv, envp);
1779 }
1780
1781 // We have seen some cases where posix_spawnp was returning a valid
1782 // looking pid even when an error was returned, so clear it out
1783 if (err.Fail())
1784 pid = INVALID_NUB_PROCESS;
1785
1786 if (pty_error == 0)
1787 {
1788 if (process != NULL)
1789 {
1790 int master_fd = pty.ReleaseMasterFD();
1791 process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
1792 }
1793 }
Greg Clayton0b42ac32010-07-02 01:29:13 +00001794 ::posix_spawnattr_destroy (&attr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001795
Greg Clayton71337622011-02-24 22:24:29 +00001796 if (pid != INVALID_NUB_PROCESS)
1797 {
1798 cpu_type_t pid_cpu_type = MachProcess::GetCPUTypeForLocalProcess (pid);
1799 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( ) pid=%i, cpu_type=0x%8.8x", __FUNCTION__, pid, pid_cpu_type);
1800 if (pid_cpu_type)
1801 DNBArchProtocol::SetArchitecture (pid_cpu_type);
1802 }
1803
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001804 if (file_actions_valid)
1805 {
1806 DNBError err2;
1807 err2.SetError( ::posix_spawn_file_actions_destroy (&file_actions), DNBError::POSIX);
1808 if (err2.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1809 err2.LogThreaded("::posix_spawn_file_actions_destroy ( &file_actions )");
1810 }
1811
1812 return pid;
1813}
1814
Greg Clayton71337622011-02-24 22:24:29 +00001815uint32_t
1816MachProcess::GetCPUTypeForLocalProcess (pid_t pid)
1817{
1818 int mib[CTL_MAXNAME]={0,};
1819 size_t len = CTL_MAXNAME;
1820 if (::sysctlnametomib("sysctl.proc_cputype", mib, &len))
1821 return 0;
1822
1823 mib[len] = pid;
1824 len++;
1825
1826 cpu_type_t cpu;
1827 size_t cpu_len = sizeof(cpu);
1828 if (::sysctl (mib, len, &cpu, &cpu_len, 0, 0))
1829 cpu = 0;
1830 return cpu;
1831}
1832
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001833pid_t
1834MachProcess::ForkChildForPTraceDebugging
1835(
1836 const char *path,
1837 char const *argv[],
1838 char const *envp[],
1839 MachProcess* process,
1840 DNBError& launch_err
1841)
1842{
1843 PseudoTerminal::Error pty_error = PseudoTerminal::success;
1844
1845 // Use a fork that ties the child process's stdin/out/err to a pseudo
1846 // terminal so we can read it in our MachProcess::STDIOThread
1847 // as unbuffered io.
1848 PseudoTerminal pty;
1849 pid_t pid = pty.Fork(pty_error);
1850
1851 if (pid < 0)
1852 {
1853 //--------------------------------------------------------------
1854 // Error during fork.
1855 //--------------------------------------------------------------
1856 return pid;
1857 }
1858 else if (pid == 0)
1859 {
1860 //--------------------------------------------------------------
1861 // Child process
1862 //--------------------------------------------------------------
1863 ::ptrace (PT_TRACE_ME, 0, 0, 0); // Debug this process
1864 ::ptrace (PT_SIGEXC, 0, 0, 0); // Get BSD signals as mach exceptions
1865
1866 // If our parent is setgid, lets make sure we don't inherit those
1867 // extra powers due to nepotism.
1868 ::setgid (getgid ());
1869
1870 // Let the child have its own process group. We need to execute
1871 // this call in both the child and parent to avoid a race condition
1872 // between the two processes.
1873 ::setpgid (0, 0); // Set the child process group to match its pid
1874
1875 // Sleep a bit to before the exec call
1876 ::sleep (1);
1877
1878 // Turn this process into
1879 ::execv (path, (char * const *)argv);
1880 // Exit with error code. Child process should have taken
1881 // over in above exec call and if the exec fails it will
1882 // exit the child process below.
1883 ::exit (127);
1884 }
1885 else
1886 {
1887 //--------------------------------------------------------------
1888 // Parent process
1889 //--------------------------------------------------------------
1890 // Let the child have its own process group. We need to execute
1891 // this call in both the child and parent to avoid a race condition
1892 // between the two processes.
1893 ::setpgid (pid, pid); // Set the child process group to match its pid
1894
1895 if (process != NULL)
1896 {
1897 // Release our master pty file descriptor so the pty class doesn't
1898 // close it and so we can continue to use it in our STDIO thread
1899 int master_fd = pty.ReleaseMasterFD();
1900 process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
1901 }
1902 }
1903 return pid;
1904}
1905
Jason Molenda42999a42012-02-22 02:18:59 +00001906#ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001907
1908pid_t
Caroline Ticef8da8632010-12-03 18:46:09 +00001909MachProcess::SBLaunchForDebug (const char *path, char const *argv[], char const *envp[], bool no_stdio, DNBError &launch_err)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001910{
1911 // Clear out and clean up from any current state
1912 Clear();
1913
1914 DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path);
1915
1916 // Fork a child process for debugging
1917 SetState(eStateLaunching);
Caroline Ticef8da8632010-12-03 18:46:09 +00001918 m_pid = MachProcess::SBForkChildForPTraceDebugging(path, argv, envp, no_stdio, this, launch_err);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001919 if (m_pid != 0)
1920 {
1921 m_flags |= eMachProcessFlagsUsingSBS;
1922 m_path = path;
1923 size_t i;
1924 char const *arg;
1925 for (i=0; (arg = argv[i]) != NULL; i++)
1926 m_args.push_back(arg);
Greg Clayton6f35f5c2010-09-09 06:32:46 +00001927 m_task.StartExceptionThread(launch_err);
1928
1929 if (launch_err.Fail())
1930 {
1931 if (launch_err.AsString() == NULL)
1932 launch_err.SetErrorString("unable to start the exception thread");
1933 ::ptrace (PT_KILL, m_pid, 0, 0);
1934 m_pid = INVALID_NUB_PROCESS;
1935 return INVALID_NUB_PROCESS;
1936 }
1937
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001938 StartSTDIOThread();
1939 SetState (eStateAttaching);
Caroline Tice5d7be2e2010-11-02 16:16:53 +00001940 int err = ::ptrace (PT_ATTACHEXC, m_pid, 0, 0);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001941 if (err == 0)
1942 {
1943 m_flags |= eMachProcessFlagsAttached;
1944 DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid);
1945 }
1946 else
1947 {
1948 SetState (eStateExited);
1949 DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", m_pid);
1950 }
1951 }
1952 return m_pid;
1953}
1954
1955#include <servers/bootstrap.h>
1956
1957// This returns a CFRetained pointer to the Bundle ID for app_bundle_path,
1958// or NULL if there was some problem getting the bundle id.
1959static CFStringRef
1960CopyBundleIDForPath (const char *app_bundle_path, DNBError &err_str)
1961{
1962 CFBundle bundle(app_bundle_path);
1963 CFStringRef bundleIDCFStr = bundle.GetIdentifier();
1964 std::string bundleID;
1965 if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL)
1966 {
1967 struct stat app_bundle_stat;
1968 char err_msg[PATH_MAX];
1969
1970 if (::stat (app_bundle_path, &app_bundle_stat) < 0)
1971 {
1972 err_str.SetError(errno, DNBError::POSIX);
1973 snprintf(err_msg, sizeof(err_msg), "%s: \"%s\"", err_str.AsString(), app_bundle_path);
1974 err_str.SetErrorString(err_msg);
1975 DNBLogThreadedIf(LOG_PROCESS, "%s() error: %s", __FUNCTION__, err_msg);
1976 }
1977 else
1978 {
1979 err_str.SetError(-1, DNBError::Generic);
1980 snprintf(err_msg, sizeof(err_msg), "failed to extract CFBundleIdentifier from %s", app_bundle_path);
1981 err_str.SetErrorString(err_msg);
1982 DNBLogThreadedIf(LOG_PROCESS, "%s() error: failed to extract CFBundleIdentifier from '%s'", __FUNCTION__, app_bundle_path);
1983 }
1984 return NULL;
1985 }
1986
1987 DNBLogThreadedIf(LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str());
1988 CFRetain (bundleIDCFStr);
1989
1990 return bundleIDCFStr;
1991}
1992
1993pid_t
Caroline Ticef8da8632010-12-03 18:46:09 +00001994MachProcess::SBForkChildForPTraceDebugging (const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, MachProcess* process, DNBError &launch_err)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001995{
1996 DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, app_bundle_path, process);
1997 CFAllocatorRef alloc = kCFAllocatorDefault;
1998
1999 if (argv[0] == NULL)
2000 return INVALID_NUB_PROCESS;
2001
2002 size_t argc = 0;
2003 // Count the number of arguments
2004 while (argv[argc] != NULL)
2005 argc++;
2006
2007 // Enumerate the arguments
2008 size_t first_launch_arg_idx = 1;
2009 CFReleaser<CFMutableArrayRef> launch_argv;
2010
2011 if (argv[first_launch_arg_idx])
2012 {
2013 size_t launch_argc = argc > 0 ? argc - 1 : 0;
2014 launch_argv.reset (::CFArrayCreateMutable (alloc, launch_argc, &kCFTypeArrayCallBacks));
2015 size_t i;
2016 char const *arg;
2017 CFString launch_arg;
2018 for (i=first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); i++)
2019 {
2020 launch_arg.reset(::CFStringCreateWithCString (alloc, arg, kCFStringEncodingUTF8));
2021 if (launch_arg.get() != NULL)
2022 CFArrayAppendValue(launch_argv.get(), launch_arg.get());
2023 else
2024 break;
2025 }
2026 }
2027
2028 // Next fill in the arguments dictionary. Note, the envp array is of the form
2029 // Variable=value but SpringBoard wants a CF dictionary. So we have to convert
2030 // this here.
2031
2032 CFReleaser<CFMutableDictionaryRef> launch_envp;
2033
2034 if (envp[0])
2035 {
2036 launch_envp.reset(::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
2037 const char *value;
2038 int name_len;
2039 CFString name_string, value_string;
2040
2041 for (int i = 0; envp[i] != NULL; i++)
2042 {
2043 value = strstr (envp[i], "=");
2044
2045 // If the name field is empty or there's no =, skip it. Somebody's messing with us.
2046 if (value == NULL || value == envp[i])
2047 continue;
2048
2049 name_len = value - envp[i];
2050
2051 // Now move value over the "="
2052 value++;
2053
2054 name_string.reset(::CFStringCreateWithBytes(alloc, (const UInt8 *) envp[i], name_len, kCFStringEncodingUTF8, false));
2055 value_string.reset(::CFStringCreateWithCString(alloc, value, kCFStringEncodingUTF8));
2056 CFDictionarySetValue (launch_envp.get(), name_string.get(), value_string.get());
2057 }
2058 }
2059
2060 CFString stdio_path;
2061
2062 PseudoTerminal pty;
Caroline Ticef8da8632010-12-03 18:46:09 +00002063 if (!no_stdio)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00002064 {
Caroline Ticef8da8632010-12-03 18:46:09 +00002065 PseudoTerminal::Error pty_err = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY);
2066 if (pty_err == PseudoTerminal::success)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00002067 {
Caroline Ticef8da8632010-12-03 18:46:09 +00002068 const char* slave_name = pty.SlaveName();
2069 DNBLogThreadedIf(LOG_PROCESS, "%s() successfully opened master pty, slave is %s", __FUNCTION__, slave_name);
2070 if (slave_name && slave_name[0])
2071 {
2072 ::chmod (slave_name, S_IRWXU | S_IRWXG | S_IRWXO);
2073 stdio_path.SetFileSystemRepresentation (slave_name);
2074 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00002075 }
2076 }
Caroline Ticef8da8632010-12-03 18:46:09 +00002077
Chris Lattner30fdc8d2010-06-08 16:52:24 +00002078 if (stdio_path.get() == NULL)
2079 {
2080 stdio_path.SetFileSystemRepresentation ("/dev/null");
2081 }
2082
2083 CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path, launch_err);
2084 if (bundleIDCFStr == NULL)
2085 return INVALID_NUB_PROCESS;
2086
2087 std::string bundleID;
2088 CFString::UTF8(bundleIDCFStr, bundleID);
2089
2090 CFData argv_data(NULL);
2091
2092 if (launch_argv.get())
2093 {
2094 if (argv_data.Serialize(launch_argv.get(), kCFPropertyListBinaryFormat_v1_0) == NULL)
2095 {
2096 DNBLogThreadedIf(LOG_PROCESS, "%s() error: failed to serialize launch arg array...", __FUNCTION__);
2097 return INVALID_NUB_PROCESS;
2098 }
2099 }
2100
2101 DNBLogThreadedIf(LOG_PROCESS, "%s() serialized launch arg array", __FUNCTION__);
2102
2103 // Find SpringBoard
2104 SBSApplicationLaunchError sbs_error = 0;
2105 sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
2106 (CFURLRef)NULL, // openURL
2107 launch_argv.get(),
2108 launch_envp.get(), // CFDictionaryRef environment
2109 stdio_path.get(),
2110 stdio_path.get(),
2111 SBSApplicationLaunchWaitForDebugger | SBSApplicationLaunchUnlockDevice);
2112
2113
2114 launch_err.SetError(sbs_error, DNBError::SpringBoard);
2115
2116 if (sbs_error == SBSApplicationLaunchErrorSuccess)
2117 {
2118 static const useconds_t pid_poll_interval = 200000;
2119 static const useconds_t pid_poll_timeout = 30000000;
2120
2121 useconds_t pid_poll_total = 0;
2122
2123 nub_process_t pid = INVALID_NUB_PROCESS;
2124 Boolean pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
2125 // Poll until the process is running, as long as we are getting valid responses and the timeout hasn't expired
2126 // A return PID of 0 means the process is not running, which may be because it hasn't been (asynchronously) started
2127 // yet, or that it died very quickly (if you weren't using waitForDebugger).
2128 while (!pid_found && pid_poll_total < pid_poll_timeout)
2129 {
2130 usleep (pid_poll_interval);
2131 pid_poll_total += pid_poll_interval;
2132 DNBLogThreadedIf(LOG_PROCESS, "%s() polling Springboard for pid for %s...", __FUNCTION__, bundleID.c_str());
2133 pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
2134 }
2135
2136 CFRelease (bundleIDCFStr);
2137 if (pid_found)
2138 {
2139 if (process != NULL)
2140 {
2141 // Release our master pty file descriptor so the pty class doesn't
2142 // close it and so we can continue to use it in our STDIO thread
2143 int master_fd = pty.ReleaseMasterFD();
2144 process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
2145 }
2146 DNBLogThreadedIf(LOG_PROCESS, "%s() => pid = %4.4x", __FUNCTION__, pid);
2147 }
2148 else
2149 {
2150 DNBLogError("failed to lookup the process ID for CFBundleIdentifier %s.", bundleID.c_str());
2151 }
2152 return pid;
2153 }
2154
2155 DNBLogError("unable to launch the application with CFBundleIdentifier '%s' sbs_error = %u", bundleID.c_str(), sbs_error);
2156 return INVALID_NUB_PROCESS;
2157}
2158
Jason Molenda42999a42012-02-22 02:18:59 +00002159#endif // #ifdef WITH_SPRINGBOARD
Chris Lattner30fdc8d2010-06-08 16:52:24 +00002160
2161