Source/PLCrashProcessInfo.m (51 lines of code) (raw):

/* * Author: Landon Fuller <landonf@plausiblelabs.com> * * Copyright (c) 2013 Plausible Labs Cooperative, Inc. * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #import "PLCrashProcessInfo.h" #import "PLCrashAsync.h" #import <unistd.h> #include "PLCrashSysctl.h" #include <sys/types.h> #include <sys/sysctl.h> /** * @internal * @ingroup plcrash_host * * @{ */ /** * The PLCrashProcessInfo provides methods to access basic information about a target process. */ @implementation PLCrashProcessInfo @synthesize processID = _processID; @synthesize processName = _processName; @synthesize parentProcessID = _parentProcessID; @synthesize traced = _traced; @synthesize startTime = _startTime; /** * Return the current process info of the calling process. Note that these values * will be fetched once, and the returned instance is immutable. */ + (instancetype) currentProcessInfo { return [[self alloc] initWithProcessID: getpid()]; } /** * Initialize a new instance with the process info for the process with @a pid. Returns nil if * @a pid does not reference a valid process. * * @param pid The process identifier of the target process. */ - (instancetype) initWithProcessID: (pid_t) pid { if ((self = [super init]) == nil) return nil; /* Fetch the kinfo_proc structure for the target pid */ int process_info_mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; struct kinfo_proc process_info; size_t process_info_len = sizeof(process_info); /* This should always succeed unless the process is not found, or on iOS 9 and similar locked down operating systems where * this may return EPERM. */ if (sysctl(process_info_mib, sizeof(process_info_mib)/sizeof(process_info_mib[0]), &process_info, &process_info_len, NULL, 0) != 0) { if (errno == ENOENT) PLCF_DEBUG("Unexpected sysctl error %d: %s", errno, strerror(errno)); return nil; } /* Fetch the traced flag */ if (process_info.kp_proc.p_flag & P_TRACED) _traced = true; /* Fetch the process name. This is a best effort attempt */ { /* Clean up any UTF-8 multibyte characters truncated by the kernel -- xnu does not * use a UTF-8-aware strcpy when copying names to the fixed p_comm buffer */ PLCF_ASSERT(sizeof(process_info.kp_proc.p_comm) == MAXCOMLEN+1); size_t valid_bytes = plcrash_sysctl_valid_utf8_bytes_max((uint8_t *) process_info.kp_proc.p_comm, MAXCOMLEN); /* If any valid data is found, try to decode the string; this will return nil if the string still contains invalid UTF-8 */ if (valid_bytes > 0) { _processName = [[NSString alloc] initWithBytes: process_info.kp_proc.p_comm length: valid_bytes encoding: NSUTF8StringEncoding]; } else { _processName = nil; } /* If decoding failed, the process name is not valid UTF-8, even after our attempt at cleaning up * any invalid multibyte sequences. */ if (_processName == nil) { /* Given that HFS+ enforces UTF-8, and the p_comm value is derived from the file system execv path, * this should happen very rarely, if ever. */ PLCF_DEBUG("Failed to decode p_comm for pid=%" PRIdMAX " as UTF-8!", (intmax_t) pid); } } _processID = pid; _parentProcessID = process_info.kp_eproc.e_ppid; _startTime = process_info.kp_proc.p_starttime; return self; } @end /* * @} */