blob: 1168f1fc0a1e6fe5328428099b82f14b9eac3085 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- DNB.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 3/23/07.
11//
12//===----------------------------------------------------------------------===//
13
14#include "DNB.h"
Jason Molenda1c739112013-02-22 07:27:08 +000015#include <inttypes.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000016#include <libproc.h>
17#include <map>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000018#include <signal.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <sys/resource.h>
22#include <sys/stat.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000023#include <sys/sysctl.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000024#include <sys/types.h>
25#include <sys/wait.h>
26#include <unistd.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000027#include <vector>
28
Kate Stoneb9c1b512016-09-06 20:57:50 +000029#if defined(__APPLE__)
Jason Molenda36a216e2014-07-24 01:36:24 +000030#include <pthread.h>
31#include <sched.h>
32#endif
33
Jason Molendaa3329782014-03-29 18:54:20 +000034#define TRY_KQUEUE 1
35
36#ifdef TRY_KQUEUE
Kate Stoneb9c1b512016-09-06 20:57:50 +000037#include <sys/event.h>
38#include <sys/time.h>
39#ifdef NOTE_EXIT_DETAIL
40#define USE_KQUEUE
41#endif
Jason Molendaa3329782014-03-29 18:54:20 +000042#endif
43
Kate Stoneb9c1b512016-09-06 20:57:50 +000044#include "CFBundle.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000045#include "CFString.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000046#include "DNBDataRef.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000047#include "DNBLog.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000048#include "DNBThreadResumeActions.h"
49#include "DNBTimer.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000050#include "MacOSX/DarwinLog/DarwinLogCollector.h"
51#include "MacOSX/Genealogy.h"
52#include "MacOSX/MachProcess.h"
53#include "MacOSX/MachTask.h"
54#include "MacOSX/ThreadInfo.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000055
Greg Clayton7b0992d2013-04-18 22:45:39 +000056typedef std::shared_ptr<MachProcess> MachProcessSP;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000057typedef std::map<nub_process_t, MachProcessSP> ProcessMap;
58typedef ProcessMap::iterator ProcessMapIter;
59typedef ProcessMap::const_iterator ProcessMapConstIter;
60
Kate Stoneb9c1b512016-09-06 20:57:50 +000061size_t GetAllInfos(std::vector<struct kinfo_proc> &proc_infos);
62static size_t
63GetAllInfosMatchingName(const char *process_name,
64 std::vector<struct kinfo_proc> &matching_proc_infos);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000065
66//----------------------------------------------------------------------
67// A Thread safe singleton to get a process map pointer.
68//
69// Returns a pointer to the existing process map, or a pointer to a
70// newly created process map if CAN_CREATE is non-zero.
71//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000072static ProcessMap *GetProcessMap(bool can_create) {
73 static ProcessMap *g_process_map_ptr = NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000074
Kate Stoneb9c1b512016-09-06 20:57:50 +000075 if (can_create && g_process_map_ptr == NULL) {
76 static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER;
77 PTHREAD_MUTEX_LOCKER(locker, &g_process_map_mutex);
78 if (g_process_map_ptr == NULL)
79 g_process_map_ptr = new ProcessMap;
80 }
81 return g_process_map_ptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000082}
83
84//----------------------------------------------------------------------
85// Add PID to the shared process pointer map.
86//
87// Return non-zero value if we succeed in adding the process to the map.
88// The only time this should fail is if we run out of memory and can't
89// allocate a ProcessMap.
90//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000091static nub_bool_t AddProcessToMap(nub_process_t pid, MachProcessSP &procSP) {
92 ProcessMap *process_map = GetProcessMap(true);
93 if (process_map) {
94 process_map->insert(std::make_pair(pid, procSP));
95 return true;
96 }
97 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000098}
99
100//----------------------------------------------------------------------
101// Remove the shared pointer for PID from the process map.
102//
103// Returns the number of items removed from the process map.
104//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105// static size_t
106// RemoveProcessFromMap (nub_process_t pid)
Greg Claytonee2ed522015-03-09 19:45:23 +0000107//{
108// ProcessMap* process_map = GetProcessMap(false);
109// if (process_map)
110// {
111// return process_map->erase(pid);
112// }
113// return 0;
114//}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000115
116//----------------------------------------------------------------------
117// Get the shared pointer for PID from the existing process map.
118//
119// Returns true if we successfully find a shared pointer to a
120// MachProcess object.
121//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000122static nub_bool_t GetProcessSP(nub_process_t pid, MachProcessSP &procSP) {
123 ProcessMap *process_map = GetProcessMap(false);
124 if (process_map != NULL) {
125 ProcessMapIter pos = process_map->find(pid);
126 if (pos != process_map->end()) {
127 procSP = pos->second;
128 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000129 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000130 }
131 procSP.reset();
132 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000133}
134
Jason Molendaa3329782014-03-29 18:54:20 +0000135#ifdef USE_KQUEUE
Kate Stoneb9c1b512016-09-06 20:57:50 +0000136void *kqueue_thread(void *arg) {
137 int kq_id = (int)(intptr_t)arg;
138
139#if defined(__APPLE__)
140 pthread_setname_np("kqueue thread");
141#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
142 struct sched_param thread_param;
143 int thread_sched_policy;
144 if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
145 &thread_param) == 0) {
146 thread_param.sched_priority = 47;
147 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
148 }
Jason Molenda36a216e2014-07-24 01:36:24 +0000149#endif
150#endif
151
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152 struct kevent death_event;
153 while (1) {
154 int n_events = kevent(kq_id, NULL, 0, &death_event, 1, NULL);
155 if (n_events == -1) {
156 if (errno == EINTR)
157 continue;
158 else {
159 DNBLogError("kqueue failed with error: (%d): %s", errno,
160 strerror(errno));
161 return NULL;
162 }
163 } else if (death_event.flags & EV_ERROR) {
164 int error_no = static_cast<int>(death_event.data);
165 const char *error_str = strerror(error_no);
166 if (error_str == NULL)
167 error_str = "Unknown error";
168 DNBLogError("Failed to initialize kqueue event: (%d): %s", error_no,
169 error_str);
170 return NULL;
171 } else {
172 int status;
173 const pid_t pid = (pid_t)death_event.ident;
174 const pid_t child_pid = waitpid(pid, &status, 0);
Greg Clayton040c5602014-04-30 20:24:10 +0000175
Kate Stoneb9c1b512016-09-06 20:57:50 +0000176 bool exited = false;
177 int signal = 0;
178 int exit_status = 0;
179 if (WIFSTOPPED(status)) {
180 signal = WSTOPSIG(status);
181 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> STOPPED (signal = %i)",
182 child_pid, signal);
183 } else if (WIFEXITED(status)) {
184 exit_status = WEXITSTATUS(status);
185 exited = true;
186 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> EXITED (status = %i)",
187 child_pid, exit_status);
188 } else if (WIFSIGNALED(status)) {
189 signal = WTERMSIG(status);
190 if (child_pid == abs(pid)) {
191 DNBLogThreadedIf(LOG_PROCESS,
192 "waitpid (%i) -> SIGNALED and EXITED (signal = %i)",
193 child_pid, signal);
194 char exit_info[64];
195 ::snprintf(exit_info, sizeof(exit_info),
196 "Terminated due to signal %i", signal);
197 DNBProcessSetExitInfo(child_pid, exit_info);
198 exited = true;
199 exit_status = INT8_MAX;
200 } else {
201 DNBLogThreadedIf(LOG_PROCESS,
202 "waitpid (%i) -> SIGNALED (signal = %i)", child_pid,
203 signal);
Jason Molendaa3329782014-03-29 18:54:20 +0000204 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000205 }
206
207 if (exited) {
208 if (death_event.data & NOTE_EXIT_MEMORY)
209 DNBProcessSetExitInfo(child_pid, "Terminated due to memory issue");
210 else if (death_event.data & NOTE_EXIT_DECRYPTFAIL)
211 DNBProcessSetExitInfo(child_pid, "Terminated due to decrypt failure");
212 else if (death_event.data & NOTE_EXIT_CSERROR)
213 DNBProcessSetExitInfo(child_pid,
214 "Terminated due to code signing error");
215
216 DNBLogThreadedIf(
217 LOG_PROCESS,
218 "waitpid_process_thread (): setting exit status for pid = %i to %i",
219 child_pid, exit_status);
220 DNBProcessSetExitStatus(child_pid, status);
221 return NULL;
222 }
Jason Molendaa3329782014-03-29 18:54:20 +0000223 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000224 }
Jason Molendaa3329782014-03-29 18:54:20 +0000225}
226
Kate Stoneb9c1b512016-09-06 20:57:50 +0000227static bool spawn_kqueue_thread(pid_t pid) {
228 pthread_t thread;
229 int kq_id;
Jason Molendaa3329782014-03-29 18:54:20 +0000230
Kate Stoneb9c1b512016-09-06 20:57:50 +0000231 kq_id = kqueue();
232 if (kq_id == -1) {
233 DNBLogError("Could not get kqueue for pid = %i.", pid);
Jason Molendaa3329782014-03-29 18:54:20 +0000234 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000235 }
236
237 struct kevent reg_event;
238
239 EV_SET(&reg_event, pid, EVFILT_PROC, EV_ADD,
240 NOTE_EXIT | NOTE_EXITSTATUS | NOTE_EXIT_DETAIL, 0, NULL);
241 // Register the event:
242 int result = kevent(kq_id, &reg_event, 1, NULL, 0, NULL);
243 if (result != 0) {
244 DNBLogError(
245 "Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid,
246 result);
247 return false;
248 }
249
250 int ret =
251 ::pthread_create(&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id);
252
253 // pthread_create returns 0 if successful
254 if (ret == 0) {
255 ::pthread_detach(thread);
256 return true;
257 }
258 return false;
Jason Molendaa3329782014-03-29 18:54:20 +0000259}
260#endif // #if USE_KQUEUE
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000261
Kate Stoneb9c1b512016-09-06 20:57:50 +0000262static void *waitpid_thread(void *arg) {
263 const pid_t pid = (pid_t)(intptr_t)arg;
264 int status;
Jason Molenda36a216e2014-07-24 01:36:24 +0000265
Kate Stoneb9c1b512016-09-06 20:57:50 +0000266#if defined(__APPLE__)
267 pthread_setname_np("waitpid thread");
268#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
269 struct sched_param thread_param;
270 int thread_sched_policy;
271 if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
272 &thread_param) == 0) {
273 thread_param.sched_priority = 47;
274 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
275 }
Jason Molenda36a216e2014-07-24 01:36:24 +0000276#endif
277#endif
278
Kate Stoneb9c1b512016-09-06 20:57:50 +0000279 while (1) {
280 pid_t child_pid = waitpid(pid, &status, 0);
281 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): waitpid (pid = %i, "
282 "&status, 0) => %i, status = %i, errno = %i",
283 pid, child_pid, status, errno);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000284
Kate Stoneb9c1b512016-09-06 20:57:50 +0000285 if (child_pid < 0) {
286 if (errno == EINTR)
287 continue;
288 break;
289 } else {
290 if (WIFSTOPPED(status)) {
291 continue;
292 } else // if (WIFEXITED(status) || WIFSIGNALED(status))
293 {
294 DNBLogThreadedIf(
295 LOG_PROCESS,
296 "waitpid_thread (): setting exit status for pid = %i to %i",
297 child_pid, status);
298 DNBProcessSetExitStatus(child_pid, status);
299 return NULL;
300 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000301 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000302 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000303
Kate Stoneb9c1b512016-09-06 20:57:50 +0000304 // We should never exit as long as our child process is alive, so if we
305 // do something else went wrong and we should exit...
306 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): main loop exited, setting "
307 "exit status to an invalid value (-1) for pid "
308 "%i",
309 pid);
310 DNBProcessSetExitStatus(pid, -1);
311 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000312}
Kate Stoneb9c1b512016-09-06 20:57:50 +0000313static bool spawn_waitpid_thread(pid_t pid) {
Jason Molendaa3329782014-03-29 18:54:20 +0000314#ifdef USE_KQUEUE
Kate Stoneb9c1b512016-09-06 20:57:50 +0000315 bool success = spawn_kqueue_thread(pid);
316 if (success)
317 return true;
Jason Molendaa3329782014-03-29 18:54:20 +0000318#endif
319
Kate Stoneb9c1b512016-09-06 20:57:50 +0000320 pthread_t thread;
321 int ret =
322 ::pthread_create(&thread, NULL, waitpid_thread, (void *)(intptr_t)pid);
323 // pthread_create returns 0 if successful
324 if (ret == 0) {
325 ::pthread_detach(thread);
326 return true;
327 }
328 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000329}
330
Kate Stoneb9c1b512016-09-06 20:57:50 +0000331nub_process_t DNBProcessLaunch(
332 const char *path, char const *argv[], const char *envp[],
333 const char *working_directory, // NULL => don't change, non-NULL => set
334 // working directory for inferior to this
335 const char *stdin_path, const char *stdout_path, const char *stderr_path,
336 bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr,
337 const char *event_data, char *err_str, size_t err_len) {
338 DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, "
339 "working_dir=%s, stdin=%s, stdout=%s, "
340 "stderr=%s, no-stdio=%i, launch_flavor = %u, "
341 "disable_aslr = %d, err = %p, err_len = "
342 "%llu) called...",
343 __FUNCTION__, path, static_cast<void *>(argv),
344 static_cast<void *>(envp), working_directory, stdin_path,
345 stdout_path, stderr_path, no_stdio, launch_flavor,
346 disable_aslr, static_cast<void *>(err_str),
347 static_cast<uint64_t>(err_len));
Saleem Abdulrasoolbd7ecf42016-05-06 17:32:58 +0000348
Kate Stoneb9c1b512016-09-06 20:57:50 +0000349 if (err_str && err_len > 0)
350 err_str[0] = '\0';
351 struct stat path_stat;
352 if (::stat(path, &path_stat) == -1) {
353 char stat_error[256];
354 ::strerror_r(errno, stat_error, sizeof(stat_error));
355 snprintf(err_str, err_len, "%s (%s)", stat_error, path);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000356 return INVALID_NUB_PROCESS;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000357 }
358
359 MachProcessSP processSP(new MachProcess);
360 if (processSP.get()) {
361 DNBError launch_err;
362 pid_t pid = processSP->LaunchForDebug(path, argv, envp, working_directory,
363 stdin_path, stdout_path, stderr_path,
364 no_stdio, launch_flavor, disable_aslr,
365 event_data, launch_err);
366 if (err_str) {
367 *err_str = '\0';
368 if (launch_err.Fail()) {
369 const char *launch_err_str = launch_err.AsString();
370 if (launch_err_str) {
Jason Molendaaae5b692017-12-09 03:37:09 +0000371 strlcpy(err_str, launch_err_str, err_len - 1);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000372 err_str[err_len - 1] =
373 '\0'; // Make sure the error string is terminated
374 }
375 }
376 }
377
378 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid);
379
380 if (pid != INVALID_NUB_PROCESS) {
381 // Spawn a thread to reap our child inferior process...
382 spawn_waitpid_thread(pid);
383
384 if (processSP->Task().TaskPortForProcessID(launch_err) == TASK_NULL) {
385 // We failed to get the task for our process ID which is bad.
386 // Kill our process otherwise it will be stopped at the entry
387 // point and get reparented to someone else and never go away.
388 DNBLog("Could not get task port for process, sending SIGKILL and "
389 "exiting.");
390 kill(SIGKILL, pid);
391
392 if (err_str && err_len > 0) {
393 if (launch_err.AsString()) {
394 ::snprintf(err_str, err_len,
395 "failed to get the task for process %i (%s)", pid,
396 launch_err.AsString());
397 } else {
398 ::snprintf(err_str, err_len,
399 "failed to get the task for process %i", pid);
400 }
401 }
402 } else {
403 bool res = AddProcessToMap(pid, processSP);
404 UNUSED_IF_ASSERT_DISABLED(res);
405 assert(res && "Couldn't add process to map!");
406 return pid;
407 }
408 }
409 }
410 return INVALID_NUB_PROCESS;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000411}
412
Jason Molenda752e1e82015-07-29 01:42:16 +0000413// If there is one process with a given name, return the pid for that process.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000414nub_process_t DNBProcessGetPIDByName(const char *name) {
415 std::vector<struct kinfo_proc> matching_proc_infos;
416 size_t num_matching_proc_infos =
417 GetAllInfosMatchingName(name, matching_proc_infos);
418 if (num_matching_proc_infos == 1) {
419 return matching_proc_infos[0].kp_proc.p_pid;
420 }
421 return INVALID_NUB_PROCESS;
422}
423
424nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
425 char *err_str, size_t err_len) {
426 if (err_str && err_len > 0)
427 err_str[0] = '\0';
428 std::vector<struct kinfo_proc> matching_proc_infos;
429 size_t num_matching_proc_infos =
430 GetAllInfosMatchingName(name, matching_proc_infos);
431 if (num_matching_proc_infos == 0) {
432 DNBLogError("error: no processes match '%s'\n", name);
Jason Molenda752e1e82015-07-29 01:42:16 +0000433 return INVALID_NUB_PROCESS;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000434 } else if (num_matching_proc_infos > 1) {
435 DNBLogError("error: %llu processes match '%s':\n",
436 (uint64_t)num_matching_proc_infos, name);
437 size_t i;
438 for (i = 0; i < num_matching_proc_infos; ++i)
439 DNBLogError("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid,
440 matching_proc_infos[i].kp_proc.p_comm);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000441 return INVALID_NUB_PROCESS;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000442 }
443
444 return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout,
445 err_str, err_len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000446}
447
Kate Stoneb9c1b512016-09-06 20:57:50 +0000448nub_process_t DNBProcessAttach(nub_process_t attach_pid,
449 struct timespec *timeout, char *err_str,
450 size_t err_len) {
451 if (err_str && err_len > 0)
452 err_str[0] = '\0';
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000453
Kate Stoneb9c1b512016-09-06 20:57:50 +0000454 pid_t pid = INVALID_NUB_PROCESS;
455 MachProcessSP processSP(new MachProcess);
456 if (processSP.get()) {
457 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...",
458 attach_pid);
459 pid = processSP->AttachForDebug(attach_pid, err_str, err_len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000460
Kate Stoneb9c1b512016-09-06 20:57:50 +0000461 if (pid != INVALID_NUB_PROCESS) {
462 bool res = AddProcessToMap(pid, processSP);
463 UNUSED_IF_ASSERT_DISABLED(res);
464 assert(res && "Couldn't add process to map!");
465 spawn_waitpid_thread(pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000466 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000467 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000468
Kate Stoneb9c1b512016-09-06 20:57:50 +0000469 while (pid != INVALID_NUB_PROCESS) {
470 // Wait for process to start up and hit entry point
471 DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
472 "eEventProcessRunningStateChanged | "
473 "eEventProcessStoppedStateChanged, true, "
474 "INFINITE)...",
475 __FUNCTION__, pid);
476 nub_event_t set_events =
477 DNBProcessWaitForEvents(pid, eEventProcessRunningStateChanged |
478 eEventProcessStoppedStateChanged,
479 true, timeout);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000480
Kate Stoneb9c1b512016-09-06 20:57:50 +0000481 DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
482 "eEventProcessRunningStateChanged | "
483 "eEventProcessStoppedStateChanged, true, "
484 "INFINITE) => 0x%8.8x",
485 __FUNCTION__, pid, set_events);
486
487 if (set_events == 0) {
488 if (err_str && err_len > 0)
489 snprintf(err_str, err_len, "operation timed out");
490 pid = INVALID_NUB_PROCESS;
491 } else {
492 if (set_events & (eEventProcessRunningStateChanged |
493 eEventProcessStoppedStateChanged)) {
494 nub_state_t pid_state = DNBProcessGetState(pid);
495 DNBLogThreadedIf(
496 LOG_PROCESS,
497 "%s process %4.4x state changed (eEventProcessStateChanged): %s",
498 __FUNCTION__, pid, DNBStateAsString(pid_state));
499
500 switch (pid_state) {
501 case eStateInvalid:
502 case eStateUnloaded:
503 case eStateAttaching:
504 case eStateLaunching:
505 case eStateSuspended:
506 break; // Ignore
507
508 case eStateRunning:
509 case eStateStepping:
510 // Still waiting to stop at entry point...
511 break;
512
513 case eStateStopped:
514 case eStateCrashed:
515 return pid;
516
517 case eStateDetached:
518 case eStateExited:
519 if (err_str && err_len > 0)
520 snprintf(err_str, err_len, "process exited");
521 return INVALID_NUB_PROCESS;
522 }
523 }
524
525 DNBProcessResetEvents(pid, set_events);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000526 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000527 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000528
Kate Stoneb9c1b512016-09-06 20:57:50 +0000529 return INVALID_NUB_PROCESS;
530}
531
532size_t GetAllInfos(std::vector<struct kinfo_proc> &proc_infos) {
533 size_t size = 0;
534 int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
535 u_int namelen = sizeof(name) / sizeof(int);
536 int err;
537
538 // Try to find out how many processes are around so we can
539 // size the buffer appropriately. sysctl's man page specifically suggests
540 // this approach, and says it returns a bit larger size than needed to
541 // handle any new processes created between then and now.
542
543 err = ::sysctl(name, namelen, NULL, &size, NULL, 0);
544
545 if ((err < 0) && (err != ENOMEM)) {
546 proc_infos.clear();
547 perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)");
548 return 0;
549 }
550
551 // Increase the size of the buffer by a few processes in case more have
552 // been spawned
553 proc_infos.resize(size / sizeof(struct kinfo_proc));
554 size = proc_infos.size() *
555 sizeof(struct kinfo_proc); // Make sure we don't exceed our resize...
556 err = ::sysctl(name, namelen, &proc_infos[0], &size, NULL, 0);
557 if (err < 0) {
558 proc_infos.clear();
559 return 0;
560 }
561
562 // Trim down our array to fit what we actually got back
563 proc_infos.resize(size / sizeof(struct kinfo_proc));
564 return proc_infos.size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000565}
566
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000567static size_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000568GetAllInfosMatchingName(const char *full_process_name,
569 std::vector<struct kinfo_proc> &matching_proc_infos) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000570
Kate Stoneb9c1b512016-09-06 20:57:50 +0000571 matching_proc_infos.clear();
572 if (full_process_name && full_process_name[0]) {
573 // We only get the process name, not the full path, from the proc_info. So
574 // just take the
575 // base name of the process name...
576 const char *process_name;
577 process_name = strrchr(full_process_name, '/');
578 if (process_name == NULL)
579 process_name = full_process_name;
580 else
581 process_name++;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000582
Kate Stoneb9c1b512016-09-06 20:57:50 +0000583 const size_t process_name_len = strlen(process_name);
584 std::vector<struct kinfo_proc> proc_infos;
585 const size_t num_proc_infos = GetAllInfos(proc_infos);
586 if (num_proc_infos > 0) {
587 uint32_t i;
588 for (i = 0; i < num_proc_infos; i++) {
589 // Skip zombie processes and processes with unset status
590 if (proc_infos[i].kp_proc.p_stat == 0 ||
591 proc_infos[i].kp_proc.p_stat == SZOMB)
592 continue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000593
Kate Stoneb9c1b512016-09-06 20:57:50 +0000594 // Check for process by name. We only check the first MAXCOMLEN
595 // chars as that is all that kp_proc.p_comm holds.
Greg Clayton7dab2be2012-07-19 02:45:35 +0000596
Kate Stoneb9c1b512016-09-06 20:57:50 +0000597 if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm,
598 MAXCOMLEN) == 0) {
599 if (process_name_len > MAXCOMLEN) {
600 // We found a matching process name whose first MAXCOMLEN
601 // characters match, but there is more to the name than
602 // this. We need to get the full process name. Use proc_pidpath,
603 // which will get
604 // us the full path to the executed process.
Greg Clayton7dab2be2012-07-19 02:45:35 +0000605
Kate Stoneb9c1b512016-09-06 20:57:50 +0000606 char proc_path_buf[PATH_MAX];
607
608 int return_val = proc_pidpath(proc_infos[i].kp_proc.p_pid,
609 proc_path_buf, PATH_MAX);
610 if (return_val > 0) {
611 // Okay, now search backwards from that to see if there is a
612 // slash in the name. Note, even though we got all the args we
613 // don't care
614 // because the list data is just a bunch of concatenated null
615 // terminated strings
616 // so strrchr will start from the end of argv0.
617
618 const char *argv_basename = strrchr(proc_path_buf, '/');
619 if (argv_basename) {
620 // Skip the '/'
621 ++argv_basename;
622 } else {
623 // We didn't find a directory delimiter in the process argv[0],
624 // just use what was in there
625 argv_basename = proc_path_buf;
626 }
627
628 if (argv_basename) {
629 if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0) {
630 matching_proc_infos.push_back(proc_infos[i]);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000631 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000632 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000633 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000634 } else {
635 // We found a matching process, add it to our list
636 matching_proc_infos.push_back(proc_infos[i]);
637 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000638 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000639 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000640 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000641 }
642 // return the newly added matches.
643 return matching_proc_infos.size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000644}
645
Kate Stoneb9c1b512016-09-06 20:57:50 +0000646nub_process_t DNBProcessAttachWait(
647 const char *waitfor_process_name, nub_launch_flavor_t launch_flavor,
648 bool ignore_existing, struct timespec *timeout_abstime,
649 useconds_t waitfor_interval, char *err_str, size_t err_len,
650 DNBShouldCancelCallback should_cancel_callback, void *callback_data) {
651 DNBError prepare_error;
652 std::vector<struct kinfo_proc> exclude_proc_infos;
653 size_t num_exclude_proc_infos;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000654
Kate Stoneb9c1b512016-09-06 20:57:50 +0000655 // If the PrepareForAttach returns a valid token, use MachProcess to check
656 // for the process, otherwise scan the process table.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000657
Kate Stoneb9c1b512016-09-06 20:57:50 +0000658 const void *attach_token = MachProcess::PrepareForAttach(
659 waitfor_process_name, launch_flavor, true, prepare_error);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000660
Kate Stoneb9c1b512016-09-06 20:57:50 +0000661 if (prepare_error.Fail()) {
662 DNBLogError("Error in PrepareForAttach: %s", prepare_error.AsString());
663 return INVALID_NUB_PROCESS;
664 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000665
Kate Stoneb9c1b512016-09-06 20:57:50 +0000666 if (attach_token == NULL) {
667 if (ignore_existing)
668 num_exclude_proc_infos =
669 GetAllInfosMatchingName(waitfor_process_name, exclude_proc_infos);
670 else
671 num_exclude_proc_infos = 0;
672 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000673
Kate Stoneb9c1b512016-09-06 20:57:50 +0000674 DNBLogThreadedIf(LOG_PROCESS, "Waiting for '%s' to appear...\n",
675 waitfor_process_name);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000676
Kate Stoneb9c1b512016-09-06 20:57:50 +0000677 // Loop and try to find the process by name
678 nub_process_t waitfor_pid = INVALID_NUB_PROCESS;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000679
Kate Stoneb9c1b512016-09-06 20:57:50 +0000680 while (waitfor_pid == INVALID_NUB_PROCESS) {
681 if (attach_token != NULL) {
682 nub_process_t pid;
683 pid = MachProcess::CheckForProcess(attach_token, launch_flavor);
684 if (pid != INVALID_NUB_PROCESS) {
685 waitfor_pid = pid;
686 break;
687 }
688 } else {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000689
Kate Stoneb9c1b512016-09-06 20:57:50 +0000690 // Get the current process list, and check for matches that
691 // aren't in our original list. If anyone wants to attach
692 // to an existing process by name, they should do it with
693 // --attach=PROCNAME. Else we will wait for the first matching
694 // process that wasn't in our exclusion list.
695 std::vector<struct kinfo_proc> proc_infos;
696 const size_t num_proc_infos =
697 GetAllInfosMatchingName(waitfor_process_name, proc_infos);
698 for (size_t i = 0; i < num_proc_infos; i++) {
699 nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid;
700 for (size_t j = 0; j < num_exclude_proc_infos; j++) {
701 if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid) {
702 // This process was in our exclusion list, don't use it.
703 curr_pid = INVALID_NUB_PROCESS;
704 break;
705 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000706 }
707
Kate Stoneb9c1b512016-09-06 20:57:50 +0000708 // If we didn't find CURR_PID in our exclusion list, then use it.
709 if (curr_pid != INVALID_NUB_PROCESS) {
710 // We found our process!
711 waitfor_pid = curr_pid;
712 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000713 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000714 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000715 }
716
Kate Stoneb9c1b512016-09-06 20:57:50 +0000717 // If we haven't found our process yet, check for a timeout
718 // and then sleep for a bit until we poll again.
719 if (waitfor_pid == INVALID_NUB_PROCESS) {
720 if (timeout_abstime != NULL) {
721 // Check to see if we have a waitfor-duration option that
722 // has timed out?
723 if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime)) {
724 if (err_str && err_len > 0)
725 snprintf(err_str, err_len, "operation timed out");
726 DNBLogError("error: waiting for process '%s' timed out.\n",
727 waitfor_process_name);
728 return INVALID_NUB_PROCESS;
729 }
730 }
731
732 // Call the should cancel callback as well...
733
734 if (should_cancel_callback != NULL &&
735 should_cancel_callback(callback_data)) {
736 DNBLogThreadedIf(
737 LOG_PROCESS,
738 "DNBProcessAttachWait cancelled by should_cancel callback.");
739 waitfor_pid = INVALID_NUB_PROCESS;
740 break;
741 }
742
743 ::usleep(waitfor_interval); // Sleep for WAITFOR_INTERVAL, then poll again
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000744 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000745 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000746
Kate Stoneb9c1b512016-09-06 20:57:50 +0000747 if (waitfor_pid != INVALID_NUB_PROCESS) {
748 DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n",
749 waitfor_process_name, waitfor_pid);
750 waitfor_pid =
751 DNBProcessAttach(waitfor_pid, timeout_abstime, err_str, err_len);
752 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000753
Kate Stoneb9c1b512016-09-06 20:57:50 +0000754 bool success = waitfor_pid != INVALID_NUB_PROCESS;
755 MachProcess::CleanupAfterAttach(attach_token, launch_flavor, success,
756 prepare_error);
757
758 return waitfor_pid;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000759}
760
Kate Stoneb9c1b512016-09-06 20:57:50 +0000761nub_bool_t DNBProcessDetach(nub_process_t pid) {
762 MachProcessSP procSP;
763 if (GetProcessSP(pid, procSP)) {
764 const bool remove = true;
765 DNBLogThreaded(
766 "Disabling breakpoints and watchpoints, and detaching from %d.", pid);
767 procSP->DisableAllBreakpoints(remove);
768 procSP->DisableAllWatchpoints(remove);
769 return procSP->Detach();
770 }
771 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000772}
773
Kate Stoneb9c1b512016-09-06 20:57:50 +0000774nub_bool_t DNBProcessKill(nub_process_t pid) {
775 MachProcessSP procSP;
776 if (GetProcessSP(pid, procSP)) {
777 return procSP->Kill();
778 }
779 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000780}
781
Kate Stoneb9c1b512016-09-06 20:57:50 +0000782nub_bool_t DNBProcessSignal(nub_process_t pid, int signal) {
783 MachProcessSP procSP;
784 if (GetProcessSP(pid, procSP)) {
785 return procSP->Signal(signal);
786 }
787 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000788}
789
Kate Stoneb9c1b512016-09-06 20:57:50 +0000790nub_bool_t DNBProcessInterrupt(nub_process_t pid) {
791 MachProcessSP procSP;
792 if (GetProcessSP(pid, procSP))
793 return procSP->Interrupt();
794 return false;
Greg Clayton4296c222014-04-24 19:54:32 +0000795}
796
Kate Stoneb9c1b512016-09-06 20:57:50 +0000797nub_bool_t DNBProcessSendEvent(nub_process_t pid, const char *event) {
798 MachProcessSP procSP;
799 if (GetProcessSP(pid, procSP)) {
800 // FIXME: Do something with the error...
801 DNBError send_error;
802 return procSP->SendEvent(event, send_error);
803 }
804 return false;
Jason Molendaa3329782014-03-29 18:54:20 +0000805}
806
Kate Stoneb9c1b512016-09-06 20:57:50 +0000807nub_bool_t DNBProcessIsAlive(nub_process_t pid) {
808 MachProcessSP procSP;
809 if (GetProcessSP(pid, procSP)) {
810 return MachTask::IsValid(procSP->Task().TaskPort());
811 }
812 return eStateInvalid;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000813}
814
815//----------------------------------------------------------------------
816// Process and Thread state information
817//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000818nub_state_t DNBProcessGetState(nub_process_t pid) {
819 MachProcessSP procSP;
820 if (GetProcessSP(pid, procSP)) {
821 return procSP->GetState();
822 }
823 return eStateInvalid;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000824}
825
826//----------------------------------------------------------------------
827// Process and Thread state information
828//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000829nub_bool_t DNBProcessGetExitStatus(nub_process_t pid, int *status) {
830 MachProcessSP procSP;
831 if (GetProcessSP(pid, procSP)) {
832 return procSP->GetExitStatus(status);
833 }
834 return false;
835}
836
837nub_bool_t DNBProcessSetExitStatus(nub_process_t pid, int status) {
838 MachProcessSP procSP;
839 if (GetProcessSP(pid, procSP)) {
840 procSP->SetExitStatus(status);
841 return true;
842 }
843 return false;
844}
845
846const char *DNBProcessGetExitInfo(nub_process_t pid) {
847 MachProcessSP procSP;
848 if (GetProcessSP(pid, procSP)) {
849 return procSP->GetExitInfo();
850 }
851 return NULL;
852}
853
854nub_bool_t DNBProcessSetExitInfo(nub_process_t pid, const char *info) {
855 MachProcessSP procSP;
856 if (GetProcessSP(pid, procSP)) {
857 procSP->SetExitInfo(info);
858 return true;
859 }
860 return false;
861}
862
863const char *DNBThreadGetName(nub_process_t pid, nub_thread_t tid) {
864 MachProcessSP procSP;
865 if (GetProcessSP(pid, procSP))
866 return procSP->ThreadGetName(tid);
867 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000868}
869
870nub_bool_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000871DNBThreadGetIdentifierInfo(nub_process_t pid, nub_thread_t tid,
872 thread_identifier_info_data_t *ident_info) {
873 MachProcessSP procSP;
874 if (GetProcessSP(pid, procSP))
875 return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info);
876 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000877}
878
Kate Stoneb9c1b512016-09-06 20:57:50 +0000879nub_state_t DNBThreadGetState(nub_process_t pid, nub_thread_t tid) {
880 MachProcessSP procSP;
881 if (GetProcessSP(pid, procSP)) {
882 return procSP->ThreadGetState(tid);
883 }
884 return eStateInvalid;
Jason Molendaa3329782014-03-29 18:54:20 +0000885}
886
Kate Stoneb9c1b512016-09-06 20:57:50 +0000887const char *DNBStateAsString(nub_state_t state) {
888 switch (state) {
889 case eStateInvalid:
890 return "Invalid";
891 case eStateUnloaded:
892 return "Unloaded";
893 case eStateAttaching:
894 return "Attaching";
895 case eStateLaunching:
896 return "Launching";
897 case eStateStopped:
898 return "Stopped";
899 case eStateRunning:
900 return "Running";
901 case eStateStepping:
902 return "Stepping";
903 case eStateCrashed:
904 return "Crashed";
905 case eStateDetached:
906 return "Detached";
907 case eStateExited:
908 return "Exited";
909 case eStateSuspended:
910 return "Suspended";
911 }
912 return "nub_state_t ???";
Jason Molendaa3329782014-03-29 18:54:20 +0000913}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000914
Kate Stoneb9c1b512016-09-06 20:57:50 +0000915Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread(nub_process_t pid,
916 nub_thread_t tid,
917 bool &timed_out) {
918 Genealogy::ThreadActivitySP thread_activity_sp;
919 MachProcessSP procSP;
920 if (GetProcessSP(pid, procSP))
921 thread_activity_sp = procSP->GetGenealogyInfoForThread(tid, timed_out);
922 return thread_activity_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000923}
924
Kate Stoneb9c1b512016-09-06 20:57:50 +0000925Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo(nub_process_t pid,
926 size_t idx) {
927 Genealogy::ProcessExecutableInfoSP image_info_sp;
928 MachProcessSP procSP;
929 if (GetProcessSP(pid, procSP)) {
930 image_info_sp = procSP->GetGenealogyImageInfo(idx);
931 }
932 return image_info_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000933}
934
Kate Stoneb9c1b512016-09-06 20:57:50 +0000935ThreadInfo::QoS DNBGetRequestedQoSForThread(nub_process_t pid, nub_thread_t tid,
936 nub_addr_t tsd,
937 uint64_t dti_qos_class_index) {
938 MachProcessSP procSP;
939 if (GetProcessSP(pid, procSP)) {
940 return procSP->GetRequestedQoS(tid, tsd, dti_qos_class_index);
941 }
942 return ThreadInfo::QoS();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000943}
944
Kate Stoneb9c1b512016-09-06 20:57:50 +0000945nub_addr_t DNBGetPThreadT(nub_process_t pid, nub_thread_t tid) {
946 MachProcessSP procSP;
947 if (GetProcessSP(pid, procSP)) {
948 return procSP->GetPThreadT(tid);
949 }
950 return INVALID_NUB_ADDRESS;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000951}
952
Kate Stoneb9c1b512016-09-06 20:57:50 +0000953nub_addr_t DNBGetDispatchQueueT(nub_process_t pid, nub_thread_t tid) {
954 MachProcessSP procSP;
955 if (GetProcessSP(pid, procSP)) {
956 return procSP->GetDispatchQueueT(tid);
957 }
958 return INVALID_NUB_ADDRESS;
Jason Molenda705b1802014-06-13 02:37:02 +0000959}
960
961nub_addr_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000962DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid,
963 uint64_t plo_pthread_tsd_base_address_offset,
964 uint64_t plo_pthread_tsd_base_offset,
965 uint64_t plo_pthread_tsd_entry_size) {
966 MachProcessSP procSP;
967 if (GetProcessSP(pid, procSP)) {
968 return procSP->GetTSDAddressForThread(
969 tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset,
970 plo_pthread_tsd_entry_size);
971 }
972 return INVALID_NUB_ADDRESS;
Jason Molenda705b1802014-06-13 02:37:02 +0000973}
974
Kate Stoneb9c1b512016-09-06 20:57:50 +0000975JSONGenerator::ObjectSP DNBGetLoadedDynamicLibrariesInfos(
976 nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) {
977 MachProcessSP procSP;
978 if (GetProcessSP(pid, procSP)) {
979 return procSP->GetLoadedDynamicLibrariesInfos(pid, image_list_address,
980 image_count);
981 }
982 return JSONGenerator::ObjectSP();
Jason Molenda705b1802014-06-13 02:37:02 +0000983}
984
Kate Stoneb9c1b512016-09-06 20:57:50 +0000985JSONGenerator::ObjectSP DNBGetAllLoadedLibrariesInfos(nub_process_t pid) {
986 MachProcessSP procSP;
987 if (GetProcessSP(pid, procSP)) {
988 return procSP->GetAllLoadedLibrariesInfos(pid);
989 }
990 return JSONGenerator::ObjectSP();
Jason Molenda705b1802014-06-13 02:37:02 +0000991}
992
Kate Stoneb9c1b512016-09-06 20:57:50 +0000993JSONGenerator::ObjectSP
994DNBGetLibrariesInfoForAddresses(nub_process_t pid,
995 std::vector<uint64_t> &macho_addresses) {
996 MachProcessSP procSP;
997 if (GetProcessSP(pid, procSP)) {
998 return procSP->GetLibrariesInfoForAddresses(pid, macho_addresses);
999 }
1000 return JSONGenerator::ObjectSP();
Jason Molenda20ee21b2015-07-10 23:15:22 +00001001}
1002
Kate Stoneb9c1b512016-09-06 20:57:50 +00001003JSONGenerator::ObjectSP DNBGetSharedCacheInfo(nub_process_t pid) {
1004 MachProcessSP procSP;
1005 if (GetProcessSP(pid, procSP)) {
1006 return procSP->GetSharedCacheInfo(pid);
1007 }
1008 return JSONGenerator::ObjectSP();
Jason Molendaa2992312016-07-07 01:09:23 +00001009}
1010
Kate Stoneb9c1b512016-09-06 20:57:50 +00001011const char *DNBProcessGetExecutablePath(nub_process_t pid) {
1012 MachProcessSP procSP;
1013 if (GetProcessSP(pid, procSP)) {
1014 return procSP->Path();
1015 }
1016 return NULL;
Jason Molendaa2992312016-07-07 01:09:23 +00001017}
1018
Kate Stoneb9c1b512016-09-06 20:57:50 +00001019nub_size_t DNBProcessGetArgumentCount(nub_process_t pid) {
1020 MachProcessSP procSP;
1021 if (GetProcessSP(pid, procSP)) {
1022 return procSP->ArgumentCount();
1023 }
1024 return 0;
Jason Molendaa2992312016-07-07 01:09:23 +00001025}
1026
Kate Stoneb9c1b512016-09-06 20:57:50 +00001027const char *DNBProcessGetArgumentAtIndex(nub_process_t pid, nub_size_t idx) {
1028 MachProcessSP procSP;
1029 if (GetProcessSP(pid, procSP)) {
1030 return procSP->ArgumentAtIndex(idx);
1031 }
1032 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001033}
1034
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001035//----------------------------------------------------------------------
1036// Execution control
1037//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001038nub_bool_t DNBProcessResume(nub_process_t pid,
1039 const DNBThreadResumeAction *actions,
1040 size_t num_actions) {
1041 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
1042 MachProcessSP procSP;
1043 if (GetProcessSP(pid, procSP)) {
1044 DNBThreadResumeActions thread_actions(actions, num_actions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001045
Kate Stoneb9c1b512016-09-06 20:57:50 +00001046 // Below we add a default thread plan just in case one wasn't
1047 // provided so all threads always know what they were supposed to do
1048 if (thread_actions.IsEmpty()) {
1049 // No thread plans were given, so the default it to run all threads
1050 thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0);
1051 } else {
1052 // Some thread plans were given which means anything that wasn't
1053 // specified should remain stopped.
1054 thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001055 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001056 return procSP->Resume(thread_actions);
1057 }
1058 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001059}
1060
Kate Stoneb9c1b512016-09-06 20:57:50 +00001061nub_bool_t DNBProcessHalt(nub_process_t pid) {
1062 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
1063 MachProcessSP procSP;
1064 if (GetProcessSP(pid, procSP))
1065 return procSP->Signal(SIGSTOP);
1066 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001067}
1068//
Kate Stoneb9c1b512016-09-06 20:57:50 +00001069// nub_bool_t
1070// DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001071//{
Kate Stoneb9c1b512016-09-06 20:57:50 +00001072// DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)",
1073// __FUNCTION__, pid, tid, (uint32_t)step);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001074// MachProcessSP procSP;
1075// if (GetProcessSP (pid, procSP))
1076// {
1077// return procSP->Resume(tid, step, 0);
1078// }
1079// return false;
1080//}
1081//
Kate Stoneb9c1b512016-09-06 20:57:50 +00001082// nub_bool_t
1083// DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t
1084// step, int signal)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001085//{
Kate Stoneb9c1b512016-09-06 20:57:50 +00001086// DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u,
1087// signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001088// MachProcessSP procSP;
1089// if (GetProcessSP (pid, procSP))
1090// {
1091// return procSP->Resume(tid, step, signal);
1092// }
1093// return false;
1094//}
1095
Kate Stoneb9c1b512016-09-06 20:57:50 +00001096nub_event_t DNBProcessWaitForEvents(nub_process_t pid, nub_event_t event_mask,
1097 bool wait_for_set,
1098 struct timespec *timeout) {
1099 nub_event_t result = 0;
1100 MachProcessSP procSP;
1101 if (GetProcessSP(pid, procSP)) {
1102 if (wait_for_set)
1103 result = procSP->Events().WaitForSetEvents(event_mask, timeout);
1104 else
1105 result = procSP->Events().WaitForEventsToReset(event_mask, timeout);
1106 }
1107 return result;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001108}
1109
Kate Stoneb9c1b512016-09-06 20:57:50 +00001110void DNBProcessResetEvents(nub_process_t pid, nub_event_t event_mask) {
1111 MachProcessSP procSP;
1112 if (GetProcessSP(pid, procSP))
1113 procSP->Events().ResetEvents(event_mask);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001114}
1115
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001116// Breakpoints
Kate Stoneb9c1b512016-09-06 20:57:50 +00001117nub_bool_t DNBBreakpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1118 nub_bool_t hardware) {
1119 MachProcessSP procSP;
1120 if (GetProcessSP(pid, procSP))
1121 return procSP->CreateBreakpoint(addr, size, hardware) != NULL;
1122 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001123}
1124
Kate Stoneb9c1b512016-09-06 20:57:50 +00001125nub_bool_t DNBBreakpointClear(nub_process_t pid, nub_addr_t addr) {
1126 MachProcessSP procSP;
1127 if (GetProcessSP(pid, procSP))
1128 return procSP->DisableBreakpoint(addr, true);
1129 return false; // Failed
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001130}
1131
1132//----------------------------------------------------------------------
1133// Watchpoints
1134//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001135nub_bool_t DNBWatchpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1136 uint32_t watch_flags, nub_bool_t hardware) {
1137 MachProcessSP procSP;
1138 if (GetProcessSP(pid, procSP))
1139 return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL;
1140 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001141}
1142
Kate Stoneb9c1b512016-09-06 20:57:50 +00001143nub_bool_t DNBWatchpointClear(nub_process_t pid, nub_addr_t addr) {
1144 MachProcessSP procSP;
1145 if (GetProcessSP(pid, procSP))
1146 return procSP->DisableWatchpoint(addr, true);
1147 return false; // Failed
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001148}
1149
1150//----------------------------------------------------------------------
Johnny Chen64637202012-05-23 21:09:52 +00001151// Return the number of supported hardware watchpoints.
1152//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001153uint32_t DNBWatchpointGetNumSupportedHWP(nub_process_t pid) {
1154 MachProcessSP procSP;
1155 if (GetProcessSP(pid, procSP))
1156 return procSP->GetNumSupportedHardwareWatchpoints();
1157 return 0;
Johnny Chen64637202012-05-23 21:09:52 +00001158}
1159
1160//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001161// Read memory in the address space of process PID. This call will take
1162// care of setting and restoring permissions and breaking up the memory
1163// read into multiple chunks as required.
1164//
1165// RETURNS: number of bytes actually read
1166//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001167nub_size_t DNBProcessMemoryRead(nub_process_t pid, nub_addr_t addr,
1168 nub_size_t size, void *buf) {
1169 MachProcessSP procSP;
1170 if (GetProcessSP(pid, procSP))
1171 return procSP->ReadMemory(addr, size, buf);
1172 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001173}
1174
Kate Stoneb9c1b512016-09-06 20:57:50 +00001175uint64_t DNBProcessMemoryReadInteger(nub_process_t pid, nub_addr_t addr,
1176 nub_size_t integer_size,
1177 uint64_t fail_value) {
1178 union Integers {
1179 uint8_t u8;
1180 uint16_t u16;
1181 uint32_t u32;
1182 uint64_t u64;
1183 };
Greg Clayton0b90be12015-06-23 21:27:50 +00001184
Kate Stoneb9c1b512016-09-06 20:57:50 +00001185 if (integer_size <= sizeof(uint64_t)) {
1186 Integers ints;
1187 if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size) {
1188 switch (integer_size) {
1189 case 1:
1190 return ints.u8;
1191 case 2:
1192 return ints.u16;
1193 case 3:
1194 return ints.u32 & 0xffffffu;
1195 case 4:
1196 return ints.u32;
1197 case 5:
1198 return ints.u32 & 0x000000ffffffffffull;
1199 case 6:
1200 return ints.u32 & 0x0000ffffffffffffull;
1201 case 7:
1202 return ints.u32 & 0x00ffffffffffffffull;
1203 case 8:
1204 return ints.u64;
1205 }
Greg Clayton0b90be12015-06-23 21:27:50 +00001206 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001207 }
1208 return fail_value;
Greg Clayton0b90be12015-06-23 21:27:50 +00001209}
1210
Kate Stoneb9c1b512016-09-06 20:57:50 +00001211nub_addr_t DNBProcessMemoryReadPointer(nub_process_t pid, nub_addr_t addr) {
1212 cpu_type_t cputype = DNBProcessGetCPUType(pid);
1213 if (cputype) {
1214 const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4;
1215 return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0);
1216 }
1217 return 0;
Greg Clayton0b90be12015-06-23 21:27:50 +00001218}
1219
Kate Stoneb9c1b512016-09-06 20:57:50 +00001220std::string DNBProcessMemoryReadCString(nub_process_t pid, nub_addr_t addr) {
1221 std::string cstr;
1222 char buffer[256];
1223 const nub_size_t max_buffer_cstr_length = sizeof(buffer) - 1;
1224 buffer[max_buffer_cstr_length] = '\0';
1225 nub_size_t length = 0;
1226 nub_addr_t curr_addr = addr;
1227 do {
1228 nub_size_t bytes_read =
1229 DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer);
1230 if (bytes_read == 0)
1231 break;
1232 length = strlen(buffer);
1233 cstr.append(buffer, length);
1234 curr_addr += length;
1235 } while (length == max_buffer_cstr_length);
1236 return cstr;
Greg Clayton0b90be12015-06-23 21:27:50 +00001237}
1238
Kate Stoneb9c1b512016-09-06 20:57:50 +00001239std::string DNBProcessMemoryReadCStringFixed(nub_process_t pid, nub_addr_t addr,
1240 nub_size_t fixed_length) {
1241 std::string cstr;
1242 char buffer[fixed_length + 1];
1243 buffer[fixed_length] = '\0';
1244 nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer);
1245 if (bytes_read > 0)
1246 cstr.assign(buffer);
1247 return cstr;
Greg Clayton0b90be12015-06-23 21:27:50 +00001248}
1249
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001250//----------------------------------------------------------------------
1251// Write memory to the address space of process PID. This call will take
1252// care of setting and restoring permissions and breaking up the memory
1253// write into multiple chunks as required.
1254//
1255// RETURNS: number of bytes actually written
1256//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001257nub_size_t DNBProcessMemoryWrite(nub_process_t pid, nub_addr_t addr,
1258 nub_size_t size, const void *buf) {
1259 MachProcessSP procSP;
1260 if (GetProcessSP(pid, procSP))
1261 return procSP->WriteMemory(addr, size, buf);
1262 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001263}
1264
Kate Stoneb9c1b512016-09-06 20:57:50 +00001265nub_addr_t DNBProcessMemoryAllocate(nub_process_t pid, nub_size_t size,
1266 uint32_t permissions) {
1267 MachProcessSP procSP;
1268 if (GetProcessSP(pid, procSP))
1269 return procSP->Task().AllocateMemory(size, permissions);
1270 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001271}
1272
Kate Stoneb9c1b512016-09-06 20:57:50 +00001273nub_bool_t DNBProcessMemoryDeallocate(nub_process_t pid, nub_addr_t addr) {
1274 MachProcessSP procSP;
1275 if (GetProcessSP(pid, procSP))
1276 return procSP->Task().DeallocateMemory(addr);
1277 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001278}
1279
Jason Molenda1f3966b2011-11-08 04:28:12 +00001280//----------------------------------------------------------------------
Jason Molenda3dc85832011-11-09 08:03:56 +00001281// Find attributes of the memory region that contains ADDR for process PID,
1282// if possible, and return a string describing those attributes.
Jason Molenda1f3966b2011-11-08 04:28:12 +00001283//
Jason Molenda3dc85832011-11-09 08:03:56 +00001284// Returns 1 if we could find attributes for this region and OUTBUF can
1285// be sent to the remote debugger.
Jason Molenda1f3966b2011-11-08 04:28:12 +00001286//
Jason Molenda3dc85832011-11-09 08:03:56 +00001287// Returns 0 if we couldn't find the attributes for a region of memory at
1288// that address and OUTBUF should not be sent.
1289//
1290// Returns -1 if this platform cannot look up information about memory regions
1291// or if we do not yet have a valid launched process.
1292//
Jason Molenda1f3966b2011-11-08 04:28:12 +00001293//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001294int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr,
1295 DNBRegionInfo *region_info) {
1296 MachProcessSP procSP;
1297 if (GetProcessSP(pid, procSP))
1298 return procSP->Task().GetMemoryRegionInfo(addr, region_info);
Greg Clayton46fb5582011-11-18 07:03:08 +00001299
Kate Stoneb9c1b512016-09-06 20:57:50 +00001300 return -1;
Jason Molenda1f3966b2011-11-08 04:28:12 +00001301}
1302
Kate Stoneb9c1b512016-09-06 20:57:50 +00001303std::string DNBProcessGetProfileData(nub_process_t pid,
1304 DNBProfileDataScanType scanType) {
1305 MachProcessSP procSP;
1306 if (GetProcessSP(pid, procSP))
1307 return procSP->Task().GetProfileData(scanType);
1308
1309 return std::string("");
Han Ming Ongab3b8b22012-11-17 00:21:04 +00001310}
1311
Kate Stoneb9c1b512016-09-06 20:57:50 +00001312nub_bool_t DNBProcessSetEnableAsyncProfiling(nub_process_t pid,
1313 nub_bool_t enable,
1314 uint64_t interval_usec,
1315 DNBProfileDataScanType scan_type) {
1316 MachProcessSP procSP;
1317 if (GetProcessSP(pid, procSP)) {
1318 procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type);
1319 return true;
1320 }
1321
1322 return false;
Han Ming Ongab3b8b22012-11-17 00:21:04 +00001323}
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001324
1325//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001326// Get the number of threads for the specified process.
1327//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001328nub_size_t DNBProcessGetNumThreads(nub_process_t pid) {
1329 MachProcessSP procSP;
1330 if (GetProcessSP(pid, procSP))
1331 return procSP->GetNumThreads();
1332 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001333}
1334
1335//----------------------------------------------------------------------
1336// Get the thread ID of the current thread.
1337//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001338nub_thread_t DNBProcessGetCurrentThread(nub_process_t pid) {
1339 MachProcessSP procSP;
1340 if (GetProcessSP(pid, procSP))
1341 return procSP->GetCurrentThread();
1342 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001343}
1344
1345//----------------------------------------------------------------------
Jason Molendad5318c02013-04-03 04:18:47 +00001346// Get the mach port number of the current thread.
1347//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001348nub_thread_t DNBProcessGetCurrentThreadMachPort(nub_process_t pid) {
1349 MachProcessSP procSP;
1350 if (GetProcessSP(pid, procSP))
1351 return procSP->GetCurrentThreadMachPort();
1352 return 0;
Jason Molendad5318c02013-04-03 04:18:47 +00001353}
1354
1355//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001356// Change the current thread.
1357//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001358nub_thread_t DNBProcessSetCurrentThread(nub_process_t pid, nub_thread_t tid) {
1359 MachProcessSP procSP;
1360 if (GetProcessSP(pid, procSP))
1361 return procSP->SetCurrentThread(tid);
1362 return INVALID_NUB_THREAD;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001363}
1364
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001365//----------------------------------------------------------------------
1366// Dump a string describing a thread's stop reason to the specified file
1367// handle
1368//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001369nub_bool_t DNBThreadGetStopReason(nub_process_t pid, nub_thread_t tid,
1370 struct DNBThreadStopInfo *stop_info) {
1371 MachProcessSP procSP;
1372 if (GetProcessSP(pid, procSP))
1373 return procSP->GetThreadStoppedReason(tid, stop_info);
1374 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001375}
1376
1377//----------------------------------------------------------------------
1378// Return string description for the specified thread.
1379//
1380// RETURNS: NULL if the thread isn't valid, else a NULL terminated C
1381// string from a static buffer that must be copied prior to subsequent
1382// calls.
1383//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001384const char *DNBThreadGetInfo(nub_process_t pid, nub_thread_t tid) {
1385 MachProcessSP procSP;
1386 if (GetProcessSP(pid, procSP))
1387 return procSP->GetThreadInfo(tid);
1388 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001389}
1390
1391//----------------------------------------------------------------------
1392// Get the thread ID given a thread index.
1393//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001394nub_thread_t DNBProcessGetThreadAtIndex(nub_process_t pid, size_t thread_idx) {
1395 MachProcessSP procSP;
1396 if (GetProcessSP(pid, procSP))
1397 return procSP->GetThreadAtIndex(thread_idx);
1398 return INVALID_NUB_THREAD;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001399}
1400
Jim Ingham279ceec2012-07-25 21:12:43 +00001401//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001402// Do whatever is needed to sync the thread's register state with it's kernel
1403// values.
Jim Ingham279ceec2012-07-25 21:12:43 +00001404//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001405nub_bool_t DNBProcessSyncThreadState(nub_process_t pid, nub_thread_t tid) {
1406 MachProcessSP procSP;
1407 if (GetProcessSP(pid, procSP))
1408 return procSP->SyncThreadState(tid);
1409 return false;
Jim Ingham279ceec2012-07-25 21:12:43 +00001410}
1411
Kate Stoneb9c1b512016-09-06 20:57:50 +00001412nub_addr_t DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid) {
1413 MachProcessSP procSP;
1414 DNBError err;
1415 if (GetProcessSP(pid, procSP))
1416 return procSP->Task().GetDYLDAllImageInfosAddress(err);
1417 return INVALID_NUB_ADDRESS;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001418}
1419
Kate Stoneb9c1b512016-09-06 20:57:50 +00001420nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) {
1421 MachProcessSP procSP;
1422 if (GetProcessSP(pid, procSP)) {
1423 procSP->SharedLibrariesUpdated();
1424 return true;
1425 }
1426 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001427}
1428
1429//----------------------------------------------------------------------
1430// Get the current shared library information for a process. Only return
1431// the shared libraries that have changed since the last shared library
1432// state changed event if only_changed is non-zero.
1433//----------------------------------------------------------------------
1434nub_size_t
Kate Stoneb9c1b512016-09-06 20:57:50 +00001435DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed,
1436 struct DNBExecutableImageInfo **image_infos) {
1437 MachProcessSP procSP;
1438 if (GetProcessSP(pid, procSP))
1439 return procSP->CopyImageInfos(image_infos, only_changed);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001440
Kate Stoneb9c1b512016-09-06 20:57:50 +00001441 // If we have no process, then return NULL for the shared library info
1442 // and zero for shared library count
1443 *image_infos = NULL;
1444 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001445}
1446
Kate Stoneb9c1b512016-09-06 20:57:50 +00001447uint32_t DNBGetRegisterCPUType() {
1448 return DNBArchProtocol::GetRegisterCPUType();
Greg Claytond04f0ed2015-05-26 18:00:51 +00001449}
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001450//----------------------------------------------------------------------
1451// Get the register set information for a specific thread.
1452//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001453const DNBRegisterSetInfo *DNBGetRegisterSetInfo(nub_size_t *num_reg_sets) {
1454 return DNBArchProtocol::GetRegisterSetInfo(num_reg_sets);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001455}
1456
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001457//----------------------------------------------------------------------
1458// Read a register value by register set and register index.
1459//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001460nub_bool_t DNBThreadGetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1461 uint32_t set, uint32_t reg,
1462 DNBRegisterValue *value) {
1463 MachProcessSP procSP;
1464 ::bzero(value, sizeof(DNBRegisterValue));
1465 if (GetProcessSP(pid, procSP)) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001466 if (tid != INVALID_NUB_THREAD)
Kate Stoneb9c1b512016-09-06 20:57:50 +00001467 return procSP->GetRegisterValue(tid, set, reg, value);
1468 }
1469 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001470}
1471
Kate Stoneb9c1b512016-09-06 20:57:50 +00001472nub_bool_t DNBThreadSetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1473 uint32_t set, uint32_t reg,
1474 const DNBRegisterValue *value) {
1475 if (tid != INVALID_NUB_THREAD) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001476 MachProcessSP procSP;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001477 if (GetProcessSP(pid, procSP))
1478 return procSP->SetRegisterValue(tid, set, reg, value);
1479 }
1480 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001481}
1482
Kate Stoneb9c1b512016-09-06 20:57:50 +00001483nub_size_t DNBThreadGetRegisterContext(nub_process_t pid, nub_thread_t tid,
1484 void *buf, size_t buf_len) {
1485 MachProcessSP procSP;
1486 if (GetProcessSP(pid, procSP)) {
1487 if (tid != INVALID_NUB_THREAD)
1488 return procSP->GetThreadList().GetRegisterContext(tid, buf, buf_len);
1489 }
1490 ::bzero(buf, buf_len);
1491 return 0;
1492}
1493
1494nub_size_t DNBThreadSetRegisterContext(nub_process_t pid, nub_thread_t tid,
1495 const void *buf, size_t buf_len) {
1496 MachProcessSP procSP;
1497 if (GetProcessSP(pid, procSP)) {
1498 if (tid != INVALID_NUB_THREAD)
1499 return procSP->GetThreadList().SetRegisterContext(tid, buf, buf_len);
1500 }
1501 return 0;
1502}
1503
1504uint32_t DNBThreadSaveRegisterState(nub_process_t pid, nub_thread_t tid) {
1505 if (tid != INVALID_NUB_THREAD) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001506 MachProcessSP procSP;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001507 if (GetProcessSP(pid, procSP))
1508 return procSP->GetThreadList().SaveRegisterState(tid);
1509 }
1510 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001511}
Kate Stoneb9c1b512016-09-06 20:57:50 +00001512nub_bool_t DNBThreadRestoreRegisterState(nub_process_t pid, nub_thread_t tid,
1513 uint32_t save_id) {
1514 if (tid != INVALID_NUB_THREAD) {
1515 MachProcessSP procSP;
1516 if (GetProcessSP(pid, procSP))
1517 return procSP->GetThreadList().RestoreRegisterState(tid, save_id);
1518 }
1519 return false;
Greg Claytonf74cf862013-11-13 23:28:31 +00001520}
Greg Claytonf74cf862013-11-13 23:28:31 +00001521
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001522//----------------------------------------------------------------------
1523// Read a register value by name.
1524//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001525nub_bool_t DNBThreadGetRegisterValueByName(nub_process_t pid, nub_thread_t tid,
1526 uint32_t reg_set,
1527 const char *reg_name,
1528 DNBRegisterValue *value) {
1529 MachProcessSP procSP;
1530 ::bzero(value, sizeof(DNBRegisterValue));
1531 if (GetProcessSP(pid, procSP)) {
1532 const struct DNBRegisterSetInfo *set_info;
1533 nub_size_t num_reg_sets = 0;
1534 set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1535 if (set_info) {
1536 uint32_t set = reg_set;
1537 uint32_t reg;
1538 if (set == REGISTER_SET_ALL) {
1539 for (set = 1; set < num_reg_sets; ++set) {
1540 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1541 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1542 return procSP->GetRegisterValue(tid, set, reg, value);
1543 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001544 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001545 } else {
1546 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1547 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1548 return procSP->GetRegisterValue(tid, set, reg, value);
1549 }
1550 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001551 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001552 }
1553 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001554}
1555
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001556//----------------------------------------------------------------------
1557// Read a register set and register number from the register name.
1558//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001559nub_bool_t DNBGetRegisterInfoByName(const char *reg_name,
1560 DNBRegisterInfo *info) {
1561 const struct DNBRegisterSetInfo *set_info;
1562 nub_size_t num_reg_sets = 0;
1563 set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1564 if (set_info) {
1565 uint32_t set, reg;
1566 for (set = 1; set < num_reg_sets; ++set) {
1567 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1568 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) {
1569 *info = set_info[set].registers[reg];
1570 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001571 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001572 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001573 }
1574
Kate Stoneb9c1b512016-09-06 20:57:50 +00001575 for (set = 1; set < num_reg_sets; ++set) {
1576 uint32_t reg;
1577 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1578 if (set_info[set].registers[reg].alt == NULL)
1579 continue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001580
Kate Stoneb9c1b512016-09-06 20:57:50 +00001581 if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0) {
1582 *info = set_info[set].registers[reg];
1583 return true;
1584 }
1585 }
1586 }
1587 }
1588
1589 ::bzero(info, sizeof(DNBRegisterInfo));
1590 return false;
1591}
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001592
1593//----------------------------------------------------------------------
1594// Set the name to address callback function that this nub can use
1595// for any name to address lookups that are needed.
1596//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001597nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid,
1598 DNBCallbackNameToAddress callback,
1599 void *baton) {
1600 MachProcessSP procSP;
1601 if (GetProcessSP(pid, procSP)) {
1602 procSP->SetNameToAddressCallback(callback, baton);
1603 return true;
1604 }
1605 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001606}
1607
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001608//----------------------------------------------------------------------
1609// Set the name to address callback function that this nub can use
1610// for any name to address lookups that are needed.
1611//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001612nub_bool_t DNBProcessSetSharedLibraryInfoCallback(
1613 nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback,
1614 void *baton) {
1615 MachProcessSP procSP;
1616 if (GetProcessSP(pid, procSP)) {
1617 procSP->SetSharedLibraryInfoCallback(callback, baton);
1618 return true;
1619 }
1620 return false;
1621}
1622
1623nub_addr_t DNBProcessLookupAddress(nub_process_t pid, const char *name,
1624 const char *shlib) {
1625 MachProcessSP procSP;
1626 if (GetProcessSP(pid, procSP)) {
1627 return procSP->LookupSymbol(name, shlib);
1628 }
1629 return INVALID_NUB_ADDRESS;
1630}
1631
1632nub_size_t DNBProcessGetAvailableSTDOUT(nub_process_t pid, char *buf,
1633 nub_size_t buf_size) {
1634 MachProcessSP procSP;
1635 if (GetProcessSP(pid, procSP))
1636 return procSP->GetAvailableSTDOUT(buf, buf_size);
1637 return 0;
1638}
1639
1640nub_size_t DNBProcessGetAvailableSTDERR(nub_process_t pid, char *buf,
1641 nub_size_t buf_size) {
1642 MachProcessSP procSP;
1643 if (GetProcessSP(pid, procSP))
1644 return procSP->GetAvailableSTDERR(buf, buf_size);
1645 return 0;
1646}
1647
1648nub_size_t DNBProcessGetAvailableProfileData(nub_process_t pid, char *buf,
1649 nub_size_t buf_size) {
1650 MachProcessSP procSP;
1651 if (GetProcessSP(pid, procSP))
1652 return procSP->GetAsyncProfileData(buf, buf_size);
1653 return 0;
1654}
1655
1656DarwinLogEventVector DNBProcessGetAvailableDarwinLogEvents(nub_process_t pid) {
1657 return DarwinLogCollector::GetEventsForProcess(pid);
1658}
1659
1660nub_size_t DNBProcessGetStopCount(nub_process_t pid) {
1661 MachProcessSP procSP;
1662 if (GetProcessSP(pid, procSP))
1663 return procSP->StopCount();
1664 return 0;
1665}
1666
1667uint32_t DNBProcessGetCPUType(nub_process_t pid) {
1668 MachProcessSP procSP;
1669 if (GetProcessSP(pid, procSP))
1670 return procSP->GetCPUType();
1671 return 0;
1672}
1673
1674nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path,
1675 size_t resolved_path_size) {
1676 if (path == NULL || path[0] == '\0')
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001677 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001678
Kate Stoneb9c1b512016-09-06 20:57:50 +00001679 char max_path[PATH_MAX];
1680 std::string result;
1681 CFString::GlobPath(path, result);
1682
1683 if (result.empty())
1684 result = path;
1685
1686 struct stat path_stat;
1687 if (::stat(path, &path_stat) == 0) {
1688 if ((path_stat.st_mode & S_IFMT) == S_IFDIR) {
1689 CFBundle bundle(path);
1690 CFReleaser<CFURLRef> url(bundle.CopyExecutableURL());
1691 if (url.get()) {
1692 if (::CFURLGetFileSystemRepresentation(
1693 url.get(), true, (UInt8 *)resolved_path, resolved_path_size))
1694 return true;
1695 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001696 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001697 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001698
Kate Stoneb9c1b512016-09-06 20:57:50 +00001699 if (realpath(path, max_path)) {
1700 // Found the path relatively...
Jason Molendaaae5b692017-12-09 03:37:09 +00001701 ::strlcpy(resolved_path, max_path, resolved_path_size);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001702 return strlen(resolved_path) + 1 < resolved_path_size;
1703 } else {
1704 // Not a relative path, check the PATH environment variable if the
1705 const char *PATH = getenv("PATH");
1706 if (PATH) {
1707 const char *curr_path_start = PATH;
1708 const char *curr_path_end;
1709 while (curr_path_start && *curr_path_start) {
1710 curr_path_end = strchr(curr_path_start, ':');
1711 if (curr_path_end == NULL) {
1712 result.assign(curr_path_start);
1713 curr_path_start = NULL;
1714 } else if (curr_path_end > curr_path_start) {
1715 size_t len = curr_path_end - curr_path_start;
1716 result.assign(curr_path_start, len);
1717 curr_path_start += len + 1;
1718 } else
1719 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001720
Kate Stoneb9c1b512016-09-06 20:57:50 +00001721 result += '/';
1722 result += path;
1723 struct stat s;
1724 if (stat(result.c_str(), &s) == 0) {
Jason Molendaaae5b692017-12-09 03:37:09 +00001725 ::strlcpy(resolved_path, result.c_str(), resolved_path_size);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001726 return result.size() + 1 < resolved_path_size;
Greg Clayton48baf7a2012-10-31 21:44:39 +00001727 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001728 }
Greg Clayton48baf7a2012-10-31 21:44:39 +00001729 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001730 }
1731 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001732}
1733
Kate Stoneb9c1b512016-09-06 20:57:50 +00001734bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch) {
1735 return MachProcess::GetOSVersionNumbers(major, minor, patch);
Jason Molenda6acc86c2015-08-12 03:27:33 +00001736}
1737
Kate Stoneb9c1b512016-09-06 20:57:50 +00001738void DNBInitialize() {
1739 DNBLogThreadedIf(LOG_PROCESS, "DNBInitialize ()");
1740#if defined(__i386__) || defined(__x86_64__)
1741 DNBArchImplI386::Initialize();
1742 DNBArchImplX86_64::Initialize();
1743#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
1744 DNBArchMachARM::Initialize();
1745 DNBArchMachARM64::Initialize();
Greg Clayton3af9ea52010-11-18 05:57:03 +00001746#endif
1747}
1748
Kate Stoneb9c1b512016-09-06 20:57:50 +00001749void DNBTerminate() {}
Greg Clayton3c144382010-12-01 22:45:40 +00001750
Kate Stoneb9c1b512016-09-06 20:57:50 +00001751nub_bool_t DNBSetArchitecture(const char *arch) {
1752 if (arch && arch[0]) {
1753 if (strcasecmp(arch, "i386") == 0)
1754 return DNBArchProtocol::SetArchitecture(CPU_TYPE_I386);
1755 else if ((strcasecmp(arch, "x86_64") == 0) ||
1756 (strcasecmp(arch, "x86_64h") == 0))
1757 return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64);
1758 else if (strstr(arch, "arm64") == arch || strstr(arch, "armv8") == arch ||
1759 strstr(arch, "aarch64") == arch)
1760 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64);
1761 else if (strstr(arch, "arm") == arch)
1762 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM);
1763 }
1764 return false;
Greg Clayton3c144382010-12-01 22:45:40 +00001765}