blob: de3ee45c24f434b49ca9279aa1e48b5e2b6809f4 [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>
16#include <spawn.h>
17#include <sys/fcntl.h>
18#include <sys/types.h>
19#include <sys/ptrace.h>
20#include <sys/stat.h>
21#include <unistd.h>
22#include "MacOSX/CFUtils.h"
23#include "SysSignal.h"
24
25#include <algorithm>
26#include <map>
27
28#include "DNBDataRef.h"
29#include "DNBLog.h"
30#include "DNBThreadResumeActions.h"
31#include "DNBTimer.h"
32#include "MachProcess.h"
33#include "PseudoTerminal.h"
34
35#include "CFBundle.h"
36#include "CFData.h"
37#include "CFString.h"
38
39static CFStringRef CopyBundleIDForPath (const char *app_buncle_path, DNBError &err_str);
40
41#if defined (__arm__)
42
43#include <CoreFoundation/CoreFoundation.h>
44#include <SpringBoardServices/SpringBoardServer.h>
45#include <SpringBoardServices/SBSWatchdogAssertion.h>
46
47
48static bool
49IsSBProcess (nub_process_t pid)
50{
51 bool opt_runningApps = true;
52 bool opt_debuggable = false;
53
54 CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
55 if (sbsAppIDs.get() != NULL)
56 {
57 CFIndex count = ::CFArrayGetCount (sbsAppIDs.get());
58 CFIndex i = 0;
59 for (i = 0; i < count; i++)
60 {
61 CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
62
63 // Get the process id for the app (if there is one)
64 pid_t sbs_pid = INVALID_NUB_PROCESS;
65 if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &sbs_pid) == TRUE)
66 {
67 if (sbs_pid == pid)
68 return true;
69 }
70 }
71 }
72 return false;
73}
74
75
76#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),
94 m_child_stdin (-1),
95 m_child_stdout (-1),
96 m_child_stderr (-1),
97 m_path (),
98 m_args (),
99 m_task (this),
100 m_flags (eMachProcessFlagsNone),
101 m_stdio_thread (0),
102 m_stdio_mutex (PTHREAD_MUTEX_RECURSIVE),
103 m_stdout_data (),
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000104 m_thread_list (),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000105 m_exception_messages (),
106 m_exception_messages_mutex (PTHREAD_MUTEX_RECURSIVE),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000107 m_state (eStateUnloaded),
108 m_state_mutex (PTHREAD_MUTEX_RECURSIVE),
109 m_events (0, kAllEventsMask),
110 m_breakpoints (),
111 m_watchpoints (),
112 m_name_to_addr_callback(NULL),
113 m_name_to_addr_baton(NULL),
114 m_image_infos_callback(NULL),
115 m_image_infos_baton(NULL)
116{
117 DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__);
118}
119
120MachProcess::~MachProcess()
121{
122 DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__);
123 Clear();
124}
125
126pid_t
127MachProcess::SetProcessID(pid_t pid)
128{
129 // Free any previous process specific data or resources
130 Clear();
131 // Set the current PID appropriately
132 if (pid == 0)
Johnny Chenc0cd18d2010-09-28 16:34:56 +0000133 m_pid = ::getpid ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000134 else
135 m_pid = pid;
136 return m_pid; // Return actualy PID in case a zero pid was passed in
137}
138
139nub_state_t
140MachProcess::GetState()
141{
142 // If any other threads access this we will need a mutex for it
143 PTHREAD_MUTEX_LOCKER(locker, m_state_mutex);
144 return m_state;
145}
146
147const char *
148MachProcess::ThreadGetName(nub_thread_t tid)
149{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000150 return m_thread_list.GetName(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000151}
152
153nub_state_t
154MachProcess::ThreadGetState(nub_thread_t tid)
155{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000156 return m_thread_list.GetState(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000157}
158
159
160nub_size_t
161MachProcess::GetNumThreads () const
162{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000163 return m_thread_list.NumThreads();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000164}
165
166nub_thread_t
167MachProcess::GetThreadAtIndex (nub_size_t thread_idx) const
168{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000169 return m_thread_list.ThreadIDAtIndex(thread_idx);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000170}
171
172uint32_t
173MachProcess::GetThreadIndexFromThreadID (nub_thread_t tid)
174{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000175 return m_thread_list.GetThreadIndexByID(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000176}
177
178nub_thread_t
179MachProcess::GetCurrentThread ()
180{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000181 return m_thread_list.CurrentThreadID();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000182}
183
184nub_thread_t
185MachProcess::SetCurrentThread(nub_thread_t tid)
186{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000187 return m_thread_list.SetCurrentThread(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000188}
189
190bool
191MachProcess::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const
192{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000193 return m_thread_list.GetThreadStoppedReason(tid, stop_info);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000194}
195
196void
197MachProcess::DumpThreadStoppedReason(nub_thread_t tid) const
198{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000199 return m_thread_list.DumpThreadStoppedReason(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000200}
201
202const char *
203MachProcess::GetThreadInfo(nub_thread_t tid) const
204{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000205 return m_thread_list.GetThreadInfo(tid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000206}
207
208const DNBRegisterSetInfo *
209MachProcess::GetRegisterSetInfo(nub_thread_t tid, nub_size_t *num_reg_sets ) const
210{
Greg Clayton3af9ea52010-11-18 05:57:03 +0000211 MachThread *thread = m_thread_list.GetThreadByID (tid);
212 if (thread)
213 {
214 DNBArchProtocol *arch = thread->GetArchProtocol();
215 if (arch)
216 return arch->GetRegisterSetInfo (num_reg_sets);
217 }
218 *num_reg_sets = 0;
219 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000220}
221
222bool
223MachProcess::GetRegisterValue ( nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value ) const
224{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000225 return m_thread_list.GetRegisterValue(tid, set, reg, value);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000226}
227
228bool
229MachProcess::SetRegisterValue ( nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value ) const
230{
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000231 return m_thread_list.SetRegisterValue(tid, set, reg, value);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000232}
233
234void
235MachProcess::SetState(nub_state_t new_state)
236{
237 // If any other threads access this we will need a mutex for it
238 uint32_t event_mask = 0;
239
240 // Scope for mutex locker
241 {
242 PTHREAD_MUTEX_LOCKER(locker, m_state_mutex);
243 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::SetState ( %s )", DNBStateAsString(new_state));
244
245 const nub_state_t old_state = m_state;
246
247 if (old_state != new_state)
248 {
249 if (NUB_STATE_IS_STOPPED(new_state))
250 event_mask = eEventProcessStoppedStateChanged;
251 else
252 event_mask = eEventProcessRunningStateChanged;
253
254 m_state = new_state;
255 if (new_state == eStateStopped)
256 m_stop_count++;
257 }
258 }
259
260 if (event_mask != 0)
261 {
262 m_events.SetEvents (event_mask);
263
264 // Wait for the event bit to reset if a reset ACK is requested
265 m_events.WaitForResetAck(event_mask);
266 }
267
268}
269
270void
271MachProcess::Clear()
272{
273 // Clear any cached thread list while the pid and task are still valid
274
275 m_task.Clear();
276 // Now clear out all member variables
277 m_pid = INVALID_NUB_PROCESS;
278 CloseChildFileDescriptors();
279 m_path.clear();
280 m_args.clear();
281 SetState(eStateUnloaded);
282 m_flags = eMachProcessFlagsNone;
283 m_stop_count = 0;
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000284 m_thread_list.Clear();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000285 {
286 PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
287 m_exception_messages.clear();
288 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000289}
290
291
292bool
293MachProcess::StartSTDIOThread()
294{
295 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__);
296 // Create the thread that watches for the child STDIO
Greg Clayton3382c2c2010-07-30 23:14:42 +0000297 return ::pthread_create (&m_stdio_thread, NULL, MachProcess::STDIOThread, this) == 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000298}
299
300
301nub_addr_t
302MachProcess::LookupSymbol(const char *name, const char *shlib)
303{
304 if (m_name_to_addr_callback != NULL && name && name[0])
305 return m_name_to_addr_callback(ProcessID(), name, shlib, m_name_to_addr_baton);
306 return INVALID_NUB_ADDRESS;
307}
308
309bool
310MachProcess::Resume (const DNBThreadResumeActions& thread_actions)
311{
312 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Resume ()");
313 nub_state_t state = GetState();
314
315 if (CanResume(state))
316 {
317 PrivateResume(thread_actions);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000318 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000319 }
320 else if (state == eStateRunning)
321 {
322 DNBLogThreadedIf(LOG_PROCESS, "Resume() - task 0x%x is running, ignoring...", m_task.TaskPort());
Greg Clayton3382c2c2010-07-30 23:14:42 +0000323 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000324 }
Greg Clayton3382c2c2010-07-30 23:14:42 +0000325 DNBLogThreadedIf(LOG_PROCESS, "Resume() - task 0x%x can't continue, ignoring...", m_task.TaskPort());
326 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000327}
328
329bool
330MachProcess::Kill (const struct timespec *timeout_abstime)
331{
332 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill ()");
333 nub_state_t state = DoSIGSTOP(true);
334 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() state = %s", DNBStateAsString(state));
335 errno = 0;
336 ::ptrace (PT_KILL, m_pid, 0, 0);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000337 DNBError err;
338 err.SetErrorToErrno();
339 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() ::ptrace (PT_KILL, pid=%u, 0, 0) => 0x%8.8x (%s)", err.Error(), err.AsString());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000340 PrivateResume (DNBThreadResumeActions (eStateRunning, 0));
341 return true;
342}
343
344bool
345MachProcess::Signal (int signal, const struct timespec *timeout_abstime)
346{
347 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p)", signal, timeout_abstime);
348 nub_state_t state = GetState();
349 if (::kill (ProcessID(), signal) == 0)
350 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000351 // If we were running and we have a timeout, wait for the signal to stop
352 if (IsRunning(state) && timeout_abstime)
353 {
354 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) waiting for signal to stop process...", signal, timeout_abstime);
355 m_events.WaitForSetEvents(eEventProcessStoppedStateChanged, timeout_abstime);
356 state = GetState();
357 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) state = %s", signal, timeout_abstime, DNBStateAsString(state));
358 return !IsRunning (state);
359 }
360 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) not waiting...", signal, timeout_abstime);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000361 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000362 }
Greg Clayton3382c2c2010-07-30 23:14:42 +0000363 DNBError err(errno, DNBError::POSIX);
364 err.LogThreadedIfError("kill (pid = %d, signo = %i)", ProcessID(), signal);
365 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000366
367}
368
369nub_state_t
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000370MachProcess::DoSIGSTOP (bool clear_bps_and_wps, uint32_t *thread_idx_ptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000371{
372 nub_state_t state = GetState();
373 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s", DNBStateAsString (state));
374
375 if (!IsRunning(state))
376 {
377 if (clear_bps_and_wps)
378 {
379 DisableAllBreakpoints (true);
380 DisableAllWatchpoints (true);
381 clear_bps_and_wps = false;
382 }
383
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000384 // If we already have a thread stopped due to a SIGSTOP, we don't have
385 // to do anything...
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000386 uint32_t thread_idx = m_thread_list.GetThreadIndexForThreadStoppedWithSignal (SIGSTOP);
387 if (thread_idx_ptr)
388 *thread_idx_ptr = thread_idx;
389 if (thread_idx != UINT32_MAX)
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000390 return GetState();
391
392 // No threads were stopped with a SIGSTOP, we need to run and halt the
393 // process with a signal
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000394 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s -- resuming process", DNBStateAsString (state));
395 PrivateResume (DNBThreadResumeActions (eStateRunning, 0));
396
397 // Reset the event that says we were indeed running
398 m_events.ResetEvents(eEventProcessRunningStateChanged);
399 state = GetState();
400 }
401
402 // We need to be stopped in order to be able to detach, so we need
403 // to send ourselves a SIGSTOP
404
405 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s -- sending SIGSTOP", DNBStateAsString (state));
406 struct timespec sigstop_timeout;
407 DNBTimer::OffsetTimeOfDay(&sigstop_timeout, 2, 0);
408 Signal (SIGSTOP, &sigstop_timeout);
409 if (clear_bps_and_wps)
410 {
411 DisableAllBreakpoints (true);
412 DisableAllWatchpoints (true);
413 clear_bps_and_wps = false;
414 }
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000415 uint32_t thread_idx = m_thread_list.GetThreadIndexForThreadStoppedWithSignal (SIGSTOP);
416 if (thread_idx_ptr)
417 *thread_idx_ptr = thread_idx;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000418 return GetState();
419}
420
421bool
422MachProcess::Detach()
423{
424 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach()");
425
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000426 uint32_t thread_idx = UINT32_MAX;
427 nub_state_t state = DoSIGSTOP(true, &thread_idx);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000428 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach() DoSIGSTOP() returned %s", DNBStateAsString(state));
429
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000430 {
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000431 DNBThreadResumeActions thread_actions;
432 DNBThreadResumeAction thread_action;
433 thread_action.tid = m_thread_list.ThreadIDAtIndex (thread_idx);
434 thread_action.state = eStateRunning;
435 thread_action.signal = -1;
436 thread_action.addr = INVALID_NUB_ADDRESS;
437
438 thread_actions.Append (thread_action);
439
440 thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0);
441
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000442 PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000443
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000444 ReplyToAllExceptions (thread_actions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000445
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000446 }
447
448 m_task.ShutDownExcecptionThread();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000449
450 // Detach from our process
451 errno = 0;
452 nub_process_t pid = m_pid;
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000453 int ret = ::ptrace (PT_DETACH, pid, (caddr_t)1, 0);
Greg Clayton3382c2c2010-07-30 23:14:42 +0000454 DNBError err(errno, DNBError::POSIX);
Caroline Tice5d7be2e2010-11-02 16:16:53 +0000455 if (DNBLogCheckLogBit(LOG_PROCESS) || err.Fail() || (ret != 0))
Greg Clayton3382c2c2010-07-30 23:14:42 +0000456 err.LogThreaded("::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000457
458 // Resume our task
459 m_task.Resume();
460
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000461 // NULL our task out as we have already retored all exception ports
462 m_task.Clear();
463
464 // Clear out any notion of the process we once were
465 Clear();
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000466
467 SetState(eStateDetached);
468
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000469 return true;
470}
471
472
473nub_size_t
474MachProcess::RemoveTrapsFromBuffer (nub_addr_t addr, nub_size_t size, uint8_t *buf) const
475{
476 nub_size_t bytes_removed = 0;
477 const DNBBreakpoint *bp;
478 nub_addr_t intersect_addr;
479 nub_size_t intersect_size;
480 nub_size_t opcode_offset;
481 nub_size_t idx;
482 for (idx = 0; (bp = m_breakpoints.GetByIndex(idx)) != NULL; ++idx)
483 {
484 if (bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset))
485 {
486 assert(addr <= intersect_addr && intersect_addr < addr + size);
487 assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size);
488 assert(opcode_offset + intersect_size <= bp->ByteSize());
489 nub_size_t buf_offset = intersect_addr - addr;
490 ::memcpy(buf + buf_offset, bp->SavedOpcodeBytes() + opcode_offset, intersect_size);
491 }
492 }
493 return bytes_removed;
494}
495
496//----------------------------------------------------------------------
497// ReadMemory from the MachProcess level will always remove any software
498// breakpoints from the memory buffer before returning. If you wish to
499// read memory and see those traps, read from the MachTask
500// (m_task.ReadMemory()) as that version will give you what is actually
501// in inferior memory.
502//----------------------------------------------------------------------
503nub_size_t
504MachProcess::ReadMemory (nub_addr_t addr, nub_size_t size, void *buf)
505{
506 // We need to remove any current software traps (enabled software
507 // breakpoints) that we may have placed in our tasks memory.
508
509 // First just read the memory as is
510 nub_size_t bytes_read = m_task.ReadMemory(addr, size, buf);
511
512 // Then place any opcodes that fall into this range back into the buffer
513 // before we return this to callers.
514 if (bytes_read > 0)
515 RemoveTrapsFromBuffer (addr, size, (uint8_t *)buf);
516 return bytes_read;
517}
518
519//----------------------------------------------------------------------
520// WriteMemory from the MachProcess level will always write memory around
521// any software breakpoints. Any software breakpoints will have their
522// opcodes modified if they are enabled. Any memory that doesn't overlap
523// with software breakpoints will be written to. If you wish to write to
524// inferior memory without this interference, then write to the MachTask
525// (m_task.WriteMemory()) as that version will always modify inferior
526// memory.
527//----------------------------------------------------------------------
528nub_size_t
529MachProcess::WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf)
530{
531 // We need to write any data that would go where any current software traps
532 // (enabled software breakpoints) any software traps (breakpoints) that we
533 // may have placed in our tasks memory.
534
535 std::map<nub_addr_t, DNBBreakpoint *> addr_to_bp_map;
536 DNBBreakpoint *bp;
537 nub_size_t idx;
538 for (idx = 0; (bp = m_breakpoints.GetByIndex(idx)) != NULL; ++idx)
539 {
540 if (bp->IntersectsRange(addr, size, NULL, NULL, NULL))
541 addr_to_bp_map[bp->Address()] = bp;
542 }
543
544 // If we don't have any software breakpoints that are in this buffer, then
545 // we can just write memory and be done with it.
546 if (addr_to_bp_map.empty())
547 return m_task.WriteMemory(addr, size, buf);
548
549 // If we make it here, we have some breakpoints that overlap and we need
550 // to work around them.
551
552 nub_size_t bytes_written = 0;
553 nub_addr_t intersect_addr;
554 nub_size_t intersect_size;
555 nub_size_t opcode_offset;
556 const uint8_t *ubuf = (const uint8_t *)buf;
557 std::map<nub_addr_t, DNBBreakpoint *>::iterator pos, end = addr_to_bp_map.end();
558 for (pos = addr_to_bp_map.begin(); pos != end; ++pos)
559 {
560 bp = pos->second;
561
562 assert(bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset));
563 assert(addr <= intersect_addr && intersect_addr < addr + size);
564 assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size);
565 assert(opcode_offset + intersect_size <= bp->ByteSize());
566
567 // Check for bytes before this breakpoint
568 const nub_addr_t curr_addr = addr + bytes_written;
569 if (intersect_addr > curr_addr)
570 {
571 // There are some bytes before this breakpoint that we need to
572 // just write to memory
573 nub_size_t curr_size = intersect_addr - curr_addr;
574 nub_size_t curr_bytes_written = m_task.WriteMemory(curr_addr, curr_size, ubuf + bytes_written);
575 bytes_written += curr_bytes_written;
576 if (curr_bytes_written != curr_size)
577 {
578 // We weren't able to write all of the requested bytes, we
579 // are done looping and will return the number of bytes that
580 // we have written so far.
581 break;
582 }
583 }
584
585 // Now write any bytes that would cover up any software breakpoints
586 // directly into the breakpoint opcode buffer
587 ::memcpy(bp->SavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, intersect_size);
588 bytes_written += intersect_size;
589 }
590
591 // Write any remaining bytes after the last breakpoint if we have any left
592 if (bytes_written < size)
593 bytes_written += m_task.WriteMemory(addr + bytes_written, size - bytes_written, ubuf + bytes_written);
594
595 return bytes_written;
596}
597
598
599void
600MachProcess::ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions)
601{
602 PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
603 if (m_exception_messages.empty() == false)
604 {
605 MachException::Message::iterator pos;
606 MachException::Message::iterator begin = m_exception_messages.begin();
607 MachException::Message::iterator end = m_exception_messages.end();
608 for (pos = begin; pos != end; ++pos)
609 {
610 DNBLogThreadedIf(LOG_EXCEPTIONS, "Replying to exception %d...", std::distance(begin, pos));
611 int thread_reply_signal = 0;
612
613 const DNBThreadResumeAction *action = thread_actions.GetActionForThread (pos->state.thread_port, false);
614
615 if (action)
616 {
617 thread_reply_signal = action->signal;
618 if (thread_reply_signal)
619 thread_actions.SetSignalHandledForThread (pos->state.thread_port);
620 }
621
Greg Clayton3382c2c2010-07-30 23:14:42 +0000622 DNBError err (pos->Reply(this, thread_reply_signal));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000623 if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
Greg Clayton3382c2c2010-07-30 23:14:42 +0000624 err.LogThreadedIfError("Error replying to exception");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000625 }
626
627 // Erase all exception message as we should have used and replied
628 // to them all already.
629 m_exception_messages.clear();
630 }
631}
632void
633MachProcess::PrivateResume (const DNBThreadResumeActions& thread_actions)
634{
635 PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
636
637 ReplyToAllExceptions (thread_actions);
638// bool stepOverBreakInstruction = step;
639
640 // Let the thread prepare to resume and see if any threads want us to
641 // step over a breakpoint instruction (ProcessWillResume will modify
642 // the value of stepOverBreakInstruction).
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000643 m_thread_list.ProcessWillResume (this, thread_actions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000644
645 // Set our state accordingly
646 if (thread_actions.NumActionsWithState(eStateStepping))
647 SetState (eStateStepping);
648 else
649 SetState (eStateRunning);
650
651 // Now resume our task.
Greg Clayton3382c2c2010-07-30 23:14:42 +0000652 m_task.Resume();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000653}
654
655nub_break_t
656MachProcess::CreateBreakpoint(nub_addr_t addr, nub_size_t length, bool hardware, thread_t tid)
657{
658 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = 0x%8.8llx, length = %u, hardware = %i, tid = 0x%4.4x )", (uint64_t)addr, length, hardware, tid);
659 if (hardware && tid == INVALID_NUB_THREAD)
660 tid = GetCurrentThread();
661
662 DNBBreakpoint bp(addr, length, tid, hardware);
663 nub_break_t breakID = m_breakpoints.Add(bp);
664 if (EnableBreakpoint(breakID))
665 {
666 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = 0x%8.8llx, length = %u, tid = 0x%4.4x ) => %u", (uint64_t)addr, length, tid, breakID);
667 return breakID;
668 }
669 else
670 {
671 m_breakpoints.Remove(breakID);
672 }
673 // We failed to enable the breakpoint
674 return INVALID_NUB_BREAK_ID;
675}
676
677nub_watch_t
678MachProcess::CreateWatchpoint(nub_addr_t addr, nub_size_t length, uint32_t watch_flags, bool hardware, thread_t tid)
679{
680 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %u, flags = 0x%8.8x, hardware = %i, tid = 0x%4.4x )", (uint64_t)addr, length, watch_flags, hardware, tid);
681 if (hardware && tid == INVALID_NUB_THREAD)
682 tid = GetCurrentThread();
683
684 DNBBreakpoint watch(addr, length, tid, hardware);
685 watch.SetIsWatchpoint(watch_flags);
686
687 nub_watch_t watchID = m_watchpoints.Add(watch);
688 if (EnableWatchpoint(watchID))
689 {
690 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %u, tid = 0x%x) => %u", (uint64_t)addr, length, tid, watchID);
691 return watchID;
692 }
693 else
694 {
695 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %u, tid = 0x%x) => FAILED (%u)", (uint64_t)addr, length, tid, watchID);
696 m_watchpoints.Remove(watchID);
697 }
698 // We failed to enable the watchpoint
699 return INVALID_NUB_BREAK_ID;
700}
701
702nub_size_t
703MachProcess::DisableAllBreakpoints(bool remove)
704{
705 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::%s (remove = %d )", __FUNCTION__, remove);
706 DNBBreakpoint *bp;
707 nub_size_t disabled_count = 0;
708 nub_size_t idx = 0;
709 while ((bp = m_breakpoints.GetByIndex(idx)) != NULL)
710 {
711 bool success = DisableBreakpoint(bp->GetID(), remove);
712
713 if (success)
714 disabled_count++;
715 // If we failed to disable the breakpoint or we aren't removing the breakpoint
716 // increment the breakpoint index. Otherwise DisableBreakpoint will have removed
717 // the breakpoint at this index and we don't need to change it.
718 if ((success == false) || (remove == false))
719 idx++;
720 }
721 return disabled_count;
722}
723
724nub_size_t
725MachProcess::DisableAllWatchpoints(bool remove)
726{
727 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::%s (remove = %d )", __FUNCTION__, remove);
728 DNBBreakpoint *wp;
729 nub_size_t disabled_count = 0;
730 nub_size_t idx = 0;
731 while ((wp = m_watchpoints.GetByIndex(idx)) != NULL)
732 {
733 bool success = DisableWatchpoint(wp->GetID(), remove);
734
735 if (success)
736 disabled_count++;
737 // If we failed to disable the watchpoint or we aren't removing the watchpoint
738 // increment the watchpoint index. Otherwise DisableWatchpoint will have removed
739 // the watchpoint at this index and we don't need to change it.
740 if ((success == false) || (remove == false))
741 idx++;
742 }
743 return disabled_count;
744}
745
746bool
747MachProcess::DisableBreakpoint(nub_break_t breakID, bool remove)
748{
749 DNBBreakpoint *bp = m_breakpoints.FindByID (breakID);
750 if (bp)
751 {
752 nub_addr_t addr = bp->Address();
753 DNBLogThreadedIf(LOG_BREAKPOINTS | LOG_VERBOSE, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx", breakID, remove, (uint64_t)addr);
754
755 if (bp->IsHardware())
756 {
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000757 bool hw_disable_result = m_thread_list.DisableHardwareBreakpoint (bp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000758
759 if (hw_disable_result == true)
760 {
761 bp->SetEnabled(false);
762 // Let the thread list know that a breakpoint has been modified
763 if (remove)
764 {
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000765 m_thread_list.NotifyBreakpointChanged(bp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000766 m_breakpoints.Remove(breakID);
767 }
768 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx (hardware) => success", breakID, remove, (uint64_t)addr);
769 return true;
770 }
771
772 return false;
773 }
774
775 const nub_size_t break_op_size = bp->ByteSize();
776 assert (break_op_size > 0);
Greg Clayton3af9ea52010-11-18 05:57:03 +0000777 const uint8_t * const break_op = DNBArchProtocol::GetBreakpointOpcode (bp->ByteSize());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000778 if (break_op_size > 0)
779 {
780 // Clear a software breakoint instruction
781 uint8_t curr_break_op[break_op_size];
782 bool break_op_found = false;
783
784 // Read the breakpoint opcode
785 if (m_task.ReadMemory(addr, break_op_size, curr_break_op) == break_op_size)
786 {
787 bool verify = false;
788 if (bp->IsEnabled())
789 {
790 // Make sure we have the a breakpoint opcode exists at this address
791 if (memcmp(curr_break_op, break_op, break_op_size) == 0)
792 {
793 break_op_found = true;
794 // We found a valid breakpoint opcode at this address, now restore
795 // the saved opcode.
796 if (m_task.WriteMemory(addr, break_op_size, bp->SavedOpcodeBytes()) == break_op_size)
797 {
798 verify = true;
799 }
800 else
801 {
802 DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx memory write failed when restoring original opcode", breakID, remove, (uint64_t)addr);
803 }
804 }
805 else
806 {
807 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);
808 // Set verify to true and so we can check if the original opcode has already been restored
809 verify = true;
810 }
811 }
812 else
813 {
814 DNBLogThreadedIf(LOG_BREAKPOINTS | LOG_VERBOSE, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x$8.8llx is not enabled", breakID, remove, (uint64_t)addr);
815 // Set verify to true and so we can check if the original opcode is there
816 verify = true;
817 }
818
819 if (verify)
820 {
821 uint8_t verify_opcode[break_op_size];
822 // Verify that our original opcode made it back to the inferior
823 if (m_task.ReadMemory(addr, break_op_size, verify_opcode) == break_op_size)
824 {
825 // compare the memory we just read with the original opcode
826 if (memcmp(bp->SavedOpcodeBytes(), verify_opcode, break_op_size) == 0)
827 {
828 // SUCCESS
829 bp->SetEnabled(false);
830 // Let the thread list know that a breakpoint has been modified
831 if (remove)
832 {
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000833 m_thread_list.NotifyBreakpointChanged(bp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000834 m_breakpoints.Remove(breakID);
835 }
836 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx => success", breakID, remove, (uint64_t)addr);
837 return true;
838 }
839 else
840 {
841 if (break_op_found)
842 DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx: failed to restore original opcode", breakID, remove, (uint64_t)addr);
843 else
844 DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) addr = 0x%8.8llx: opcode changed", breakID, remove, (uint64_t)addr);
845 }
846 }
847 else
848 {
849 DNBLogWarning("MachProcess::DisableBreakpoint: unable to disable breakpoint 0x%8.8llx", (uint64_t)addr);
850 }
851 }
852 }
853 else
854 {
855 DNBLogWarning("MachProcess::DisableBreakpoint: unable to read memory at 0x%8.8llx", (uint64_t)addr);
856 }
857 }
858 }
859 else
860 {
861 DNBLogError("MachProcess::DisableBreakpoint ( breakID = %d, remove = %d ) invalid breakpoint ID", breakID, remove);
862 }
863 return false;
864}
865
866bool
867MachProcess::DisableWatchpoint(nub_watch_t watchID, bool remove)
868{
869 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::%s(watchID = %d, remove = %d)", __FUNCTION__, watchID, remove);
870 DNBBreakpoint *wp = m_watchpoints.FindByID (watchID);
871 if (wp)
872 {
873 nub_addr_t addr = wp->Address();
874 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::DisableWatchpoint ( watchID = %d, remove = %d ) addr = 0x%8.8llx", watchID, remove, (uint64_t)addr);
875
876 if (wp->IsHardware())
877 {
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000878 bool hw_disable_result = m_thread_list.DisableHardwareWatchpoint (wp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000879
880 if (hw_disable_result == true)
881 {
882 wp->SetEnabled(false);
883 if (remove)
884 m_watchpoints.Remove(watchID);
885 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::Disablewatchpoint ( watchID = %d, remove = %d ) addr = 0x%8.8llx (hardware) => success", watchID, remove, (uint64_t)addr);
886 return true;
887 }
888 }
889
890 // TODO: clear software watchpoints if we implement them
891 }
892 else
893 {
894 DNBLogError("MachProcess::DisableWatchpoint ( watchID = %d, remove = %d ) invalid watchpoint ID", watchID, remove);
895 }
896 return false;
897}
898
899
900void
901MachProcess::DumpBreakpoint(nub_break_t breakID) const
902{
903 DNBLogThreaded("MachProcess::DumpBreakpoint(breakID = %d)", breakID);
904
905 if (NUB_BREAK_ID_IS_VALID(breakID))
906 {
907 const DNBBreakpoint *bp = m_breakpoints.FindByID(breakID);
908 if (bp)
909 bp->Dump();
910 else
911 DNBLog("MachProcess::DumpBreakpoint(breakID = %d): invalid breakID", breakID);
912 }
913 else
914 {
915 m_breakpoints.Dump();
916 }
917}
918
919void
920MachProcess::DumpWatchpoint(nub_watch_t watchID) const
921{
922 DNBLogThreaded("MachProcess::DumpWatchpoint(watchID = %d)", watchID);
923
924 if (NUB_BREAK_ID_IS_VALID(watchID))
925 {
926 const DNBBreakpoint *wp = m_watchpoints.FindByID(watchID);
927 if (wp)
928 wp->Dump();
929 else
930 DNBLog("MachProcess::DumpWatchpoint(watchID = %d): invalid watchID", watchID);
931 }
932 else
933 {
934 m_watchpoints.Dump();
935 }
936}
937
938bool
939MachProcess::EnableBreakpoint(nub_break_t breakID)
940{
941 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::EnableBreakpoint ( breakID = %d )", breakID);
942 DNBBreakpoint *bp = m_breakpoints.FindByID (breakID);
943 if (bp)
944 {
945 nub_addr_t addr = bp->Address();
946 if (bp->IsEnabled())
947 {
948 DNBLogWarning("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: breakpoint already enabled.", breakID, (uint64_t)addr);
949 return true;
950 }
951 else
952 {
953 if (bp->HardwarePreferred())
954 {
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000955 bp->SetHardwareIndex(m_thread_list.EnableHardwareBreakpoint(bp));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000956 if (bp->IsHardware())
957 {
958 bp->SetEnabled(true);
959 return true;
960 }
961 }
962
963 const nub_size_t break_op_size = bp->ByteSize();
964 assert (break_op_size != 0);
Greg Clayton3af9ea52010-11-18 05:57:03 +0000965 const uint8_t * const break_op = DNBArchProtocol::GetBreakpointOpcode (break_op_size);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000966 if (break_op_size > 0)
967 {
968 // Save the original opcode by reading it
969 if (m_task.ReadMemory(addr, break_op_size, bp->SavedOpcodeBytes()) == break_op_size)
970 {
971 // Write a software breakpoint in place of the original opcode
972 if (m_task.WriteMemory(addr, break_op_size, break_op) == break_op_size)
973 {
974 uint8_t verify_break_op[4];
975 if (m_task.ReadMemory(addr, break_op_size, verify_break_op) == break_op_size)
976 {
977 if (memcmp(break_op, verify_break_op, break_op_size) == 0)
978 {
979 bp->SetEnabled(true);
980 // Let the thread list know that a breakpoint has been modified
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000981 m_thread_list.NotifyBreakpointChanged(bp);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000982 DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: SUCCESS.", breakID, (uint64_t)addr);
983 return true;
984 }
985 else
986 {
987 DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: breakpoint opcode verification failed.", breakID, (uint64_t)addr);
988 }
989 }
990 else
991 {
992 DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: unable to read memory to verify breakpoint opcode.", breakID, (uint64_t)addr);
993 }
994 }
995 else
996 {
997 DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: unable to write breakpoint opcode to memory.", breakID, (uint64_t)addr);
998 }
999 }
1000 else
1001 {
1002 DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) addr = 0x%8.8llx: unable to read memory at breakpoint address.", breakID, (uint64_t)addr);
1003 }
1004 }
1005 else
1006 {
1007 DNBLogError("MachProcess::EnableBreakpoint ( breakID = %d ) no software breakpoint opcode for current architecture.", breakID);
1008 }
1009 }
1010 }
1011 return false;
1012}
1013
1014bool
1015MachProcess::EnableWatchpoint(nub_watch_t watchID)
1016{
1017 DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::EnableWatchpoint(watchID = %d)", watchID);
1018 DNBBreakpoint *wp = m_watchpoints.FindByID (watchID);
1019 if (wp)
1020 {
1021 nub_addr_t addr = wp->Address();
1022 if (wp->IsEnabled())
1023 {
1024 DNBLogWarning("MachProcess::EnableWatchpoint(watchID = %d) addr = 0x%8.8llx: watchpoint already enabled.", watchID, (uint64_t)addr);
1025 return true;
1026 }
1027 else
1028 {
1029 // Currently only try and set hardware watchpoints.
Greg Clayton58d1c9a2010-10-18 04:14:23 +00001030 wp->SetHardwareIndex(m_thread_list.EnableHardwareWatchpoint(wp));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001031 if (wp->IsHardware())
1032 {
1033 wp->SetEnabled(true);
1034 return true;
1035 }
1036 // TODO: Add software watchpoints by doing page protection tricks.
1037 }
1038 }
1039 return false;
1040}
1041
1042// Called by the exception thread when an exception has been received from
1043// our process. The exception message is completely filled and the exception
1044// data has already been copied.
1045void
1046MachProcess::ExceptionMessageReceived (const MachException::Message& exceptionMessage)
1047{
1048 PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
1049
1050 if (m_exception_messages.empty())
1051 m_task.Suspend();
1052
1053 DNBLogThreadedIf(LOG_EXCEPTIONS, "MachProcess::ExceptionMessageReceived ( )");
1054
1055 // Use a locker to automatically unlock our mutex in case of exceptions
1056 // Add the exception to our internal exception stack
1057 m_exception_messages.push_back(exceptionMessage);
1058}
1059
1060void
1061MachProcess::ExceptionMessageBundleComplete()
1062{
1063 // We have a complete bundle of exceptions for our child process.
1064 PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
1065 DNBLogThreadedIf(LOG_EXCEPTIONS, "%s: %d exception messages.", __PRETTY_FUNCTION__, m_exception_messages.size());
1066 if (!m_exception_messages.empty())
1067 {
1068 // Let all threads recover from stopping and do any clean up based
1069 // on the previous thread state (if any).
Greg Clayton58d1c9a2010-10-18 04:14:23 +00001070 m_thread_list.ProcessDidStop(this);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001071
1072 // Let each thread know of any exceptions
1073 task_t task = m_task.TaskPort();
1074 size_t i;
1075 for (i=0; i<m_exception_messages.size(); ++i)
1076 {
1077 // Let the thread list figure use the MachProcess to forward all exceptions
1078 // on down to each thread.
1079 if (m_exception_messages[i].state.task_port == task)
Greg Clayton58d1c9a2010-10-18 04:14:23 +00001080 m_thread_list.NotifyException(m_exception_messages[i].state);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001081 if (DNBLogCheckLogBit(LOG_EXCEPTIONS))
1082 m_exception_messages[i].Dump();
1083 }
1084
1085 if (DNBLogCheckLogBit(LOG_THREAD))
Greg Clayton58d1c9a2010-10-18 04:14:23 +00001086 m_thread_list.Dump();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001087
1088 bool step_more = false;
Greg Clayton58d1c9a2010-10-18 04:14:23 +00001089 if (m_thread_list.ShouldStop(step_more))
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001090 {
1091 // Wait for the eEventProcessRunningStateChanged event to be reset
1092 // before changing state to stopped to avoid race condition with
1093 // very fast start/stops
1094 struct timespec timeout;
1095 //DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 ms
1096 DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms
1097 m_events.WaitForEventsToReset(eEventProcessRunningStateChanged, &timeout);
1098 SetState(eStateStopped);
1099 }
1100 else
1101 {
1102 // Resume without checking our current state.
1103 PrivateResume (DNBThreadResumeActions (eStateRunning, 0));
1104 }
1105 }
1106 else
1107 {
1108 DNBLogThreadedIf(LOG_EXCEPTIONS, "%s empty exception messages bundle.", __PRETTY_FUNCTION__, m_exception_messages.size());
1109 }
1110}
1111
1112nub_size_t
1113MachProcess::CopyImageInfos ( struct DNBExecutableImageInfo **image_infos, bool only_changed)
1114{
1115 if (m_image_infos_callback != NULL)
1116 return m_image_infos_callback(ProcessID(), image_infos, only_changed, m_image_infos_baton);
1117 return 0;
1118}
1119
1120void
1121MachProcess::SharedLibrariesUpdated ( )
1122{
1123 uint32_t event_bits = eEventSharedLibsStateChange;
1124 // Set the shared library event bit to let clients know of shared library
1125 // changes
1126 m_events.SetEvents(event_bits);
1127 // Wait for the event bit to reset if a reset ACK is requested
1128 m_events.WaitForResetAck(event_bits);
1129}
1130
1131void
1132MachProcess::AppendSTDOUT (char* s, size_t len)
1133{
1134 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (<%d> %s) ...", __FUNCTION__, len, s);
1135 PTHREAD_MUTEX_LOCKER (locker, m_stdio_mutex);
1136 m_stdout_data.append(s, len);
1137 m_events.SetEvents(eEventStdioAvailable);
1138
1139 // Wait for the event bit to reset if a reset ACK is requested
1140 m_events.WaitForResetAck(eEventStdioAvailable);
1141}
1142
1143size_t
1144MachProcess::GetAvailableSTDOUT (char *buf, size_t buf_size)
1145{
1146 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (&%p[%u]) ...", __FUNCTION__, buf, buf_size);
1147 PTHREAD_MUTEX_LOCKER (locker, m_stdio_mutex);
1148 size_t bytes_available = m_stdout_data.size();
1149 if (bytes_available > 0)
1150 {
1151 if (bytes_available > buf_size)
1152 {
1153 memcpy(buf, m_stdout_data.data(), buf_size);
1154 m_stdout_data.erase(0, buf_size);
1155 bytes_available = buf_size;
1156 }
1157 else
1158 {
1159 memcpy(buf, m_stdout_data.data(), bytes_available);
1160 m_stdout_data.clear();
1161 }
1162 }
1163 return bytes_available;
1164}
1165
1166nub_addr_t
1167MachProcess::GetDYLDAllImageInfosAddress ()
1168{
Greg Clayton3382c2c2010-07-30 23:14:42 +00001169 DNBError err;
1170 return m_task.GetDYLDAllImageInfosAddress(err);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001171}
1172
1173size_t
1174MachProcess::GetAvailableSTDERR (char *buf, size_t buf_size)
1175{
1176 return 0;
1177}
1178
1179void *
1180MachProcess::STDIOThread(void *arg)
1181{
1182 MachProcess *proc = (MachProcess*) arg;
1183 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( arg = %p ) thread starting...", __FUNCTION__, arg);
1184
1185 // We start use a base and more options so we can control if we
1186 // are currently using a timeout on the mach_msg. We do this to get a
1187 // bunch of related exceptions on our exception port so we can process
1188 // then together. When we have multiple threads, we can get an exception
1189 // per thread and they will come in consecutively. The main thread loop
1190 // will start by calling mach_msg to without having the MACH_RCV_TIMEOUT
1191 // flag set in the options, so we will wait forever for an exception on
1192 // our exception port. After we get one exception, we then will use the
1193 // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
1194 // exceptions for our process. After we have received the last pending
1195 // exception, we will get a timeout which enables us to then notify
1196 // our main thread that we have an exception bundle avaiable. We then wait
1197 // for the main thread to tell this exception thread to start trying to get
1198 // exceptions messages again and we start again with a mach_msg read with
1199 // infinite timeout.
1200 DNBError err;
1201 int stdout_fd = proc->GetStdoutFileDescriptor();
1202 int stderr_fd = proc->GetStderrFileDescriptor();
1203 if (stdout_fd == stderr_fd)
1204 stderr_fd = -1;
1205
1206 while (stdout_fd >= 0 || stderr_fd >= 0)
1207 {
1208 ::pthread_testcancel ();
1209
1210 fd_set read_fds;
1211 FD_ZERO (&read_fds);
1212 if (stdout_fd >= 0)
1213 FD_SET (stdout_fd, &read_fds);
1214 if (stderr_fd >= 0)
1215 FD_SET (stderr_fd, &read_fds);
1216 int nfds = std::max<int>(stdout_fd, stderr_fd) + 1;
1217
1218 int num_set_fds = select (nfds, &read_fds, NULL, NULL, NULL);
1219 DNBLogThreadedIf(LOG_PROCESS, "select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
1220
1221 if (num_set_fds < 0)
1222 {
1223 int select_errno = errno;
1224 if (DNBLogCheckLogBit(LOG_PROCESS))
1225 {
1226 err.SetError (select_errno, DNBError::POSIX);
1227 err.LogThreadedIfError("select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds);
1228 }
1229
1230 switch (select_errno)
1231 {
1232 case EAGAIN: // The kernel was (perhaps temporarily) unable to allocate the requested number of file descriptors, or we have non-blocking IO
1233 break;
1234 case EBADF: // One of the descriptor sets specified an invalid descriptor.
1235 return NULL;
1236 break;
1237 case EINTR: // A signal was delivered before the time limit expired and before any of the selected events occurred.
1238 case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
1239 default: // Other unknown error
1240 break;
1241 }
1242 }
1243 else if (num_set_fds == 0)
1244 {
1245 }
1246 else
1247 {
1248 char s[1024];
1249 s[sizeof(s)-1] = '\0'; // Ensure we have NULL termination
1250 int bytes_read = 0;
1251 if (stdout_fd >= 0 && FD_ISSET (stdout_fd, &read_fds))
1252 {
1253 do
1254 {
1255 bytes_read = ::read (stdout_fd, s, sizeof(s)-1);
1256 if (bytes_read < 0)
1257 {
1258 int read_errno = errno;
1259 DNBLogThreadedIf(LOG_PROCESS, "read (stdout_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
1260 }
1261 else if (bytes_read == 0)
1262 {
1263 // EOF...
1264 DNBLogThreadedIf(LOG_PROCESS, "read (stdout_fd, ) => %d (reached EOF for child STDOUT)", bytes_read);
1265 stdout_fd = -1;
1266 }
1267 else if (bytes_read > 0)
1268 {
1269 proc->AppendSTDOUT(s, bytes_read);
1270 }
1271
1272 } while (bytes_read > 0);
1273 }
1274
1275 if (stderr_fd >= 0 && FD_ISSET (stderr_fd, &read_fds))
1276 {
1277 do
1278 {
1279 bytes_read = ::read (stderr_fd, s, sizeof(s)-1);
1280 if (bytes_read < 0)
1281 {
1282 int read_errno = errno;
1283 DNBLogThreadedIf(LOG_PROCESS, "read (stderr_fd, ) => %d errno: %d (%s)", bytes_read, read_errno, strerror(read_errno));
1284 }
1285 else if (bytes_read == 0)
1286 {
1287 // EOF...
1288 DNBLogThreadedIf(LOG_PROCESS, "read (stderr_fd, ) => %d (reached EOF for child STDERR)", bytes_read);
1289 stderr_fd = -1;
1290 }
1291 else if (bytes_read > 0)
1292 {
1293 proc->AppendSTDOUT(s, bytes_read);
1294 }
1295
1296 } while (bytes_read > 0);
1297 }
1298 }
1299 }
1300 DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%p): thread exiting...", __FUNCTION__, arg);
1301 return NULL;
1302}
1303
1304pid_t
1305MachProcess::AttachForDebug (pid_t pid, char *err_str, size_t err_len)
1306{
1307 // Clear out and clean up from any current state
1308 Clear();
1309 if (pid != 0)
1310 {
Greg Clayton3382c2c2010-07-30 23:14:42 +00001311 DNBError err;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001312 // Make sure the process exists...
1313 if (::getpgid (pid) < 0)
1314 {
Greg Clayton3382c2c2010-07-30 23:14:42 +00001315 err.SetErrorToErrno();
1316 const char *err_cstr = err.AsString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001317 ::snprintf (err_str, err_len, "%s", err_cstr ? err_cstr : "No such process");
1318 return INVALID_NUB_PROCESS;
1319 }
1320
1321 SetState(eStateAttaching);
1322 m_pid = pid;
1323 // Let ourselves know we are going to be using SBS if the correct flag bit is set...
1324#if defined (__arm__)
1325 if (IsSBProcess(pid))
1326 m_flags |= eMachProcessFlagsUsingSBS;
1327#endif
Greg Clayton3382c2c2010-07-30 23:14:42 +00001328 if (!m_task.StartExceptionThread(err))
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001329 {
Greg Clayton3382c2c2010-07-30 23:14:42 +00001330 const char *err_cstr = err.AsString();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001331 ::snprintf (err_str, err_len, "%s", err_cstr ? err_cstr : "unable to start the exception thread");
1332 DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid);
1333 m_pid = INVALID_NUB_PROCESS;
1334 return INVALID_NUB_PROCESS;
1335 }
1336
1337 errno = 0;
Greg Clayton3382c2c2010-07-30 23:14:42 +00001338 if (::ptrace (PT_ATTACHEXC, pid, 0, 0))
1339 err.SetError(errno);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001340 else
Greg Clayton3382c2c2010-07-30 23:14:42 +00001341 err.Clear();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001342
Greg Clayton3382c2c2010-07-30 23:14:42 +00001343 if (err.Success())
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001344 {
1345 m_flags |= eMachProcessFlagsAttached;
1346 // Sleep a bit to let the exception get received and set our process status
1347 // to stopped.
1348 ::usleep(250000);
1349 DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", pid);
1350 return m_pid;
1351 }
1352 else
1353 {
Greg Clayton3382c2c2010-07-30 23:14:42 +00001354 ::snprintf (err_str, err_len, "%s", err.AsString());
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001355 DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid);
1356 }
1357 }
1358 return INVALID_NUB_PROCESS;
1359}
1360
1361// Do the process specific setup for attach. If this returns NULL, then there's no
1362// platform specific stuff to be done to wait for the attach. If you get non-null,
1363// pass that token to the CheckForProcess method, and then to CleanupAfterAttach.
1364
1365// Call PrepareForAttach before attaching to a process that has not yet launched
1366// This returns a token that can be passed to CheckForProcess, and to CleanupAfterAttach.
1367// You should call CleanupAfterAttach to free the token, and do whatever other
1368// cleanup seems good.
1369
1370const void *
1371MachProcess::PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &err_str)
1372{
1373#if defined (__arm__)
1374 // Tell SpringBoard to halt the next launch of this application on startup.
1375
1376 if (!waitfor)
1377 return NULL;
1378
1379 const char *app_ext = strstr(path, ".app");
1380 if (app_ext == NULL)
1381 {
1382 DNBLogThreadedIf(LOG_PROCESS, "%s: path '%s' doesn't contain .app, we can't tell springboard to wait for launch...", path);
1383 return NULL;
1384 }
1385
1386 if (launch_flavor != eLaunchFlavorSpringBoard
1387 && launch_flavor != eLaunchFlavorDefault)
1388 return NULL;
1389
1390 std::string app_bundle_path(path, app_ext + strlen(".app"));
1391
1392 CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path.c_str (), err_str);
1393 std::string bundleIDStr;
1394 CFString::UTF8(bundleIDCFStr, bundleIDStr);
1395 DNBLogThreadedIf(LOG_PROCESS, "CopyBundleIDForPath (%s, err_str) returned @\"%s\"", app_bundle_path.c_str (), bundleIDStr.c_str());
1396
1397 if (bundleIDCFStr == NULL)
1398 {
1399 return NULL;
1400 }
1401
1402 SBSApplicationLaunchError sbs_error = 0;
1403
1404 const char *stdout_err = "/dev/null";
1405 CFString stdio_path;
1406 stdio_path.SetFileSystemRepresentation (stdout_err);
1407
1408 DNBLogThreadedIf(LOG_PROCESS, "SBSLaunchApplicationForDebugging ( @\"%s\" , NULL, NULL, NULL, @\"%s\", @\"%s\", SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger )", bundleIDStr.c_str(), stdout_err, stdout_err);
1409 sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
1410 (CFURLRef)NULL, // openURL
1411 NULL, // launch_argv.get(),
1412 NULL, // launch_envp.get(), // CFDictionaryRef environment
1413 stdio_path.get(),
1414 stdio_path.get(),
1415 SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger);
1416
1417 if (sbs_error != SBSApplicationLaunchErrorSuccess)
1418 {
1419 err_str.SetError(sbs_error, DNBError::SpringBoard);
1420 return NULL;
1421 }
1422
1423 DNBLogThreadedIf(LOG_PROCESS, "Successfully set DebugOnNextLaunch.");
1424 return bundleIDCFStr;
1425# else
1426 return NULL;
1427#endif
1428}
1429
1430// Pass in the token you got from PrepareForAttach. If there is a process
1431// for that token, then the pid will be returned, otherwise INVALID_NUB_PROCESS
1432// will be returned.
1433
1434nub_process_t
1435MachProcess::CheckForProcess (const void *attach_token)
1436{
1437 if (attach_token == NULL)
1438 return INVALID_NUB_PROCESS;
1439
1440#if defined (__arm__)
1441 CFStringRef bundleIDCFStr = (CFStringRef) attach_token;
1442 Boolean got_it;
1443 nub_process_t attach_pid;
1444 got_it = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &attach_pid);
1445 if (got_it)
1446 return attach_pid;
1447 else
1448 return INVALID_NUB_PROCESS;
1449#endif
1450 return INVALID_NUB_PROCESS;
1451}
1452
1453// Call this to clean up after you have either attached or given up on the attach.
1454// Pass true for success if you have attached, false if you have not.
1455// The token will also be freed at this point, so you can't use it after calling
1456// this method.
1457
1458void
1459MachProcess::CleanupAfterAttach (const void *attach_token, bool success, DNBError &err_str)
1460{
1461#if defined (__arm__)
1462 if (attach_token == NULL)
1463 return;
1464
1465 // Tell SpringBoard to cancel the debug on next launch of this application
1466 // if we failed to attach
1467 if (!success)
1468 {
1469 SBSApplicationLaunchError sbs_error = 0;
1470 CFStringRef bundleIDCFStr = (CFStringRef) attach_token;
1471
1472 sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
1473 (CFURLRef)NULL,
1474 NULL,
1475 NULL,
1476 NULL,
1477 NULL,
1478 SBSApplicationCancelDebugOnNextLaunch);
1479
1480 if (sbs_error != SBSApplicationLaunchErrorSuccess)
1481 {
1482 err_str.SetError(sbs_error, DNBError::SpringBoard);
1483 return;
1484 }
1485 }
1486
1487 CFRelease((CFStringRef) attach_token);
1488#endif
1489}
1490
1491pid_t
1492MachProcess::LaunchForDebug
1493(
1494 const char *path,
1495 char const *argv[],
1496 char const *envp[],
1497 const char *stdio_path,
1498 nub_launch_flavor_t launch_flavor,
Greg Claytonf681b942010-08-31 18:35:14 +00001499 int disable_aslr,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001500 DNBError &launch_err
1501)
1502{
1503 // Clear out and clean up from any current state
1504 Clear();
1505
Greg Claytonf681b942010-08-31 18:35:14 +00001506 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 +00001507
1508 // Fork a child process for debugging
1509 SetState(eStateLaunching);
1510
1511 switch (launch_flavor)
1512 {
1513 case eLaunchFlavorForkExec:
1514 m_pid = MachProcess::ForkChildForPTraceDebugging (path, argv, envp, this, launch_err);
1515 break;
1516
1517 case eLaunchFlavorPosixSpawn:
Greg Clayton3af9ea52010-11-18 05:57:03 +00001518 m_pid = MachProcess::PosixSpawnChildForPTraceDebugging (path,
Greg Clayton3c144382010-12-01 22:45:40 +00001519 DNBArchProtocol::GetArchitecture (),
Greg Clayton3af9ea52010-11-18 05:57:03 +00001520 argv,
1521 envp,
1522 stdio_path,
1523 this,
1524 disable_aslr,
1525 launch_err);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001526 break;
1527
1528#if defined (__arm__)
1529
1530 case eLaunchFlavorSpringBoard:
1531 {
1532 const char *app_ext = strstr(path, ".app");
1533 if (app_ext != NULL)
1534 {
1535 std::string app_bundle_path(path, app_ext + strlen(".app"));
1536 return SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, launch_err);
1537 }
1538 }
1539 break;
1540
1541#endif
1542
1543 default:
1544 // Invalid launch
1545 launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic);
1546 return INVALID_NUB_PROCESS;
1547 }
1548
1549 if (m_pid == INVALID_NUB_PROCESS)
1550 {
1551 // If we don't have a valid process ID and no one has set the error,
1552 // then return a generic error
1553 if (launch_err.Success())
1554 launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic);
1555 }
1556 else
1557 {
1558 m_path = path;
1559 size_t i;
1560 char const *arg;
1561 for (i=0; (arg = argv[i]) != NULL; i++)
1562 m_args.push_back(arg);
1563
Greg Clayton3382c2c2010-07-30 23:14:42 +00001564 m_task.StartExceptionThread(launch_err);
1565 if (launch_err.Fail())
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001566 {
Greg Clayton3382c2c2010-07-30 23:14:42 +00001567 if (launch_err.AsString() == NULL)
1568 launch_err.SetErrorString("unable to start the exception thread");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001569 ::ptrace (PT_KILL, m_pid, 0, 0);
1570 m_pid = INVALID_NUB_PROCESS;
1571 return INVALID_NUB_PROCESS;
1572 }
1573
1574 StartSTDIOThread();
1575
1576 if (launch_flavor == eLaunchFlavorPosixSpawn)
1577 {
1578
1579 SetState (eStateAttaching);
1580 errno = 0;
Caroline Tice5d7be2e2010-11-02 16:16:53 +00001581 int err = ::ptrace (PT_ATTACHEXC, m_pid, 0, 0);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001582 if (err == 0)
1583 {
1584 m_flags |= eMachProcessFlagsAttached;
1585 DNBLogThreadedIf(LOG_PROCESS, "successfully spawned pid %d", m_pid);
1586 launch_err.Clear();
1587 }
1588 else
1589 {
1590 SetState (eStateExited);
1591 DNBError ptrace_err(errno, DNBError::POSIX);
1592 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());
1593 launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic);
1594 }
1595 }
1596 else
1597 {
1598 launch_err.Clear();
1599 }
1600 }
1601 return m_pid;
1602}
1603
1604pid_t
1605MachProcess::PosixSpawnChildForPTraceDebugging
1606(
1607 const char *path,
Greg Clayton3af9ea52010-11-18 05:57:03 +00001608 cpu_type_t cpu_type,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001609 char const *argv[],
1610 char const *envp[],
1611 const char *stdio_path,
1612 MachProcess* process,
Greg Claytonf681b942010-08-31 18:35:14 +00001613 int disable_aslr,
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001614 DNBError& err
1615)
1616{
1617 posix_spawnattr_t attr;
Greg Claytonf681b942010-08-31 18:35:14 +00001618 short flags;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001619 DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv=%p, envp=%p, process )", __FUNCTION__, path, argv, envp);
1620
1621 err.SetError( ::posix_spawnattr_init (&attr), DNBError::POSIX);
1622 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1623 err.LogThreaded("::posix_spawnattr_init ( &attr )");
1624 if (err.Fail())
1625 return INVALID_NUB_PROCESS;
1626
Greg Claytonf681b942010-08-31 18:35:14 +00001627 flags = POSIX_SPAWN_START_SUSPENDED;
1628 if (disable_aslr)
1629 flags |= _POSIX_SPAWN_DISABLE_ASLR;
1630
1631 err.SetError( ::posix_spawnattr_setflags (&attr, flags), DNBError::POSIX);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001632 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
Greg Claytonf681b942010-08-31 18:35:14 +00001633 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 +00001634 if (err.Fail())
1635 return INVALID_NUB_PROCESS;
1636
1637 // Don't do this on SnowLeopard, _sometimes_ the TASK_BASIC_INFO will fail
1638 // and we will fail to continue with our process...
1639
1640 // On SnowLeopard we should set "DYLD_NO_PIE" in the inferior environment....
1641
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001642#if !defined(__arm__)
1643
1644 // We don't need to do this for ARM, and we really shouldn't now that we
1645 // have multiple CPU subtypes and no posix_spawnattr call that allows us
1646 // to set which CPU subtype to launch...
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001647 size_t ocount = 0;
1648 err.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu_type, &ocount), DNBError::POSIX);
1649 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1650 err.LogThreaded("::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %zu )", cpu_type, ocount);
1651
1652 if (err.Fail() != 0 || ocount != 1)
1653 return INVALID_NUB_PROCESS;
1654
1655#endif
1656
1657 PseudoTerminal pty;
1658
1659 posix_spawn_file_actions_t file_actions;
1660 err.SetError( ::posix_spawn_file_actions_init (&file_actions), DNBError::POSIX);
1661 int file_actions_valid = err.Success();
1662 if (!file_actions_valid || DNBLogCheckLogBit(LOG_PROCESS))
1663 err.LogThreaded("::posix_spawn_file_actions_init ( &file_actions )");
1664 int pty_error = -1;
1665 pid_t pid = INVALID_NUB_PROCESS;
1666 if (file_actions_valid)
1667 {
1668 if (stdio_path == NULL)
1669 {
1670 pty_error = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY);
1671 if (pty_error == PseudoTerminal::success)
1672 stdio_path = pty.SlaveName();
1673 // Make sure we were able to get the slave name
1674 if (stdio_path == NULL)
1675 stdio_path = "/dev/null";
1676 }
1677
1678 if (stdio_path != NULL)
1679 {
Caroline Tice5e254d32010-11-05 22:37:44 +00001680 int slave_fd_err = open (stdio_path, O_RDWR, 0);
1681 int slave_fd_in = open (stdio_path, O_RDONLY, 0);
1682 int slave_fd_out = open (stdio_path, O_WRONLY, 0);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001683
Caroline Tice5e254d32010-11-05 22:37:44 +00001684 err.SetError( ::posix_spawn_file_actions_adddup2(&file_actions, slave_fd_err, STDERR_FILENO), DNBError::POSIX);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001685 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
Caroline Tice5e254d32010-11-05 22:37:44 +00001686 err.LogThreaded("::posix_spawn_file_actions_adddup2 ( &file_actions, filedes = %d, newfiledes = STDERR_FILENO )", slave_fd_err);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001687
Caroline Tice5e254d32010-11-05 22:37:44 +00001688 err.SetError( ::posix_spawn_file_actions_adddup2(&file_actions, slave_fd_in, STDIN_FILENO), DNBError::POSIX);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001689 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
Caroline Tice5e254d32010-11-05 22:37:44 +00001690 err.LogThreaded("::posix_spawn_file_actions_adddup2 ( &file_actions, filedes = %d, newfiledes = STDIN_FILENO )", slave_fd_in);
1691
1692 err.SetError( ::posix_spawn_file_actions_adddup2(&file_actions, slave_fd_out, STDOUT_FILENO), DNBError::POSIX);
1693 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1694 err.LogThreaded("::posix_spawn_file_actions_adddup2 ( &file_actions, filedes = %d, newfiledes = STDOUT_FILENO )", slave_fd_out);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001695 }
1696 err.SetError( ::posix_spawnp (&pid, path, &file_actions, &attr, (char * const*)argv, (char * const*)envp), DNBError::POSIX);
1697 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1698 err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, &file_actions, &attr, argv, envp);
1699 }
1700 else
1701 {
1702 err.SetError( ::posix_spawnp (&pid, path, NULL, &attr, (char * const*)argv, (char * const*)envp), DNBError::POSIX);
1703 if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1704 err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, NULL, &attr, argv, envp);
1705 }
1706
1707 // We have seen some cases where posix_spawnp was returning a valid
1708 // looking pid even when an error was returned, so clear it out
1709 if (err.Fail())
1710 pid = INVALID_NUB_PROCESS;
1711
1712 if (pty_error == 0)
1713 {
1714 if (process != NULL)
1715 {
1716 int master_fd = pty.ReleaseMasterFD();
1717 process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
1718 }
1719 }
Greg Clayton0b42ac32010-07-02 01:29:13 +00001720
1721 ::posix_spawnattr_destroy (&attr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001722
1723 if (file_actions_valid)
1724 {
1725 DNBError err2;
1726 err2.SetError( ::posix_spawn_file_actions_destroy (&file_actions), DNBError::POSIX);
1727 if (err2.Fail() || DNBLogCheckLogBit(LOG_PROCESS))
1728 err2.LogThreaded("::posix_spawn_file_actions_destroy ( &file_actions )");
1729 }
1730
1731 return pid;
1732}
1733
1734pid_t
1735MachProcess::ForkChildForPTraceDebugging
1736(
1737 const char *path,
1738 char const *argv[],
1739 char const *envp[],
1740 MachProcess* process,
1741 DNBError& launch_err
1742)
1743{
1744 PseudoTerminal::Error pty_error = PseudoTerminal::success;
1745
1746 // Use a fork that ties the child process's stdin/out/err to a pseudo
1747 // terminal so we can read it in our MachProcess::STDIOThread
1748 // as unbuffered io.
1749 PseudoTerminal pty;
1750 pid_t pid = pty.Fork(pty_error);
1751
1752 if (pid < 0)
1753 {
1754 //--------------------------------------------------------------
1755 // Error during fork.
1756 //--------------------------------------------------------------
1757 return pid;
1758 }
1759 else if (pid == 0)
1760 {
1761 //--------------------------------------------------------------
1762 // Child process
1763 //--------------------------------------------------------------
1764 ::ptrace (PT_TRACE_ME, 0, 0, 0); // Debug this process
1765 ::ptrace (PT_SIGEXC, 0, 0, 0); // Get BSD signals as mach exceptions
1766
1767 // If our parent is setgid, lets make sure we don't inherit those
1768 // extra powers due to nepotism.
1769 ::setgid (getgid ());
1770
1771 // Let the child have its own process group. We need to execute
1772 // this call in both the child and parent to avoid a race condition
1773 // between the two processes.
1774 ::setpgid (0, 0); // Set the child process group to match its pid
1775
1776 // Sleep a bit to before the exec call
1777 ::sleep (1);
1778
1779 // Turn this process into
1780 ::execv (path, (char * const *)argv);
1781 // Exit with error code. Child process should have taken
1782 // over in above exec call and if the exec fails it will
1783 // exit the child process below.
1784 ::exit (127);
1785 }
1786 else
1787 {
1788 //--------------------------------------------------------------
1789 // Parent process
1790 //--------------------------------------------------------------
1791 // Let the child have its own process group. We need to execute
1792 // this call in both the child and parent to avoid a race condition
1793 // between the two processes.
1794 ::setpgid (pid, pid); // Set the child process group to match its pid
1795
1796 if (process != NULL)
1797 {
1798 // Release our master pty file descriptor so the pty class doesn't
1799 // close it and so we can continue to use it in our STDIO thread
1800 int master_fd = pty.ReleaseMasterFD();
1801 process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
1802 }
1803 }
1804 return pid;
1805}
1806
1807#if defined (__arm__)
1808
1809pid_t
1810MachProcess::SBLaunchForDebug (const char *path, char const *argv[], char const *envp[], DNBError &launch_err)
1811{
1812 // Clear out and clean up from any current state
1813 Clear();
1814
1815 DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path);
1816
1817 // Fork a child process for debugging
1818 SetState(eStateLaunching);
1819 m_pid = MachProcess::SBForkChildForPTraceDebugging(path, argv, envp, this, launch_err);
1820 if (m_pid != 0)
1821 {
1822 m_flags |= eMachProcessFlagsUsingSBS;
1823 m_path = path;
1824 size_t i;
1825 char const *arg;
1826 for (i=0; (arg = argv[i]) != NULL; i++)
1827 m_args.push_back(arg);
Greg Clayton6f35f5c2010-09-09 06:32:46 +00001828 m_task.StartExceptionThread(launch_err);
1829
1830 if (launch_err.Fail())
1831 {
1832 if (launch_err.AsString() == NULL)
1833 launch_err.SetErrorString("unable to start the exception thread");
1834 ::ptrace (PT_KILL, m_pid, 0, 0);
1835 m_pid = INVALID_NUB_PROCESS;
1836 return INVALID_NUB_PROCESS;
1837 }
1838
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001839 StartSTDIOThread();
1840 SetState (eStateAttaching);
Caroline Tice5d7be2e2010-11-02 16:16:53 +00001841 int err = ::ptrace (PT_ATTACHEXC, m_pid, 0, 0);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001842 if (err == 0)
1843 {
1844 m_flags |= eMachProcessFlagsAttached;
1845 DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid);
1846 }
1847 else
1848 {
1849 SetState (eStateExited);
1850 DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", m_pid);
1851 }
1852 }
1853 return m_pid;
1854}
1855
1856#include <servers/bootstrap.h>
1857
1858// This returns a CFRetained pointer to the Bundle ID for app_bundle_path,
1859// or NULL if there was some problem getting the bundle id.
1860static CFStringRef
1861CopyBundleIDForPath (const char *app_bundle_path, DNBError &err_str)
1862{
1863 CFBundle bundle(app_bundle_path);
1864 CFStringRef bundleIDCFStr = bundle.GetIdentifier();
1865 std::string bundleID;
1866 if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL)
1867 {
1868 struct stat app_bundle_stat;
1869 char err_msg[PATH_MAX];
1870
1871 if (::stat (app_bundle_path, &app_bundle_stat) < 0)
1872 {
1873 err_str.SetError(errno, DNBError::POSIX);
1874 snprintf(err_msg, sizeof(err_msg), "%s: \"%s\"", err_str.AsString(), app_bundle_path);
1875 err_str.SetErrorString(err_msg);
1876 DNBLogThreadedIf(LOG_PROCESS, "%s() error: %s", __FUNCTION__, err_msg);
1877 }
1878 else
1879 {
1880 err_str.SetError(-1, DNBError::Generic);
1881 snprintf(err_msg, sizeof(err_msg), "failed to extract CFBundleIdentifier from %s", app_bundle_path);
1882 err_str.SetErrorString(err_msg);
1883 DNBLogThreadedIf(LOG_PROCESS, "%s() error: failed to extract CFBundleIdentifier from '%s'", __FUNCTION__, app_bundle_path);
1884 }
1885 return NULL;
1886 }
1887
1888 DNBLogThreadedIf(LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str());
1889 CFRetain (bundleIDCFStr);
1890
1891 return bundleIDCFStr;
1892}
1893
1894pid_t
1895MachProcess::SBForkChildForPTraceDebugging (const char *app_bundle_path, char const *argv[], char const *envp[], MachProcess* process, DNBError &launch_err)
1896{
1897 DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, app_bundle_path, process);
1898 CFAllocatorRef alloc = kCFAllocatorDefault;
1899
1900 if (argv[0] == NULL)
1901 return INVALID_NUB_PROCESS;
1902
1903 size_t argc = 0;
1904 // Count the number of arguments
1905 while (argv[argc] != NULL)
1906 argc++;
1907
1908 // Enumerate the arguments
1909 size_t first_launch_arg_idx = 1;
1910 CFReleaser<CFMutableArrayRef> launch_argv;
1911
1912 if (argv[first_launch_arg_idx])
1913 {
1914 size_t launch_argc = argc > 0 ? argc - 1 : 0;
1915 launch_argv.reset (::CFArrayCreateMutable (alloc, launch_argc, &kCFTypeArrayCallBacks));
1916 size_t i;
1917 char const *arg;
1918 CFString launch_arg;
1919 for (i=first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); i++)
1920 {
1921 launch_arg.reset(::CFStringCreateWithCString (alloc, arg, kCFStringEncodingUTF8));
1922 if (launch_arg.get() != NULL)
1923 CFArrayAppendValue(launch_argv.get(), launch_arg.get());
1924 else
1925 break;
1926 }
1927 }
1928
1929 // Next fill in the arguments dictionary. Note, the envp array is of the form
1930 // Variable=value but SpringBoard wants a CF dictionary. So we have to convert
1931 // this here.
1932
1933 CFReleaser<CFMutableDictionaryRef> launch_envp;
1934
1935 if (envp[0])
1936 {
1937 launch_envp.reset(::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
1938 const char *value;
1939 int name_len;
1940 CFString name_string, value_string;
1941
1942 for (int i = 0; envp[i] != NULL; i++)
1943 {
1944 value = strstr (envp[i], "=");
1945
1946 // If the name field is empty or there's no =, skip it. Somebody's messing with us.
1947 if (value == NULL || value == envp[i])
1948 continue;
1949
1950 name_len = value - envp[i];
1951
1952 // Now move value over the "="
1953 value++;
1954
1955 name_string.reset(::CFStringCreateWithBytes(alloc, (const UInt8 *) envp[i], name_len, kCFStringEncodingUTF8, false));
1956 value_string.reset(::CFStringCreateWithCString(alloc, value, kCFStringEncodingUTF8));
1957 CFDictionarySetValue (launch_envp.get(), name_string.get(), value_string.get());
1958 }
1959 }
1960
1961 CFString stdio_path;
1962
1963 PseudoTerminal pty;
1964 PseudoTerminal::Error pty_err = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY);
1965 if (pty_err == PseudoTerminal::success)
1966 {
1967 const char* slave_name = pty.SlaveName();
1968 DNBLogThreadedIf(LOG_PROCESS, "%s() successfully opened master pty, slave is %s", __FUNCTION__, slave_name);
1969 if (slave_name && slave_name[0])
1970 {
1971 ::chmod (slave_name, S_IRWXU | S_IRWXG | S_IRWXO);
1972 stdio_path.SetFileSystemRepresentation (slave_name);
1973 }
1974 }
1975
1976 if (stdio_path.get() == NULL)
1977 {
1978 stdio_path.SetFileSystemRepresentation ("/dev/null");
1979 }
1980
1981 CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path, launch_err);
1982 if (bundleIDCFStr == NULL)
1983 return INVALID_NUB_PROCESS;
1984
1985 std::string bundleID;
1986 CFString::UTF8(bundleIDCFStr, bundleID);
1987
1988 CFData argv_data(NULL);
1989
1990 if (launch_argv.get())
1991 {
1992 if (argv_data.Serialize(launch_argv.get(), kCFPropertyListBinaryFormat_v1_0) == NULL)
1993 {
1994 DNBLogThreadedIf(LOG_PROCESS, "%s() error: failed to serialize launch arg array...", __FUNCTION__);
1995 return INVALID_NUB_PROCESS;
1996 }
1997 }
1998
1999 DNBLogThreadedIf(LOG_PROCESS, "%s() serialized launch arg array", __FUNCTION__);
2000
2001 // Find SpringBoard
2002 SBSApplicationLaunchError sbs_error = 0;
2003 sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
2004 (CFURLRef)NULL, // openURL
2005 launch_argv.get(),
2006 launch_envp.get(), // CFDictionaryRef environment
2007 stdio_path.get(),
2008 stdio_path.get(),
2009 SBSApplicationLaunchWaitForDebugger | SBSApplicationLaunchUnlockDevice);
2010
2011
2012 launch_err.SetError(sbs_error, DNBError::SpringBoard);
2013
2014 if (sbs_error == SBSApplicationLaunchErrorSuccess)
2015 {
2016 static const useconds_t pid_poll_interval = 200000;
2017 static const useconds_t pid_poll_timeout = 30000000;
2018
2019 useconds_t pid_poll_total = 0;
2020
2021 nub_process_t pid = INVALID_NUB_PROCESS;
2022 Boolean pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
2023 // Poll until the process is running, as long as we are getting valid responses and the timeout hasn't expired
2024 // A return PID of 0 means the process is not running, which may be because it hasn't been (asynchronously) started
2025 // yet, or that it died very quickly (if you weren't using waitForDebugger).
2026 while (!pid_found && pid_poll_total < pid_poll_timeout)
2027 {
2028 usleep (pid_poll_interval);
2029 pid_poll_total += pid_poll_interval;
2030 DNBLogThreadedIf(LOG_PROCESS, "%s() polling Springboard for pid for %s...", __FUNCTION__, bundleID.c_str());
2031 pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid);
2032 }
2033
2034 CFRelease (bundleIDCFStr);
2035 if (pid_found)
2036 {
2037 if (process != NULL)
2038 {
2039 // Release our master pty file descriptor so the pty class doesn't
2040 // close it and so we can continue to use it in our STDIO thread
2041 int master_fd = pty.ReleaseMasterFD();
2042 process->SetChildFileDescriptors(master_fd, master_fd, master_fd);
2043 }
2044 DNBLogThreadedIf(LOG_PROCESS, "%s() => pid = %4.4x", __FUNCTION__, pid);
2045 }
2046 else
2047 {
2048 DNBLogError("failed to lookup the process ID for CFBundleIdentifier %s.", bundleID.c_str());
2049 }
2050 return pid;
2051 }
2052
2053 DNBLogError("unable to launch the application with CFBundleIdentifier '%s' sbs_error = %u", bundleID.c_str(), sbs_error);
2054 return INVALID_NUB_PROCESS;
2055}
2056
2057#endif // #if defined (__arm__)
2058
2059