blob: 6b57d488b2ffa28f4875e9ce268227a585ab7018 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- DNB.cpp -------------------------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Chris Lattner30fdc8d2010-06-08 16:52:24 +00006//
7//===----------------------------------------------------------------------===//
8//
9// Created by Greg Clayton on 3/23/07.
10//
11//===----------------------------------------------------------------------===//
12
13#include "DNB.h"
Jason Molenda1c739112013-02-22 07:27:08 +000014#include <inttypes.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000015#include <libproc.h>
16#include <map>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000017#include <signal.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <sys/resource.h>
21#include <sys/stat.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000022#include <sys/sysctl.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000023#include <sys/types.h>
24#include <sys/wait.h>
25#include <unistd.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000026#include <vector>
27
Kate Stoneb9c1b512016-09-06 20:57:50 +000028#if defined(__APPLE__)
Jason Molenda36a216e2014-07-24 01:36:24 +000029#include <pthread.h>
30#include <sched.h>
31#endif
32
Jason Molendaa3329782014-03-29 18:54:20 +000033#define TRY_KQUEUE 1
34
35#ifdef TRY_KQUEUE
Kate Stoneb9c1b512016-09-06 20:57:50 +000036#include <sys/event.h>
37#include <sys/time.h>
38#ifdef NOTE_EXIT_DETAIL
39#define USE_KQUEUE
40#endif
Jason Molendaa3329782014-03-29 18:54:20 +000041#endif
42
Kate Stoneb9c1b512016-09-06 20:57:50 +000043#include "CFBundle.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000044#include "CFString.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000045#include "DNBDataRef.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000046#include "DNBLog.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000047#include "DNBThreadResumeActions.h"
48#include "DNBTimer.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000049#include "MacOSX/DarwinLog/DarwinLogCollector.h"
50#include "MacOSX/Genealogy.h"
51#include "MacOSX/MachProcess.h"
52#include "MacOSX/MachTask.h"
53#include "MacOSX/ThreadInfo.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000054
Greg Clayton7b0992d2013-04-18 22:45:39 +000055typedef std::shared_ptr<MachProcess> MachProcessSP;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000056typedef std::map<nub_process_t, MachProcessSP> ProcessMap;
57typedef ProcessMap::iterator ProcessMapIter;
58typedef ProcessMap::const_iterator ProcessMapConstIter;
59
Kate Stoneb9c1b512016-09-06 20:57:50 +000060size_t GetAllInfos(std::vector<struct kinfo_proc> &proc_infos);
61static size_t
62GetAllInfosMatchingName(const char *process_name,
63 std::vector<struct kinfo_proc> &matching_proc_infos);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000064
65//----------------------------------------------------------------------
66// A Thread safe singleton to get a process map pointer.
67//
68// Returns a pointer to the existing process map, or a pointer to a
69// newly created process map if CAN_CREATE is non-zero.
70//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000071static ProcessMap *GetProcessMap(bool can_create) {
72 static ProcessMap *g_process_map_ptr = NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000073
Kate Stoneb9c1b512016-09-06 20:57:50 +000074 if (can_create && g_process_map_ptr == NULL) {
75 static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER;
76 PTHREAD_MUTEX_LOCKER(locker, &g_process_map_mutex);
77 if (g_process_map_ptr == NULL)
78 g_process_map_ptr = new ProcessMap;
79 }
80 return g_process_map_ptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000081}
82
83//----------------------------------------------------------------------
84// Add PID to the shared process pointer map.
85//
86// Return non-zero value if we succeed in adding the process to the map.
87// The only time this should fail is if we run out of memory and can't
88// allocate a ProcessMap.
89//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000090static nub_bool_t AddProcessToMap(nub_process_t pid, MachProcessSP &procSP) {
91 ProcessMap *process_map = GetProcessMap(true);
92 if (process_map) {
93 process_map->insert(std::make_pair(pid, procSP));
94 return true;
95 }
96 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000097}
98
99//----------------------------------------------------------------------
100// Remove the shared pointer for PID from the process map.
101//
102// Returns the number of items removed from the process map.
103//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104// static size_t
105// RemoveProcessFromMap (nub_process_t pid)
Greg Claytonee2ed522015-03-09 19:45:23 +0000106//{
107// ProcessMap* process_map = GetProcessMap(false);
108// if (process_map)
109// {
110// return process_map->erase(pid);
111// }
112// return 0;
113//}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000114
115//----------------------------------------------------------------------
116// Get the shared pointer for PID from the existing process map.
117//
118// Returns true if we successfully find a shared pointer to a
119// MachProcess object.
120//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121static nub_bool_t GetProcessSP(nub_process_t pid, MachProcessSP &procSP) {
122 ProcessMap *process_map = GetProcessMap(false);
123 if (process_map != NULL) {
124 ProcessMapIter pos = process_map->find(pid);
125 if (pos != process_map->end()) {
126 procSP = pos->second;
127 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000128 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129 }
130 procSP.reset();
131 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000132}
133
Jason Molendaa3329782014-03-29 18:54:20 +0000134#ifdef USE_KQUEUE
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135void *kqueue_thread(void *arg) {
136 int kq_id = (int)(intptr_t)arg;
137
138#if defined(__APPLE__)
139 pthread_setname_np("kqueue thread");
140#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
141 struct sched_param thread_param;
142 int thread_sched_policy;
143 if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
144 &thread_param) == 0) {
145 thread_param.sched_priority = 47;
146 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
147 }
Jason Molenda36a216e2014-07-24 01:36:24 +0000148#endif
149#endif
150
Kate Stoneb9c1b512016-09-06 20:57:50 +0000151 struct kevent death_event;
152 while (1) {
153 int n_events = kevent(kq_id, NULL, 0, &death_event, 1, NULL);
154 if (n_events == -1) {
155 if (errno == EINTR)
156 continue;
157 else {
158 DNBLogError("kqueue failed with error: (%d): %s", errno,
159 strerror(errno));
160 return NULL;
161 }
162 } else if (death_event.flags & EV_ERROR) {
163 int error_no = static_cast<int>(death_event.data);
164 const char *error_str = strerror(error_no);
165 if (error_str == NULL)
166 error_str = "Unknown error";
167 DNBLogError("Failed to initialize kqueue event: (%d): %s", error_no,
168 error_str);
169 return NULL;
170 } else {
171 int status;
172 const pid_t pid = (pid_t)death_event.ident;
173 const pid_t child_pid = waitpid(pid, &status, 0);
Greg Clayton040c5602014-04-30 20:24:10 +0000174
Kate Stoneb9c1b512016-09-06 20:57:50 +0000175 bool exited = false;
176 int signal = 0;
177 int exit_status = 0;
178 if (WIFSTOPPED(status)) {
179 signal = WSTOPSIG(status);
180 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> STOPPED (signal = %i)",
181 child_pid, signal);
182 } else if (WIFEXITED(status)) {
183 exit_status = WEXITSTATUS(status);
184 exited = true;
185 DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> EXITED (status = %i)",
186 child_pid, exit_status);
187 } else if (WIFSIGNALED(status)) {
188 signal = WTERMSIG(status);
189 if (child_pid == abs(pid)) {
190 DNBLogThreadedIf(LOG_PROCESS,
191 "waitpid (%i) -> SIGNALED and EXITED (signal = %i)",
192 child_pid, signal);
193 char exit_info[64];
194 ::snprintf(exit_info, sizeof(exit_info),
195 "Terminated due to signal %i", signal);
196 DNBProcessSetExitInfo(child_pid, exit_info);
197 exited = true;
198 exit_status = INT8_MAX;
199 } else {
200 DNBLogThreadedIf(LOG_PROCESS,
201 "waitpid (%i) -> SIGNALED (signal = %i)", child_pid,
202 signal);
Jason Molendaa3329782014-03-29 18:54:20 +0000203 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000204 }
205
206 if (exited) {
207 if (death_event.data & NOTE_EXIT_MEMORY)
208 DNBProcessSetExitInfo(child_pid, "Terminated due to memory issue");
209 else if (death_event.data & NOTE_EXIT_DECRYPTFAIL)
210 DNBProcessSetExitInfo(child_pid, "Terminated due to decrypt failure");
211 else if (death_event.data & NOTE_EXIT_CSERROR)
212 DNBProcessSetExitInfo(child_pid,
213 "Terminated due to code signing error");
214
215 DNBLogThreadedIf(
216 LOG_PROCESS,
217 "waitpid_process_thread (): setting exit status for pid = %i to %i",
218 child_pid, exit_status);
219 DNBProcessSetExitStatus(child_pid, status);
220 return NULL;
221 }
Jason Molendaa3329782014-03-29 18:54:20 +0000222 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000223 }
Jason Molendaa3329782014-03-29 18:54:20 +0000224}
225
Kate Stoneb9c1b512016-09-06 20:57:50 +0000226static bool spawn_kqueue_thread(pid_t pid) {
227 pthread_t thread;
228 int kq_id;
Jason Molendaa3329782014-03-29 18:54:20 +0000229
Kate Stoneb9c1b512016-09-06 20:57:50 +0000230 kq_id = kqueue();
231 if (kq_id == -1) {
232 DNBLogError("Could not get kqueue for pid = %i.", pid);
Jason Molendaa3329782014-03-29 18:54:20 +0000233 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000234 }
235
236 struct kevent reg_event;
237
238 EV_SET(&reg_event, pid, EVFILT_PROC, EV_ADD,
239 NOTE_EXIT | NOTE_EXITSTATUS | NOTE_EXIT_DETAIL, 0, NULL);
240 // Register the event:
241 int result = kevent(kq_id, &reg_event, 1, NULL, 0, NULL);
242 if (result != 0) {
243 DNBLogError(
244 "Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid,
245 result);
246 return false;
247 }
248
249 int ret =
250 ::pthread_create(&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id);
251
252 // pthread_create returns 0 if successful
253 if (ret == 0) {
254 ::pthread_detach(thread);
255 return true;
256 }
257 return false;
Jason Molendaa3329782014-03-29 18:54:20 +0000258}
259#endif // #if USE_KQUEUE
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000260
Kate Stoneb9c1b512016-09-06 20:57:50 +0000261static void *waitpid_thread(void *arg) {
262 const pid_t pid = (pid_t)(intptr_t)arg;
263 int status;
Jason Molenda36a216e2014-07-24 01:36:24 +0000264
Kate Stoneb9c1b512016-09-06 20:57:50 +0000265#if defined(__APPLE__)
266 pthread_setname_np("waitpid thread");
267#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
268 struct sched_param thread_param;
269 int thread_sched_policy;
270 if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
271 &thread_param) == 0) {
272 thread_param.sched_priority = 47;
273 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
274 }
Jason Molenda36a216e2014-07-24 01:36:24 +0000275#endif
276#endif
277
Kate Stoneb9c1b512016-09-06 20:57:50 +0000278 while (1) {
279 pid_t child_pid = waitpid(pid, &status, 0);
280 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): waitpid (pid = %i, "
281 "&status, 0) => %i, status = %i, errno = %i",
282 pid, child_pid, status, errno);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000283
Kate Stoneb9c1b512016-09-06 20:57:50 +0000284 if (child_pid < 0) {
285 if (errno == EINTR)
286 continue;
287 break;
288 } else {
289 if (WIFSTOPPED(status)) {
290 continue;
291 } else // if (WIFEXITED(status) || WIFSIGNALED(status))
292 {
293 DNBLogThreadedIf(
294 LOG_PROCESS,
295 "waitpid_thread (): setting exit status for pid = %i to %i",
296 child_pid, status);
297 DNBProcessSetExitStatus(child_pid, status);
298 return NULL;
299 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000300 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000301 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000302
Kate Stoneb9c1b512016-09-06 20:57:50 +0000303 // We should never exit as long as our child process is alive, so if we
304 // do something else went wrong and we should exit...
305 DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): main loop exited, setting "
306 "exit status to an invalid value (-1) for pid "
307 "%i",
308 pid);
309 DNBProcessSetExitStatus(pid, -1);
310 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000311}
Kate Stoneb9c1b512016-09-06 20:57:50 +0000312static bool spawn_waitpid_thread(pid_t pid) {
Jason Molendaa3329782014-03-29 18:54:20 +0000313#ifdef USE_KQUEUE
Kate Stoneb9c1b512016-09-06 20:57:50 +0000314 bool success = spawn_kqueue_thread(pid);
315 if (success)
316 return true;
Jason Molendaa3329782014-03-29 18:54:20 +0000317#endif
318
Kate Stoneb9c1b512016-09-06 20:57:50 +0000319 pthread_t thread;
320 int ret =
321 ::pthread_create(&thread, NULL, waitpid_thread, (void *)(intptr_t)pid);
322 // pthread_create returns 0 if successful
323 if (ret == 0) {
324 ::pthread_detach(thread);
325 return true;
326 }
327 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000328}
329
Kate Stoneb9c1b512016-09-06 20:57:50 +0000330nub_process_t DNBProcessLaunch(
331 const char *path, char const *argv[], const char *envp[],
332 const char *working_directory, // NULL => don't change, non-NULL => set
333 // working directory for inferior to this
334 const char *stdin_path, const char *stdout_path, const char *stderr_path,
335 bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr,
336 const char *event_data, char *err_str, size_t err_len) {
337 DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, "
338 "working_dir=%s, stdin=%s, stdout=%s, "
339 "stderr=%s, no-stdio=%i, launch_flavor = %u, "
340 "disable_aslr = %d, err = %p, err_len = "
341 "%llu) called...",
342 __FUNCTION__, path, static_cast<void *>(argv),
343 static_cast<void *>(envp), working_directory, stdin_path,
344 stdout_path, stderr_path, no_stdio, launch_flavor,
345 disable_aslr, static_cast<void *>(err_str),
346 static_cast<uint64_t>(err_len));
Saleem Abdulrasoolbd7ecf42016-05-06 17:32:58 +0000347
Kate Stoneb9c1b512016-09-06 20:57:50 +0000348 if (err_str && err_len > 0)
349 err_str[0] = '\0';
350 struct stat path_stat;
351 if (::stat(path, &path_stat) == -1) {
352 char stat_error[256];
353 ::strerror_r(errno, stat_error, sizeof(stat_error));
354 snprintf(err_str, err_len, "%s (%s)", stat_error, path);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000355 return INVALID_NUB_PROCESS;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000356 }
357
358 MachProcessSP processSP(new MachProcess);
359 if (processSP.get()) {
360 DNBError launch_err;
361 pid_t pid = processSP->LaunchForDebug(path, argv, envp, working_directory,
362 stdin_path, stdout_path, stderr_path,
363 no_stdio, launch_flavor, disable_aslr,
364 event_data, launch_err);
365 if (err_str) {
366 *err_str = '\0';
367 if (launch_err.Fail()) {
368 const char *launch_err_str = launch_err.AsString();
369 if (launch_err_str) {
Jason Molendaaae5b692017-12-09 03:37:09 +0000370 strlcpy(err_str, launch_err_str, err_len - 1);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000371 err_str[err_len - 1] =
372 '\0'; // Make sure the error string is terminated
373 }
374 }
375 }
376
377 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid);
378
379 if (pid != INVALID_NUB_PROCESS) {
380 // Spawn a thread to reap our child inferior process...
381 spawn_waitpid_thread(pid);
382
383 if (processSP->Task().TaskPortForProcessID(launch_err) == TASK_NULL) {
384 // We failed to get the task for our process ID which is bad.
385 // Kill our process otherwise it will be stopped at the entry
386 // point and get reparented to someone else and never go away.
387 DNBLog("Could not get task port for process, sending SIGKILL and "
388 "exiting.");
389 kill(SIGKILL, pid);
390
391 if (err_str && err_len > 0) {
392 if (launch_err.AsString()) {
393 ::snprintf(err_str, err_len,
394 "failed to get the task for process %i (%s)", pid,
395 launch_err.AsString());
396 } else {
397 ::snprintf(err_str, err_len,
398 "failed to get the task for process %i", pid);
399 }
400 }
401 } else {
402 bool res = AddProcessToMap(pid, processSP);
403 UNUSED_IF_ASSERT_DISABLED(res);
404 assert(res && "Couldn't add process to map!");
405 return pid;
406 }
407 }
408 }
409 return INVALID_NUB_PROCESS;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000410}
411
Jason Molenda752e1e82015-07-29 01:42:16 +0000412// If there is one process with a given name, return the pid for that process.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000413nub_process_t DNBProcessGetPIDByName(const char *name) {
414 std::vector<struct kinfo_proc> matching_proc_infos;
415 size_t num_matching_proc_infos =
416 GetAllInfosMatchingName(name, matching_proc_infos);
417 if (num_matching_proc_infos == 1) {
418 return matching_proc_infos[0].kp_proc.p_pid;
419 }
420 return INVALID_NUB_PROCESS;
421}
422
423nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout,
424 char *err_str, size_t err_len) {
425 if (err_str && err_len > 0)
426 err_str[0] = '\0';
427 std::vector<struct kinfo_proc> matching_proc_infos;
428 size_t num_matching_proc_infos =
429 GetAllInfosMatchingName(name, matching_proc_infos);
430 if (num_matching_proc_infos == 0) {
431 DNBLogError("error: no processes match '%s'\n", name);
Jason Molenda752e1e82015-07-29 01:42:16 +0000432 return INVALID_NUB_PROCESS;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000433 } else if (num_matching_proc_infos > 1) {
434 DNBLogError("error: %llu processes match '%s':\n",
435 (uint64_t)num_matching_proc_infos, name);
436 size_t i;
437 for (i = 0; i < num_matching_proc_infos; ++i)
438 DNBLogError("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid,
439 matching_proc_infos[i].kp_proc.p_comm);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000440 return INVALID_NUB_PROCESS;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000441 }
442
443 return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout,
444 err_str, err_len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000445}
446
Kate Stoneb9c1b512016-09-06 20:57:50 +0000447nub_process_t DNBProcessAttach(nub_process_t attach_pid,
448 struct timespec *timeout, char *err_str,
449 size_t err_len) {
450 if (err_str && err_len > 0)
451 err_str[0] = '\0';
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000452
Kate Stoneb9c1b512016-09-06 20:57:50 +0000453 pid_t pid = INVALID_NUB_PROCESS;
454 MachProcessSP processSP(new MachProcess);
455 if (processSP.get()) {
456 DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...",
457 attach_pid);
458 pid = processSP->AttachForDebug(attach_pid, err_str, err_len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000459
Kate Stoneb9c1b512016-09-06 20:57:50 +0000460 if (pid != INVALID_NUB_PROCESS) {
461 bool res = AddProcessToMap(pid, processSP);
462 UNUSED_IF_ASSERT_DISABLED(res);
463 assert(res && "Couldn't add process to map!");
464 spawn_waitpid_thread(pid);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000465 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000466 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000467
Kate Stoneb9c1b512016-09-06 20:57:50 +0000468 while (pid != INVALID_NUB_PROCESS) {
469 // Wait for process to start up and hit entry point
470 DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
471 "eEventProcessRunningStateChanged | "
472 "eEventProcessStoppedStateChanged, true, "
473 "INFINITE)...",
474 __FUNCTION__, pid);
475 nub_event_t set_events =
476 DNBProcessWaitForEvents(pid, eEventProcessRunningStateChanged |
477 eEventProcessStoppedStateChanged,
478 true, timeout);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000479
Kate Stoneb9c1b512016-09-06 20:57:50 +0000480 DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, "
481 "eEventProcessRunningStateChanged | "
482 "eEventProcessStoppedStateChanged, true, "
483 "INFINITE) => 0x%8.8x",
484 __FUNCTION__, pid, set_events);
485
486 if (set_events == 0) {
487 if (err_str && err_len > 0)
488 snprintf(err_str, err_len, "operation timed out");
489 pid = INVALID_NUB_PROCESS;
490 } else {
491 if (set_events & (eEventProcessRunningStateChanged |
492 eEventProcessStoppedStateChanged)) {
493 nub_state_t pid_state = DNBProcessGetState(pid);
494 DNBLogThreadedIf(
495 LOG_PROCESS,
496 "%s process %4.4x state changed (eEventProcessStateChanged): %s",
497 __FUNCTION__, pid, DNBStateAsString(pid_state));
498
499 switch (pid_state) {
500 case eStateInvalid:
501 case eStateUnloaded:
502 case eStateAttaching:
503 case eStateLaunching:
504 case eStateSuspended:
505 break; // Ignore
506
507 case eStateRunning:
508 case eStateStepping:
509 // Still waiting to stop at entry point...
510 break;
511
512 case eStateStopped:
513 case eStateCrashed:
514 return pid;
515
516 case eStateDetached:
517 case eStateExited:
518 if (err_str && err_len > 0)
519 snprintf(err_str, err_len, "process exited");
520 return INVALID_NUB_PROCESS;
521 }
522 }
523
524 DNBProcessResetEvents(pid, set_events);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000525 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000526 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000527
Kate Stoneb9c1b512016-09-06 20:57:50 +0000528 return INVALID_NUB_PROCESS;
529}
530
531size_t GetAllInfos(std::vector<struct kinfo_proc> &proc_infos) {
532 size_t size = 0;
533 int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
534 u_int namelen = sizeof(name) / sizeof(int);
535 int err;
536
537 // Try to find out how many processes are around so we can
538 // size the buffer appropriately. sysctl's man page specifically suggests
539 // this approach, and says it returns a bit larger size than needed to
540 // handle any new processes created between then and now.
541
542 err = ::sysctl(name, namelen, NULL, &size, NULL, 0);
543
544 if ((err < 0) && (err != ENOMEM)) {
545 proc_infos.clear();
546 perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)");
547 return 0;
548 }
549
550 // Increase the size of the buffer by a few processes in case more have
551 // been spawned
552 proc_infos.resize(size / sizeof(struct kinfo_proc));
553 size = proc_infos.size() *
554 sizeof(struct kinfo_proc); // Make sure we don't exceed our resize...
555 err = ::sysctl(name, namelen, &proc_infos[0], &size, NULL, 0);
556 if (err < 0) {
557 proc_infos.clear();
558 return 0;
559 }
560
561 // Trim down our array to fit what we actually got back
562 proc_infos.resize(size / sizeof(struct kinfo_proc));
563 return proc_infos.size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000564}
565
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000566static size_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000567GetAllInfosMatchingName(const char *full_process_name,
568 std::vector<struct kinfo_proc> &matching_proc_infos) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000569
Kate Stoneb9c1b512016-09-06 20:57:50 +0000570 matching_proc_infos.clear();
571 if (full_process_name && full_process_name[0]) {
572 // We only get the process name, not the full path, from the proc_info. So
573 // just take the
574 // base name of the process name...
575 const char *process_name;
576 process_name = strrchr(full_process_name, '/');
577 if (process_name == NULL)
578 process_name = full_process_name;
579 else
580 process_name++;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000581
Kate Stoneb9c1b512016-09-06 20:57:50 +0000582 const size_t process_name_len = strlen(process_name);
583 std::vector<struct kinfo_proc> proc_infos;
584 const size_t num_proc_infos = GetAllInfos(proc_infos);
585 if (num_proc_infos > 0) {
586 uint32_t i;
587 for (i = 0; i < num_proc_infos; i++) {
588 // Skip zombie processes and processes with unset status
589 if (proc_infos[i].kp_proc.p_stat == 0 ||
590 proc_infos[i].kp_proc.p_stat == SZOMB)
591 continue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000592
Kate Stoneb9c1b512016-09-06 20:57:50 +0000593 // Check for process by name. We only check the first MAXCOMLEN
594 // chars as that is all that kp_proc.p_comm holds.
Greg Clayton7dab2be2012-07-19 02:45:35 +0000595
Kate Stoneb9c1b512016-09-06 20:57:50 +0000596 if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm,
597 MAXCOMLEN) == 0) {
598 if (process_name_len > MAXCOMLEN) {
599 // We found a matching process name whose first MAXCOMLEN
600 // characters match, but there is more to the name than
601 // this. We need to get the full process name. Use proc_pidpath,
602 // which will get
603 // us the full path to the executed process.
Greg Clayton7dab2be2012-07-19 02:45:35 +0000604
Kate Stoneb9c1b512016-09-06 20:57:50 +0000605 char proc_path_buf[PATH_MAX];
606
607 int return_val = proc_pidpath(proc_infos[i].kp_proc.p_pid,
608 proc_path_buf, PATH_MAX);
609 if (return_val > 0) {
610 // Okay, now search backwards from that to see if there is a
611 // slash in the name. Note, even though we got all the args we
612 // don't care
613 // because the list data is just a bunch of concatenated null
614 // terminated strings
615 // so strrchr will start from the end of argv0.
616
617 const char *argv_basename = strrchr(proc_path_buf, '/');
618 if (argv_basename) {
619 // Skip the '/'
620 ++argv_basename;
621 } else {
622 // We didn't find a directory delimiter in the process argv[0],
623 // just use what was in there
624 argv_basename = proc_path_buf;
625 }
626
627 if (argv_basename) {
628 if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0) {
629 matching_proc_infos.push_back(proc_infos[i]);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000630 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000631 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000632 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000633 } else {
634 // We found a matching process, add it to our list
635 matching_proc_infos.push_back(proc_infos[i]);
636 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000637 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000638 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000639 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000640 }
641 // return the newly added matches.
642 return matching_proc_infos.size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000643}
644
Kate Stoneb9c1b512016-09-06 20:57:50 +0000645nub_process_t DNBProcessAttachWait(
646 const char *waitfor_process_name, nub_launch_flavor_t launch_flavor,
647 bool ignore_existing, struct timespec *timeout_abstime,
648 useconds_t waitfor_interval, char *err_str, size_t err_len,
649 DNBShouldCancelCallback should_cancel_callback, void *callback_data) {
650 DNBError prepare_error;
651 std::vector<struct kinfo_proc> exclude_proc_infos;
652 size_t num_exclude_proc_infos;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000653
Kate Stoneb9c1b512016-09-06 20:57:50 +0000654 // If the PrepareForAttach returns a valid token, use MachProcess to check
655 // for the process, otherwise scan the process table.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000656
Kate Stoneb9c1b512016-09-06 20:57:50 +0000657 const void *attach_token = MachProcess::PrepareForAttach(
658 waitfor_process_name, launch_flavor, true, prepare_error);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000659
Kate Stoneb9c1b512016-09-06 20:57:50 +0000660 if (prepare_error.Fail()) {
661 DNBLogError("Error in PrepareForAttach: %s", prepare_error.AsString());
662 return INVALID_NUB_PROCESS;
663 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000664
Kate Stoneb9c1b512016-09-06 20:57:50 +0000665 if (attach_token == NULL) {
666 if (ignore_existing)
667 num_exclude_proc_infos =
668 GetAllInfosMatchingName(waitfor_process_name, exclude_proc_infos);
669 else
670 num_exclude_proc_infos = 0;
671 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000672
Kate Stoneb9c1b512016-09-06 20:57:50 +0000673 DNBLogThreadedIf(LOG_PROCESS, "Waiting for '%s' to appear...\n",
674 waitfor_process_name);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000675
Kate Stoneb9c1b512016-09-06 20:57:50 +0000676 // Loop and try to find the process by name
677 nub_process_t waitfor_pid = INVALID_NUB_PROCESS;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000678
Kate Stoneb9c1b512016-09-06 20:57:50 +0000679 while (waitfor_pid == INVALID_NUB_PROCESS) {
680 if (attach_token != NULL) {
681 nub_process_t pid;
682 pid = MachProcess::CheckForProcess(attach_token, launch_flavor);
683 if (pid != INVALID_NUB_PROCESS) {
684 waitfor_pid = pid;
685 break;
686 }
687 } else {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000688
Kate Stoneb9c1b512016-09-06 20:57:50 +0000689 // Get the current process list, and check for matches that
690 // aren't in our original list. If anyone wants to attach
691 // to an existing process by name, they should do it with
692 // --attach=PROCNAME. Else we will wait for the first matching
693 // process that wasn't in our exclusion list.
694 std::vector<struct kinfo_proc> proc_infos;
695 const size_t num_proc_infos =
696 GetAllInfosMatchingName(waitfor_process_name, proc_infos);
697 for (size_t i = 0; i < num_proc_infos; i++) {
698 nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid;
699 for (size_t j = 0; j < num_exclude_proc_infos; j++) {
700 if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid) {
701 // This process was in our exclusion list, don't use it.
702 curr_pid = INVALID_NUB_PROCESS;
703 break;
704 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000705 }
706
Kate Stoneb9c1b512016-09-06 20:57:50 +0000707 // If we didn't find CURR_PID in our exclusion list, then use it.
708 if (curr_pid != INVALID_NUB_PROCESS) {
709 // We found our process!
710 waitfor_pid = curr_pid;
711 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000712 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000713 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000714 }
715
Kate Stoneb9c1b512016-09-06 20:57:50 +0000716 // If we haven't found our process yet, check for a timeout
717 // and then sleep for a bit until we poll again.
718 if (waitfor_pid == INVALID_NUB_PROCESS) {
719 if (timeout_abstime != NULL) {
720 // Check to see if we have a waitfor-duration option that
721 // has timed out?
722 if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime)) {
723 if (err_str && err_len > 0)
724 snprintf(err_str, err_len, "operation timed out");
725 DNBLogError("error: waiting for process '%s' timed out.\n",
726 waitfor_process_name);
727 return INVALID_NUB_PROCESS;
728 }
729 }
730
731 // Call the should cancel callback as well...
732
733 if (should_cancel_callback != NULL &&
734 should_cancel_callback(callback_data)) {
735 DNBLogThreadedIf(
736 LOG_PROCESS,
737 "DNBProcessAttachWait cancelled by should_cancel callback.");
738 waitfor_pid = INVALID_NUB_PROCESS;
739 break;
740 }
741
742 ::usleep(waitfor_interval); // Sleep for WAITFOR_INTERVAL, then poll again
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000743 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000744 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000745
Kate Stoneb9c1b512016-09-06 20:57:50 +0000746 if (waitfor_pid != INVALID_NUB_PROCESS) {
747 DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n",
748 waitfor_process_name, waitfor_pid);
749 waitfor_pid =
750 DNBProcessAttach(waitfor_pid, timeout_abstime, err_str, err_len);
751 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000752
Kate Stoneb9c1b512016-09-06 20:57:50 +0000753 bool success = waitfor_pid != INVALID_NUB_PROCESS;
754 MachProcess::CleanupAfterAttach(attach_token, launch_flavor, success,
755 prepare_error);
756
757 return waitfor_pid;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000758}
759
Kate Stoneb9c1b512016-09-06 20:57:50 +0000760nub_bool_t DNBProcessDetach(nub_process_t pid) {
761 MachProcessSP procSP;
762 if (GetProcessSP(pid, procSP)) {
763 const bool remove = true;
764 DNBLogThreaded(
765 "Disabling breakpoints and watchpoints, and detaching from %d.", pid);
766 procSP->DisableAllBreakpoints(remove);
767 procSP->DisableAllWatchpoints(remove);
768 return procSP->Detach();
769 }
770 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000771}
772
Kate Stoneb9c1b512016-09-06 20:57:50 +0000773nub_bool_t DNBProcessKill(nub_process_t pid) {
774 MachProcessSP procSP;
775 if (GetProcessSP(pid, procSP)) {
776 return procSP->Kill();
777 }
778 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000779}
780
Kate Stoneb9c1b512016-09-06 20:57:50 +0000781nub_bool_t DNBProcessSignal(nub_process_t pid, int signal) {
782 MachProcessSP procSP;
783 if (GetProcessSP(pid, procSP)) {
784 return procSP->Signal(signal);
785 }
786 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000787}
788
Kate Stoneb9c1b512016-09-06 20:57:50 +0000789nub_bool_t DNBProcessInterrupt(nub_process_t pid) {
790 MachProcessSP procSP;
791 if (GetProcessSP(pid, procSP))
792 return procSP->Interrupt();
793 return false;
Greg Clayton4296c222014-04-24 19:54:32 +0000794}
795
Kate Stoneb9c1b512016-09-06 20:57:50 +0000796nub_bool_t DNBProcessSendEvent(nub_process_t pid, const char *event) {
797 MachProcessSP procSP;
798 if (GetProcessSP(pid, procSP)) {
799 // FIXME: Do something with the error...
800 DNBError send_error;
801 return procSP->SendEvent(event, send_error);
802 }
803 return false;
Jason Molendaa3329782014-03-29 18:54:20 +0000804}
805
Kate Stoneb9c1b512016-09-06 20:57:50 +0000806nub_bool_t DNBProcessIsAlive(nub_process_t pid) {
807 MachProcessSP procSP;
808 if (GetProcessSP(pid, procSP)) {
809 return MachTask::IsValid(procSP->Task().TaskPort());
810 }
811 return eStateInvalid;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000812}
813
814//----------------------------------------------------------------------
815// Process and Thread state information
816//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000817nub_state_t DNBProcessGetState(nub_process_t pid) {
818 MachProcessSP procSP;
819 if (GetProcessSP(pid, procSP)) {
820 return procSP->GetState();
821 }
822 return eStateInvalid;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000823}
824
825//----------------------------------------------------------------------
826// Process and Thread state information
827//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000828nub_bool_t DNBProcessGetExitStatus(nub_process_t pid, int *status) {
829 MachProcessSP procSP;
830 if (GetProcessSP(pid, procSP)) {
831 return procSP->GetExitStatus(status);
832 }
833 return false;
834}
835
836nub_bool_t DNBProcessSetExitStatus(nub_process_t pid, int status) {
837 MachProcessSP procSP;
838 if (GetProcessSP(pid, procSP)) {
839 procSP->SetExitStatus(status);
840 return true;
841 }
842 return false;
843}
844
845const char *DNBProcessGetExitInfo(nub_process_t pid) {
846 MachProcessSP procSP;
847 if (GetProcessSP(pid, procSP)) {
848 return procSP->GetExitInfo();
849 }
850 return NULL;
851}
852
853nub_bool_t DNBProcessSetExitInfo(nub_process_t pid, const char *info) {
854 MachProcessSP procSP;
855 if (GetProcessSP(pid, procSP)) {
856 procSP->SetExitInfo(info);
857 return true;
858 }
859 return false;
860}
861
862const char *DNBThreadGetName(nub_process_t pid, nub_thread_t tid) {
863 MachProcessSP procSP;
864 if (GetProcessSP(pid, procSP))
865 return procSP->ThreadGetName(tid);
866 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000867}
868
869nub_bool_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000870DNBThreadGetIdentifierInfo(nub_process_t pid, nub_thread_t tid,
871 thread_identifier_info_data_t *ident_info) {
872 MachProcessSP procSP;
873 if (GetProcessSP(pid, procSP))
874 return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info);
875 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000876}
877
Kate Stoneb9c1b512016-09-06 20:57:50 +0000878nub_state_t DNBThreadGetState(nub_process_t pid, nub_thread_t tid) {
879 MachProcessSP procSP;
880 if (GetProcessSP(pid, procSP)) {
881 return procSP->ThreadGetState(tid);
882 }
883 return eStateInvalid;
Jason Molendaa3329782014-03-29 18:54:20 +0000884}
885
Kate Stoneb9c1b512016-09-06 20:57:50 +0000886const char *DNBStateAsString(nub_state_t state) {
887 switch (state) {
888 case eStateInvalid:
889 return "Invalid";
890 case eStateUnloaded:
891 return "Unloaded";
892 case eStateAttaching:
893 return "Attaching";
894 case eStateLaunching:
895 return "Launching";
896 case eStateStopped:
897 return "Stopped";
898 case eStateRunning:
899 return "Running";
900 case eStateStepping:
901 return "Stepping";
902 case eStateCrashed:
903 return "Crashed";
904 case eStateDetached:
905 return "Detached";
906 case eStateExited:
907 return "Exited";
908 case eStateSuspended:
909 return "Suspended";
910 }
911 return "nub_state_t ???";
Jason Molendaa3329782014-03-29 18:54:20 +0000912}
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000913
Kate Stoneb9c1b512016-09-06 20:57:50 +0000914Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread(nub_process_t pid,
915 nub_thread_t tid,
916 bool &timed_out) {
917 Genealogy::ThreadActivitySP thread_activity_sp;
918 MachProcessSP procSP;
919 if (GetProcessSP(pid, procSP))
920 thread_activity_sp = procSP->GetGenealogyInfoForThread(tid, timed_out);
921 return thread_activity_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000922}
923
Kate Stoneb9c1b512016-09-06 20:57:50 +0000924Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo(nub_process_t pid,
925 size_t idx) {
926 Genealogy::ProcessExecutableInfoSP image_info_sp;
927 MachProcessSP procSP;
928 if (GetProcessSP(pid, procSP)) {
929 image_info_sp = procSP->GetGenealogyImageInfo(idx);
930 }
931 return image_info_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000932}
933
Kate Stoneb9c1b512016-09-06 20:57:50 +0000934ThreadInfo::QoS DNBGetRequestedQoSForThread(nub_process_t pid, nub_thread_t tid,
935 nub_addr_t tsd,
936 uint64_t dti_qos_class_index) {
937 MachProcessSP procSP;
938 if (GetProcessSP(pid, procSP)) {
939 return procSP->GetRequestedQoS(tid, tsd, dti_qos_class_index);
940 }
941 return ThreadInfo::QoS();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000942}
943
Kate Stoneb9c1b512016-09-06 20:57:50 +0000944nub_addr_t DNBGetPThreadT(nub_process_t pid, nub_thread_t tid) {
945 MachProcessSP procSP;
946 if (GetProcessSP(pid, procSP)) {
947 return procSP->GetPThreadT(tid);
948 }
949 return INVALID_NUB_ADDRESS;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000950}
951
Kate Stoneb9c1b512016-09-06 20:57:50 +0000952nub_addr_t DNBGetDispatchQueueT(nub_process_t pid, nub_thread_t tid) {
953 MachProcessSP procSP;
954 if (GetProcessSP(pid, procSP)) {
955 return procSP->GetDispatchQueueT(tid);
956 }
957 return INVALID_NUB_ADDRESS;
Jason Molenda705b1802014-06-13 02:37:02 +0000958}
959
960nub_addr_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000961DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid,
962 uint64_t plo_pthread_tsd_base_address_offset,
963 uint64_t plo_pthread_tsd_base_offset,
964 uint64_t plo_pthread_tsd_entry_size) {
965 MachProcessSP procSP;
966 if (GetProcessSP(pid, procSP)) {
967 return procSP->GetTSDAddressForThread(
968 tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset,
969 plo_pthread_tsd_entry_size);
970 }
971 return INVALID_NUB_ADDRESS;
Jason Molenda705b1802014-06-13 02:37:02 +0000972}
973
Kate Stoneb9c1b512016-09-06 20:57:50 +0000974JSONGenerator::ObjectSP DNBGetLoadedDynamicLibrariesInfos(
975 nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) {
976 MachProcessSP procSP;
977 if (GetProcessSP(pid, procSP)) {
978 return procSP->GetLoadedDynamicLibrariesInfos(pid, image_list_address,
979 image_count);
980 }
981 return JSONGenerator::ObjectSP();
Jason Molenda705b1802014-06-13 02:37:02 +0000982}
983
Kate Stoneb9c1b512016-09-06 20:57:50 +0000984JSONGenerator::ObjectSP DNBGetAllLoadedLibrariesInfos(nub_process_t pid) {
985 MachProcessSP procSP;
986 if (GetProcessSP(pid, procSP)) {
987 return procSP->GetAllLoadedLibrariesInfos(pid);
988 }
989 return JSONGenerator::ObjectSP();
Jason Molenda705b1802014-06-13 02:37:02 +0000990}
991
Kate Stoneb9c1b512016-09-06 20:57:50 +0000992JSONGenerator::ObjectSP
993DNBGetLibrariesInfoForAddresses(nub_process_t pid,
994 std::vector<uint64_t> &macho_addresses) {
995 MachProcessSP procSP;
996 if (GetProcessSP(pid, procSP)) {
997 return procSP->GetLibrariesInfoForAddresses(pid, macho_addresses);
998 }
999 return JSONGenerator::ObjectSP();
Jason Molenda20ee21b2015-07-10 23:15:22 +00001000}
1001
Kate Stoneb9c1b512016-09-06 20:57:50 +00001002JSONGenerator::ObjectSP DNBGetSharedCacheInfo(nub_process_t pid) {
1003 MachProcessSP procSP;
1004 if (GetProcessSP(pid, procSP)) {
1005 return procSP->GetSharedCacheInfo(pid);
1006 }
1007 return JSONGenerator::ObjectSP();
Jason Molendaa2992312016-07-07 01:09:23 +00001008}
1009
Kate Stoneb9c1b512016-09-06 20:57:50 +00001010const char *DNBProcessGetExecutablePath(nub_process_t pid) {
1011 MachProcessSP procSP;
1012 if (GetProcessSP(pid, procSP)) {
1013 return procSP->Path();
1014 }
1015 return NULL;
Jason Molendaa2992312016-07-07 01:09:23 +00001016}
1017
Kate Stoneb9c1b512016-09-06 20:57:50 +00001018nub_size_t DNBProcessGetArgumentCount(nub_process_t pid) {
1019 MachProcessSP procSP;
1020 if (GetProcessSP(pid, procSP)) {
1021 return procSP->ArgumentCount();
1022 }
1023 return 0;
Jason Molendaa2992312016-07-07 01:09:23 +00001024}
1025
Kate Stoneb9c1b512016-09-06 20:57:50 +00001026const char *DNBProcessGetArgumentAtIndex(nub_process_t pid, nub_size_t idx) {
1027 MachProcessSP procSP;
1028 if (GetProcessSP(pid, procSP)) {
1029 return procSP->ArgumentAtIndex(idx);
1030 }
1031 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001032}
1033
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001034//----------------------------------------------------------------------
1035// Execution control
1036//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001037nub_bool_t DNBProcessResume(nub_process_t pid,
1038 const DNBThreadResumeAction *actions,
1039 size_t num_actions) {
1040 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
1041 MachProcessSP procSP;
1042 if (GetProcessSP(pid, procSP)) {
1043 DNBThreadResumeActions thread_actions(actions, num_actions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001044
Kate Stoneb9c1b512016-09-06 20:57:50 +00001045 // Below we add a default thread plan just in case one wasn't
1046 // provided so all threads always know what they were supposed to do
1047 if (thread_actions.IsEmpty()) {
1048 // No thread plans were given, so the default it to run all threads
1049 thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0);
1050 } else {
1051 // Some thread plans were given which means anything that wasn't
1052 // specified should remain stopped.
1053 thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001054 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001055 return procSP->Resume(thread_actions);
1056 }
1057 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001058}
1059
Kate Stoneb9c1b512016-09-06 20:57:50 +00001060nub_bool_t DNBProcessHalt(nub_process_t pid) {
1061 DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid);
1062 MachProcessSP procSP;
1063 if (GetProcessSP(pid, procSP))
1064 return procSP->Signal(SIGSTOP);
1065 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001066}
1067//
Kate Stoneb9c1b512016-09-06 20:57:50 +00001068// nub_bool_t
1069// DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001070//{
Kate Stoneb9c1b512016-09-06 20:57:50 +00001071// DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)",
1072// __FUNCTION__, pid, tid, (uint32_t)step);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001073// MachProcessSP procSP;
1074// if (GetProcessSP (pid, procSP))
1075// {
1076// return procSP->Resume(tid, step, 0);
1077// }
1078// return false;
1079//}
1080//
Kate Stoneb9c1b512016-09-06 20:57:50 +00001081// nub_bool_t
1082// DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t
1083// step, int signal)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001084//{
Kate Stoneb9c1b512016-09-06 20:57:50 +00001085// DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u,
1086// signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001087// MachProcessSP procSP;
1088// if (GetProcessSP (pid, procSP))
1089// {
1090// return procSP->Resume(tid, step, signal);
1091// }
1092// return false;
1093//}
1094
Kate Stoneb9c1b512016-09-06 20:57:50 +00001095nub_event_t DNBProcessWaitForEvents(nub_process_t pid, nub_event_t event_mask,
1096 bool wait_for_set,
1097 struct timespec *timeout) {
1098 nub_event_t result = 0;
1099 MachProcessSP procSP;
1100 if (GetProcessSP(pid, procSP)) {
1101 if (wait_for_set)
1102 result = procSP->Events().WaitForSetEvents(event_mask, timeout);
1103 else
1104 result = procSP->Events().WaitForEventsToReset(event_mask, timeout);
1105 }
1106 return result;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001107}
1108
Kate Stoneb9c1b512016-09-06 20:57:50 +00001109void DNBProcessResetEvents(nub_process_t pid, nub_event_t event_mask) {
1110 MachProcessSP procSP;
1111 if (GetProcessSP(pid, procSP))
1112 procSP->Events().ResetEvents(event_mask);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001113}
1114
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001115// Breakpoints
Kate Stoneb9c1b512016-09-06 20:57:50 +00001116nub_bool_t DNBBreakpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1117 nub_bool_t hardware) {
1118 MachProcessSP procSP;
1119 if (GetProcessSP(pid, procSP))
1120 return procSP->CreateBreakpoint(addr, size, hardware) != NULL;
1121 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001122}
1123
Kate Stoneb9c1b512016-09-06 20:57:50 +00001124nub_bool_t DNBBreakpointClear(nub_process_t pid, nub_addr_t addr) {
1125 MachProcessSP procSP;
1126 if (GetProcessSP(pid, procSP))
1127 return procSP->DisableBreakpoint(addr, true);
1128 return false; // Failed
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001129}
1130
1131//----------------------------------------------------------------------
1132// Watchpoints
1133//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001134nub_bool_t DNBWatchpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
1135 uint32_t watch_flags, nub_bool_t hardware) {
1136 MachProcessSP procSP;
1137 if (GetProcessSP(pid, procSP))
1138 return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL;
1139 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001140}
1141
Kate Stoneb9c1b512016-09-06 20:57:50 +00001142nub_bool_t DNBWatchpointClear(nub_process_t pid, nub_addr_t addr) {
1143 MachProcessSP procSP;
1144 if (GetProcessSP(pid, procSP))
1145 return procSP->DisableWatchpoint(addr, true);
1146 return false; // Failed
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001147}
1148
1149//----------------------------------------------------------------------
Johnny Chen64637202012-05-23 21:09:52 +00001150// Return the number of supported hardware watchpoints.
1151//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001152uint32_t DNBWatchpointGetNumSupportedHWP(nub_process_t pid) {
1153 MachProcessSP procSP;
1154 if (GetProcessSP(pid, procSP))
1155 return procSP->GetNumSupportedHardwareWatchpoints();
1156 return 0;
Johnny Chen64637202012-05-23 21:09:52 +00001157}
1158
1159//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001160// Read memory in the address space of process PID. This call will take
1161// care of setting and restoring permissions and breaking up the memory
1162// read into multiple chunks as required.
1163//
1164// RETURNS: number of bytes actually read
1165//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001166nub_size_t DNBProcessMemoryRead(nub_process_t pid, nub_addr_t addr,
1167 nub_size_t size, void *buf) {
1168 MachProcessSP procSP;
1169 if (GetProcessSP(pid, procSP))
1170 return procSP->ReadMemory(addr, size, buf);
1171 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001172}
1173
Kate Stoneb9c1b512016-09-06 20:57:50 +00001174uint64_t DNBProcessMemoryReadInteger(nub_process_t pid, nub_addr_t addr,
1175 nub_size_t integer_size,
1176 uint64_t fail_value) {
1177 union Integers {
1178 uint8_t u8;
1179 uint16_t u16;
1180 uint32_t u32;
1181 uint64_t u64;
1182 };
Greg Clayton0b90be12015-06-23 21:27:50 +00001183
Kate Stoneb9c1b512016-09-06 20:57:50 +00001184 if (integer_size <= sizeof(uint64_t)) {
1185 Integers ints;
1186 if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size) {
1187 switch (integer_size) {
1188 case 1:
1189 return ints.u8;
1190 case 2:
1191 return ints.u16;
1192 case 3:
1193 return ints.u32 & 0xffffffu;
1194 case 4:
1195 return ints.u32;
1196 case 5:
1197 return ints.u32 & 0x000000ffffffffffull;
1198 case 6:
1199 return ints.u32 & 0x0000ffffffffffffull;
1200 case 7:
1201 return ints.u32 & 0x00ffffffffffffffull;
1202 case 8:
1203 return ints.u64;
1204 }
Greg Clayton0b90be12015-06-23 21:27:50 +00001205 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001206 }
1207 return fail_value;
Greg Clayton0b90be12015-06-23 21:27:50 +00001208}
1209
Kate Stoneb9c1b512016-09-06 20:57:50 +00001210nub_addr_t DNBProcessMemoryReadPointer(nub_process_t pid, nub_addr_t addr) {
1211 cpu_type_t cputype = DNBProcessGetCPUType(pid);
1212 if (cputype) {
1213 const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4;
1214 return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0);
1215 }
1216 return 0;
Greg Clayton0b90be12015-06-23 21:27:50 +00001217}
1218
Kate Stoneb9c1b512016-09-06 20:57:50 +00001219std::string DNBProcessMemoryReadCString(nub_process_t pid, nub_addr_t addr) {
1220 std::string cstr;
1221 char buffer[256];
1222 const nub_size_t max_buffer_cstr_length = sizeof(buffer) - 1;
1223 buffer[max_buffer_cstr_length] = '\0';
1224 nub_size_t length = 0;
1225 nub_addr_t curr_addr = addr;
1226 do {
1227 nub_size_t bytes_read =
1228 DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer);
1229 if (bytes_read == 0)
1230 break;
1231 length = strlen(buffer);
1232 cstr.append(buffer, length);
1233 curr_addr += length;
1234 } while (length == max_buffer_cstr_length);
1235 return cstr;
Greg Clayton0b90be12015-06-23 21:27:50 +00001236}
1237
Kate Stoneb9c1b512016-09-06 20:57:50 +00001238std::string DNBProcessMemoryReadCStringFixed(nub_process_t pid, nub_addr_t addr,
1239 nub_size_t fixed_length) {
1240 std::string cstr;
1241 char buffer[fixed_length + 1];
1242 buffer[fixed_length] = '\0';
1243 nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer);
1244 if (bytes_read > 0)
1245 cstr.assign(buffer);
1246 return cstr;
Greg Clayton0b90be12015-06-23 21:27:50 +00001247}
1248
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001249//----------------------------------------------------------------------
1250// Write memory to the address space of process PID. This call will take
1251// care of setting and restoring permissions and breaking up the memory
1252// write into multiple chunks as required.
1253//
1254// RETURNS: number of bytes actually written
1255//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001256nub_size_t DNBProcessMemoryWrite(nub_process_t pid, nub_addr_t addr,
1257 nub_size_t size, const void *buf) {
1258 MachProcessSP procSP;
1259 if (GetProcessSP(pid, procSP))
1260 return procSP->WriteMemory(addr, size, buf);
1261 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001262}
1263
Kate Stoneb9c1b512016-09-06 20:57:50 +00001264nub_addr_t DNBProcessMemoryAllocate(nub_process_t pid, nub_size_t size,
1265 uint32_t permissions) {
1266 MachProcessSP procSP;
1267 if (GetProcessSP(pid, procSP))
1268 return procSP->Task().AllocateMemory(size, permissions);
1269 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001270}
1271
Kate Stoneb9c1b512016-09-06 20:57:50 +00001272nub_bool_t DNBProcessMemoryDeallocate(nub_process_t pid, nub_addr_t addr) {
1273 MachProcessSP procSP;
1274 if (GetProcessSP(pid, procSP))
1275 return procSP->Task().DeallocateMemory(addr);
1276 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001277}
1278
Jason Molenda1f3966b2011-11-08 04:28:12 +00001279//----------------------------------------------------------------------
Jason Molenda3dc85832011-11-09 08:03:56 +00001280// Find attributes of the memory region that contains ADDR for process PID,
1281// if possible, and return a string describing those attributes.
Jason Molenda1f3966b2011-11-08 04:28:12 +00001282//
Jason Molenda3dc85832011-11-09 08:03:56 +00001283// Returns 1 if we could find attributes for this region and OUTBUF can
1284// be sent to the remote debugger.
Jason Molenda1f3966b2011-11-08 04:28:12 +00001285//
Jason Molenda3dc85832011-11-09 08:03:56 +00001286// Returns 0 if we couldn't find the attributes for a region of memory at
1287// that address and OUTBUF should not be sent.
1288//
1289// Returns -1 if this platform cannot look up information about memory regions
1290// or if we do not yet have a valid launched process.
1291//
Jason Molenda1f3966b2011-11-08 04:28:12 +00001292//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001293int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr,
1294 DNBRegionInfo *region_info) {
1295 MachProcessSP procSP;
1296 if (GetProcessSP(pid, procSP))
1297 return procSP->Task().GetMemoryRegionInfo(addr, region_info);
Greg Clayton46fb5582011-11-18 07:03:08 +00001298
Kate Stoneb9c1b512016-09-06 20:57:50 +00001299 return -1;
Jason Molenda1f3966b2011-11-08 04:28:12 +00001300}
1301
Kate Stoneb9c1b512016-09-06 20:57:50 +00001302std::string DNBProcessGetProfileData(nub_process_t pid,
1303 DNBProfileDataScanType scanType) {
1304 MachProcessSP procSP;
1305 if (GetProcessSP(pid, procSP))
1306 return procSP->Task().GetProfileData(scanType);
1307
1308 return std::string("");
Han Ming Ongab3b8b22012-11-17 00:21:04 +00001309}
1310
Kate Stoneb9c1b512016-09-06 20:57:50 +00001311nub_bool_t DNBProcessSetEnableAsyncProfiling(nub_process_t pid,
1312 nub_bool_t enable,
1313 uint64_t interval_usec,
1314 DNBProfileDataScanType scan_type) {
1315 MachProcessSP procSP;
1316 if (GetProcessSP(pid, procSP)) {
1317 procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type);
1318 return true;
1319 }
1320
1321 return false;
Han Ming Ongab3b8b22012-11-17 00:21:04 +00001322}
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001323
1324//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001325// Get the number of threads for the specified process.
1326//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001327nub_size_t DNBProcessGetNumThreads(nub_process_t pid) {
1328 MachProcessSP procSP;
1329 if (GetProcessSP(pid, procSP))
1330 return procSP->GetNumThreads();
1331 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001332}
1333
1334//----------------------------------------------------------------------
1335// Get the thread ID of the current thread.
1336//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001337nub_thread_t DNBProcessGetCurrentThread(nub_process_t pid) {
1338 MachProcessSP procSP;
1339 if (GetProcessSP(pid, procSP))
1340 return procSP->GetCurrentThread();
1341 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001342}
1343
1344//----------------------------------------------------------------------
Jason Molendad5318c02013-04-03 04:18:47 +00001345// Get the mach port number of the current thread.
1346//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001347nub_thread_t DNBProcessGetCurrentThreadMachPort(nub_process_t pid) {
1348 MachProcessSP procSP;
1349 if (GetProcessSP(pid, procSP))
1350 return procSP->GetCurrentThreadMachPort();
1351 return 0;
Jason Molendad5318c02013-04-03 04:18:47 +00001352}
1353
1354//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001355// Change the current thread.
1356//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001357nub_thread_t DNBProcessSetCurrentThread(nub_process_t pid, nub_thread_t tid) {
1358 MachProcessSP procSP;
1359 if (GetProcessSP(pid, procSP))
1360 return procSP->SetCurrentThread(tid);
1361 return INVALID_NUB_THREAD;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001362}
1363
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001364//----------------------------------------------------------------------
1365// Dump a string describing a thread's stop reason to the specified file
1366// handle
1367//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001368nub_bool_t DNBThreadGetStopReason(nub_process_t pid, nub_thread_t tid,
1369 struct DNBThreadStopInfo *stop_info) {
1370 MachProcessSP procSP;
1371 if (GetProcessSP(pid, procSP))
1372 return procSP->GetThreadStoppedReason(tid, stop_info);
1373 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001374}
1375
1376//----------------------------------------------------------------------
1377// Return string description for the specified thread.
1378//
1379// RETURNS: NULL if the thread isn't valid, else a NULL terminated C
1380// string from a static buffer that must be copied prior to subsequent
1381// calls.
1382//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001383const char *DNBThreadGetInfo(nub_process_t pid, nub_thread_t tid) {
1384 MachProcessSP procSP;
1385 if (GetProcessSP(pid, procSP))
1386 return procSP->GetThreadInfo(tid);
1387 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001388}
1389
1390//----------------------------------------------------------------------
1391// Get the thread ID given a thread index.
1392//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001393nub_thread_t DNBProcessGetThreadAtIndex(nub_process_t pid, size_t thread_idx) {
1394 MachProcessSP procSP;
1395 if (GetProcessSP(pid, procSP))
1396 return procSP->GetThreadAtIndex(thread_idx);
1397 return INVALID_NUB_THREAD;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001398}
1399
Jim Ingham279ceec2012-07-25 21:12:43 +00001400//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001401// Do whatever is needed to sync the thread's register state with it's kernel
1402// values.
Jim Ingham279ceec2012-07-25 21:12:43 +00001403//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001404nub_bool_t DNBProcessSyncThreadState(nub_process_t pid, nub_thread_t tid) {
1405 MachProcessSP procSP;
1406 if (GetProcessSP(pid, procSP))
1407 return procSP->SyncThreadState(tid);
1408 return false;
Jim Ingham279ceec2012-07-25 21:12:43 +00001409}
1410
Kate Stoneb9c1b512016-09-06 20:57:50 +00001411nub_addr_t DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid) {
1412 MachProcessSP procSP;
1413 DNBError err;
1414 if (GetProcessSP(pid, procSP))
1415 return procSP->Task().GetDYLDAllImageInfosAddress(err);
1416 return INVALID_NUB_ADDRESS;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001417}
1418
Kate Stoneb9c1b512016-09-06 20:57:50 +00001419nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) {
1420 MachProcessSP procSP;
1421 if (GetProcessSP(pid, procSP)) {
1422 procSP->SharedLibrariesUpdated();
1423 return true;
1424 }
1425 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001426}
1427
Frederic Risscd90f872018-04-06 04:28:12 +00001428const char *DNBGetDeploymentInfo(nub_process_t pid,
1429 const struct load_command& lc,
1430 uint64_t load_command_address,
1431 uint32_t& major_version,
1432 uint32_t& minor_version,
1433 uint32_t& patch_version) {
1434 MachProcessSP procSP;
1435 if (GetProcessSP(pid, procSP))
1436 return procSP->GetDeploymentInfo(lc, load_command_address,
1437 major_version, minor_version,
1438 patch_version);
1439 return nullptr;
1440}
1441
1442
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001443//----------------------------------------------------------------------
1444// Get the current shared library information for a process. Only return
1445// the shared libraries that have changed since the last shared library
1446// state changed event if only_changed is non-zero.
1447//----------------------------------------------------------------------
1448nub_size_t
Kate Stoneb9c1b512016-09-06 20:57:50 +00001449DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed,
1450 struct DNBExecutableImageInfo **image_infos) {
1451 MachProcessSP procSP;
1452 if (GetProcessSP(pid, procSP))
1453 return procSP->CopyImageInfos(image_infos, only_changed);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001454
Kate Stoneb9c1b512016-09-06 20:57:50 +00001455 // If we have no process, then return NULL for the shared library info
1456 // and zero for shared library count
1457 *image_infos = NULL;
1458 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001459}
1460
Kate Stoneb9c1b512016-09-06 20:57:50 +00001461uint32_t DNBGetRegisterCPUType() {
1462 return DNBArchProtocol::GetRegisterCPUType();
Greg Claytond04f0ed2015-05-26 18:00:51 +00001463}
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001464//----------------------------------------------------------------------
1465// Get the register set information for a specific thread.
1466//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001467const DNBRegisterSetInfo *DNBGetRegisterSetInfo(nub_size_t *num_reg_sets) {
1468 return DNBArchProtocol::GetRegisterSetInfo(num_reg_sets);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001469}
1470
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001471//----------------------------------------------------------------------
1472// Read a register value by register set and register index.
1473//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001474nub_bool_t DNBThreadGetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1475 uint32_t set, uint32_t reg,
1476 DNBRegisterValue *value) {
1477 MachProcessSP procSP;
1478 ::bzero(value, sizeof(DNBRegisterValue));
1479 if (GetProcessSP(pid, procSP)) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001480 if (tid != INVALID_NUB_THREAD)
Kate Stoneb9c1b512016-09-06 20:57:50 +00001481 return procSP->GetRegisterValue(tid, set, reg, value);
1482 }
1483 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001484}
1485
Kate Stoneb9c1b512016-09-06 20:57:50 +00001486nub_bool_t DNBThreadSetRegisterValueByID(nub_process_t pid, nub_thread_t tid,
1487 uint32_t set, uint32_t reg,
1488 const DNBRegisterValue *value) {
1489 if (tid != INVALID_NUB_THREAD) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001490 MachProcessSP procSP;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001491 if (GetProcessSP(pid, procSP))
1492 return procSP->SetRegisterValue(tid, set, reg, value);
1493 }
1494 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001495}
1496
Kate Stoneb9c1b512016-09-06 20:57:50 +00001497nub_size_t DNBThreadGetRegisterContext(nub_process_t pid, nub_thread_t tid,
1498 void *buf, size_t buf_len) {
1499 MachProcessSP procSP;
1500 if (GetProcessSP(pid, procSP)) {
1501 if (tid != INVALID_NUB_THREAD)
1502 return procSP->GetThreadList().GetRegisterContext(tid, buf, buf_len);
1503 }
1504 ::bzero(buf, buf_len);
1505 return 0;
1506}
1507
1508nub_size_t DNBThreadSetRegisterContext(nub_process_t pid, nub_thread_t tid,
1509 const void *buf, size_t buf_len) {
1510 MachProcessSP procSP;
1511 if (GetProcessSP(pid, procSP)) {
1512 if (tid != INVALID_NUB_THREAD)
1513 return procSP->GetThreadList().SetRegisterContext(tid, buf, buf_len);
1514 }
1515 return 0;
1516}
1517
1518uint32_t DNBThreadSaveRegisterState(nub_process_t pid, nub_thread_t tid) {
1519 if (tid != INVALID_NUB_THREAD) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001520 MachProcessSP procSP;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001521 if (GetProcessSP(pid, procSP))
1522 return procSP->GetThreadList().SaveRegisterState(tid);
1523 }
1524 return 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001525}
Kate Stoneb9c1b512016-09-06 20:57:50 +00001526nub_bool_t DNBThreadRestoreRegisterState(nub_process_t pid, nub_thread_t tid,
1527 uint32_t save_id) {
1528 if (tid != INVALID_NUB_THREAD) {
1529 MachProcessSP procSP;
1530 if (GetProcessSP(pid, procSP))
1531 return procSP->GetThreadList().RestoreRegisterState(tid, save_id);
1532 }
1533 return false;
Greg Claytonf74cf862013-11-13 23:28:31 +00001534}
Greg Claytonf74cf862013-11-13 23:28:31 +00001535
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001536//----------------------------------------------------------------------
1537// Read a register value by name.
1538//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001539nub_bool_t DNBThreadGetRegisterValueByName(nub_process_t pid, nub_thread_t tid,
1540 uint32_t reg_set,
1541 const char *reg_name,
1542 DNBRegisterValue *value) {
1543 MachProcessSP procSP;
1544 ::bzero(value, sizeof(DNBRegisterValue));
1545 if (GetProcessSP(pid, procSP)) {
1546 const struct DNBRegisterSetInfo *set_info;
1547 nub_size_t num_reg_sets = 0;
1548 set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1549 if (set_info) {
1550 uint32_t set = reg_set;
1551 uint32_t reg;
1552 if (set == REGISTER_SET_ALL) {
1553 for (set = 1; set < num_reg_sets; ++set) {
1554 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1555 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1556 return procSP->GetRegisterValue(tid, set, reg, value);
1557 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001558 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001559 } else {
1560 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1561 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0)
1562 return procSP->GetRegisterValue(tid, set, reg, value);
1563 }
1564 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001565 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001566 }
1567 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001568}
1569
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001570//----------------------------------------------------------------------
1571// Read a register set and register number from the register name.
1572//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001573nub_bool_t DNBGetRegisterInfoByName(const char *reg_name,
1574 DNBRegisterInfo *info) {
1575 const struct DNBRegisterSetInfo *set_info;
1576 nub_size_t num_reg_sets = 0;
1577 set_info = DNBGetRegisterSetInfo(&num_reg_sets);
1578 if (set_info) {
1579 uint32_t set, reg;
1580 for (set = 1; set < num_reg_sets; ++set) {
1581 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1582 if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) {
1583 *info = set_info[set].registers[reg];
1584 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001585 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001586 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001587 }
1588
Kate Stoneb9c1b512016-09-06 20:57:50 +00001589 for (set = 1; set < num_reg_sets; ++set) {
1590 uint32_t reg;
1591 for (reg = 0; reg < set_info[set].num_registers; ++reg) {
1592 if (set_info[set].registers[reg].alt == NULL)
1593 continue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001594
Kate Stoneb9c1b512016-09-06 20:57:50 +00001595 if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0) {
1596 *info = set_info[set].registers[reg];
1597 return true;
1598 }
1599 }
1600 }
1601 }
1602
1603 ::bzero(info, sizeof(DNBRegisterInfo));
1604 return false;
1605}
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001606
1607//----------------------------------------------------------------------
1608// Set the name to address callback function that this nub can use
1609// for any name to address lookups that are needed.
1610//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001611nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid,
1612 DNBCallbackNameToAddress callback,
1613 void *baton) {
1614 MachProcessSP procSP;
1615 if (GetProcessSP(pid, procSP)) {
1616 procSP->SetNameToAddressCallback(callback, baton);
1617 return true;
1618 }
1619 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001620}
1621
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001622//----------------------------------------------------------------------
1623// Set the name to address callback function that this nub can use
1624// for any name to address lookups that are needed.
1625//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +00001626nub_bool_t DNBProcessSetSharedLibraryInfoCallback(
1627 nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback,
1628 void *baton) {
1629 MachProcessSP procSP;
1630 if (GetProcessSP(pid, procSP)) {
1631 procSP->SetSharedLibraryInfoCallback(callback, baton);
1632 return true;
1633 }
1634 return false;
1635}
1636
1637nub_addr_t DNBProcessLookupAddress(nub_process_t pid, const char *name,
1638 const char *shlib) {
1639 MachProcessSP procSP;
1640 if (GetProcessSP(pid, procSP)) {
1641 return procSP->LookupSymbol(name, shlib);
1642 }
1643 return INVALID_NUB_ADDRESS;
1644}
1645
1646nub_size_t DNBProcessGetAvailableSTDOUT(nub_process_t pid, char *buf,
1647 nub_size_t buf_size) {
1648 MachProcessSP procSP;
1649 if (GetProcessSP(pid, procSP))
1650 return procSP->GetAvailableSTDOUT(buf, buf_size);
1651 return 0;
1652}
1653
1654nub_size_t DNBProcessGetAvailableSTDERR(nub_process_t pid, char *buf,
1655 nub_size_t buf_size) {
1656 MachProcessSP procSP;
1657 if (GetProcessSP(pid, procSP))
1658 return procSP->GetAvailableSTDERR(buf, buf_size);
1659 return 0;
1660}
1661
1662nub_size_t DNBProcessGetAvailableProfileData(nub_process_t pid, char *buf,
1663 nub_size_t buf_size) {
1664 MachProcessSP procSP;
1665 if (GetProcessSP(pid, procSP))
1666 return procSP->GetAsyncProfileData(buf, buf_size);
1667 return 0;
1668}
1669
1670DarwinLogEventVector DNBProcessGetAvailableDarwinLogEvents(nub_process_t pid) {
1671 return DarwinLogCollector::GetEventsForProcess(pid);
1672}
1673
1674nub_size_t DNBProcessGetStopCount(nub_process_t pid) {
1675 MachProcessSP procSP;
1676 if (GetProcessSP(pid, procSP))
1677 return procSP->StopCount();
1678 return 0;
1679}
1680
1681uint32_t DNBProcessGetCPUType(nub_process_t pid) {
1682 MachProcessSP procSP;
1683 if (GetProcessSP(pid, procSP))
1684 return procSP->GetCPUType();
1685 return 0;
1686}
1687
1688nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path,
1689 size_t resolved_path_size) {
1690 if (path == NULL || path[0] == '\0')
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001691 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001692
Kate Stoneb9c1b512016-09-06 20:57:50 +00001693 char max_path[PATH_MAX];
1694 std::string result;
1695 CFString::GlobPath(path, result);
1696
1697 if (result.empty())
1698 result = path;
1699
1700 struct stat path_stat;
1701 if (::stat(path, &path_stat) == 0) {
1702 if ((path_stat.st_mode & S_IFMT) == S_IFDIR) {
1703 CFBundle bundle(path);
1704 CFReleaser<CFURLRef> url(bundle.CopyExecutableURL());
1705 if (url.get()) {
1706 if (::CFURLGetFileSystemRepresentation(
1707 url.get(), true, (UInt8 *)resolved_path, resolved_path_size))
1708 return true;
1709 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001710 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001711 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001712
Kate Stoneb9c1b512016-09-06 20:57:50 +00001713 if (realpath(path, max_path)) {
1714 // Found the path relatively...
Jason Molendaaae5b692017-12-09 03:37:09 +00001715 ::strlcpy(resolved_path, max_path, resolved_path_size);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001716 return strlen(resolved_path) + 1 < resolved_path_size;
1717 } else {
1718 // Not a relative path, check the PATH environment variable if the
1719 const char *PATH = getenv("PATH");
1720 if (PATH) {
1721 const char *curr_path_start = PATH;
1722 const char *curr_path_end;
1723 while (curr_path_start && *curr_path_start) {
1724 curr_path_end = strchr(curr_path_start, ':');
1725 if (curr_path_end == NULL) {
1726 result.assign(curr_path_start);
1727 curr_path_start = NULL;
1728 } else if (curr_path_end > curr_path_start) {
1729 size_t len = curr_path_end - curr_path_start;
1730 result.assign(curr_path_start, len);
1731 curr_path_start += len + 1;
1732 } else
1733 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001734
Kate Stoneb9c1b512016-09-06 20:57:50 +00001735 result += '/';
1736 result += path;
1737 struct stat s;
1738 if (stat(result.c_str(), &s) == 0) {
Jason Molendaaae5b692017-12-09 03:37:09 +00001739 ::strlcpy(resolved_path, result.c_str(), resolved_path_size);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001740 return result.size() + 1 < resolved_path_size;
Greg Clayton48baf7a2012-10-31 21:44:39 +00001741 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001742 }
Greg Clayton48baf7a2012-10-31 21:44:39 +00001743 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001744 }
1745 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001746}
1747
Kate Stoneb9c1b512016-09-06 20:57:50 +00001748bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch) {
1749 return MachProcess::GetOSVersionNumbers(major, minor, patch);
Jason Molenda6acc86c2015-08-12 03:27:33 +00001750}
1751
Kate Stoneb9c1b512016-09-06 20:57:50 +00001752void DNBInitialize() {
1753 DNBLogThreadedIf(LOG_PROCESS, "DNBInitialize ()");
1754#if defined(__i386__) || defined(__x86_64__)
1755 DNBArchImplI386::Initialize();
1756 DNBArchImplX86_64::Initialize();
1757#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
1758 DNBArchMachARM::Initialize();
1759 DNBArchMachARM64::Initialize();
Greg Clayton3af9ea52010-11-18 05:57:03 +00001760#endif
1761}
1762
Kate Stoneb9c1b512016-09-06 20:57:50 +00001763void DNBTerminate() {}
Greg Clayton3c144382010-12-01 22:45:40 +00001764
Kate Stoneb9c1b512016-09-06 20:57:50 +00001765nub_bool_t DNBSetArchitecture(const char *arch) {
1766 if (arch && arch[0]) {
1767 if (strcasecmp(arch, "i386") == 0)
1768 return DNBArchProtocol::SetArchitecture(CPU_TYPE_I386);
1769 else if ((strcasecmp(arch, "x86_64") == 0) ||
1770 (strcasecmp(arch, "x86_64h") == 0))
1771 return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64);
1772 else if (strstr(arch, "arm64") == arch || strstr(arch, "armv8") == arch ||
1773 strstr(arch, "aarch64") == arch)
1774 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64);
1775 else if (strstr(arch, "arm") == arch)
1776 return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM);
1777 }
1778 return false;
Greg Clayton3c144382010-12-01 22:45:40 +00001779}