1a332978bSJason Molenda//===-- MachProcess.cpp -----------------------------------------*- C++ -*-===// 2a332978bSJason Molenda// 32946cd70SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth// See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a332978bSJason Molenda// 7a332978bSJason Molenda//===----------------------------------------------------------------------===// 8a332978bSJason Molenda// 9a332978bSJason Molenda// Created by Greg Clayton on 6/15/07. 10a332978bSJason Molenda// 11a332978bSJason Molenda//===----------------------------------------------------------------------===// 12a332978bSJason Molenda 13a332978bSJason Molenda#include "DNB.h" 14b9c1b51eSKate Stone#include "MacOSX/CFUtils.h" 15b9c1b51eSKate Stone#include "SysSignal.h" 16a2992311SJason Molenda#include <dlfcn.h> 17a332978bSJason Molenda#include <inttypes.h> 18b9c1b51eSKate Stone#include <mach-o/loader.h> 19a332978bSJason Molenda#include <mach/mach.h> 20a2992311SJason Molenda#include <mach/task.h> 21b9c1b51eSKate Stone#include <pthread.h> 22a332978bSJason Molenda#include <signal.h> 23a332978bSJason Molenda#include <spawn.h> 24a332978bSJason Molenda#include <sys/fcntl.h> 25a332978bSJason Molenda#include <sys/ptrace.h> 26a332978bSJason Molenda#include <sys/stat.h> 27a332978bSJason Molenda#include <sys/sysctl.h> 283cd13c46SJim Ingham#include <sys/time.h> 29b9c1b51eSKate Stone#include <sys/types.h> 30a332978bSJason Molenda#include <unistd.h> 3120ee21bdSJason Molenda#include <uuid/uuid.h> 32a332978bSJason Molenda 33a332978bSJason Molenda#include <algorithm> 343cd13c46SJim Ingham#include <chrono> 35a332978bSJason Molenda#include <map> 36a332978bSJason Molenda 37c9537b9cSFred Riss#include <TargetConditionals.h> 386acc86c3SJason Molenda#import <Foundation/Foundation.h> 396acc86c3SJason Molenda 40a332978bSJason Molenda#include "DNBDataRef.h" 41a332978bSJason Molenda#include "DNBLog.h" 42a332978bSJason Molenda#include "DNBThreadResumeActions.h" 43a332978bSJason Molenda#include "DNBTimer.h" 44a332978bSJason Molenda#include "MachProcess.h" 45a332978bSJason Molenda#include "PseudoTerminal.h" 46a332978bSJason Molenda 47a332978bSJason Molenda#include "CFBundle.h" 48a332978bSJason Molenda#include "CFString.h" 49a332978bSJason Molenda 506cebeafaSJason Molenda#ifndef PLATFORM_BRIDGEOS 516cebeafaSJason Molenda#define PLATFORM_BRIDGEOS 5 526cebeafaSJason Molenda#endif 536cebeafaSJason Molenda 546cebeafaSJason Molenda#ifndef PLATFORM_MACCATALYST 556cebeafaSJason Molenda#define PLATFORM_MACCATALYST 6 566cebeafaSJason Molenda#endif 576cebeafaSJason Molenda 586cebeafaSJason Molenda#ifndef PLATFORM_IOSSIMULATOR 596cebeafaSJason Molenda#define PLATFORM_IOSSIMULATOR 7 606cebeafaSJason Molenda#endif 616cebeafaSJason Molenda 626cebeafaSJason Molenda#ifndef PLATFORM_TVOSSIMULATOR 636cebeafaSJason Molenda#define PLATFORM_TVOSSIMULATOR 8 646cebeafaSJason Molenda#endif 656cebeafaSJason Molenda 666cebeafaSJason Molenda#ifndef PLATFORM_WATCHOSSIMULATOR 676cebeafaSJason Molenda#define PLATFORM_WATCHOSSIMULATOR 9 686cebeafaSJason Molenda#endif 696cebeafaSJason Molenda 706cebeafaSJason Molenda#ifndef PLATFORM_DRIVERKIT 716cebeafaSJason Molenda#define PLATFORM_DRIVERKIT 10 726cebeafaSJason Molenda#endif 736cebeafaSJason Molenda 74a332978bSJason Molenda#ifdef WITH_SPRINGBOARD 75a332978bSJason Molenda 76a332978bSJason Molenda#include <CoreFoundation/CoreFoundation.h> 77a332978bSJason Molenda#include <SpringBoardServices/SBSWatchdogAssertion.h> 78b9c1b51eSKate Stone#include <SpringBoardServices/SpringBoardServer.h> 79a332978bSJason Molenda 80a332978bSJason Molenda#endif // WITH_SPRINGBOARD 81a332978bSJason Molenda 82e763709dSJason Molenda#if WITH_CAROUSEL 83e763709dSJason Molenda// For definition of CSLSOpenApplicationOptionForClockKit. 84e763709dSJason Molenda#include <CarouselServices/CSLSOpenApplicationOptions.h> 85e763709dSJason Molenda#endif // WITH_CAROUSEL 86e763709dSJason Molenda 87c611a740SJason Molenda#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) || defined(WITH_FBS) 88c611a740SJason Molenda// This returns a CFRetained pointer to the Bundle ID for app_bundle_path, 89c611a740SJason Molenda// or NULL if there was some problem getting the bundle id. 90b9c1b51eSKate Stonestatic CFStringRef CopyBundleIDForPath(const char *app_bundle_path, 91b9c1b51eSKate Stone DNBError &err_str); 92c611a740SJason Molenda#endif 93c611a740SJason Molenda 94c611a740SJason Molenda#if defined(WITH_BKS) || defined(WITH_FBS) 95c611a740SJason Molenda#import <Foundation/Foundation.h> 96c611a740SJason Molendastatic const int OPEN_APPLICATION_TIMEOUT_ERROR = 111; 97d44a0743SJason Molendatypedef void (*SetErrorFunction)(NSInteger, std::string, DNBError &); 98b9c1b51eSKate Stonetypedef bool (*CallOpenApplicationFunction)(NSString *bundleIDNSStr, 99b9c1b51eSKate Stone NSDictionary *options, 100b9c1b51eSKate Stone DNBError &error, pid_t *return_pid); 1017e9bab6aSAdrian Prantl 102b9c1b51eSKate Stone// This function runs the BKSSystemService (or FBSSystemService) method 103b9c1b51eSKate Stone// openApplication:options:clientPort:withResult, 104c611a740SJason Molenda// messaging the app passed in bundleIDNSStr. 105c611a740SJason Molenda// The function should be run inside of an NSAutoReleasePool. 106c611a740SJason Molenda// 107b9c1b51eSKate Stone// It will use the "options" dictionary passed in, and fill the error passed in 108b9c1b51eSKate Stone// if there is an error. 109b9c1b51eSKate Stone// If return_pid is not NULL, we'll fetch the pid that was made for the 110b9c1b51eSKate Stone// bundleID. 111c611a740SJason Molenda// If bundleIDNSStr is NULL, then the system application will be messaged. 112c611a740SJason Molenda 113b9c1b51eSKate Stonetemplate <typename OpenFlavor, typename ErrorFlavor, 114b9c1b51eSKate Stone ErrorFlavor no_error_enum_value, SetErrorFunction error_function> 115b9c1b51eSKate Stonestatic bool CallBoardSystemServiceOpenApplication(NSString *bundleIDNSStr, 116b9c1b51eSKate Stone NSDictionary *options, 117b9c1b51eSKate Stone DNBError &error, 118b9c1b51eSKate Stone pid_t *return_pid) { 119c611a740SJason Molenda // Now make our systemService: 120c611a740SJason Molenda OpenFlavor *system_service = [[OpenFlavor alloc] init]; 121c611a740SJason Molenda 122b9c1b51eSKate Stone if (bundleIDNSStr == nil) { 123c611a740SJason Molenda bundleIDNSStr = [system_service systemApplicationBundleIdentifier]; 124b9c1b51eSKate Stone if (bundleIDNSStr == nil) { 125c611a740SJason Molenda // Okay, no system app... 126c611a740SJason Molenda error.SetErrorString("No system application to message."); 127c611a740SJason Molenda return false; 128c611a740SJason Molenda } 129c611a740SJason Molenda } 130c611a740SJason Molenda 131c611a740SJason Molenda mach_port_t client_port = [system_service createClientPort]; 132c611a740SJason Molenda __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 133c611a740SJason Molenda __block ErrorFlavor open_app_error = no_error_enum_value; 134d44a0743SJason Molenda __block std::string open_app_error_string; 135c611a740SJason Molenda bool wants_pid = (return_pid != NULL); 136c611a740SJason Molenda __block pid_t pid_in_block; 137c611a740SJason Molenda 138c611a740SJason Molenda const char *cstr = [bundleIDNSStr UTF8String]; 139c611a740SJason Molenda if (!cstr) 140c611a740SJason Molenda cstr = "<Unknown Bundle ID>"; 141c611a740SJason Molenda 142e28a93deSJim Ingham NSString *description = [options description]; 143edde2eb1SJason Molenda DNBLog("[LaunchAttach] START (%d) templated *Board launcher: app lunch " 144edde2eb1SJason Molenda "request for " 145edde2eb1SJason Molenda "'%s' - options:\n%s", 146edde2eb1SJason Molenda getpid(), cstr, [description UTF8String]); 147b9c1b51eSKate Stone [system_service 148b9c1b51eSKate Stone openApplication:bundleIDNSStr 149c611a740SJason Molenda options:options 150c611a740SJason Molenda clientPort:client_port 151b9c1b51eSKate Stone withResult:^(NSError *bks_error) { 152b9c1b51eSKate Stone // The system service will cleanup the client port we created for 153b9c1b51eSKate Stone // us. 154c611a740SJason Molenda if (bks_error) 155c611a740SJason Molenda open_app_error = (ErrorFlavor)[bks_error code]; 156c611a740SJason Molenda 157b9c1b51eSKate Stone if (open_app_error == no_error_enum_value) { 158b9c1b51eSKate Stone if (wants_pid) { 159b9c1b51eSKate Stone pid_in_block = 160b9c1b51eSKate Stone [system_service pidForApplication:bundleIDNSStr]; 161edde2eb1SJason Molenda DNBLog("[LaunchAttach] In completion handler, got pid for " 162edde2eb1SJason Molenda "bundle id " 163edde2eb1SJason Molenda "'%s', pid: %d.", 164edde2eb1SJason Molenda cstr, pid_in_block); 165edde2eb1SJason Molenda } else { 166edde2eb1SJason Molenda DNBLog("[LaunchAttach] In completion handler, launch was " 167edde2eb1SJason Molenda "successful, " 168edde2eb1SJason Molenda "debugserver did not ask for the pid"); 169edde2eb1SJason Molenda } 170b9c1b51eSKate Stone } else { 171b9c1b51eSKate Stone const char *error_str = 172b9c1b51eSKate Stone [(NSString *)[bks_error localizedDescription] UTF8String]; 173d44a0743SJason Molenda if (error_str) { 174d44a0743SJason Molenda open_app_error_string = error_str; 175edde2eb1SJason Molenda DNBLogError( 176edde2eb1SJason Molenda "[LaunchAttach] END (%d) In app launch attempt, got error " 177edde2eb1SJason Molenda "localizedDescription '%s'.", 178edde2eb1SJason Molenda getpid(), error_str); 1795034102bSJason Molenda const char *obj_desc = 1805034102bSJason Molenda [NSString stringWithFormat:@"%@", bks_error].UTF8String; 181edde2eb1SJason Molenda DNBLogError( 182edde2eb1SJason Molenda "[LaunchAttach] END (%d) In app launch attempt, got error " 1835034102bSJason Molenda "NSError object description: '%s'.", 184edde2eb1SJason Molenda getpid(), obj_desc); 185d44a0743SJason Molenda } 186edde2eb1SJason Molenda DNBLogThreadedIf(LOG_PROCESS, 187edde2eb1SJason Molenda "In completion handler for send " 188b9c1b51eSKate Stone "event, got error \"%s\"(%ld).", 189c611a740SJason Molenda error_str ? error_str : "<unknown error>", 190edde2eb1SJason Molenda (long)open_app_error); 191c611a740SJason Molenda } 192c611a740SJason Molenda 193c611a740SJason Molenda [system_service release]; 194c611a740SJason Molenda dispatch_semaphore_signal(semaphore); 195c611a740SJason Molenda } 196c611a740SJason Molenda 197c611a740SJason Molenda ]; 198c611a740SJason Molenda 19997c96cb4SJason Molenda const uint32_t timeout_secs = 30; 200c611a740SJason Molenda 201b9c1b51eSKate Stone dispatch_time_t timeout = 202b9c1b51eSKate Stone dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); 203c611a740SJason Molenda 204c611a740SJason Molenda long success = dispatch_semaphore_wait(semaphore, timeout) == 0; 205c611a740SJason Molenda 206c611a740SJason Molenda dispatch_release(semaphore); 207c611a740SJason Molenda 208edde2eb1SJason Molenda DNBLog("[LaunchAttach] END (%d) templated *Board launcher finished app lunch " 209edde2eb1SJason Molenda "request for " 210edde2eb1SJason Molenda "'%s'", 211edde2eb1SJason Molenda getpid(), cstr); 212edde2eb1SJason Molenda 213b9c1b51eSKate Stone if (!success) { 214edde2eb1SJason Molenda DNBLogError("[LaunchAttach] END (%d) timed out trying to send " 215edde2eb1SJason Molenda "openApplication to %s.", 216edde2eb1SJason Molenda getpid(), cstr); 217c611a740SJason Molenda error.SetError(OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); 218c611a740SJason Molenda error.SetErrorString("timed out trying to launch app"); 219b9c1b51eSKate Stone } else if (open_app_error != no_error_enum_value) { 220d44a0743SJason Molenda error_function(open_app_error, open_app_error_string, error); 221edde2eb1SJason Molenda DNBLogError("[LaunchAttach] END (%d) unable to launch the application with " 222edde2eb1SJason Molenda "CFBundleIdentifier '%s' " 223edde2eb1SJason Molenda "bks_error = %ld", 224edde2eb1SJason Molenda getpid(), cstr, (long)open_app_error); 225c611a740SJason Molenda success = false; 226b9c1b51eSKate Stone } else if (wants_pid) { 227c611a740SJason Molenda *return_pid = pid_in_block; 228b9c1b51eSKate Stone DNBLogThreadedIf( 229b9c1b51eSKate Stone LOG_PROCESS, 230b9c1b51eSKate Stone "Out of completion handler, pid from block %d and passing out: %d", 231b9c1b51eSKate Stone pid_in_block, *return_pid); 232c611a740SJason Molenda } 233c611a740SJason Molenda 234c611a740SJason Molenda return success; 235c611a740SJason Molenda} 236c611a740SJason Molenda#endif 237c611a740SJason Molenda 23850048ac6SVedant Kumar#if defined(WITH_BKS) || defined(WITH_FBS) 239eacb0929SVedant Kumarstatic void SplitEventData(const char *data, std::vector<std::string> &elements) 240eacb0929SVedant Kumar{ 241eacb0929SVedant Kumar elements.clear(); 242eacb0929SVedant Kumar if (!data) 243eacb0929SVedant Kumar return; 244eacb0929SVedant Kumar 245eacb0929SVedant Kumar const char *start = data; 246eacb0929SVedant Kumar 247eacb0929SVedant Kumar while (*start != '\0') { 248eacb0929SVedant Kumar const char *token = strchr(start, ':'); 249eacb0929SVedant Kumar if (!token) { 250eacb0929SVedant Kumar elements.push_back(std::string(start)); 251eacb0929SVedant Kumar return; 252eacb0929SVedant Kumar } 253eacb0929SVedant Kumar if (token != start) 254eacb0929SVedant Kumar elements.push_back(std::string(start, token - start)); 255eacb0929SVedant Kumar start = ++token; 256eacb0929SVedant Kumar } 257eacb0929SVedant Kumar} 258eacb0929SVedant Kumar#endif 259eacb0929SVedant Kumar 260a332978bSJason Molenda#ifdef WITH_BKS 261a332978bSJason Molenda#import <Foundation/Foundation.h> 262b9c1b51eSKate Stoneextern "C" { 263a332978bSJason Molenda#import <BackBoardServices/BKSOpenApplicationConstants_Private.h> 264b9c1b51eSKate Stone#import <BackBoardServices/BKSSystemService_LaunchServices.h> 265b9c1b51eSKate Stone#import <BackBoardServices/BackBoardServices.h> 266a332978bSJason Molenda} 267a332978bSJason Molenda 268b9c1b51eSKate Stonestatic bool IsBKSProcess(nub_process_t pid) { 269b9c1b51eSKate Stone BKSApplicationStateMonitor *state_monitor = 270b9c1b51eSKate Stone [[BKSApplicationStateMonitor alloc] init]; 271b9c1b51eSKate Stone BKSApplicationState app_state = 272b9c1b51eSKate Stone [state_monitor mostElevatedApplicationStateForPID:pid]; 273a332978bSJason Molenda return app_state != BKSApplicationStateUnknown; 274a332978bSJason Molenda} 275a332978bSJason Molenda 276d44a0743SJason Molendastatic void SetBKSError(NSInteger error_code, 277d44a0743SJason Molenda std::string error_description, 278d44a0743SJason Molenda DNBError &error) { 279a332978bSJason Molenda error.SetError(error_code, DNBError::BackBoard); 280b9c1b51eSKate Stone NSString *err_nsstr = ::BKSOpenApplicationErrorCodeToString( 281b9c1b51eSKate Stone (BKSOpenApplicationErrorCode)error_code); 282d44a0743SJason Molenda std::string err_str = "unknown BKS error"; 283d44a0743SJason Molenda if (error_description.empty() == false) { 284d44a0743SJason Molenda err_str = error_description; 285d44a0743SJason Molenda } else if (err_nsstr != nullptr) { 286a332978bSJason Molenda err_str = [err_nsstr UTF8String]; 287a332978bSJason Molenda } 288d44a0743SJason Molenda error.SetErrorString(err_str.c_str()); 289a332978bSJason Molenda} 290a332978bSJason Molenda 291b9c1b51eSKate Stonestatic bool BKSAddEventDataToOptions(NSMutableDictionary *options, 292b9c1b51eSKate Stone const char *event_data, 293b9c1b51eSKate Stone DNBError &option_error) { 294e28a93deSJim Ingham std::vector<std::string> values; 295e28a93deSJim Ingham SplitEventData(event_data, values); 296e28a93deSJim Ingham bool found_one = false; 297e28a93deSJim Ingham for (std::string value : values) 298e28a93deSJim Ingham { 299e28a93deSJim Ingham if (value.compare("BackgroundContentFetching") == 0) { 300c611a740SJason Molenda DNBLog("Setting ActivateForEvent key in options dictionary."); 301c611a740SJason Molenda NSDictionary *event_details = [NSDictionary dictionary]; 302b9c1b51eSKate Stone NSDictionary *event_dictionary = [NSDictionary 303b9c1b51eSKate Stone dictionaryWithObject:event_details 304b9c1b51eSKate Stone forKey: 305b9c1b51eSKate Stone BKSActivateForEventOptionTypeBackgroundContentFetching]; 306b9c1b51eSKate Stone [options setObject:event_dictionary 307b9c1b51eSKate Stone forKey:BKSOpenApplicationOptionKeyActivateForEvent]; 308e28a93deSJim Ingham found_one = true; 309e28a93deSJim Ingham } else if (value.compare("ActivateSuspended") == 0) { 310e28a93deSJim Ingham DNBLog("Setting ActivateSuspended key in options dictionary."); 311e28a93deSJim Ingham [options setObject:@YES forKey: BKSOpenApplicationOptionKeyActivateSuspended]; 312e28a93deSJim Ingham found_one = true; 313b9c1b51eSKate Stone } else { 314e28a93deSJim Ingham DNBLogError("Unrecognized event type: %s. Ignoring.", value.c_str()); 315e28a93deSJim Ingham option_error.SetErrorString("Unrecognized event data"); 316c611a740SJason Molenda } 317c611a740SJason Molenda } 318e28a93deSJim Ingham return found_one; 319e28a93deSJim Ingham} 320c611a740SJason Molenda 321b9c1b51eSKate Stonestatic NSMutableDictionary *BKSCreateOptionsDictionary( 322b9c1b51eSKate Stone const char *app_bundle_path, NSMutableArray *launch_argv, 323b9c1b51eSKate Stone NSMutableDictionary *launch_envp, NSString *stdio_path, bool disable_aslr, 324b9c1b51eSKate Stone const char *event_data) { 325c611a740SJason Molenda NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; 326c611a740SJason Molenda if (launch_argv != nil) 327c611a740SJason Molenda [debug_options setObject:launch_argv forKey:BKSDebugOptionKeyArguments]; 328c611a740SJason Molenda if (launch_envp != nil) 329c611a740SJason Molenda [debug_options setObject:launch_envp forKey:BKSDebugOptionKeyEnvironment]; 330c611a740SJason Molenda 331c611a740SJason Molenda [debug_options setObject:stdio_path forKey:BKSDebugOptionKeyStandardOutPath]; 332b9c1b51eSKate Stone [debug_options setObject:stdio_path 333b9c1b51eSKate Stone forKey:BKSDebugOptionKeyStandardErrorPath]; 334b9c1b51eSKate Stone [debug_options setObject:[NSNumber numberWithBool:YES] 335b9c1b51eSKate Stone forKey:BKSDebugOptionKeyWaitForDebugger]; 336c611a740SJason Molenda if (disable_aslr) 337b9c1b51eSKate Stone [debug_options setObject:[NSNumber numberWithBool:YES] 338b9c1b51eSKate Stone forKey:BKSDebugOptionKeyDisableASLR]; 339c611a740SJason Molenda 340c611a740SJason Molenda // That will go in the overall dictionary: 341c611a740SJason Molenda 342c611a740SJason Molenda NSMutableDictionary *options = [NSMutableDictionary dictionary]; 343b9c1b51eSKate Stone [options setObject:debug_options 344b9c1b51eSKate Stone forKey:BKSOpenApplicationOptionKeyDebuggingOptions]; 345c611a740SJason Molenda // And there are some other options at the top level in this dictionary: 346b9c1b51eSKate Stone [options setObject:[NSNumber numberWithBool:YES] 347b9c1b51eSKate Stone forKey:BKSOpenApplicationOptionKeyUnlockDevice]; 348c611a740SJason Molenda 349c611a740SJason Molenda DNBError error; 350c611a740SJason Molenda BKSAddEventDataToOptions(options, event_data, error); 351c611a740SJason Molenda 352c611a740SJason Molenda return options; 353c611a740SJason Molenda} 354c611a740SJason Molenda 355b9c1b51eSKate Stonestatic CallOpenApplicationFunction BKSCallOpenApplicationFunction = 356b9c1b51eSKate Stone CallBoardSystemServiceOpenApplication< 357b9c1b51eSKate Stone BKSSystemService, BKSOpenApplicationErrorCode, 358b9c1b51eSKate Stone BKSOpenApplicationErrorCodeNone, SetBKSError>; 359a332978bSJason Molenda#endif // WITH_BKS 360c611a740SJason Molenda 361c611a740SJason Molenda#ifdef WITH_FBS 362c611a740SJason Molenda#import <Foundation/Foundation.h> 363b9c1b51eSKate Stoneextern "C" { 364c611a740SJason Molenda#import <FrontBoardServices/FBSOpenApplicationConstants_Private.h> 365b9c1b51eSKate Stone#import <FrontBoardServices/FBSSystemService_LaunchServices.h> 366b9c1b51eSKate Stone#import <FrontBoardServices/FrontBoardServices.h> 367c611a740SJason Molenda#import <MobileCoreServices/LSResourceProxy.h> 368b9c1b51eSKate Stone#import <MobileCoreServices/MobileCoreServices.h> 369c611a740SJason Molenda} 370c611a740SJason Molenda 371c611a740SJason Molenda#ifdef WITH_BKS 372b9c1b51eSKate Stonestatic bool IsFBSProcess(nub_process_t pid) { 373b9c1b51eSKate Stone BKSApplicationStateMonitor *state_monitor = 374b9c1b51eSKate Stone [[BKSApplicationStateMonitor alloc] init]; 375b9c1b51eSKate Stone BKSApplicationState app_state = 376b9c1b51eSKate Stone [state_monitor mostElevatedApplicationStateForPID:pid]; 377c611a740SJason Molenda return app_state != BKSApplicationStateUnknown; 378c611a740SJason Molenda} 379c611a740SJason Molenda#else 380b9c1b51eSKate Stonestatic bool IsFBSProcess(nub_process_t pid) { 381c611a740SJason Molenda // FIXME: What is the FBS equivalent of BKSApplicationStateMonitor 382461c4168SJason Molenda return false; 383c611a740SJason Molenda} 384c611a740SJason Molenda#endif 385c611a740SJason Molenda 386d44a0743SJason Molendastatic void SetFBSError(NSInteger error_code, 387d44a0743SJason Molenda std::string error_description, 388d44a0743SJason Molenda DNBError &error) { 389c611a740SJason Molenda error.SetError((DNBError::ValueType)error_code, DNBError::FrontBoard); 390b9c1b51eSKate Stone NSString *err_nsstr = ::FBSOpenApplicationErrorCodeToString( 391b9c1b51eSKate Stone (FBSOpenApplicationErrorCode)error_code); 392d44a0743SJason Molenda std::string err_str = "unknown FBS error"; 393d44a0743SJason Molenda if (error_description.empty() == false) { 394d44a0743SJason Molenda err_str = error_description; 395d44a0743SJason Molenda } else if (err_nsstr != nullptr) { 396c611a740SJason Molenda err_str = [err_nsstr UTF8String]; 397c611a740SJason Molenda } 398d44a0743SJason Molenda error.SetErrorString(err_str.c_str()); 399c611a740SJason Molenda} 400c611a740SJason Molenda 401b9c1b51eSKate Stonestatic bool FBSAddEventDataToOptions(NSMutableDictionary *options, 402b9c1b51eSKate Stone const char *event_data, 403b9c1b51eSKate Stone DNBError &option_error) { 404e28a93deSJim Ingham std::vector<std::string> values; 405e28a93deSJim Ingham SplitEventData(event_data, values); 406e28a93deSJim Ingham bool found_one = false; 407e28a93deSJim Ingham for (std::string value : values) 408e28a93deSJim Ingham { 409e28a93deSJim Ingham if (value.compare("BackgroundContentFetching") == 0) { 410c611a740SJason Molenda DNBLog("Setting ActivateForEvent key in options dictionary."); 411c611a740SJason Molenda NSDictionary *event_details = [NSDictionary dictionary]; 412b9c1b51eSKate Stone NSDictionary *event_dictionary = [NSDictionary 413b9c1b51eSKate Stone dictionaryWithObject:event_details 414b9c1b51eSKate Stone forKey: 415b9c1b51eSKate Stone FBSActivateForEventOptionTypeBackgroundContentFetching]; 416b9c1b51eSKate Stone [options setObject:event_dictionary 417b9c1b51eSKate Stone forKey:FBSOpenApplicationOptionKeyActivateForEvent]; 418e28a93deSJim Ingham found_one = true; 419e28a93deSJim Ingham } else if (value.compare("ActivateSuspended") == 0) { 420e28a93deSJim Ingham DNBLog("Setting ActivateSuspended key in options dictionary."); 421e28a93deSJim Ingham [options setObject:@YES forKey: FBSOpenApplicationOptionKeyActivateSuspended]; 422e28a93deSJim Ingham found_one = true; 423e763709dSJason Molenda#if WITH_CAROUSEL 424e763709dSJason Molenda } else if (value.compare("WatchComplicationLaunch") == 0) { 425e763709dSJason Molenda DNBLog("Setting FBSOpenApplicationOptionKeyActivateSuspended key in options dictionary."); 426e763709dSJason Molenda [options setObject:@YES forKey: CSLSOpenApplicationOptionForClockKit]; 427e763709dSJason Molenda found_one = true; 428e763709dSJason Molenda#endif // WITH_CAROUSEL 429b9c1b51eSKate Stone } else { 430e28a93deSJim Ingham DNBLogError("Unrecognized event type: %s. Ignoring.", value.c_str()); 431c611a740SJason Molenda option_error.SetErrorString("Unrecognized event data."); 432c611a740SJason Molenda } 433c611a740SJason Molenda } 434e28a93deSJim Ingham return found_one; 435e28a93deSJim Ingham} 436c611a740SJason Molenda 437c611a740SJason Molendastatic NSMutableDictionary * 438b9c1b51eSKate StoneFBSCreateOptionsDictionary(const char *app_bundle_path, 439b9c1b51eSKate Stone NSMutableArray *launch_argv, 440b9c1b51eSKate Stone NSDictionary *launch_envp, NSString *stdio_path, 441b9c1b51eSKate Stone bool disable_aslr, const char *event_data) { 442c611a740SJason Molenda NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; 443c611a740SJason Molenda 444c611a740SJason Molenda if (launch_argv != nil) 445c611a740SJason Molenda [debug_options setObject:launch_argv forKey:FBSDebugOptionKeyArguments]; 446c611a740SJason Molenda if (launch_envp != nil) 447c611a740SJason Molenda [debug_options setObject:launch_envp forKey:FBSDebugOptionKeyEnvironment]; 448c611a740SJason Molenda 449c611a740SJason Molenda [debug_options setObject:stdio_path forKey:FBSDebugOptionKeyStandardOutPath]; 450b9c1b51eSKate Stone [debug_options setObject:stdio_path 451b9c1b51eSKate Stone forKey:FBSDebugOptionKeyStandardErrorPath]; 452b9c1b51eSKate Stone [debug_options setObject:[NSNumber numberWithBool:YES] 453b9c1b51eSKate Stone forKey:FBSDebugOptionKeyWaitForDebugger]; 454c611a740SJason Molenda if (disable_aslr) 455b9c1b51eSKate Stone [debug_options setObject:[NSNumber numberWithBool:YES] 456b9c1b51eSKate Stone forKey:FBSDebugOptionKeyDisableASLR]; 457c611a740SJason Molenda 458c611a740SJason Molenda // That will go in the overall dictionary: 459c611a740SJason Molenda 460c611a740SJason Molenda NSMutableDictionary *options = [NSMutableDictionary dictionary]; 461b9c1b51eSKate Stone [options setObject:debug_options 462b9c1b51eSKate Stone forKey:FBSOpenApplicationOptionKeyDebuggingOptions]; 463c611a740SJason Molenda // And there are some other options at the top level in this dictionary: 464b9c1b51eSKate Stone [options setObject:[NSNumber numberWithBool:YES] 465b9c1b51eSKate Stone forKey:FBSOpenApplicationOptionKeyUnlockDevice]; 466c611a740SJason Molenda 467b9c1b51eSKate Stone // We have to get the "sequence ID & UUID" for this app bundle path and send 468b9c1b51eSKate Stone // them to FBS: 469c611a740SJason Molenda 470b9c1b51eSKate Stone NSURL *app_bundle_url = 471b9c1b51eSKate Stone [NSURL fileURLWithPath:[NSString stringWithUTF8String:app_bundle_path] 472b9c1b51eSKate Stone isDirectory:YES]; 473b9c1b51eSKate Stone LSApplicationProxy *app_proxy = 474b9c1b51eSKate Stone [LSApplicationProxy applicationProxyForBundleURL:app_bundle_url]; 475b9c1b51eSKate Stone if (app_proxy) { 476b9c1b51eSKate Stone DNBLog("Sending AppProxy info: sequence no: %lu, GUID: %s.", 477b9c1b51eSKate Stone app_proxy.sequenceNumber, 478b9c1b51eSKate Stone [app_proxy.cacheGUID.UUIDString UTF8String]); 479b9c1b51eSKate Stone [options 480b9c1b51eSKate Stone setObject:[NSNumber numberWithUnsignedInteger:app_proxy.sequenceNumber] 481b9c1b51eSKate Stone forKey:FBSOpenApplicationOptionKeyLSSequenceNumber]; 482b9c1b51eSKate Stone [options setObject:app_proxy.cacheGUID.UUIDString 483b9c1b51eSKate Stone forKey:FBSOpenApplicationOptionKeyLSCacheGUID]; 484c611a740SJason Molenda } 485c611a740SJason Molenda 486c611a740SJason Molenda DNBError error; 487c611a740SJason Molenda FBSAddEventDataToOptions(options, event_data, error); 488c611a740SJason Molenda 489c611a740SJason Molenda return options; 490c611a740SJason Molenda} 491b9c1b51eSKate Stonestatic CallOpenApplicationFunction FBSCallOpenApplicationFunction = 492b9c1b51eSKate Stone CallBoardSystemServiceOpenApplication< 493b9c1b51eSKate Stone FBSSystemService, FBSOpenApplicationErrorCode, 494b9c1b51eSKate Stone FBSOpenApplicationErrorCodeNone, SetFBSError>; 495c611a740SJason Molenda#endif // WITH_FBS 496c611a740SJason Molenda 497a332978bSJason Molenda#if 0 498a332978bSJason Molenda#define DEBUG_LOG(fmt, ...) printf(fmt, ##__VA_ARGS__) 499a332978bSJason Molenda#else 500a332978bSJason Molenda#define DEBUG_LOG(fmt, ...) 501a332978bSJason Molenda#endif 502a332978bSJason Molenda 503a332978bSJason Molenda#ifndef MACH_PROCESS_USE_POSIX_SPAWN 504a332978bSJason Molenda#define MACH_PROCESS_USE_POSIX_SPAWN 1 505a332978bSJason Molenda#endif 506a332978bSJason Molenda 507a332978bSJason Molenda#ifndef _POSIX_SPAWN_DISABLE_ASLR 508a332978bSJason Molenda#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 509a332978bSJason Molenda#endif 510a332978bSJason Molenda 5117e9bab6aSAdrian Prantl 512b9c1b51eSKate StoneMachProcess::MachProcess() 513b9c1b51eSKate Stone : m_pid(0), m_cpu_type(0), m_child_stdin(-1), m_child_stdout(-1), 514b9c1b51eSKate Stone m_child_stderr(-1), m_path(), m_args(), m_task(this), 515b9c1b51eSKate Stone m_flags(eMachProcessFlagsNone), m_stdio_thread(0), 516b9c1b51eSKate Stone m_stdio_mutex(PTHREAD_MUTEX_RECURSIVE), m_stdout_data(), 517b9c1b51eSKate Stone m_profile_enabled(false), m_profile_interval_usec(0), m_profile_thread(0), 518b9c1b51eSKate Stone m_profile_data_mutex(PTHREAD_MUTEX_RECURSIVE), m_profile_data(), 5193cd13c46SJim Ingham m_profile_events(0, eMachProcessProfileCancel), 520b9c1b51eSKate Stone m_thread_actions(), m_exception_messages(), 521b9c1b51eSKate Stone m_exception_messages_mutex(PTHREAD_MUTEX_RECURSIVE), m_thread_list(), 522b9c1b51eSKate Stone m_activities(), m_state(eStateUnloaded), 523b9c1b51eSKate Stone m_state_mutex(PTHREAD_MUTEX_RECURSIVE), m_events(0, kAllEventsMask), 524b9c1b51eSKate Stone m_private_events(0, kAllEventsMask), m_breakpoints(), m_watchpoints(), 525b9c1b51eSKate Stone m_name_to_addr_callback(NULL), m_name_to_addr_baton(NULL), 526b9c1b51eSKate Stone m_image_infos_callback(NULL), m_image_infos_baton(NULL), 527b9c1b51eSKate Stone m_sent_interrupt_signo(0), m_auto_resume_signo(0), m_did_exec(false), 528a2992311SJason Molenda m_dyld_process_info_create(nullptr), 529a2992311SJason Molenda m_dyld_process_info_for_each_image(nullptr), 530a2992311SJason Molenda m_dyld_process_info_release(nullptr), 531b9c1b51eSKate Stone m_dyld_process_info_get_cache(nullptr) { 532b9c1b51eSKate Stone m_dyld_process_info_create = 533b9c1b51eSKate Stone (void *(*)(task_t task, uint64_t timestamp, kern_return_t * kernelError)) 534b9c1b51eSKate Stone dlsym(RTLD_DEFAULT, "_dyld_process_info_create"); 535b9c1b51eSKate Stone m_dyld_process_info_for_each_image = 536b9c1b51eSKate Stone (void (*)(void *info, void (^)(uint64_t machHeaderAddress, 537b9c1b51eSKate Stone const uuid_t uuid, const char *path))) 538b9c1b51eSKate Stone dlsym(RTLD_DEFAULT, "_dyld_process_info_for_each_image"); 539b9c1b51eSKate Stone m_dyld_process_info_release = 540b9c1b51eSKate Stone (void (*)(void *info))dlsym(RTLD_DEFAULT, "_dyld_process_info_release"); 541b9c1b51eSKate Stone m_dyld_process_info_get_cache = (void (*)(void *info, void *cacheInfo))dlsym( 542b9c1b51eSKate Stone RTLD_DEFAULT, "_dyld_process_info_get_cache"); 5436cebeafaSJason Molenda m_dyld_process_info_get_platform = (uint32_t (*)(void *info))dlsym( 5446cebeafaSJason Molenda RTLD_DEFAULT, "_dyld_process_info_get_platform"); 545a2992311SJason Molenda 546a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__); 547a332978bSJason Molenda} 548a332978bSJason Molenda 549b9c1b51eSKate StoneMachProcess::~MachProcess() { 550a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__); 551a332978bSJason Molenda Clear(); 552a332978bSJason Molenda} 553a332978bSJason Molenda 554b9c1b51eSKate Stonepid_t MachProcess::SetProcessID(pid_t pid) { 555a332978bSJason Molenda // Free any previous process specific data or resources 556a332978bSJason Molenda Clear(); 557a332978bSJason Molenda // Set the current PID appropriately 558a332978bSJason Molenda if (pid == 0) 559a332978bSJason Molenda m_pid = ::getpid(); 560a332978bSJason Molenda else 561a332978bSJason Molenda m_pid = pid; 562d93c4a33SBruce Mitchener return m_pid; // Return actually PID in case a zero pid was passed in 563a332978bSJason Molenda} 564a332978bSJason Molenda 565b9c1b51eSKate Stonenub_state_t MachProcess::GetState() { 566a332978bSJason Molenda // If any other threads access this we will need a mutex for it 567a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_state_mutex); 568a332978bSJason Molenda return m_state; 569a332978bSJason Molenda} 570a332978bSJason Molenda 571b9c1b51eSKate Stoneconst char *MachProcess::ThreadGetName(nub_thread_t tid) { 572a332978bSJason Molenda return m_thread_list.GetName(tid); 573a332978bSJason Molenda} 574a332978bSJason Molenda 575b9c1b51eSKate Stonenub_state_t MachProcess::ThreadGetState(nub_thread_t tid) { 576a332978bSJason Molenda return m_thread_list.GetState(tid); 577a332978bSJason Molenda} 578a332978bSJason Molenda 579b9c1b51eSKate Stonenub_size_t MachProcess::GetNumThreads() const { 580a332978bSJason Molenda return m_thread_list.NumThreads(); 581a332978bSJason Molenda} 582a332978bSJason Molenda 583b9c1b51eSKate Stonenub_thread_t MachProcess::GetThreadAtIndex(nub_size_t thread_idx) const { 584a332978bSJason Molenda return m_thread_list.ThreadIDAtIndex(thread_idx); 585a332978bSJason Molenda} 586a332978bSJason Molenda 587a332978bSJason Molendanub_thread_t 588b9c1b51eSKate StoneMachProcess::GetThreadIDForMachPortNumber(thread_t mach_port_number) const { 589a332978bSJason Molenda return m_thread_list.GetThreadIDByMachPortNumber(mach_port_number); 590a332978bSJason Molenda} 591a332978bSJason Molenda 592b9c1b51eSKate Stonenub_bool_t MachProcess::SyncThreadState(nub_thread_t tid) { 593a332978bSJason Molenda MachThreadSP thread_sp(m_thread_list.GetThreadByID(tid)); 594a332978bSJason Molenda if (!thread_sp) 595a332978bSJason Molenda return false; 596a332978bSJason Molenda kern_return_t kret = ::thread_abort_safely(thread_sp->MachPortNumber()); 597b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD, "thread = 0x%8.8" PRIx32 598b9c1b51eSKate Stone " calling thread_abort_safely (tid) => %u " 599b9c1b51eSKate Stone "(GetGPRState() for stop_count = %u)", 600b9c1b51eSKate Stone thread_sp->MachPortNumber(), kret, 601b9c1b51eSKate Stone thread_sp->Process()->StopCount()); 602a332978bSJason Molenda 603a332978bSJason Molenda if (kret == KERN_SUCCESS) 604a332978bSJason Molenda return true; 605a332978bSJason Molenda else 606a332978bSJason Molenda return false; 607a332978bSJason Molenda} 608a332978bSJason Molenda 609b9c1b51eSKate StoneThreadInfo::QoS MachProcess::GetRequestedQoS(nub_thread_t tid, nub_addr_t tsd, 610b9c1b51eSKate Stone uint64_t dti_qos_class_index) { 611705b1809SJason Molenda return m_thread_list.GetRequestedQoS(tid, tsd, dti_qos_class_index); 612705b1809SJason Molenda} 613705b1809SJason Molenda 614b9c1b51eSKate Stonenub_addr_t MachProcess::GetPThreadT(nub_thread_t tid) { 615705b1809SJason Molenda return m_thread_list.GetPThreadT(tid); 616705b1809SJason Molenda} 617705b1809SJason Molenda 618b9c1b51eSKate Stonenub_addr_t MachProcess::GetDispatchQueueT(nub_thread_t tid) { 619705b1809SJason Molenda return m_thread_list.GetDispatchQueueT(tid); 620705b1809SJason Molenda} 621705b1809SJason Molenda 622b9c1b51eSKate Stonenub_addr_t MachProcess::GetTSDAddressForThread( 623b9c1b51eSKate Stone nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, 624b9c1b51eSKate Stone uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) { 625b9c1b51eSKate Stone return m_thread_list.GetTSDAddressForThread( 626b9c1b51eSKate Stone tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, 627b9c1b51eSKate Stone plo_pthread_tsd_entry_size); 628705b1809SJason Molenda} 629705b1809SJason Molenda 630116b1033SAdrian PrantlMachProcess::DeploymentInfo 631116b1033SAdrian PrantlMachProcess::GetDeploymentInfo(const struct load_command &lc, 6327e9bab6aSAdrian Prantl uint64_t load_command_address, 6337e9bab6aSAdrian Prantl bool is_executable) { 634116b1033SAdrian Prantl DeploymentInfo info; 63598c3a38aSJonas Devlieghere uint32_t cmd = lc.cmd & ~LC_REQ_DYLD; 6367e9bab6aSAdrian Prantl 63798c3a38aSJonas Devlieghere // Handle the older LC_VERSION load commands, which don't 63898c3a38aSJonas Devlieghere // distinguish between simulator and real hardware. 639116b1033SAdrian Prantl auto handle_version_min = [&](char platform) { 640116b1033SAdrian Prantl struct version_min_command vers_cmd; 641116b1033SAdrian Prantl if (ReadMemory(load_command_address, sizeof(struct version_min_command), 642116b1033SAdrian Prantl &vers_cmd) != sizeof(struct version_min_command)) 643116b1033SAdrian Prantl return; 644116b1033SAdrian Prantl info.platform = platform; 64515149e40SAdrian Prantl info.major_version = vers_cmd.version >> 16; 64615149e40SAdrian Prantl info.minor_version = (vers_cmd.version >> 8) & 0xffu; 64715149e40SAdrian Prantl info.patch_version = vers_cmd.version & 0xffu; 64858d84eb5SAdrian Prantl 64958d84eb5SAdrian Prantl // Disambiguate legacy simulator platforms. 65058d84eb5SAdrian Prantl#if (defined(__x86_64__) || defined(__i386__)) 65158d84eb5SAdrian Prantl // If we are running on Intel macOS, it is safe to assume this is 65258d84eb5SAdrian Prantl // really a back-deploying simulator binary. 65358d84eb5SAdrian Prantl switch (info.platform) { 65458d84eb5SAdrian Prantl case PLATFORM_IOS: 65558d84eb5SAdrian Prantl info.platform = PLATFORM_IOSSIMULATOR; 65658d84eb5SAdrian Prantl break; 65758d84eb5SAdrian Prantl case PLATFORM_TVOS: 65858d84eb5SAdrian Prantl info.platform = PLATFORM_TVOSSIMULATOR; 65958d84eb5SAdrian Prantl break; 66058d84eb5SAdrian Prantl case PLATFORM_WATCHOS: 66158d84eb5SAdrian Prantl info.platform = PLATFORM_WATCHOSSIMULATOR; 66258d84eb5SAdrian Prantl break; 66358d84eb5SAdrian Prantl } 66458d84eb5SAdrian Prantl#else 66558d84eb5SAdrian Prantl // On an Apple Silicon macOS host, there is no ambiguity. The only 66658d84eb5SAdrian Prantl // binaries that use legacy load commands are back-deploying 66758d84eb5SAdrian Prantl // native iOS binaries. All simulator binaries use the newer, 66858d84eb5SAdrian Prantl // unambiguous LC_BUILD_VERSION load commands. 66958d84eb5SAdrian Prantl#endif 670116b1033SAdrian Prantl }; 6717e9bab6aSAdrian Prantl 67298c3a38aSJonas Devlieghere switch (cmd) { 67398c3a38aSJonas Devlieghere case LC_VERSION_MIN_IPHONEOS: 674116b1033SAdrian Prantl handle_version_min(PLATFORM_IOS); 675116b1033SAdrian Prantl break; 67698c3a38aSJonas Devlieghere case LC_VERSION_MIN_MACOSX: 677116b1033SAdrian Prantl handle_version_min(PLATFORM_MACOS); 678116b1033SAdrian Prantl break; 67998c3a38aSJonas Devlieghere case LC_VERSION_MIN_TVOS: 680116b1033SAdrian Prantl handle_version_min(PLATFORM_TVOS); 681116b1033SAdrian Prantl break; 68298c3a38aSJonas Devlieghere case LC_VERSION_MIN_WATCHOS: 683116b1033SAdrian Prantl handle_version_min(PLATFORM_WATCHOS); 684116b1033SAdrian Prantl break; 68598c3a38aSJonas Devlieghere#if defined(LC_BUILD_VERSION) 686116b1033SAdrian Prantl case LC_BUILD_VERSION: { 68798c3a38aSJonas Devlieghere struct build_version_command build_vers; 68898c3a38aSJonas Devlieghere if (ReadMemory(load_command_address, sizeof(struct build_version_command), 689116b1033SAdrian Prantl &build_vers) != sizeof(struct build_version_command)) 690116b1033SAdrian Prantl break; 691116b1033SAdrian Prantl info.platform = build_vers.platform; 69215149e40SAdrian Prantl info.major_version = build_vers.minos >> 16; 69315149e40SAdrian Prantl info.minor_version = (build_vers.minos >> 8) & 0xffu; 69415149e40SAdrian Prantl info.patch_version = build_vers.minos & 0xffu; 695116b1033SAdrian Prantl break; 69698c3a38aSJonas Devlieghere } 697116b1033SAdrian Prantl#endif 698116b1033SAdrian Prantl } 6997e9bab6aSAdrian Prantl 7007e9bab6aSAdrian Prantl // The xctest binary is a pure macOS binary but is launched with 7017e9bab6aSAdrian Prantl // DYLD_FORCE_PLATFORM=6. In that case, force the platform to 7027e9bab6aSAdrian Prantl // macCatalyst and use the macCatalyst version of the host OS 7037e9bab6aSAdrian Prantl // instead of the macOS deployment target. 7048dd10602Skuperxu if (is_executable && GetPlatform() == PLATFORM_MACCATALYST) { 7057e9bab6aSAdrian Prantl info.platform = PLATFORM_MACCATALYST; 7067e9bab6aSAdrian Prantl std::string catalyst_version = GetMacCatalystVersionString(); 7077e9bab6aSAdrian Prantl const char *major = catalyst_version.c_str(); 7087e9bab6aSAdrian Prantl char *minor = nullptr; 7097e9bab6aSAdrian Prantl char *patch = nullptr; 7107e9bab6aSAdrian Prantl info.major_version = std::strtoul(major, &minor, 10); 7117e9bab6aSAdrian Prantl info.minor_version = 0; 7127e9bab6aSAdrian Prantl info.patch_version = 0; 7137e9bab6aSAdrian Prantl if (minor && *minor == '.') { 7147e9bab6aSAdrian Prantl info.minor_version = std::strtoul(++minor, &patch, 10); 7157e9bab6aSAdrian Prantl if (patch && *patch == '.') 7167e9bab6aSAdrian Prantl info.patch_version = std::strtoul(++patch, nullptr, 10); 7177e9bab6aSAdrian Prantl } 7187e9bab6aSAdrian Prantl } 7197e9bab6aSAdrian Prantl 720116b1033SAdrian Prantl return info; 721116b1033SAdrian Prantl} 72298c3a38aSJonas Devlieghere 723116b1033SAdrian Prantlconst char *MachProcess::GetPlatformString(unsigned char platform) { 724116b1033SAdrian Prantl switch (platform) { 725cd90f878SFrederic Riss case PLATFORM_MACOS: 726cd90f878SFrederic Riss return "macosx"; 7276cebeafaSJason Molenda case PLATFORM_MACCATALYST: 7286cebeafaSJason Molenda return "maccatalyst"; 729cd90f878SFrederic Riss case PLATFORM_IOS: 7304ebe9b49SAdrian Prantl return "ios"; 731000847f8SAdrian Prantl case PLATFORM_IOSSIMULATOR: 732000847f8SAdrian Prantl return "iossimulator"; 733cd90f878SFrederic Riss case PLATFORM_TVOS: 7344ebe9b49SAdrian Prantl return "tvos"; 735000847f8SAdrian Prantl case PLATFORM_TVOSSIMULATOR: 736000847f8SAdrian Prantl return "tvossimulator"; 737cd90f878SFrederic Riss case PLATFORM_WATCHOS: 7384ebe9b49SAdrian Prantl return "watchos"; 739000847f8SAdrian Prantl case PLATFORM_WATCHOSSIMULATOR: 740000847f8SAdrian Prantl return "watchossimulator"; 741cd90f878SFrederic Riss case PLATFORM_BRIDGEOS: 742cd90f878SFrederic Riss return "bridgeos"; 7436cebeafaSJason Molenda case PLATFORM_DRIVERKIT: 7446cebeafaSJason Molenda return "driverkit"; 745cd90f878SFrederic Riss } 746278874f0SAdrian Prantl return nullptr; 747cd90f878SFrederic Riss} 748cd90f878SFrederic Riss 749*ac49e902SJason Molendastatic bool mach_header_validity_test(uint32_t magic, uint32_t cputype) { 750*ac49e902SJason Molenda if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 && 751*ac49e902SJason Molenda magic != MH_CIGAM_64) 752*ac49e902SJason Molenda return false; 753*ac49e902SJason Molenda if (cputype != CPU_TYPE_I386 && cputype != CPU_TYPE_X86_64 && 754*ac49e902SJason Molenda cputype != CPU_TYPE_ARM && cputype != CPU_TYPE_ARM64 && 755*ac49e902SJason Molenda cputype != CPU_TYPE_ARM64_32) 756*ac49e902SJason Molenda return false; 757*ac49e902SJason Molenda return true; 758*ac49e902SJason Molenda} 759*ac49e902SJason Molenda 760b9c1b51eSKate Stone// Given an address, read the mach-o header and load commands out of memory to 761b9c1b51eSKate Stone// fill in 762a2992311SJason Molenda// the mach_o_information "inf" object. 763a2992311SJason Molenda// 764b9c1b51eSKate Stone// Returns false if there was an error in reading this mach-o file header/load 765b9c1b51eSKate Stone// commands. 76620ee21bdSJason Molenda 767b9c1b51eSKate Stonebool MachProcess::GetMachOInformationFromMemory( 7686cebeafaSJason Molenda uint32_t dyld_platform, nub_addr_t mach_o_header_addr, int wordsize, 769b9c1b51eSKate Stone struct mach_o_information &inf) { 770a2992311SJason Molenda uint64_t load_cmds_p; 771*ac49e902SJason Molenda 772b9c1b51eSKate Stone if (wordsize == 4) { 773a2992311SJason Molenda struct mach_header header; 774b9c1b51eSKate Stone if (ReadMemory(mach_o_header_addr, sizeof(struct mach_header), &header) != 775b9c1b51eSKate Stone sizeof(struct mach_header)) { 776a2992311SJason Molenda return false; 777a2992311SJason Molenda } 778*ac49e902SJason Molenda if (!mach_header_validity_test(header.magic, header.cputype)) 779*ac49e902SJason Molenda return false; 780*ac49e902SJason Molenda 781a2992311SJason Molenda load_cmds_p = mach_o_header_addr + sizeof(struct mach_header); 782a2992311SJason Molenda inf.mach_header.magic = header.magic; 783a2992311SJason Molenda inf.mach_header.cputype = header.cputype; 784b9c1b51eSKate Stone // high byte of cpusubtype is used for "capability bits", v. 785b9c1b51eSKate Stone // CPU_SUBTYPE_MASK, CPU_SUBTYPE_LIB64 in machine.h 786a2992311SJason Molenda inf.mach_header.cpusubtype = header.cpusubtype & 0x00ffffff; 787a2992311SJason Molenda inf.mach_header.filetype = header.filetype; 788a2992311SJason Molenda inf.mach_header.ncmds = header.ncmds; 789a2992311SJason Molenda inf.mach_header.sizeofcmds = header.sizeofcmds; 790a2992311SJason Molenda inf.mach_header.flags = header.flags; 791b9c1b51eSKate Stone } else { 792a2992311SJason Molenda struct mach_header_64 header; 793b9c1b51eSKate Stone if (ReadMemory(mach_o_header_addr, sizeof(struct mach_header_64), 794b9c1b51eSKate Stone &header) != sizeof(struct mach_header_64)) { 795a2992311SJason Molenda return false; 796a2992311SJason Molenda } 797*ac49e902SJason Molenda if (!mach_header_validity_test(header.magic, header.cputype)) 798*ac49e902SJason Molenda return false; 799a2992311SJason Molenda load_cmds_p = mach_o_header_addr + sizeof(struct mach_header_64); 800a2992311SJason Molenda inf.mach_header.magic = header.magic; 801a2992311SJason Molenda inf.mach_header.cputype = header.cputype; 802b9c1b51eSKate Stone // high byte of cpusubtype is used for "capability bits", v. 803b9c1b51eSKate Stone // CPU_SUBTYPE_MASK, CPU_SUBTYPE_LIB64 in machine.h 804a2992311SJason Molenda inf.mach_header.cpusubtype = header.cpusubtype & 0x00ffffff; 805a2992311SJason Molenda inf.mach_header.filetype = header.filetype; 806a2992311SJason Molenda inf.mach_header.ncmds = header.ncmds; 807a2992311SJason Molenda inf.mach_header.sizeofcmds = header.sizeofcmds; 808a2992311SJason Molenda inf.mach_header.flags = header.flags; 809a2992311SJason Molenda } 810b9c1b51eSKate Stone for (uint32_t j = 0; j < inf.mach_header.ncmds; j++) { 811a2992311SJason Molenda struct load_command lc; 812b9c1b51eSKate Stone if (ReadMemory(load_cmds_p, sizeof(struct load_command), &lc) != 813b9c1b51eSKate Stone sizeof(struct load_command)) { 814a2992311SJason Molenda return false; 815a2992311SJason Molenda } 816b9c1b51eSKate Stone if (lc.cmd == LC_SEGMENT) { 817a2992311SJason Molenda struct segment_command seg; 818b9c1b51eSKate Stone if (ReadMemory(load_cmds_p, sizeof(struct segment_command), &seg) != 819b9c1b51eSKate Stone sizeof(struct segment_command)) { 820a2992311SJason Molenda return false; 821a2992311SJason Molenda } 822a2992311SJason Molenda struct mach_o_segment this_seg; 823a2992311SJason Molenda char name[17]; 824a2992311SJason Molenda ::memset(name, 0, sizeof(name)); 825a2992311SJason Molenda memcpy(name, seg.segname, sizeof(seg.segname)); 826a2992311SJason Molenda this_seg.name = name; 827a2992311SJason Molenda this_seg.vmaddr = seg.vmaddr; 828a2992311SJason Molenda this_seg.vmsize = seg.vmsize; 829a2992311SJason Molenda this_seg.fileoff = seg.fileoff; 830a2992311SJason Molenda this_seg.filesize = seg.filesize; 831a2992311SJason Molenda this_seg.maxprot = seg.maxprot; 832a2992311SJason Molenda this_seg.initprot = seg.initprot; 833a2992311SJason Molenda this_seg.nsects = seg.nsects; 834a2992311SJason Molenda this_seg.flags = seg.flags; 835a2992311SJason Molenda inf.segments.push_back(this_seg); 83683a131b2SJason Molenda if (this_seg.name == "ExecExtraSuspend") 83783a131b2SJason Molenda m_task.TaskWillExecProcessesSuspended(); 838a2992311SJason Molenda } 839b9c1b51eSKate Stone if (lc.cmd == LC_SEGMENT_64) { 840a2992311SJason Molenda struct segment_command_64 seg; 841b9c1b51eSKate Stone if (ReadMemory(load_cmds_p, sizeof(struct segment_command_64), &seg) != 842b9c1b51eSKate Stone sizeof(struct segment_command_64)) { 843a2992311SJason Molenda return false; 844a2992311SJason Molenda } 845a2992311SJason Molenda struct mach_o_segment this_seg; 846a2992311SJason Molenda char name[17]; 847a2992311SJason Molenda ::memset(name, 0, sizeof(name)); 848a2992311SJason Molenda memcpy(name, seg.segname, sizeof(seg.segname)); 849a2992311SJason Molenda this_seg.name = name; 850a2992311SJason Molenda this_seg.vmaddr = seg.vmaddr; 851a2992311SJason Molenda this_seg.vmsize = seg.vmsize; 852a2992311SJason Molenda this_seg.fileoff = seg.fileoff; 853a2992311SJason Molenda this_seg.filesize = seg.filesize; 854a2992311SJason Molenda this_seg.maxprot = seg.maxprot; 855a2992311SJason Molenda this_seg.initprot = seg.initprot; 856a2992311SJason Molenda this_seg.nsects = seg.nsects; 857a2992311SJason Molenda this_seg.flags = seg.flags; 858a2992311SJason Molenda inf.segments.push_back(this_seg); 85983a131b2SJason Molenda if (this_seg.name == "ExecExtraSuspend") 86083a131b2SJason Molenda m_task.TaskWillExecProcessesSuspended(); 861a2992311SJason Molenda } 862b9c1b51eSKate Stone if (lc.cmd == LC_UUID) { 863a2992311SJason Molenda struct uuid_command uuidcmd; 864b9c1b51eSKate Stone if (ReadMemory(load_cmds_p, sizeof(struct uuid_command), &uuidcmd) == 865b9c1b51eSKate Stone sizeof(struct uuid_command)) 866a2992311SJason Molenda uuid_copy(inf.uuid, uuidcmd.uuid); 867a2992311SJason Molenda } 8687e9bab6aSAdrian Prantl if (DeploymentInfo deployment_info = GetDeploymentInfo( 8697e9bab6aSAdrian Prantl lc, load_cmds_p, inf.mach_header.filetype == MH_EXECUTE)) { 870116b1033SAdrian Prantl const char *lc_platform = GetPlatformString(deployment_info.platform); 8717e9bab6aSAdrian Prantl if (dyld_platform != PLATFORM_MACCATALYST && 8727e9bab6aSAdrian Prantl inf.min_version_os_name == "macosx") { 87324610611SAdrian Prantl // macCatalyst support. 87424610611SAdrian Prantl // 8757e9bab6aSAdrian Prantl // This the special case of "zippered" frameworks that have both 8767e9bab6aSAdrian Prantl // a PLATFORM_MACOS and a PLATFORM_MACCATALYST load command. 87724610611SAdrian Prantl // 8787e9bab6aSAdrian Prantl // When we are in this block, this is a binary with both 8797e9bab6aSAdrian Prantl // PLATFORM_MACOS and PLATFORM_MACCATALYST load commands and 8807e9bab6aSAdrian Prantl // the process is not running as PLATFORM_MACCATALYST. Stick 8817e9bab6aSAdrian Prantl // with the "macosx" load command that we've already 8827e9bab6aSAdrian Prantl // processed, ignore this one, which is presumed to be a 88324610611SAdrian Prantl // PLATFORM_MACCATALYST one. 8846cebeafaSJason Molenda } else { 8856cebeafaSJason Molenda inf.min_version_os_name = lc_platform; 886df8aef43SJason Molenda inf.min_version_os_version = ""; 887116b1033SAdrian Prantl inf.min_version_os_version += 888116b1033SAdrian Prantl std::to_string(deployment_info.major_version); 889df8aef43SJason Molenda inf.min_version_os_version += "."; 890116b1033SAdrian Prantl inf.min_version_os_version += 891116b1033SAdrian Prantl std::to_string(deployment_info.minor_version); 892116b1033SAdrian Prantl if (deployment_info.patch_version != 0) { 893df8aef43SJason Molenda inf.min_version_os_version += "."; 894116b1033SAdrian Prantl inf.min_version_os_version += 895116b1033SAdrian Prantl std::to_string(deployment_info.patch_version); 896df8aef43SJason Molenda } 897df8aef43SJason Molenda } 8986cebeafaSJason Molenda } 899cd90f878SFrederic Riss 900a2992311SJason Molenda load_cmds_p += lc.cmdsize; 901a2992311SJason Molenda } 902a2992311SJason Molenda return true; 903a2992311SJason Molenda} 90420ee21bdSJason Molenda 905b9c1b51eSKate Stone// Given completely filled in array of binary_image_information structures, 906b9c1b51eSKate Stone// create a JSONGenerator object 907a2992311SJason Molenda// with all the details we want to send to lldb. 908b9c1b51eSKate StoneJSONGenerator::ObjectSP MachProcess::FormatDynamicLibrariesIntoJSON( 909b9c1b51eSKate Stone const std::vector<struct binary_image_information> &image_infos) { 910a2992311SJason Molenda 911a2992311SJason Molenda JSONGenerator::ArraySP image_infos_array_sp(new JSONGenerator::Array()); 912a2992311SJason Molenda 913a2992311SJason Molenda const size_t image_count = image_infos.size(); 914a2992311SJason Molenda 915b9c1b51eSKate Stone for (size_t i = 0; i < image_count; i++) { 916*ac49e902SJason Molenda if (!image_infos[i].is_valid_mach_header) 917*ac49e902SJason Molenda continue; 918b9c1b51eSKate Stone JSONGenerator::DictionarySP image_info_dict_sp( 919b9c1b51eSKate Stone new JSONGenerator::Dictionary()); 920b9c1b51eSKate Stone image_info_dict_sp->AddIntegerItem("load_address", 921b9c1b51eSKate Stone image_infos[i].load_address); 922a2992311SJason Molenda image_info_dict_sp->AddIntegerItem("mod_date", image_infos[i].mod_date); 923a2992311SJason Molenda image_info_dict_sp->AddStringItem("pathname", image_infos[i].filename); 924a2992311SJason Molenda 925a2992311SJason Molenda uuid_string_t uuidstr; 926a2992311SJason Molenda uuid_unparse_upper(image_infos[i].macho_info.uuid, uuidstr); 927a2992311SJason Molenda image_info_dict_sp->AddStringItem("uuid", uuidstr); 928a2992311SJason Molenda 929a6682a41SJonas Devlieghere if (!image_infos[i].macho_info.min_version_os_name.empty() && 930a6682a41SJonas Devlieghere !image_infos[i].macho_info.min_version_os_version.empty()) { 931b9c1b51eSKate Stone image_info_dict_sp->AddStringItem( 932b9c1b51eSKate Stone "min_version_os_name", image_infos[i].macho_info.min_version_os_name); 933b9c1b51eSKate Stone image_info_dict_sp->AddStringItem( 934b9c1b51eSKate Stone "min_version_os_sdk", 935b9c1b51eSKate Stone image_infos[i].macho_info.min_version_os_version); 936df8aef43SJason Molenda } 937df8aef43SJason Molenda 938b9c1b51eSKate Stone JSONGenerator::DictionarySP mach_header_dict_sp( 939b9c1b51eSKate Stone new JSONGenerator::Dictionary()); 940b9c1b51eSKate Stone mach_header_dict_sp->AddIntegerItem( 941b9c1b51eSKate Stone "magic", image_infos[i].macho_info.mach_header.magic); 942b9c1b51eSKate Stone mach_header_dict_sp->AddIntegerItem( 943b9c1b51eSKate Stone "cputype", (uint32_t)image_infos[i].macho_info.mach_header.cputype); 944b9c1b51eSKate Stone mach_header_dict_sp->AddIntegerItem( 945b9c1b51eSKate Stone "cpusubtype", 946b9c1b51eSKate Stone (uint32_t)image_infos[i].macho_info.mach_header.cpusubtype); 947b9c1b51eSKate Stone mach_header_dict_sp->AddIntegerItem( 948b9c1b51eSKate Stone "filetype", image_infos[i].macho_info.mach_header.filetype); 949b0d33e9bSJason Molenda mach_header_dict_sp->AddIntegerItem ("flags", 950b0d33e9bSJason Molenda image_infos[i].macho_info.mach_header.flags); 951a2992311SJason Molenda 952b9c1b51eSKate Stone // DynamicLoaderMacOSX doesn't currently need these fields, so 953b9c1b51eSKate Stone // don't send them. 954b9c1b51eSKate Stone // mach_header_dict_sp->AddIntegerItem ("ncmds", 955b9c1b51eSKate Stone // image_infos[i].macho_info.mach_header.ncmds); 956b9c1b51eSKate Stone // mach_header_dict_sp->AddIntegerItem ("sizeofcmds", 957b9c1b51eSKate Stone // image_infos[i].macho_info.mach_header.sizeofcmds); 958a2992311SJason Molenda image_info_dict_sp->AddItem("mach_header", mach_header_dict_sp); 959a2992311SJason Molenda 960a2992311SJason Molenda JSONGenerator::ArraySP segments_sp(new JSONGenerator::Array()); 961b9c1b51eSKate Stone for (size_t j = 0; j < image_infos[i].macho_info.segments.size(); j++) { 962a2992311SJason Molenda JSONGenerator::DictionarySP segment_sp(new JSONGenerator::Dictionary()); 963b9c1b51eSKate Stone segment_sp->AddStringItem("name", 964b9c1b51eSKate Stone image_infos[i].macho_info.segments[j].name); 965b9c1b51eSKate Stone segment_sp->AddIntegerItem("vmaddr", 966b9c1b51eSKate Stone image_infos[i].macho_info.segments[j].vmaddr); 967b9c1b51eSKate Stone segment_sp->AddIntegerItem("vmsize", 968b9c1b51eSKate Stone image_infos[i].macho_info.segments[j].vmsize); 969b9c1b51eSKate Stone segment_sp->AddIntegerItem("fileoff", 970b9c1b51eSKate Stone image_infos[i].macho_info.segments[j].fileoff); 971b9c1b51eSKate Stone segment_sp->AddIntegerItem( 972b9c1b51eSKate Stone "filesize", image_infos[i].macho_info.segments[j].filesize); 973b9c1b51eSKate Stone segment_sp->AddIntegerItem("maxprot", 974b9c1b51eSKate Stone image_infos[i].macho_info.segments[j].maxprot); 975a2992311SJason Molenda 976b9c1b51eSKate Stone // DynamicLoaderMacOSX doesn't currently need these fields, 977b9c1b51eSKate Stone // so don't send them. 978b9c1b51eSKate Stone // segment_sp->AddIntegerItem ("initprot", 979b9c1b51eSKate Stone // image_infos[i].macho_info.segments[j].initprot); 980b9c1b51eSKate Stone // segment_sp->AddIntegerItem ("nsects", 981b9c1b51eSKate Stone // image_infos[i].macho_info.segments[j].nsects); 982b9c1b51eSKate Stone // segment_sp->AddIntegerItem ("flags", 983b9c1b51eSKate Stone // image_infos[i].macho_info.segments[j].flags); 984a2992311SJason Molenda segments_sp->AddItem(segment_sp); 985a2992311SJason Molenda } 986a2992311SJason Molenda image_info_dict_sp->AddItem("segments", segments_sp); 987a2992311SJason Molenda 988a2992311SJason Molenda image_infos_array_sp->AddItem(image_info_dict_sp); 989a2992311SJason Molenda } 990a2992311SJason Molenda 991b9c1b51eSKate Stone JSONGenerator::DictionarySP reply_sp(new JSONGenerator::Dictionary()); 992a2992311SJason Molenda reply_sp->AddItem("images", image_infos_array_sp); 993a2992311SJason Molenda 994a2992311SJason Molenda return reply_sp; 995a2992311SJason Molenda} 996a2992311SJason Molenda 997b9c1b51eSKate Stone// Get the shared library information using the old (pre-macOS 10.12, pre-iOS 998b9c1b51eSKate Stone// 10, pre-tvOS 10, pre-watchOS 3) 999a2992311SJason Molenda// code path. We'll be given the address of an array of structures in the form 1000a2992311SJason Molenda// {void* load_addr, void* mod_date, void* pathname} 1001a2992311SJason Molenda// 1002b9c1b51eSKate Stone// In macOS 10.12 etc and newer, we'll use SPI calls into dyld to gather this 1003b9c1b51eSKate Stone// information. 1004b9c1b51eSKate StoneJSONGenerator::ObjectSP MachProcess::GetLoadedDynamicLibrariesInfos( 1005b9c1b51eSKate Stone nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) { 100620ee21bdSJason Molenda 1007*ac49e902SJason Molenda JSONGenerator::ObjectSP empty_reply_sp(new JSONGenerator::Dictionary()); 1008afee0975SJason Molenda int pointer_size = GetInferiorAddrSize(pid); 100920ee21bdSJason Molenda 1010a2992311SJason Molenda std::vector<struct binary_image_information> image_infos; 101120ee21bdSJason Molenda size_t image_infos_size = image_count * 3 * pointer_size; 101220ee21bdSJason Molenda 101320ee21bdSJason Molenda uint8_t *image_info_buf = (uint8_t *)malloc(image_infos_size); 1014b9c1b51eSKate Stone if (image_info_buf == NULL) { 1015*ac49e902SJason Molenda return empty_reply_sp; 101620ee21bdSJason Molenda } 1017b9c1b51eSKate Stone if (ReadMemory(image_list_address, image_infos_size, image_info_buf) != 1018b9c1b51eSKate Stone image_infos_size) { 1019*ac49e902SJason Molenda return empty_reply_sp; 102020ee21bdSJason Molenda } 102120ee21bdSJason Molenda 1022*ac49e902SJason Molenda /// First the image_infos array with (load addr, pathname, mod date) 1023b9c1b51eSKate Stone /// tuples 102420ee21bdSJason Molenda 1025b9c1b51eSKate Stone for (size_t i = 0; i < image_count; i++) { 1026a2992311SJason Molenda struct binary_image_information info; 102720ee21bdSJason Molenda nub_addr_t pathname_address; 1028b9c1b51eSKate Stone if (pointer_size == 4) { 102920ee21bdSJason Molenda uint32_t load_address_32; 103020ee21bdSJason Molenda uint32_t pathname_address_32; 103120ee21bdSJason Molenda uint32_t mod_date_32; 103220ee21bdSJason Molenda ::memcpy(&load_address_32, image_info_buf + (i * 3 * pointer_size), 4); 1033b9c1b51eSKate Stone ::memcpy(&pathname_address_32, 1034b9c1b51eSKate Stone image_info_buf + (i * 3 * pointer_size) + pointer_size, 4); 1035*ac49e902SJason Molenda ::memcpy(&mod_date_32, 1036*ac49e902SJason Molenda image_info_buf + (i * 3 * pointer_size) + pointer_size + 1037*ac49e902SJason Molenda pointer_size, 1038b9c1b51eSKate Stone 4); 103920ee21bdSJason Molenda info.load_address = load_address_32; 104020ee21bdSJason Molenda info.mod_date = mod_date_32; 104120ee21bdSJason Molenda pathname_address = pathname_address_32; 1042b9c1b51eSKate Stone } else { 104320ee21bdSJason Molenda uint64_t load_address_64; 104420ee21bdSJason Molenda uint64_t pathname_address_64; 104520ee21bdSJason Molenda uint64_t mod_date_64; 104620ee21bdSJason Molenda ::memcpy(&load_address_64, image_info_buf + (i * 3 * pointer_size), 8); 1047b9c1b51eSKate Stone ::memcpy(&pathname_address_64, 1048b9c1b51eSKate Stone image_info_buf + (i * 3 * pointer_size) + pointer_size, 8); 1049*ac49e902SJason Molenda ::memcpy(&mod_date_64, 1050*ac49e902SJason Molenda image_info_buf + (i * 3 * pointer_size) + pointer_size + 1051*ac49e902SJason Molenda pointer_size, 1052b9c1b51eSKate Stone 8); 105320ee21bdSJason Molenda info.load_address = load_address_64; 105420ee21bdSJason Molenda info.mod_date = mod_date_64; 105520ee21bdSJason Molenda pathname_address = pathname_address_64; 105620ee21bdSJason Molenda } 105720ee21bdSJason Molenda char strbuf[17]; 1058a2992311SJason Molenda info.filename = ""; 105920ee21bdSJason Molenda uint64_t pathname_ptr = pathname_address; 106020ee21bdSJason Molenda bool still_reading = true; 1061*ac49e902SJason Molenda while (still_reading && ReadMemory(pathname_ptr, sizeof(strbuf) - 1, 1062*ac49e902SJason Molenda strbuf) == sizeof(strbuf) - 1) { 106320ee21bdSJason Molenda strbuf[sizeof(strbuf) - 1] = '\0'; 1064a2992311SJason Molenda info.filename += strbuf; 106520ee21bdSJason Molenda pathname_ptr += sizeof(strbuf) - 1; 106620ee21bdSJason Molenda // Stop if we found nul byte indicating the end of the string 1067b9c1b51eSKate Stone for (size_t i = 0; i < sizeof(strbuf) - 1; i++) { 1068b9c1b51eSKate Stone if (strbuf[i] == '\0') { 106920ee21bdSJason Molenda still_reading = false; 107020ee21bdSJason Molenda break; 107120ee21bdSJason Molenda } 107220ee21bdSJason Molenda } 107320ee21bdSJason Molenda } 1074a2992311SJason Molenda uuid_clear(info.macho_info.uuid); 107520ee21bdSJason Molenda image_infos.push_back(info); 107620ee21bdSJason Molenda } 1077b9c1b51eSKate Stone if (image_infos.size() == 0) { 1078*ac49e902SJason Molenda return empty_reply_sp; 107920ee21bdSJason Molenda } 108020ee21bdSJason Molenda 1081a2992311SJason Molenda free(image_info_buf); 108220ee21bdSJason Molenda 1083*ac49e902SJason Molenda /// Second, read the mach header / load commands for all the dylibs 108420ee21bdSJason Molenda 1085b9c1b51eSKate Stone for (size_t i = 0; i < image_count; i++) { 10866cebeafaSJason Molenda // The SPI to provide platform is not available on older systems. 10876cebeafaSJason Molenda uint32_t platform = 0; 1088*ac49e902SJason Molenda if (GetMachOInformationFromMemory(platform, image_infos[i].load_address, 1089b9c1b51eSKate Stone pointer_size, 1090b9c1b51eSKate Stone image_infos[i].macho_info)) { 1091*ac49e902SJason Molenda image_infos[i].is_valid_mach_header = true; 109220ee21bdSJason Molenda } 109320ee21bdSJason Molenda } 109420ee21bdSJason Molenda 1095*ac49e902SJason Molenda /// Third, format all of the above in the JSONGenerator object. 109620ee21bdSJason Molenda 1097a2992311SJason Molenda return FormatDynamicLibrariesIntoJSON(image_infos); 1098a2992311SJason Molenda} 1099a2992311SJason Molenda 11007e9bab6aSAdrian Prantl/// From dyld SPI header dyld_process_info.h 1101a2992311SJason Molendatypedef void *dyld_process_info; 1102b9c1b51eSKate Stonestruct dyld_process_cache_info { 11037e9bab6aSAdrian Prantl /// UUID of cache used by process. 11047e9bab6aSAdrian Prantl uuid_t cacheUUID; 11057e9bab6aSAdrian Prantl /// Load address of dyld shared cache. 11067e9bab6aSAdrian Prantl uint64_t cacheBaseAddress; 11077e9bab6aSAdrian Prantl /// Process is running without a dyld cache. 11087e9bab6aSAdrian Prantl bool noCache; 11097e9bab6aSAdrian Prantl /// Process is using a private copy of its dyld cache. 11107e9bab6aSAdrian Prantl bool privateCache; 1111a2992311SJason Molenda}; 1112a2992311SJason Molenda 11138dd10602Skuperxuuint32_t MachProcess::GetPlatform() { 11148dd10602Skuperxu if (m_platform == 0) 11158dd10602Skuperxu m_platform = MachProcess::GetProcessPlatformViaDYLDSPI(); 11168dd10602Skuperxu return m_platform; 11178dd10602Skuperxu} 11188dd10602Skuperxu 11197e9bab6aSAdrian Prantluint32_t MachProcess::GetProcessPlatformViaDYLDSPI() { 11207e9bab6aSAdrian Prantl kern_return_t kern_ret; 11216cebeafaSJason Molenda uint32_t platform = 0; 11227e9bab6aSAdrian Prantl if (m_dyld_process_info_create) { 11237e9bab6aSAdrian Prantl dyld_process_info info = 11247e9bab6aSAdrian Prantl m_dyld_process_info_create(m_task.TaskPort(), 0, &kern_ret); 11257e9bab6aSAdrian Prantl if (info) { 11267e9bab6aSAdrian Prantl if (m_dyld_process_info_get_platform) 11277e9bab6aSAdrian Prantl platform = m_dyld_process_info_get_platform(info); 11287e9bab6aSAdrian Prantl m_dyld_process_info_release(info); 11297e9bab6aSAdrian Prantl } 11307e9bab6aSAdrian Prantl } 11317e9bab6aSAdrian Prantl return platform; 11327e9bab6aSAdrian Prantl} 11337e9bab6aSAdrian Prantl 11347e9bab6aSAdrian Prantlvoid MachProcess::GetAllLoadedBinariesViaDYLDSPI( 11357e9bab6aSAdrian Prantl std::vector<struct binary_image_information> &image_infos) { 1136a2992311SJason Molenda kern_return_t kern_ret; 1137b9c1b51eSKate Stone if (m_dyld_process_info_create) { 1138b9c1b51eSKate Stone dyld_process_info info = 1139b9c1b51eSKate Stone m_dyld_process_info_create(m_task.TaskPort(), 0, &kern_ret); 1140b9c1b51eSKate Stone if (info) { 1141b9c1b51eSKate Stone m_dyld_process_info_for_each_image( 1142b9c1b51eSKate Stone info, 1143b9c1b51eSKate Stone ^(uint64_t mach_header_addr, const uuid_t uuid, const char *path) { 1144a2992311SJason Molenda struct binary_image_information image; 1145a2992311SJason Molenda image.filename = path; 1146a2992311SJason Molenda uuid_copy(image.macho_info.uuid, uuid); 1147a2992311SJason Molenda image.load_address = mach_header_addr; 1148a2992311SJason Molenda image_infos.push_back(image); 1149a2992311SJason Molenda }); 1150a2992311SJason Molenda m_dyld_process_info_release(info); 1151a2992311SJason Molenda } 1152a2992311SJason Molenda } 1153a2992311SJason Molenda} 1154a2992311SJason Molenda 1155b9c1b51eSKate Stone// Fetch information about all shared libraries using the dyld SPIs that exist 1156b9c1b51eSKate Stone// in 1157a2992311SJason Molenda// macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer. 1158a2992311SJason MolendaJSONGenerator::ObjectSP 1159b9c1b51eSKate StoneMachProcess::GetAllLoadedLibrariesInfos(nub_process_t pid) { 1160a2992311SJason Molenda 1161afee0975SJason Molenda int pointer_size = GetInferiorAddrSize(pid); 1162a2992311SJason Molenda std::vector<struct binary_image_information> image_infos; 11637e9bab6aSAdrian Prantl GetAllLoadedBinariesViaDYLDSPI(image_infos); 11648dd10602Skuperxu uint32_t platform = GetPlatform(); 1165a2992311SJason Molenda const size_t image_count = image_infos.size(); 1166b9c1b51eSKate Stone for (size_t i = 0; i < image_count; i++) { 1167*ac49e902SJason Molenda if (GetMachOInformationFromMemory(platform, image_infos[i].load_address, 1168*ac49e902SJason Molenda pointer_size, 1169*ac49e902SJason Molenda image_infos[i].macho_info)) { 1170*ac49e902SJason Molenda image_infos[i].is_valid_mach_header = true; 1171*ac49e902SJason Molenda } 1172a2992311SJason Molenda } 1173a2992311SJason Molenda return FormatDynamicLibrariesIntoJSON(image_infos); 1174a2992311SJason Molenda} 1175a2992311SJason Molenda 1176b9c1b51eSKate Stone// Fetch information about the shared libraries at the given load addresses 1177b9c1b51eSKate Stone// using the 1178a2992311SJason Molenda// dyld SPIs that exist in macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer. 1179b9c1b51eSKate StoneJSONGenerator::ObjectSP MachProcess::GetLibrariesInfoForAddresses( 1180b9c1b51eSKate Stone nub_process_t pid, std::vector<uint64_t> &macho_addresses) { 1181a2992311SJason Molenda 1182afee0975SJason Molenda int pointer_size = GetInferiorAddrSize(pid); 1183a2992311SJason Molenda 1184*ac49e902SJason Molenda // Collect the list of all binaries that dyld knows about in 1185*ac49e902SJason Molenda // the inferior process. 1186a2992311SJason Molenda std::vector<struct binary_image_information> all_image_infos; 11877e9bab6aSAdrian Prantl GetAllLoadedBinariesViaDYLDSPI(all_image_infos); 11888dd10602Skuperxu uint32_t platform = GetPlatform(); 1189a2992311SJason Molenda 1190a2992311SJason Molenda std::vector<struct binary_image_information> image_infos; 1191a2992311SJason Molenda const size_t macho_addresses_count = macho_addresses.size(); 1192a2992311SJason Molenda const size_t all_image_infos_count = all_image_infos.size(); 1193*ac49e902SJason Molenda 1194b9c1b51eSKate Stone for (size_t i = 0; i < macho_addresses_count; i++) { 1195*ac49e902SJason Molenda bool found_matching_entry = false; 1196b9c1b51eSKate Stone for (size_t j = 0; j < all_image_infos_count; j++) { 1197b9c1b51eSKate Stone if (all_image_infos[j].load_address == macho_addresses[i]) { 1198a2992311SJason Molenda image_infos.push_back(all_image_infos[j]); 1199*ac49e902SJason Molenda found_matching_entry = true; 1200a2992311SJason Molenda } 1201a2992311SJason Molenda } 1202*ac49e902SJason Molenda if (!found_matching_entry) { 1203*ac49e902SJason Molenda // dyld doesn't think there is a binary at this address, 1204*ac49e902SJason Molenda // but maybe there isn't a binary YET - let's look in memory 1205*ac49e902SJason Molenda // for a proper mach-o header etc and return what we can. 1206*ac49e902SJason Molenda // We will have an empty filename for the binary (because dyld 1207*ac49e902SJason Molenda // doesn't know about it yet) but we can read all of the mach-o 1208*ac49e902SJason Molenda // load commands from memory directly. 1209*ac49e902SJason Molenda struct binary_image_information entry; 1210*ac49e902SJason Molenda entry.load_address = macho_addresses[i]; 1211*ac49e902SJason Molenda image_infos.push_back(entry); 1212*ac49e902SJason Molenda } 1213a2992311SJason Molenda } 1214a2992311SJason Molenda 1215a2992311SJason Molenda const size_t image_infos_count = image_infos.size(); 1216b9c1b51eSKate Stone for (size_t i = 0; i < image_infos_count; i++) { 1217*ac49e902SJason Molenda if (GetMachOInformationFromMemory(platform, image_infos[i].load_address, 1218*ac49e902SJason Molenda pointer_size, 1219*ac49e902SJason Molenda image_infos[i].macho_info)) { 1220*ac49e902SJason Molenda image_infos[i].is_valid_mach_header = true; 1221*ac49e902SJason Molenda } 1222a2992311SJason Molenda } 1223a2992311SJason Molenda return FormatDynamicLibrariesIntoJSON(image_infos); 1224a2992311SJason Molenda} 1225a2992311SJason Molenda 1226a2992311SJason Molenda// From dyld's internal podyld_process_info.h: 1227a2992311SJason Molenda 1228b9c1b51eSKate StoneJSONGenerator::ObjectSP MachProcess::GetSharedCacheInfo(nub_process_t pid) { 1229b9c1b51eSKate Stone JSONGenerator::DictionarySP reply_sp(new JSONGenerator::Dictionary()); 12307e9bab6aSAdrian Prantl 1231a2992311SJason Molenda kern_return_t kern_ret; 1232b9c1b51eSKate Stone if (m_dyld_process_info_create && m_dyld_process_info_get_cache) { 1233b9c1b51eSKate Stone dyld_process_info info = 1234b9c1b51eSKate Stone m_dyld_process_info_create(m_task.TaskPort(), 0, &kern_ret); 1235b9c1b51eSKate Stone if (info) { 1236a2992311SJason Molenda struct dyld_process_cache_info shared_cache_info; 1237a2992311SJason Molenda m_dyld_process_info_get_cache(info, &shared_cache_info); 1238a2992311SJason Molenda 1239b9c1b51eSKate Stone reply_sp->AddIntegerItem("shared_cache_base_address", 1240b9c1b51eSKate Stone shared_cache_info.cacheBaseAddress); 124120ee21bdSJason Molenda 124220ee21bdSJason Molenda uuid_string_t uuidstr; 1243a2992311SJason Molenda uuid_unparse_upper(shared_cache_info.cacheUUID, uuidstr); 1244a2992311SJason Molenda reply_sp->AddStringItem("shared_cache_uuid", uuidstr); 124520ee21bdSJason Molenda 1246a2992311SJason Molenda reply_sp->AddBooleanItem("no_shared_cache", shared_cache_info.noCache); 1247b9c1b51eSKate Stone reply_sp->AddBooleanItem("shared_cache_private_cache", 1248b9c1b51eSKate Stone shared_cache_info.privateCache); 124920ee21bdSJason Molenda 1250a2992311SJason Molenda m_dyld_process_info_release(info); 125120ee21bdSJason Molenda } 125220ee21bdSJason Molenda } 125320ee21bdSJason Molenda return reply_sp; 125420ee21bdSJason Molenda} 125520ee21bdSJason Molenda 1256b9c1b51eSKate Stonenub_thread_t MachProcess::GetCurrentThread() { 1257a332978bSJason Molenda return m_thread_list.CurrentThreadID(); 1258a332978bSJason Molenda} 1259a332978bSJason Molenda 1260b9c1b51eSKate Stonenub_thread_t MachProcess::GetCurrentThreadMachPort() { 1261b9c1b51eSKate Stone return m_thread_list.GetMachPortNumberByThreadID( 1262b9c1b51eSKate Stone m_thread_list.CurrentThreadID()); 1263a332978bSJason Molenda} 1264a332978bSJason Molenda 1265b9c1b51eSKate Stonenub_thread_t MachProcess::SetCurrentThread(nub_thread_t tid) { 1266a332978bSJason Molenda return m_thread_list.SetCurrentThread(tid); 1267a332978bSJason Molenda} 1268a332978bSJason Molenda 1269b9c1b51eSKate Stonebool MachProcess::GetThreadStoppedReason(nub_thread_t tid, 1270b9c1b51eSKate Stone struct DNBThreadStopInfo *stop_info) { 1271b9c1b51eSKate Stone if (m_thread_list.GetThreadStoppedReason(tid, stop_info)) { 1272a332978bSJason Molenda if (m_did_exec) 1273a332978bSJason Molenda stop_info->reason = eStopTypeExec; 1274a332978bSJason Molenda return true; 1275a332978bSJason Molenda } 1276a332978bSJason Molenda return false; 1277a332978bSJason Molenda} 1278a332978bSJason Molenda 1279b9c1b51eSKate Stonevoid MachProcess::DumpThreadStoppedReason(nub_thread_t tid) const { 1280a332978bSJason Molenda return m_thread_list.DumpThreadStoppedReason(tid); 1281a332978bSJason Molenda} 1282a332978bSJason Molenda 1283b9c1b51eSKate Stoneconst char *MachProcess::GetThreadInfo(nub_thread_t tid) const { 1284a332978bSJason Molenda return m_thread_list.GetThreadInfo(tid); 1285a332978bSJason Molenda} 1286a332978bSJason Molenda 1287b9c1b51eSKate Stoneuint32_t MachProcess::GetCPUType() { 1288a332978bSJason Molenda if (m_cpu_type == 0 && m_pid != 0) 1289a332978bSJason Molenda m_cpu_type = MachProcess::GetCPUTypeForLocalProcess(m_pid); 1290a332978bSJason Molenda return m_cpu_type; 1291a332978bSJason Molenda} 1292a332978bSJason Molenda 1293a332978bSJason Molendaconst DNBRegisterSetInfo * 1294b9c1b51eSKate StoneMachProcess::GetRegisterSetInfo(nub_thread_t tid, 1295b9c1b51eSKate Stone nub_size_t *num_reg_sets) const { 1296a332978bSJason Molenda MachThreadSP thread_sp(m_thread_list.GetThreadByID(tid)); 1297b9c1b51eSKate Stone if (thread_sp) { 1298a332978bSJason Molenda DNBArchProtocol *arch = thread_sp->GetArchProtocol(); 1299a332978bSJason Molenda if (arch) 1300a332978bSJason Molenda return arch->GetRegisterSetInfo(num_reg_sets); 1301a332978bSJason Molenda } 1302a332978bSJason Molenda *num_reg_sets = 0; 1303a332978bSJason Molenda return NULL; 1304a332978bSJason Molenda} 1305a332978bSJason Molenda 1306b9c1b51eSKate Stonebool MachProcess::GetRegisterValue(nub_thread_t tid, uint32_t set, uint32_t reg, 1307b9c1b51eSKate Stone DNBRegisterValue *value) const { 1308a332978bSJason Molenda return m_thread_list.GetRegisterValue(tid, set, reg, value); 1309a332978bSJason Molenda} 1310a332978bSJason Molenda 1311b9c1b51eSKate Stonebool MachProcess::SetRegisterValue(nub_thread_t tid, uint32_t set, uint32_t reg, 1312b9c1b51eSKate Stone const DNBRegisterValue *value) const { 1313a332978bSJason Molenda return m_thread_list.SetRegisterValue(tid, set, reg, value); 1314a332978bSJason Molenda} 1315a332978bSJason Molenda 1316b9c1b51eSKate Stonevoid MachProcess::SetState(nub_state_t new_state) { 1317a332978bSJason Molenda // If any other threads access this we will need a mutex for it 1318a332978bSJason Molenda uint32_t event_mask = 0; 1319a332978bSJason Molenda 1320a332978bSJason Molenda // Scope for mutex locker 1321a332978bSJason Molenda { 1322a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_state_mutex); 1323a332978bSJason Molenda const nub_state_t old_state = m_state; 1324a332978bSJason Molenda 1325b9c1b51eSKate Stone if (old_state == eStateExited) { 1326b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::SetState(%s) ignoring new " 1327b9c1b51eSKate Stone "state since current state is exited", 1328b9c1b51eSKate Stone DNBStateAsString(new_state)); 1329b9c1b51eSKate Stone } else if (old_state == new_state) { 1330b9c1b51eSKate Stone DNBLogThreadedIf( 1331b9c1b51eSKate Stone LOG_PROCESS, 1332b9c1b51eSKate Stone "MachProcess::SetState(%s) ignoring redundant state change...", 1333b9c1b51eSKate Stone DNBStateAsString(new_state)); 1334b9c1b51eSKate Stone } else { 1335a332978bSJason Molenda if (NUB_STATE_IS_STOPPED(new_state)) 1336a332978bSJason Molenda event_mask = eEventProcessStoppedStateChanged; 1337a332978bSJason Molenda else 1338a332978bSJason Molenda event_mask = eEventProcessRunningStateChanged; 1339a332978bSJason Molenda 1340b9c1b51eSKate Stone DNBLogThreadedIf( 1341b9c1b51eSKate Stone LOG_PROCESS, "MachProcess::SetState(%s) upating state (previous " 1342b9c1b51eSKate Stone "state was %s), event_mask = 0x%8.8x", 1343b9c1b51eSKate Stone DNBStateAsString(new_state), DNBStateAsString(old_state), event_mask); 1344a332978bSJason Molenda 1345a332978bSJason Molenda m_state = new_state; 1346a332978bSJason Molenda if (new_state == eStateStopped) 1347a332978bSJason Molenda m_stop_count++; 1348a332978bSJason Molenda } 1349a332978bSJason Molenda } 1350a332978bSJason Molenda 1351b9c1b51eSKate Stone if (event_mask != 0) { 1352a332978bSJason Molenda m_events.SetEvents(event_mask); 1353a332978bSJason Molenda m_private_events.SetEvents(event_mask); 1354a332978bSJason Molenda if (event_mask == eEventProcessStoppedStateChanged) 1355a332978bSJason Molenda m_private_events.ResetEvents(eEventProcessRunningStateChanged); 1356a332978bSJason Molenda else 1357a332978bSJason Molenda m_private_events.ResetEvents(eEventProcessStoppedStateChanged); 1358a332978bSJason Molenda 1359a332978bSJason Molenda // Wait for the event bit to reset if a reset ACK is requested 1360a332978bSJason Molenda m_events.WaitForResetAck(event_mask); 1361a332978bSJason Molenda } 1362a332978bSJason Molenda} 1363a332978bSJason Molenda 1364b9c1b51eSKate Stonevoid MachProcess::Clear(bool detaching) { 1365a332978bSJason Molenda // Clear any cached thread list while the pid and task are still valid 1366a332978bSJason Molenda 1367a332978bSJason Molenda m_task.Clear(); 13688dd10602Skuperxu m_platform = 0; 1369a332978bSJason Molenda // Now clear out all member variables 1370a332978bSJason Molenda m_pid = INVALID_NUB_PROCESS; 1371a332978bSJason Molenda if (!detaching) 1372a332978bSJason Molenda CloseChildFileDescriptors(); 1373a332978bSJason Molenda 1374a332978bSJason Molenda m_path.clear(); 1375a332978bSJason Molenda m_args.clear(); 1376a332978bSJason Molenda SetState(eStateUnloaded); 1377a332978bSJason Molenda m_flags = eMachProcessFlagsNone; 1378a332978bSJason Molenda m_stop_count = 0; 1379a332978bSJason Molenda m_thread_list.Clear(); 1380a332978bSJason Molenda { 1381a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); 1382a332978bSJason Molenda m_exception_messages.clear(); 1383a332978bSJason Molenda } 1384705b1809SJason Molenda m_activities.Clear(); 13853cd13c46SJim Ingham StopProfileThread(); 1386a332978bSJason Molenda} 1387a332978bSJason Molenda 1388b9c1b51eSKate Stonebool MachProcess::StartSTDIOThread() { 1389a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__); 1390a332978bSJason Molenda // Create the thread that watches for the child STDIO 1391b9c1b51eSKate Stone return ::pthread_create(&m_stdio_thread, NULL, MachProcess::STDIOThread, 1392b9c1b51eSKate Stone this) == 0; 1393a332978bSJason Molenda} 1394a332978bSJason Molenda 1395b9c1b51eSKate Stonevoid MachProcess::SetEnableAsyncProfiling(bool enable, uint64_t interval_usec, 1396b9c1b51eSKate Stone DNBProfileDataScanType scan_type) { 1397a332978bSJason Molenda m_profile_enabled = enable; 1398ee2ed525SGreg Clayton m_profile_interval_usec = static_cast<useconds_t>(interval_usec); 1399a332978bSJason Molenda m_profile_scan_type = scan_type; 1400a332978bSJason Molenda 1401b9c1b51eSKate Stone if (m_profile_enabled && (m_profile_thread == NULL)) { 1402a332978bSJason Molenda StartProfileThread(); 1403b9c1b51eSKate Stone } else if (!m_profile_enabled && m_profile_thread) { 14043cd13c46SJim Ingham StopProfileThread(); 14053cd13c46SJim Ingham } 14063cd13c46SJim Ingham} 14073cd13c46SJim Ingham 14083cd13c46SJim Inghamvoid MachProcess::StopProfileThread() { 14093cd13c46SJim Ingham if (m_profile_thread == NULL) 14103cd13c46SJim Ingham return; 14113cd13c46SJim Ingham m_profile_events.SetEvents(eMachProcessProfileCancel); 1412a332978bSJason Molenda pthread_join(m_profile_thread, NULL); 1413a332978bSJason Molenda m_profile_thread = NULL; 14143cd13c46SJim Ingham m_profile_events.ResetEvents(eMachProcessProfileCancel); 1415a332978bSJason Molenda} 1416a332978bSJason Molenda 1417b9c1b51eSKate Stonebool MachProcess::StartProfileThread() { 1418a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__); 1419a332978bSJason Molenda // Create the thread that profiles the inferior and reports back if enabled 1420b9c1b51eSKate Stone return ::pthread_create(&m_profile_thread, NULL, MachProcess::ProfileThread, 1421b9c1b51eSKate Stone this) == 0; 1422a332978bSJason Molenda} 1423a332978bSJason Molenda 1424b9c1b51eSKate Stonenub_addr_t MachProcess::LookupSymbol(const char *name, const char *shlib) { 1425a332978bSJason Molenda if (m_name_to_addr_callback != NULL && name && name[0]) 1426b9c1b51eSKate Stone return m_name_to_addr_callback(ProcessID(), name, shlib, 1427b9c1b51eSKate Stone m_name_to_addr_baton); 1428a332978bSJason Molenda return INVALID_NUB_ADDRESS; 1429a332978bSJason Molenda} 1430a332978bSJason Molenda 1431b9c1b51eSKate Stonebool MachProcess::Resume(const DNBThreadResumeActions &thread_actions) { 1432a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Resume ()"); 1433a332978bSJason Molenda nub_state_t state = GetState(); 1434a332978bSJason Molenda 1435b9c1b51eSKate Stone if (CanResume(state)) { 1436a332978bSJason Molenda m_thread_actions = thread_actions; 1437a332978bSJason Molenda PrivateResume(); 1438a332978bSJason Molenda return true; 1439b9c1b51eSKate Stone } else if (state == eStateRunning) { 1440b9c1b51eSKate Stone DNBLog("Resume() - task 0x%x is already running, ignoring...", 1441b9c1b51eSKate Stone m_task.TaskPort()); 1442a332978bSJason Molenda return true; 1443a332978bSJason Molenda } 1444b9c1b51eSKate Stone DNBLog("Resume() - task 0x%x has state %s, can't continue...", 1445b9c1b51eSKate Stone m_task.TaskPort(), DNBStateAsString(state)); 1446a332978bSJason Molenda return false; 1447a332978bSJason Molenda} 1448a332978bSJason Molenda 1449b9c1b51eSKate Stonebool MachProcess::Kill(const struct timespec *timeout_abstime) { 1450a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill ()"); 1451a332978bSJason Molenda nub_state_t state = DoSIGSTOP(true, false, NULL); 1452b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() state = %s", 1453b9c1b51eSKate Stone DNBStateAsString(state)); 1454a332978bSJason Molenda errno = 0; 1455edde2eb1SJason Molenda DNBLog("Sending ptrace PT_KILL to terminate inferior process pid %d.", m_pid); 1456a332978bSJason Molenda ::ptrace(PT_KILL, m_pid, 0, 0); 1457a332978bSJason Molenda DNBError err; 1458a332978bSJason Molenda err.SetErrorToErrno(); 14599d760a0aSJason Molenda if (DNBLogCheckLogBit(LOG_PROCESS) || err.Fail()) { 14609d760a0aSJason Molenda err.LogThreaded("MachProcess::Kill() DoSIGSTOP() ::ptrace " 1461b9c1b51eSKate Stone "(PT_KILL, pid=%u, 0, 0) => 0x%8.8x (%s)", 146297206d57SZachary Turner m_pid, err.Status(), err.AsString()); 14639d760a0aSJason Molenda } 1464a332978bSJason Molenda m_thread_actions = DNBThreadResumeActions(eStateRunning, 0); 1465a332978bSJason Molenda PrivateResume(); 1466a332978bSJason Molenda 1467a332978bSJason Molenda // Try and reap the process without touching our m_events since 1468a332978bSJason Molenda // we want the code above this to still get the eStateExited event 1469b9c1b51eSKate Stone const uint32_t reap_timeout_usec = 1470b9c1b51eSKate Stone 1000000; // Wait 1 second and try to reap the process 1471a332978bSJason Molenda const uint32_t reap_interval_usec = 10000; // 1472a332978bSJason Molenda uint32_t reap_time_elapsed; 1473b9c1b51eSKate Stone for (reap_time_elapsed = 0; reap_time_elapsed < reap_timeout_usec; 1474b9c1b51eSKate Stone reap_time_elapsed += reap_interval_usec) { 1475a332978bSJason Molenda if (GetState() == eStateExited) 1476a332978bSJason Molenda break; 1477a332978bSJason Molenda usleep(reap_interval_usec); 1478a332978bSJason Molenda } 1479b9c1b51eSKate Stone DNBLog("Waited %u ms for process to be reaped (state = %s)", 1480b9c1b51eSKate Stone reap_time_elapsed / 1000, DNBStateAsString(GetState())); 1481a332978bSJason Molenda return true; 1482a332978bSJason Molenda} 1483a332978bSJason Molenda 1484b9c1b51eSKate Stonebool MachProcess::Interrupt() { 14854296c221SGreg Clayton nub_state_t state = GetState(); 1486b9c1b51eSKate Stone if (IsRunning(state)) { 1487b9c1b51eSKate Stone if (m_sent_interrupt_signo == 0) { 14884296c221SGreg Clayton m_sent_interrupt_signo = SIGSTOP; 1489b9c1b51eSKate Stone if (Signal(m_sent_interrupt_signo)) { 1490b9c1b51eSKate Stone DNBLogThreadedIf( 1491b9c1b51eSKate Stone LOG_PROCESS, 1492b9c1b51eSKate Stone "MachProcess::Interrupt() - sent %i signal to interrupt process", 1493b9c1b51eSKate Stone m_sent_interrupt_signo); 1494830c81d5SGreg Clayton return true; 1495b9c1b51eSKate Stone } else { 14964296c221SGreg Clayton m_sent_interrupt_signo = 0; 1497b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Interrupt() - failed to " 1498b9c1b51eSKate Stone "send %i signal to interrupt process", 1499b9c1b51eSKate Stone m_sent_interrupt_signo); 15004296c221SGreg Clayton } 1501b9c1b51eSKate Stone } else { 1502b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Interrupt() - previously " 1503b9c1b51eSKate Stone "sent an interrupt signal %i that hasn't " 1504b9c1b51eSKate Stone "been received yet, interrupt aborted", 1505b9c1b51eSKate Stone m_sent_interrupt_signo); 15064296c221SGreg Clayton } 1507b9c1b51eSKate Stone } else { 1508b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Interrupt() - process already " 1509b9c1b51eSKate Stone "stopped, no interrupt sent"); 15104296c221SGreg Clayton } 15114296c221SGreg Clayton return false; 15124296c221SGreg Clayton} 15134296c221SGreg Clayton 1514b9c1b51eSKate Stonebool MachProcess::Signal(int signal, const struct timespec *timeout_abstime) { 1515b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 1516b9c1b51eSKate Stone "MachProcess::Signal (signal = %d, timeout = %p)", signal, 151765fdb342SRaphael Isemann static_cast<const void *>(timeout_abstime)); 1518a332978bSJason Molenda nub_state_t state = GetState(); 1519b9c1b51eSKate Stone if (::kill(ProcessID(), signal) == 0) { 1520a332978bSJason Molenda // If we were running and we have a timeout, wait for the signal to stop 1521b9c1b51eSKate Stone if (IsRunning(state) && timeout_abstime) { 152265fdb342SRaphael Isemann DNBLogThreadedIf(LOG_PROCESS, 152365fdb342SRaphael Isemann "MachProcess::Signal (signal = %d, timeout " 1524b9c1b51eSKate Stone "= %p) waiting for signal to stop " 1525b9c1b51eSKate Stone "process...", 152665fdb342SRaphael Isemann signal, static_cast<const void *>(timeout_abstime)); 1527b9c1b51eSKate Stone m_private_events.WaitForSetEvents(eEventProcessStoppedStateChanged, 1528b9c1b51eSKate Stone timeout_abstime); 1529a332978bSJason Molenda state = GetState(); 1530b9c1b51eSKate Stone DNBLogThreadedIf( 1531b9c1b51eSKate Stone LOG_PROCESS, 1532b9c1b51eSKate Stone "MachProcess::Signal (signal = %d, timeout = %p) state = %s", signal, 153365fdb342SRaphael Isemann static_cast<const void *>(timeout_abstime), DNBStateAsString(state)); 1534a332978bSJason Molenda return !IsRunning(state); 1535a332978bSJason Molenda } 1536b9c1b51eSKate Stone DNBLogThreadedIf( 1537b9c1b51eSKate Stone LOG_PROCESS, 1538b9c1b51eSKate Stone "MachProcess::Signal (signal = %d, timeout = %p) not waiting...", 153965fdb342SRaphael Isemann signal, static_cast<const void *>(timeout_abstime)); 1540a332978bSJason Molenda return true; 1541a332978bSJason Molenda } 1542a332978bSJason Molenda DNBError err(errno, DNBError::POSIX); 1543a332978bSJason Molenda err.LogThreadedIfError("kill (pid = %d, signo = %i)", ProcessID(), signal); 1544a332978bSJason Molenda return false; 1545a332978bSJason Molenda} 1546a332978bSJason Molenda 1547b9c1b51eSKate Stonebool MachProcess::SendEvent(const char *event, DNBError &send_err) { 1548b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 1549b9c1b51eSKate Stone "MachProcess::SendEvent (event = %s) to pid: %d", event, 1550b9c1b51eSKate Stone m_pid); 1551a332978bSJason Molenda if (m_pid == INVALID_NUB_PROCESS) 1552a332978bSJason Molenda return false; 1553c611a740SJason Molenda// FIXME: Shouldn't we use the launch flavor we were started with? 1554c611a740SJason Molenda#if defined(WITH_FBS) || defined(WITH_BKS) 1555c611a740SJason Molenda return BoardServiceSendEvent(event, send_err); 1556a332978bSJason Molenda#endif 1557a332978bSJason Molenda return true; 1558a332978bSJason Molenda} 1559a332978bSJason Molenda 1560b9c1b51eSKate Stonenub_state_t MachProcess::DoSIGSTOP(bool clear_bps_and_wps, bool allow_running, 1561b9c1b51eSKate Stone uint32_t *thread_idx_ptr) { 1562a332978bSJason Molenda nub_state_t state = GetState(); 1563b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s", 1564b9c1b51eSKate Stone DNBStateAsString(state)); 1565a332978bSJason Molenda 1566b9c1b51eSKate Stone if (!IsRunning(state)) { 1567b9c1b51eSKate Stone if (clear_bps_and_wps) { 1568a332978bSJason Molenda DisableAllBreakpoints(true); 1569a332978bSJason Molenda DisableAllWatchpoints(true); 1570a332978bSJason Molenda clear_bps_and_wps = false; 1571a332978bSJason Molenda } 1572a332978bSJason Molenda 1573a332978bSJason Molenda // If we already have a thread stopped due to a SIGSTOP, we don't have 1574a332978bSJason Molenda // to do anything... 1575b9c1b51eSKate Stone uint32_t thread_idx = 1576b9c1b51eSKate Stone m_thread_list.GetThreadIndexForThreadStoppedWithSignal(SIGSTOP); 1577a332978bSJason Molenda if (thread_idx_ptr) 1578a332978bSJason Molenda *thread_idx_ptr = thread_idx; 1579a332978bSJason Molenda if (thread_idx != UINT32_MAX) 1580a332978bSJason Molenda return GetState(); 1581a332978bSJason Molenda 1582a332978bSJason Molenda // No threads were stopped with a SIGSTOP, we need to run and halt the 1583a332978bSJason Molenda // process with a signal 1584b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 1585b9c1b51eSKate Stone "MachProcess::DoSIGSTOP() state = %s -- resuming process", 1586b9c1b51eSKate Stone DNBStateAsString(state)); 1587a332978bSJason Molenda if (allow_running) 1588a332978bSJason Molenda m_thread_actions = DNBThreadResumeActions(eStateRunning, 0); 1589a332978bSJason Molenda else 1590a332978bSJason Molenda m_thread_actions = DNBThreadResumeActions(eStateSuspended, 0); 1591a332978bSJason Molenda 1592a332978bSJason Molenda PrivateResume(); 1593a332978bSJason Molenda 1594a332978bSJason Molenda // Reset the event that says we were indeed running 1595a332978bSJason Molenda m_events.ResetEvents(eEventProcessRunningStateChanged); 1596a332978bSJason Molenda state = GetState(); 1597a332978bSJason Molenda } 1598a332978bSJason Molenda 1599a332978bSJason Molenda // We need to be stopped in order to be able to detach, so we need 1600a332978bSJason Molenda // to send ourselves a SIGSTOP 1601a332978bSJason Molenda 1602b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 1603b9c1b51eSKate Stone "MachProcess::DoSIGSTOP() state = %s -- sending SIGSTOP", 1604b9c1b51eSKate Stone DNBStateAsString(state)); 1605a332978bSJason Molenda struct timespec sigstop_timeout; 1606a332978bSJason Molenda DNBTimer::OffsetTimeOfDay(&sigstop_timeout, 2, 0); 1607a332978bSJason Molenda Signal(SIGSTOP, &sigstop_timeout); 1608b9c1b51eSKate Stone if (clear_bps_and_wps) { 1609a332978bSJason Molenda DisableAllBreakpoints(true); 1610a332978bSJason Molenda DisableAllWatchpoints(true); 1611a332978bSJason Molenda // clear_bps_and_wps = false; 1612a332978bSJason Molenda } 1613b9c1b51eSKate Stone uint32_t thread_idx = 1614b9c1b51eSKate Stone m_thread_list.GetThreadIndexForThreadStoppedWithSignal(SIGSTOP); 1615a332978bSJason Molenda if (thread_idx_ptr) 1616a332978bSJason Molenda *thread_idx_ptr = thread_idx; 1617a332978bSJason Molenda return GetState(); 1618a332978bSJason Molenda} 1619a332978bSJason Molenda 1620b9c1b51eSKate Stonebool MachProcess::Detach() { 1621a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach()"); 1622a332978bSJason Molenda 1623a332978bSJason Molenda uint32_t thread_idx = UINT32_MAX; 1624a332978bSJason Molenda nub_state_t state = DoSIGSTOP(true, true, &thread_idx); 1625b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach() DoSIGSTOP() returned %s", 1626b9c1b51eSKate Stone DNBStateAsString(state)); 1627a332978bSJason Molenda 1628a332978bSJason Molenda { 1629a332978bSJason Molenda m_thread_actions.Clear(); 1630705b1809SJason Molenda m_activities.Clear(); 1631a332978bSJason Molenda DNBThreadResumeAction thread_action; 1632a332978bSJason Molenda thread_action.tid = m_thread_list.ThreadIDAtIndex(thread_idx); 1633a332978bSJason Molenda thread_action.state = eStateRunning; 1634a332978bSJason Molenda thread_action.signal = -1; 1635a332978bSJason Molenda thread_action.addr = INVALID_NUB_ADDRESS; 1636a332978bSJason Molenda 1637a332978bSJason Molenda m_thread_actions.Append(thread_action); 1638a332978bSJason Molenda m_thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0); 1639a332978bSJason Molenda 1640a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); 1641a332978bSJason Molenda 1642a332978bSJason Molenda ReplyToAllExceptions(); 1643a332978bSJason Molenda } 1644a332978bSJason Molenda 1645a332978bSJason Molenda m_task.ShutDownExcecptionThread(); 1646a332978bSJason Molenda 1647a332978bSJason Molenda // Detach from our process 1648a332978bSJason Molenda errno = 0; 1649a332978bSJason Molenda nub_process_t pid = m_pid; 1650a332978bSJason Molenda int ret = ::ptrace(PT_DETACH, pid, (caddr_t)1, 0); 1651a332978bSJason Molenda DNBError err(errno, DNBError::POSIX); 1652a332978bSJason Molenda if (DNBLogCheckLogBit(LOG_PROCESS) || err.Fail() || (ret != 0)) 1653a332978bSJason Molenda err.LogThreaded("::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid); 1654a332978bSJason Molenda 1655a332978bSJason Molenda // Resume our task 1656a332978bSJason Molenda m_task.Resume(); 1657a332978bSJason Molenda 16584ebdee0aSBruce Mitchener // NULL our task out as we have already restored all exception ports 1659a332978bSJason Molenda m_task.Clear(); 16608dd10602Skuperxu m_platform = 0; 1661a332978bSJason Molenda 1662a332978bSJason Molenda // Clear out any notion of the process we once were 1663a332978bSJason Molenda const bool detaching = true; 1664a332978bSJason Molenda Clear(detaching); 1665a332978bSJason Molenda 1666a332978bSJason Molenda SetState(eStateDetached); 1667a332978bSJason Molenda 1668a332978bSJason Molenda return true; 1669a332978bSJason Molenda} 1670a332978bSJason Molenda 1671a332978bSJason Molenda//---------------------------------------------------------------------- 1672a332978bSJason Molenda// ReadMemory from the MachProcess level will always remove any software 1673a332978bSJason Molenda// breakpoints from the memory buffer before returning. If you wish to 1674a332978bSJason Molenda// read memory and see those traps, read from the MachTask 1675a332978bSJason Molenda// (m_task.ReadMemory()) as that version will give you what is actually 1676a332978bSJason Molenda// in inferior memory. 1677a332978bSJason Molenda//---------------------------------------------------------------------- 1678b9c1b51eSKate Stonenub_size_t MachProcess::ReadMemory(nub_addr_t addr, nub_size_t size, 1679b9c1b51eSKate Stone void *buf) { 1680a332978bSJason Molenda // We need to remove any current software traps (enabled software 1681a332978bSJason Molenda // breakpoints) that we may have placed in our tasks memory. 1682a332978bSJason Molenda 1683a332978bSJason Molenda // First just read the memory as is 1684a332978bSJason Molenda nub_size_t bytes_read = m_task.ReadMemory(addr, size, buf); 1685a332978bSJason Molenda 1686a332978bSJason Molenda // Then place any opcodes that fall into this range back into the buffer 1687a332978bSJason Molenda // before we return this to callers. 1688a332978bSJason Molenda if (bytes_read > 0) 1689a332978bSJason Molenda m_breakpoints.RemoveTrapsFromBuffer(addr, bytes_read, buf); 1690a332978bSJason Molenda return bytes_read; 1691a332978bSJason Molenda} 1692a332978bSJason Molenda 1693a332978bSJason Molenda//---------------------------------------------------------------------- 1694a332978bSJason Molenda// WriteMemory from the MachProcess level will always write memory around 1695a332978bSJason Molenda// any software breakpoints. Any software breakpoints will have their 1696a332978bSJason Molenda// opcodes modified if they are enabled. Any memory that doesn't overlap 1697a332978bSJason Molenda// with software breakpoints will be written to. If you wish to write to 1698a332978bSJason Molenda// inferior memory without this interference, then write to the MachTask 1699a332978bSJason Molenda// (m_task.WriteMemory()) as that version will always modify inferior 1700a332978bSJason Molenda// memory. 1701a332978bSJason Molenda//---------------------------------------------------------------------- 1702b9c1b51eSKate Stonenub_size_t MachProcess::WriteMemory(nub_addr_t addr, nub_size_t size, 1703b9c1b51eSKate Stone const void *buf) { 1704a332978bSJason Molenda // We need to write any data that would go where any current software traps 1705a332978bSJason Molenda // (enabled software breakpoints) any software traps (breakpoints) that we 1706a332978bSJason Molenda // may have placed in our tasks memory. 1707a332978bSJason Molenda 1708a332978bSJason Molenda std::vector<DNBBreakpoint *> bps; 1709a332978bSJason Molenda 1710b9c1b51eSKate Stone const size_t num_bps = 1711b9c1b51eSKate Stone m_breakpoints.FindBreakpointsThatOverlapRange(addr, size, bps); 1712a332978bSJason Molenda if (num_bps == 0) 1713a332978bSJason Molenda return m_task.WriteMemory(addr, size, buf); 1714a332978bSJason Molenda 1715a332978bSJason Molenda nub_size_t bytes_written = 0; 1716a332978bSJason Molenda nub_addr_t intersect_addr; 1717a332978bSJason Molenda nub_size_t intersect_size; 1718a332978bSJason Molenda nub_size_t opcode_offset; 1719a332978bSJason Molenda const uint8_t *ubuf = (const uint8_t *)buf; 1720a332978bSJason Molenda 1721b9c1b51eSKate Stone for (size_t i = 0; i < num_bps; ++i) { 1722a332978bSJason Molenda DNBBreakpoint *bp = bps[i]; 1723a332978bSJason Molenda 1724b9c1b51eSKate Stone const bool intersects = bp->IntersectsRange( 1725b9c1b51eSKate Stone addr, size, &intersect_addr, &intersect_size, &opcode_offset); 17268a67bf72SBruce Mitchener UNUSED_IF_ASSERT_DISABLED(intersects); 1727a332978bSJason Molenda assert(intersects); 1728a332978bSJason Molenda assert(addr <= intersect_addr && intersect_addr < addr + size); 1729b9c1b51eSKate Stone assert(addr < intersect_addr + intersect_size && 1730b9c1b51eSKate Stone intersect_addr + intersect_size <= addr + size); 1731a332978bSJason Molenda assert(opcode_offset + intersect_size <= bp->ByteSize()); 1732a332978bSJason Molenda 1733a332978bSJason Molenda // Check for bytes before this breakpoint 1734a332978bSJason Molenda const nub_addr_t curr_addr = addr + bytes_written; 1735b9c1b51eSKate Stone if (intersect_addr > curr_addr) { 1736a332978bSJason Molenda // There are some bytes before this breakpoint that we need to 1737a332978bSJason Molenda // just write to memory 1738a332978bSJason Molenda nub_size_t curr_size = intersect_addr - curr_addr; 1739b9c1b51eSKate Stone nub_size_t curr_bytes_written = 1740b9c1b51eSKate Stone m_task.WriteMemory(curr_addr, curr_size, ubuf + bytes_written); 1741a332978bSJason Molenda bytes_written += curr_bytes_written; 1742b9c1b51eSKate Stone if (curr_bytes_written != curr_size) { 1743a332978bSJason Molenda // We weren't able to write all of the requested bytes, we 1744a332978bSJason Molenda // are done looping and will return the number of bytes that 1745a332978bSJason Molenda // we have written so far. 1746a332978bSJason Molenda break; 1747a332978bSJason Molenda } 1748a332978bSJason Molenda } 1749a332978bSJason Molenda 1750a332978bSJason Molenda // Now write any bytes that would cover up any software breakpoints 1751a332978bSJason Molenda // directly into the breakpoint opcode buffer 1752b9c1b51eSKate Stone ::memcpy(bp->SavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, 1753b9c1b51eSKate Stone intersect_size); 1754a332978bSJason Molenda bytes_written += intersect_size; 1755a332978bSJason Molenda } 1756a332978bSJason Molenda 1757a332978bSJason Molenda // Write any remaining bytes after the last breakpoint if we have any left 1758a332978bSJason Molenda if (bytes_written < size) 1759b9c1b51eSKate Stone bytes_written += m_task.WriteMemory( 1760b9c1b51eSKate Stone addr + bytes_written, size - bytes_written, ubuf + bytes_written); 1761a332978bSJason Molenda 1762a332978bSJason Molenda return bytes_written; 1763a332978bSJason Molenda} 1764a332978bSJason Molenda 1765b9c1b51eSKate Stonevoid MachProcess::ReplyToAllExceptions() { 1766a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); 1767a6682a41SJonas Devlieghere if (!m_exception_messages.empty()) { 1768a332978bSJason Molenda MachException::Message::iterator pos; 1769a332978bSJason Molenda MachException::Message::iterator begin = m_exception_messages.begin(); 1770a332978bSJason Molenda MachException::Message::iterator end = m_exception_messages.end(); 1771b9c1b51eSKate Stone for (pos = begin; pos != end; ++pos) { 1772b9c1b51eSKate Stone DNBLogThreadedIf(LOG_EXCEPTIONS, "Replying to exception %u...", 1773b9c1b51eSKate Stone (uint32_t)std::distance(begin, pos)); 1774a332978bSJason Molenda int thread_reply_signal = 0; 1775a332978bSJason Molenda 1776b9c1b51eSKate Stone nub_thread_t tid = 1777b9c1b51eSKate Stone m_thread_list.GetThreadIDByMachPortNumber(pos->state.thread_port); 1778a332978bSJason Molenda const DNBThreadResumeAction *action = NULL; 1779b9c1b51eSKate Stone if (tid != INVALID_NUB_THREAD) { 1780a332978bSJason Molenda action = m_thread_actions.GetActionForThread(tid, false); 1781a332978bSJason Molenda } 1782a332978bSJason Molenda 1783b9c1b51eSKate Stone if (action) { 1784a332978bSJason Molenda thread_reply_signal = action->signal; 1785a332978bSJason Molenda if (thread_reply_signal) 1786a332978bSJason Molenda m_thread_actions.SetSignalHandledForThread(tid); 1787a332978bSJason Molenda } 1788a332978bSJason Molenda 1789a332978bSJason Molenda DNBError err(pos->Reply(this, thread_reply_signal)); 1790a332978bSJason Molenda if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) 1791a332978bSJason Molenda err.LogThreadedIfError("Error replying to exception"); 1792a332978bSJason Molenda } 1793a332978bSJason Molenda 1794a332978bSJason Molenda // Erase all exception message as we should have used and replied 1795a332978bSJason Molenda // to them all already. 1796a332978bSJason Molenda m_exception_messages.clear(); 1797a332978bSJason Molenda } 1798a332978bSJason Molenda} 1799b9c1b51eSKate Stonevoid MachProcess::PrivateResume() { 1800a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); 1801a332978bSJason Molenda 18024296c221SGreg Clayton m_auto_resume_signo = m_sent_interrupt_signo; 18034296c221SGreg Clayton if (m_auto_resume_signo) 1804b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::PrivateResume() - task 0x%x " 1805b9c1b51eSKate Stone "resuming (with unhandled interrupt signal " 1806b9c1b51eSKate Stone "%i)...", 1807b9c1b51eSKate Stone m_task.TaskPort(), m_auto_resume_signo); 18084296c221SGreg Clayton else 1809b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 1810b9c1b51eSKate Stone "MachProcess::PrivateResume() - task 0x%x resuming...", 1811b9c1b51eSKate Stone m_task.TaskPort()); 18124296c221SGreg Clayton 1813a332978bSJason Molenda ReplyToAllExceptions(); 1814a332978bSJason Molenda // bool stepOverBreakInstruction = step; 1815a332978bSJason Molenda 1816a332978bSJason Molenda // Let the thread prepare to resume and see if any threads want us to 1817a332978bSJason Molenda // step over a breakpoint instruction (ProcessWillResume will modify 1818a332978bSJason Molenda // the value of stepOverBreakInstruction). 1819a332978bSJason Molenda m_thread_list.ProcessWillResume(this, m_thread_actions); 1820a332978bSJason Molenda 1821a332978bSJason Molenda // Set our state accordingly 1822a332978bSJason Molenda if (m_thread_actions.NumActionsWithState(eStateStepping)) 1823a332978bSJason Molenda SetState(eStateStepping); 1824a332978bSJason Molenda else 1825a332978bSJason Molenda SetState(eStateRunning); 1826a332978bSJason Molenda 1827a332978bSJason Molenda // Now resume our task. 1828a332978bSJason Molenda m_task.Resume(); 1829a332978bSJason Molenda} 1830a332978bSJason Molenda 1831b9c1b51eSKate StoneDNBBreakpoint *MachProcess::CreateBreakpoint(nub_addr_t addr, nub_size_t length, 1832b9c1b51eSKate Stone bool hardware) { 1833b9c1b51eSKate Stone DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = " 1834b9c1b51eSKate Stone "0x%8.8llx, length = %llu, hardware = %i)", 1835b9c1b51eSKate Stone (uint64_t)addr, (uint64_t)length, hardware); 1836a332978bSJason Molenda 1837a332978bSJason Molenda DNBBreakpoint *bp = m_breakpoints.FindByAddress(addr); 1838a332978bSJason Molenda if (bp) 1839a332978bSJason Molenda bp->Retain(); 1840a332978bSJason Molenda else 1841a332978bSJason Molenda bp = m_breakpoints.Add(addr, length, hardware); 1842a332978bSJason Molenda 1843b9c1b51eSKate Stone if (EnableBreakpoint(addr)) { 184465fdb342SRaphael Isemann DNBLogThreadedIf(LOG_BREAKPOINTS, 184565fdb342SRaphael Isemann "MachProcess::CreateBreakpoint ( addr = " 1846b9c1b51eSKate Stone "0x%8.8llx, length = %llu) => %p", 184765fdb342SRaphael Isemann (uint64_t)addr, (uint64_t)length, static_cast<void *>(bp)); 1848a332978bSJason Molenda return bp; 1849b9c1b51eSKate Stone } else if (bp->Release() == 0) { 1850a332978bSJason Molenda m_breakpoints.Remove(addr); 1851a332978bSJason Molenda } 1852a332978bSJason Molenda // We failed to enable the breakpoint 1853a332978bSJason Molenda return NULL; 1854a332978bSJason Molenda} 1855a332978bSJason Molenda 1856b9c1b51eSKate StoneDNBBreakpoint *MachProcess::CreateWatchpoint(nub_addr_t addr, nub_size_t length, 1857b9c1b51eSKate Stone uint32_t watch_flags, 1858b9c1b51eSKate Stone bool hardware) { 1859b9c1b51eSKate Stone DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = " 1860b9c1b51eSKate Stone "0x%8.8llx, length = %llu, flags = " 1861b9c1b51eSKate Stone "0x%8.8x, hardware = %i)", 1862b9c1b51eSKate Stone (uint64_t)addr, (uint64_t)length, watch_flags, hardware); 1863a332978bSJason Molenda 1864a332978bSJason Molenda DNBBreakpoint *wp = m_watchpoints.FindByAddress(addr); 1865b9c1b51eSKate Stone // since the Z packets only send an address, we can only have one watchpoint 1866b9c1b51eSKate Stone // at 1867b9c1b51eSKate Stone // an address. If there is already one, we must refuse to create another 1868b9c1b51eSKate Stone // watchpoint 1869a332978bSJason Molenda if (wp) 1870a332978bSJason Molenda return NULL; 1871a332978bSJason Molenda 1872a332978bSJason Molenda wp = m_watchpoints.Add(addr, length, hardware); 1873a332978bSJason Molenda wp->SetIsWatchpoint(watch_flags); 1874a332978bSJason Molenda 1875b9c1b51eSKate Stone if (EnableWatchpoint(addr)) { 187665fdb342SRaphael Isemann DNBLogThreadedIf(LOG_WATCHPOINTS, 187765fdb342SRaphael Isemann "MachProcess::CreateWatchpoint ( addr = " 1878b9c1b51eSKate Stone "0x%8.8llx, length = %llu) => %p", 187965fdb342SRaphael Isemann (uint64_t)addr, (uint64_t)length, static_cast<void *>(wp)); 1880a332978bSJason Molenda return wp; 1881b9c1b51eSKate Stone } else { 1882b9c1b51eSKate Stone DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = " 1883b9c1b51eSKate Stone "0x%8.8llx, length = %llu) => FAILED", 1884b9c1b51eSKate Stone (uint64_t)addr, (uint64_t)length); 1885a332978bSJason Molenda m_watchpoints.Remove(addr); 1886a332978bSJason Molenda } 1887a332978bSJason Molenda // We failed to enable the watchpoint 1888a332978bSJason Molenda return NULL; 1889a332978bSJason Molenda} 1890a332978bSJason Molenda 1891b9c1b51eSKate Stonevoid MachProcess::DisableAllBreakpoints(bool remove) { 1892b9c1b51eSKate Stone DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::%s (remove = %d )", 1893b9c1b51eSKate Stone __FUNCTION__, remove); 1894a332978bSJason Molenda 1895a332978bSJason Molenda m_breakpoints.DisableAllBreakpoints(this); 1896a332978bSJason Molenda 1897a332978bSJason Molenda if (remove) 1898a332978bSJason Molenda m_breakpoints.RemoveDisabled(); 1899a332978bSJason Molenda} 1900a332978bSJason Molenda 1901b9c1b51eSKate Stonevoid MachProcess::DisableAllWatchpoints(bool remove) { 1902b9c1b51eSKate Stone DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::%s (remove = %d )", 1903b9c1b51eSKate Stone __FUNCTION__, remove); 1904a332978bSJason Molenda 1905a332978bSJason Molenda m_watchpoints.DisableAllWatchpoints(this); 1906a332978bSJason Molenda 1907a332978bSJason Molenda if (remove) 1908a332978bSJason Molenda m_watchpoints.RemoveDisabled(); 1909a332978bSJason Molenda} 1910a332978bSJason Molenda 1911b9c1b51eSKate Stonebool MachProcess::DisableBreakpoint(nub_addr_t addr, bool remove) { 1912a332978bSJason Molenda DNBBreakpoint *bp = m_breakpoints.FindByAddress(addr); 1913b9c1b51eSKate Stone if (bp) { 1914b9c1b51eSKate Stone // After "exec" we might end up with a bunch of breakpoints that were 1915b9c1b51eSKate Stone // disabled 1916a332978bSJason Molenda // manually, just ignore them 1917b9c1b51eSKate Stone if (!bp->IsEnabled()) { 1918a332978bSJason Molenda // Breakpoint might have been disabled by an exec 1919b9c1b51eSKate Stone if (remove && bp->Release() == 0) { 1920a332978bSJason Molenda m_thread_list.NotifyBreakpointChanged(bp); 1921a332978bSJason Molenda m_breakpoints.Remove(addr); 1922a332978bSJason Molenda } 1923a332978bSJason Molenda return true; 1924a332978bSJason Molenda } 1925a332978bSJason Molenda 1926a332978bSJason Molenda // We have multiple references to this breakpoint, decrement the ref count 1927a332978bSJason Molenda // and if it isn't zero, then return true; 1928a332978bSJason Molenda if (remove && bp->Release() > 0) 1929a332978bSJason Molenda return true; 1930a332978bSJason Molenda 1931b9c1b51eSKate Stone DNBLogThreadedIf( 1932b9c1b51eSKate Stone LOG_BREAKPOINTS | LOG_VERBOSE, 1933b9c1b51eSKate Stone "MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d )", 1934b9c1b51eSKate Stone (uint64_t)addr, remove); 1935a332978bSJason Molenda 1936b9c1b51eSKate Stone if (bp->IsHardware()) { 1937a332978bSJason Molenda bool hw_disable_result = m_thread_list.DisableHardwareBreakpoint(bp); 1938a332978bSJason Molenda 1939a6682a41SJonas Devlieghere if (hw_disable_result) { 1940a332978bSJason Molenda bp->SetEnabled(false); 1941a332978bSJason Molenda // Let the thread list know that a breakpoint has been modified 1942b9c1b51eSKate Stone if (remove) { 1943a332978bSJason Molenda m_thread_list.NotifyBreakpointChanged(bp); 1944a332978bSJason Molenda m_breakpoints.Remove(addr); 1945a332978bSJason Molenda } 1946b9c1b51eSKate Stone DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::DisableBreakpoint ( " 1947b9c1b51eSKate Stone "addr = 0x%8.8llx, remove = %d ) " 1948b9c1b51eSKate Stone "(hardware) => success", 1949b9c1b51eSKate Stone (uint64_t)addr, remove); 1950a332978bSJason Molenda return true; 1951a332978bSJason Molenda } 1952a332978bSJason Molenda 1953a332978bSJason Molenda return false; 1954a332978bSJason Molenda } 1955a332978bSJason Molenda 1956a332978bSJason Molenda const nub_size_t break_op_size = bp->ByteSize(); 1957a332978bSJason Molenda assert(break_op_size > 0); 1958b9c1b51eSKate Stone const uint8_t *const break_op = 1959b9c1b51eSKate Stone DNBArchProtocol::GetBreakpointOpcode(bp->ByteSize()); 1960b9c1b51eSKate Stone if (break_op_size > 0) { 1961d93c4a33SBruce Mitchener // Clear a software breakpoint instruction 1962a332978bSJason Molenda uint8_t curr_break_op[break_op_size]; 1963a332978bSJason Molenda bool break_op_found = false; 1964a332978bSJason Molenda 1965a332978bSJason Molenda // Read the breakpoint opcode 1966b9c1b51eSKate Stone if (m_task.ReadMemory(addr, break_op_size, curr_break_op) == 1967b9c1b51eSKate Stone break_op_size) { 1968a332978bSJason Molenda bool verify = false; 1969b9c1b51eSKate Stone if (bp->IsEnabled()) { 19704ebdee0aSBruce Mitchener // Make sure a breakpoint opcode exists at this address 1971b9c1b51eSKate Stone if (memcmp(curr_break_op, break_op, break_op_size) == 0) { 1972a332978bSJason Molenda break_op_found = true; 1973a332978bSJason Molenda // We found a valid breakpoint opcode at this address, now restore 1974a332978bSJason Molenda // the saved opcode. 1975b9c1b51eSKate Stone if (m_task.WriteMemory(addr, break_op_size, 1976b9c1b51eSKate Stone bp->SavedOpcodeBytes()) == break_op_size) { 1977b9c1b51eSKate Stone verify = true; 1978b9c1b51eSKate Stone } else { 1979b9c1b51eSKate Stone DNBLogError("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, " 1980b9c1b51eSKate Stone "remove = %d ) memory write failed when restoring " 1981b9c1b51eSKate Stone "original opcode", 1982b9c1b51eSKate Stone (uint64_t)addr, remove); 1983b9c1b51eSKate Stone } 1984b9c1b51eSKate Stone } else { 1985b9c1b51eSKate Stone DNBLogWarning("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, " 1986b9c1b51eSKate Stone "remove = %d ) expected a breakpoint opcode but " 1987b9c1b51eSKate Stone "didn't find one.", 1988b9c1b51eSKate Stone (uint64_t)addr, remove); 1989b9c1b51eSKate Stone // Set verify to true and so we can check if the original opcode has 1990b9c1b51eSKate Stone // already been restored 1991a332978bSJason Molenda verify = true; 1992a332978bSJason Molenda } 1993b9c1b51eSKate Stone } else { 1994b9c1b51eSKate Stone DNBLogThreadedIf(LOG_BREAKPOINTS | LOG_VERBOSE, 1995b9c1b51eSKate Stone "MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, " 1996b9c1b51eSKate Stone "remove = %d ) is not enabled", 1997b9c1b51eSKate Stone (uint64_t)addr, remove); 1998b9c1b51eSKate Stone // Set verify to true and so we can check if the original opcode is 1999b9c1b51eSKate Stone // there 2000a332978bSJason Molenda verify = true; 2001a332978bSJason Molenda } 2002a332978bSJason Molenda 2003b9c1b51eSKate Stone if (verify) { 2004a332978bSJason Molenda uint8_t verify_opcode[break_op_size]; 2005a332978bSJason Molenda // Verify that our original opcode made it back to the inferior 2006b9c1b51eSKate Stone if (m_task.ReadMemory(addr, break_op_size, verify_opcode) == 2007b9c1b51eSKate Stone break_op_size) { 2008a332978bSJason Molenda // compare the memory we just read with the original opcode 2009b9c1b51eSKate Stone if (memcmp(bp->SavedOpcodeBytes(), verify_opcode, break_op_size) == 2010b9c1b51eSKate Stone 0) { 2011a332978bSJason Molenda // SUCCESS 2012a332978bSJason Molenda bp->SetEnabled(false); 2013a332978bSJason Molenda // Let the thread list know that a breakpoint has been modified 2014b9c1b51eSKate Stone if (remove && bp->Release() == 0) { 2015a332978bSJason Molenda m_thread_list.NotifyBreakpointChanged(bp); 2016a332978bSJason Molenda m_breakpoints.Remove(addr); 2017a332978bSJason Molenda } 2018b9c1b51eSKate Stone DNBLogThreadedIf(LOG_BREAKPOINTS, 2019b9c1b51eSKate Stone "MachProcess::DisableBreakpoint ( addr = " 2020b9c1b51eSKate Stone "0x%8.8llx, remove = %d ) => success", 2021b9c1b51eSKate Stone (uint64_t)addr, remove); 2022a332978bSJason Molenda return true; 2023b9c1b51eSKate Stone } else { 2024a332978bSJason Molenda if (break_op_found) 2025b9c1b51eSKate Stone DNBLogError("MachProcess::DisableBreakpoint ( addr = " 2026b9c1b51eSKate Stone "0x%8.8llx, remove = %d ) : failed to restore " 2027b9c1b51eSKate Stone "original opcode", 2028b9c1b51eSKate Stone (uint64_t)addr, remove); 2029a332978bSJason Molenda else 2030b9c1b51eSKate Stone DNBLogError("MachProcess::DisableBreakpoint ( addr = " 2031b9c1b51eSKate Stone "0x%8.8llx, remove = %d ) : opcode changed", 2032b9c1b51eSKate Stone (uint64_t)addr, remove); 2033b9c1b51eSKate Stone } 2034b9c1b51eSKate Stone } else { 2035b9c1b51eSKate Stone DNBLogWarning("MachProcess::DisableBreakpoint: unable to disable " 2036b9c1b51eSKate Stone "breakpoint 0x%8.8llx", 2037b9c1b51eSKate Stone (uint64_t)addr); 2038a332978bSJason Molenda } 2039a332978bSJason Molenda } 2040b9c1b51eSKate Stone } else { 2041b9c1b51eSKate Stone DNBLogWarning("MachProcess::DisableBreakpoint: unable to read memory " 2042b9c1b51eSKate Stone "at 0x%8.8llx", 2043b9c1b51eSKate Stone (uint64_t)addr); 2044a332978bSJason Molenda } 2045a332978bSJason Molenda } 2046b9c1b51eSKate Stone } else { 2047b9c1b51eSKate Stone DNBLogError("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = " 2048b9c1b51eSKate Stone "%d ) invalid breakpoint address", 2049b9c1b51eSKate Stone (uint64_t)addr, remove); 2050a332978bSJason Molenda } 2051a332978bSJason Molenda return false; 2052a332978bSJason Molenda} 2053a332978bSJason Molenda 2054b9c1b51eSKate Stonebool MachProcess::DisableWatchpoint(nub_addr_t addr, bool remove) { 2055b9c1b51eSKate Stone DNBLogThreadedIf(LOG_WATCHPOINTS, 2056b9c1b51eSKate Stone "MachProcess::%s(addr = 0x%8.8llx, remove = %d)", 2057b9c1b51eSKate Stone __FUNCTION__, (uint64_t)addr, remove); 2058a332978bSJason Molenda DNBBreakpoint *wp = m_watchpoints.FindByAddress(addr); 2059b9c1b51eSKate Stone if (wp) { 2060b9c1b51eSKate Stone // If we have multiple references to a watchpoint, removing the watchpoint 2061b9c1b51eSKate Stone // shouldn't clear it 2062a332978bSJason Molenda if (remove && wp->Release() > 0) 2063a332978bSJason Molenda return true; 2064a332978bSJason Molenda 2065a332978bSJason Molenda nub_addr_t addr = wp->Address(); 2066b9c1b51eSKate Stone DNBLogThreadedIf( 2067b9c1b51eSKate Stone LOG_WATCHPOINTS, 2068b9c1b51eSKate Stone "MachProcess::DisableWatchpoint ( addr = 0x%8.8llx, remove = %d )", 2069b9c1b51eSKate Stone (uint64_t)addr, remove); 2070a332978bSJason Molenda 2071b9c1b51eSKate Stone if (wp->IsHardware()) { 2072a332978bSJason Molenda bool hw_disable_result = m_thread_list.DisableHardwareWatchpoint(wp); 2073a332978bSJason Molenda 2074a6682a41SJonas Devlieghere if (hw_disable_result) { 2075a332978bSJason Molenda wp->SetEnabled(false); 2076a332978bSJason Molenda if (remove) 2077a332978bSJason Molenda m_watchpoints.Remove(addr); 2078b9c1b51eSKate Stone DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::Disablewatchpoint ( " 2079b9c1b51eSKate Stone "addr = 0x%8.8llx, remove = %d ) " 2080b9c1b51eSKate Stone "(hardware) => success", 2081b9c1b51eSKate Stone (uint64_t)addr, remove); 2082a332978bSJason Molenda return true; 2083a332978bSJason Molenda } 2084a332978bSJason Molenda } 2085a332978bSJason Molenda 2086a332978bSJason Molenda // TODO: clear software watchpoints if we implement them 2087b9c1b51eSKate Stone } else { 2088b9c1b51eSKate Stone DNBLogError("MachProcess::DisableWatchpoint ( addr = 0x%8.8llx, remove = " 2089b9c1b51eSKate Stone "%d ) invalid watchpoint ID", 2090b9c1b51eSKate Stone (uint64_t)addr, remove); 2091a332978bSJason Molenda } 2092a332978bSJason Molenda return false; 2093a332978bSJason Molenda} 2094a332978bSJason Molenda 2095b9c1b51eSKate Stoneuint32_t MachProcess::GetNumSupportedHardwareWatchpoints() const { 2096a332978bSJason Molenda return m_thread_list.NumSupportedHardwareWatchpoints(); 2097a332978bSJason Molenda} 2098a332978bSJason Molenda 2099b9c1b51eSKate Stonebool MachProcess::EnableBreakpoint(nub_addr_t addr) { 2100b9c1b51eSKate Stone DNBLogThreadedIf(LOG_BREAKPOINTS, 2101b9c1b51eSKate Stone "MachProcess::EnableBreakpoint ( addr = 0x%8.8llx )", 2102b9c1b51eSKate Stone (uint64_t)addr); 2103a332978bSJason Molenda DNBBreakpoint *bp = m_breakpoints.FindByAddress(addr); 2104b9c1b51eSKate Stone if (bp) { 2105b9c1b51eSKate Stone if (bp->IsEnabled()) { 2106b9c1b51eSKate Stone DNBLogWarning("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): " 2107b9c1b51eSKate Stone "breakpoint already enabled.", 2108b9c1b51eSKate Stone (uint64_t)addr); 2109a332978bSJason Molenda return true; 2110b9c1b51eSKate Stone } else { 2111b9c1b51eSKate Stone if (bp->HardwarePreferred()) { 2112a332978bSJason Molenda bp->SetHardwareIndex(m_thread_list.EnableHardwareBreakpoint(bp)); 2113b9c1b51eSKate Stone if (bp->IsHardware()) { 2114a332978bSJason Molenda bp->SetEnabled(true); 2115a332978bSJason Molenda return true; 2116a332978bSJason Molenda } 2117a332978bSJason Molenda } 2118a332978bSJason Molenda 2119a332978bSJason Molenda const nub_size_t break_op_size = bp->ByteSize(); 2120a332978bSJason Molenda assert(break_op_size != 0); 2121b9c1b51eSKate Stone const uint8_t *const break_op = 2122b9c1b51eSKate Stone DNBArchProtocol::GetBreakpointOpcode(break_op_size); 2123b9c1b51eSKate Stone if (break_op_size > 0) { 2124a332978bSJason Molenda // Save the original opcode by reading it 2125b9c1b51eSKate Stone if (m_task.ReadMemory(addr, break_op_size, bp->SavedOpcodeBytes()) == 2126b9c1b51eSKate Stone break_op_size) { 2127a332978bSJason Molenda // Write a software breakpoint in place of the original opcode 2128b9c1b51eSKate Stone if (m_task.WriteMemory(addr, break_op_size, break_op) == 2129b9c1b51eSKate Stone break_op_size) { 2130a332978bSJason Molenda uint8_t verify_break_op[4]; 2131b9c1b51eSKate Stone if (m_task.ReadMemory(addr, break_op_size, verify_break_op) == 2132b9c1b51eSKate Stone break_op_size) { 2133b9c1b51eSKate Stone if (memcmp(break_op, verify_break_op, break_op_size) == 0) { 2134a332978bSJason Molenda bp->SetEnabled(true); 2135a332978bSJason Molenda // Let the thread list know that a breakpoint has been modified 2136a332978bSJason Molenda m_thread_list.NotifyBreakpointChanged(bp); 2137b9c1b51eSKate Stone DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::" 2138b9c1b51eSKate Stone "EnableBreakpoint ( addr = " 2139b9c1b51eSKate Stone "0x%8.8llx ) : SUCCESS.", 2140b9c1b51eSKate Stone (uint64_t)addr); 2141a332978bSJason Molenda return true; 2142b9c1b51eSKate Stone } else { 2143b9c1b51eSKate Stone DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx " 2144b9c1b51eSKate Stone "): breakpoint opcode verification failed.", 2145b9c1b51eSKate Stone (uint64_t)addr); 2146a332978bSJason Molenda } 2147b9c1b51eSKate Stone } else { 2148b9c1b51eSKate Stone DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): " 2149b9c1b51eSKate Stone "unable to read memory to verify breakpoint opcode.", 2150b9c1b51eSKate Stone (uint64_t)addr); 2151a332978bSJason Molenda } 2152b9c1b51eSKate Stone } else { 2153b9c1b51eSKate Stone DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): " 2154b9c1b51eSKate Stone "unable to write breakpoint opcode to memory.", 2155b9c1b51eSKate Stone (uint64_t)addr); 2156a332978bSJason Molenda } 2157b9c1b51eSKate Stone } else { 2158b9c1b51eSKate Stone DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): " 2159b9c1b51eSKate Stone "unable to read memory at breakpoint address.", 2160b9c1b51eSKate Stone (uint64_t)addr); 2161a332978bSJason Molenda } 2162b9c1b51eSKate Stone } else { 2163b9c1b51eSKate Stone DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ) no " 2164b9c1b51eSKate Stone "software breakpoint opcode for current architecture.", 2165b9c1b51eSKate Stone (uint64_t)addr); 2166a332978bSJason Molenda } 2167a332978bSJason Molenda } 2168a332978bSJason Molenda } 2169a332978bSJason Molenda return false; 2170a332978bSJason Molenda} 2171a332978bSJason Molenda 2172b9c1b51eSKate Stonebool MachProcess::EnableWatchpoint(nub_addr_t addr) { 2173b9c1b51eSKate Stone DNBLogThreadedIf(LOG_WATCHPOINTS, 2174b9c1b51eSKate Stone "MachProcess::EnableWatchpoint(addr = 0x%8.8llx)", 2175b9c1b51eSKate Stone (uint64_t)addr); 2176a332978bSJason Molenda DNBBreakpoint *wp = m_watchpoints.FindByAddress(addr); 2177b9c1b51eSKate Stone if (wp) { 2178a332978bSJason Molenda nub_addr_t addr = wp->Address(); 2179b9c1b51eSKate Stone if (wp->IsEnabled()) { 2180b9c1b51eSKate Stone DNBLogWarning("MachProcess::EnableWatchpoint(addr = 0x%8.8llx): " 2181b9c1b51eSKate Stone "watchpoint already enabled.", 2182b9c1b51eSKate Stone (uint64_t)addr); 2183a332978bSJason Molenda return true; 2184b9c1b51eSKate Stone } else { 2185a332978bSJason Molenda // Currently only try and set hardware watchpoints. 2186a332978bSJason Molenda wp->SetHardwareIndex(m_thread_list.EnableHardwareWatchpoint(wp)); 2187b9c1b51eSKate Stone if (wp->IsHardware()) { 2188a332978bSJason Molenda wp->SetEnabled(true); 2189a332978bSJason Molenda return true; 2190a332978bSJason Molenda } 2191a332978bSJason Molenda // TODO: Add software watchpoints by doing page protection tricks. 2192a332978bSJason Molenda } 2193a332978bSJason Molenda } 2194a332978bSJason Molenda return false; 2195a332978bSJason Molenda} 2196a332978bSJason Molenda 2197a332978bSJason Molenda// Called by the exception thread when an exception has been received from 2198a332978bSJason Molenda// our process. The exception message is completely filled and the exception 2199a332978bSJason Molenda// data has already been copied. 2200b9c1b51eSKate Stonevoid MachProcess::ExceptionMessageReceived( 2201b9c1b51eSKate Stone const MachException::Message &exceptionMessage) { 2202a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); 2203a332978bSJason Molenda 2204a332978bSJason Molenda if (m_exception_messages.empty()) 2205a332978bSJason Molenda m_task.Suspend(); 2206a332978bSJason Molenda 2207a332978bSJason Molenda DNBLogThreadedIf(LOG_EXCEPTIONS, "MachProcess::ExceptionMessageReceived ( )"); 2208a332978bSJason Molenda 2209a332978bSJason Molenda // Use a locker to automatically unlock our mutex in case of exceptions 2210a332978bSJason Molenda // Add the exception to our internal exception stack 2211a332978bSJason Molenda m_exception_messages.push_back(exceptionMessage); 2212a332978bSJason Molenda} 2213a332978bSJason Molenda 2214b9c1b51eSKate Stonetask_t MachProcess::ExceptionMessageBundleComplete() { 2215a332978bSJason Molenda // We have a complete bundle of exceptions for our child process. 2216a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); 2217b9c1b51eSKate Stone DNBLogThreadedIf(LOG_EXCEPTIONS, "%s: %llu exception messages.", 2218b9c1b51eSKate Stone __PRETTY_FUNCTION__, (uint64_t)m_exception_messages.size()); 22194296c221SGreg Clayton bool auto_resume = false; 2220b9c1b51eSKate Stone if (!m_exception_messages.empty()) { 2221a332978bSJason Molenda m_did_exec = false; 2222a332978bSJason Molenda // First check for any SIGTRAP and make sure we didn't exec 2223a332978bSJason Molenda const task_t task = m_task.TaskPort(); 2224a332978bSJason Molenda size_t i; 2225b9c1b51eSKate Stone if (m_pid != 0) { 22264296c221SGreg Clayton bool received_interrupt = false; 22274296c221SGreg Clayton uint32_t num_task_exceptions = 0; 2228b9c1b51eSKate Stone for (i = 0; i < m_exception_messages.size(); ++i) { 2229b9c1b51eSKate Stone if (m_exception_messages[i].state.task_port == task) { 22304296c221SGreg Clayton ++num_task_exceptions; 2231a332978bSJason Molenda const int signo = m_exception_messages[i].state.SoftSignal(); 2232b9c1b51eSKate Stone if (signo == SIGTRAP) { 2233a332978bSJason Molenda // SIGTRAP could mean that we exec'ed. We need to check the 2234a332978bSJason Molenda // dyld all_image_infos.infoArray to see if it is NULL and if 2235a332978bSJason Molenda // so, say that we exec'ed. 2236a332978bSJason Molenda const nub_addr_t aii_addr = GetDYLDAllImageInfosAddress(); 2237b9c1b51eSKate Stone if (aii_addr != INVALID_NUB_ADDRESS) { 2238a332978bSJason Molenda const nub_addr_t info_array_count_addr = aii_addr + 4; 2239a332978bSJason Molenda uint32_t info_array_count = 0; 2240b9c1b51eSKate Stone if (m_task.ReadMemory(info_array_count_addr, 4, 2241b9c1b51eSKate Stone &info_array_count) == 4) { 2242b9c1b51eSKate Stone if (info_array_count == 0) { 2243a332978bSJason Molenda m_did_exec = true; 2244b9c1b51eSKate Stone // Force the task port to update itself in case the task port 2245b9c1b51eSKate Stone // changed after exec 2246bb492890SGreg Clayton DNBError err; 2247bb492890SGreg Clayton const task_t old_task = m_task.TaskPort(); 2248b9c1b51eSKate Stone const task_t new_task = 2249b9c1b51eSKate Stone m_task.TaskPortForProcessID(err, true); 2250bb492890SGreg Clayton if (old_task != new_task) 2251b9c1b51eSKate Stone DNBLogThreadedIf( 2252b9c1b51eSKate Stone LOG_PROCESS, 2253b9c1b51eSKate Stone "exec: task changed from 0x%4.4x to 0x%4.4x", old_task, 2254b9c1b51eSKate Stone new_task); 2255bb492890SGreg Clayton } 2256b9c1b51eSKate Stone } else { 2257b9c1b51eSKate Stone DNBLog("error: failed to read all_image_infos.infoArrayCount " 2258b9c1b51eSKate Stone "from 0x%8.8llx", 2259b9c1b51eSKate Stone (uint64_t)info_array_count_addr); 2260a332978bSJason Molenda } 2261a332978bSJason Molenda } 2262a332978bSJason Molenda break; 2263b9c1b51eSKate Stone } else if (m_sent_interrupt_signo != 0 && 2264b9c1b51eSKate Stone signo == m_sent_interrupt_signo) { 22654296c221SGreg Clayton received_interrupt = true; 22664296c221SGreg Clayton } 2267a332978bSJason Molenda } 2268a332978bSJason Molenda } 2269a332978bSJason Molenda 2270b9c1b51eSKate Stone if (m_did_exec) { 2271b9c1b51eSKate Stone cpu_type_t process_cpu_type = 2272b9c1b51eSKate Stone MachProcess::GetCPUTypeForLocalProcess(m_pid); 2273b9c1b51eSKate Stone if (m_cpu_type != process_cpu_type) { 2274b9c1b51eSKate Stone DNBLog("arch changed from 0x%8.8x to 0x%8.8x", m_cpu_type, 2275b9c1b51eSKate Stone process_cpu_type); 2276a332978bSJason Molenda m_cpu_type = process_cpu_type; 2277a332978bSJason Molenda DNBArchProtocol::SetArchitecture(process_cpu_type); 2278a332978bSJason Molenda } 2279a332978bSJason Molenda m_thread_list.Clear(); 2280705b1809SJason Molenda m_activities.Clear(); 2281a332978bSJason Molenda m_breakpoints.DisableAll(); 2282a332978bSJason Molenda } 22834296c221SGreg Clayton 2284b9c1b51eSKate Stone if (m_sent_interrupt_signo != 0) { 2285b9c1b51eSKate Stone if (received_interrupt) { 2286b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 2287b9c1b51eSKate Stone "MachProcess::ExceptionMessageBundleComplete(): " 2288b9c1b51eSKate Stone "process successfully interrupted with signal %i", 2289b9c1b51eSKate Stone m_sent_interrupt_signo); 22904296c221SGreg Clayton 22914296c221SGreg Clayton // Mark that we received the interrupt signal 22924296c221SGreg Clayton m_sent_interrupt_signo = 0; 22934296c221SGreg Clayton // Not check if we had a case where: 2294b9c1b51eSKate Stone // 1 - We called MachProcess::Interrupt() but we stopped for another 2295b9c1b51eSKate Stone // reason 2296b9c1b51eSKate Stone // 2 - We called MachProcess::Resume() (but still haven't gotten the 2297b9c1b51eSKate Stone // interrupt signal) 2298b9c1b51eSKate Stone // 3 - We are now incorrectly stopped because we are handling the 2299b9c1b51eSKate Stone // interrupt signal we missed 2300b9c1b51eSKate Stone // 4 - We might need to resume if we stopped only with the interrupt 2301b9c1b51eSKate Stone // signal that we never handled 2302b9c1b51eSKate Stone if (m_auto_resume_signo != 0) { 23034296c221SGreg Clayton // Only auto_resume if we stopped with _only_ the interrupt signal 2304b9c1b51eSKate Stone if (num_task_exceptions == 1) { 23054296c221SGreg Clayton auto_resume = true; 2306b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::" 2307b9c1b51eSKate Stone "ExceptionMessageBundleComplete(): " 2308b9c1b51eSKate Stone "auto resuming due to unhandled " 2309b9c1b51eSKate Stone "interrupt signal %i", 2310b9c1b51eSKate Stone m_auto_resume_signo); 23114296c221SGreg Clayton } 23124296c221SGreg Clayton m_auto_resume_signo = 0; 23134296c221SGreg Clayton } 2314b9c1b51eSKate Stone } else { 2315b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::" 2316b9c1b51eSKate Stone "ExceptionMessageBundleComplete(): " 2317b9c1b51eSKate Stone "didn't get signal %i after " 2318b9c1b51eSKate Stone "MachProcess::Interrupt()", 23194296c221SGreg Clayton m_sent_interrupt_signo); 23204296c221SGreg Clayton } 23214296c221SGreg Clayton } 2322a332978bSJason Molenda } 2323a332978bSJason Molenda 2324a332978bSJason Molenda // Let all threads recover from stopping and do any clean up based 2325a332978bSJason Molenda // on the previous thread state (if any). 2326a332978bSJason Molenda m_thread_list.ProcessDidStop(this); 2327705b1809SJason Molenda m_activities.Clear(); 2328a332978bSJason Molenda 2329a332978bSJason Molenda // Let each thread know of any exceptions 2330b9c1b51eSKate Stone for (i = 0; i < m_exception_messages.size(); ++i) { 2331b9c1b51eSKate Stone // Let the thread list figure use the MachProcess to forward all 2332b9c1b51eSKate Stone // exceptions 2333a332978bSJason Molenda // on down to each thread. 2334a332978bSJason Molenda if (m_exception_messages[i].state.task_port == task) 2335a332978bSJason Molenda m_thread_list.NotifyException(m_exception_messages[i].state); 2336a332978bSJason Molenda if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) 2337a332978bSJason Molenda m_exception_messages[i].Dump(); 2338a332978bSJason Molenda } 2339a332978bSJason Molenda 2340a332978bSJason Molenda if (DNBLogCheckLogBit(LOG_THREAD)) 2341a332978bSJason Molenda m_thread_list.Dump(); 2342a332978bSJason Molenda 2343a332978bSJason Molenda bool step_more = false; 2344a6682a41SJonas Devlieghere if (m_thread_list.ShouldStop(step_more) && !auto_resume) { 2345a332978bSJason Molenda // Wait for the eEventProcessRunningStateChanged event to be reset 2346a332978bSJason Molenda // before changing state to stopped to avoid race condition with 2347a332978bSJason Molenda // very fast start/stops 2348a332978bSJason Molenda struct timespec timeout; 2349b9c1b51eSKate Stone // DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 2350b9c1b51eSKate Stone // ms 2351a332978bSJason Molenda DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms 2352a332978bSJason Molenda m_events.WaitForEventsToReset(eEventProcessRunningStateChanged, &timeout); 2353a332978bSJason Molenda SetState(eStateStopped); 2354b9c1b51eSKate Stone } else { 2355a332978bSJason Molenda // Resume without checking our current state. 2356a332978bSJason Molenda PrivateResume(); 2357a332978bSJason Molenda } 2358b9c1b51eSKate Stone } else { 2359b9c1b51eSKate Stone DNBLogThreadedIf( 2360b9c1b51eSKate Stone LOG_EXCEPTIONS, "%s empty exception messages bundle (%llu exceptions).", 2361b9c1b51eSKate Stone __PRETTY_FUNCTION__, (uint64_t)m_exception_messages.size()); 2362a332978bSJason Molenda } 2363bb492890SGreg Clayton return m_task.TaskPort(); 2364a332978bSJason Molenda} 2365a332978bSJason Molenda 2366a332978bSJason Molendanub_size_t 2367b9c1b51eSKate StoneMachProcess::CopyImageInfos(struct DNBExecutableImageInfo **image_infos, 2368b9c1b51eSKate Stone bool only_changed) { 2369a332978bSJason Molenda if (m_image_infos_callback != NULL) 2370b9c1b51eSKate Stone return m_image_infos_callback(ProcessID(), image_infos, only_changed, 2371b9c1b51eSKate Stone m_image_infos_baton); 2372a332978bSJason Molenda return 0; 2373a332978bSJason Molenda} 2374a332978bSJason Molenda 2375b9c1b51eSKate Stonevoid MachProcess::SharedLibrariesUpdated() { 2376a332978bSJason Molenda uint32_t event_bits = eEventSharedLibsStateChange; 2377a332978bSJason Molenda // Set the shared library event bit to let clients know of shared library 2378a332978bSJason Molenda // changes 2379a332978bSJason Molenda m_events.SetEvents(event_bits); 2380a332978bSJason Molenda // Wait for the event bit to reset if a reset ACK is requested 2381a332978bSJason Molenda m_events.WaitForResetAck(event_bits); 2382a332978bSJason Molenda} 2383a332978bSJason Molenda 2384b9c1b51eSKate Stonevoid MachProcess::SetExitInfo(const char *info) { 2385b9c1b51eSKate Stone if (info && info[0]) { 2386b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s(\"%s\")", __FUNCTION__, 2387b9c1b51eSKate Stone info); 2388bb492890SGreg Clayton m_exit_info.assign(info); 2389b9c1b51eSKate Stone } else { 2390bb492890SGreg Clayton DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s(NULL)", __FUNCTION__); 2391bb492890SGreg Clayton m_exit_info.clear(); 2392bb492890SGreg Clayton } 2393bb492890SGreg Clayton} 2394bb492890SGreg Clayton 2395b9c1b51eSKate Stonevoid MachProcess::AppendSTDOUT(char *s, size_t len) { 2396b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (<%llu> %s) ...", __FUNCTION__, 2397b9c1b51eSKate Stone (uint64_t)len, s); 2398a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_stdio_mutex); 2399a332978bSJason Molenda m_stdout_data.append(s, len); 2400a332978bSJason Molenda m_events.SetEvents(eEventStdioAvailable); 2401a332978bSJason Molenda 2402a332978bSJason Molenda // Wait for the event bit to reset if a reset ACK is requested 2403a332978bSJason Molenda m_events.WaitForResetAck(eEventStdioAvailable); 2404a332978bSJason Molenda} 2405a332978bSJason Molenda 2406b9c1b51eSKate Stonesize_t MachProcess::GetAvailableSTDOUT(char *buf, size_t buf_size) { 2407b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (&%p[%llu]) ...", __FUNCTION__, 240865fdb342SRaphael Isemann static_cast<void *>(buf), (uint64_t)buf_size); 2409a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_stdio_mutex); 2410a332978bSJason Molenda size_t bytes_available = m_stdout_data.size(); 2411b9c1b51eSKate Stone if (bytes_available > 0) { 2412b9c1b51eSKate Stone if (bytes_available > buf_size) { 2413a332978bSJason Molenda memcpy(buf, m_stdout_data.data(), buf_size); 2414a332978bSJason Molenda m_stdout_data.erase(0, buf_size); 2415a332978bSJason Molenda bytes_available = buf_size; 2416b9c1b51eSKate Stone } else { 2417a332978bSJason Molenda memcpy(buf, m_stdout_data.data(), bytes_available); 2418a332978bSJason Molenda m_stdout_data.clear(); 2419a332978bSJason Molenda } 2420a332978bSJason Molenda } 2421a332978bSJason Molenda return bytes_available; 2422a332978bSJason Molenda} 2423a332978bSJason Molenda 2424b9c1b51eSKate Stonenub_addr_t MachProcess::GetDYLDAllImageInfosAddress() { 2425a332978bSJason Molenda DNBError err; 2426a332978bSJason Molenda return m_task.GetDYLDAllImageInfosAddress(err); 2427a332978bSJason Molenda} 2428a332978bSJason Molenda 2429b9c1b51eSKate Stonesize_t MachProcess::GetAvailableSTDERR(char *buf, size_t buf_size) { return 0; } 2430a332978bSJason Molenda 2431b9c1b51eSKate Stonevoid *MachProcess::STDIOThread(void *arg) { 2432a332978bSJason Molenda MachProcess *proc = (MachProcess *)arg; 2433b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 2434b9c1b51eSKate Stone "MachProcess::%s ( arg = %p ) thread starting...", 2435b9c1b51eSKate Stone __FUNCTION__, arg); 2436a332978bSJason Molenda 243736a216eeSJason Molenda#if defined(__APPLE__) 243836a216eeSJason Molenda pthread_setname_np("stdio monitoring thread"); 243936a216eeSJason Molenda#endif 244036a216eeSJason Molenda 2441a332978bSJason Molenda // We start use a base and more options so we can control if we 2442a332978bSJason Molenda // are currently using a timeout on the mach_msg. We do this to get a 2443a332978bSJason Molenda // bunch of related exceptions on our exception port so we can process 2444a332978bSJason Molenda // then together. When we have multiple threads, we can get an exception 2445a332978bSJason Molenda // per thread and they will come in consecutively. The main thread loop 2446a332978bSJason Molenda // will start by calling mach_msg to without having the MACH_RCV_TIMEOUT 2447a332978bSJason Molenda // flag set in the options, so we will wait forever for an exception on 2448a332978bSJason Molenda // our exception port. After we get one exception, we then will use the 2449a332978bSJason Molenda // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current 2450a332978bSJason Molenda // exceptions for our process. After we have received the last pending 2451a332978bSJason Molenda // exception, we will get a timeout which enables us to then notify 2452d93c4a33SBruce Mitchener // our main thread that we have an exception bundle available. We then wait 2453a332978bSJason Molenda // for the main thread to tell this exception thread to start trying to get 2454a332978bSJason Molenda // exceptions messages again and we start again with a mach_msg read with 2455a332978bSJason Molenda // infinite timeout. 2456a332978bSJason Molenda DNBError err; 2457a332978bSJason Molenda int stdout_fd = proc->GetStdoutFileDescriptor(); 2458a332978bSJason Molenda int stderr_fd = proc->GetStderrFileDescriptor(); 2459a332978bSJason Molenda if (stdout_fd == stderr_fd) 2460a332978bSJason Molenda stderr_fd = -1; 2461a332978bSJason Molenda 2462b9c1b51eSKate Stone while (stdout_fd >= 0 || stderr_fd >= 0) { 2463a332978bSJason Molenda ::pthread_testcancel(); 2464a332978bSJason Molenda 2465a332978bSJason Molenda fd_set read_fds; 2466a332978bSJason Molenda FD_ZERO(&read_fds); 2467a332978bSJason Molenda if (stdout_fd >= 0) 2468a332978bSJason Molenda FD_SET(stdout_fd, &read_fds); 2469a332978bSJason Molenda if (stderr_fd >= 0) 2470a332978bSJason Molenda FD_SET(stderr_fd, &read_fds); 2471a332978bSJason Molenda int nfds = std::max<int>(stdout_fd, stderr_fd) + 1; 2472a332978bSJason Molenda 2473a332978bSJason Molenda int num_set_fds = select(nfds, &read_fds, NULL, NULL, NULL); 2474b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 2475b9c1b51eSKate Stone "select (nfds, &read_fds, NULL, NULL, NULL) => %d", 2476b9c1b51eSKate Stone num_set_fds); 2477a332978bSJason Molenda 2478b9c1b51eSKate Stone if (num_set_fds < 0) { 2479a332978bSJason Molenda int select_errno = errno; 2480b9c1b51eSKate Stone if (DNBLogCheckLogBit(LOG_PROCESS)) { 2481a332978bSJason Molenda err.SetError(select_errno, DNBError::POSIX); 2482b9c1b51eSKate Stone err.LogThreadedIfError( 2483b9c1b51eSKate Stone "select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds); 2484a332978bSJason Molenda } 2485a332978bSJason Molenda 2486b9c1b51eSKate Stone switch (select_errno) { 2487b9c1b51eSKate Stone case EAGAIN: // The kernel was (perhaps temporarily) unable to allocate 2488b9c1b51eSKate Stone // the requested number of file descriptors, or we have 2489b9c1b51eSKate Stone // non-blocking IO 2490a332978bSJason Molenda break; 2491a332978bSJason Molenda case EBADF: // One of the descriptor sets specified an invalid descriptor. 2492a332978bSJason Molenda return NULL; 2493a332978bSJason Molenda break; 2494b9c1b51eSKate Stone case EINTR: // A signal was delivered before the time limit expired and 2495b9c1b51eSKate Stone // before any of the selected events occurred. 2496b9c1b51eSKate Stone case EINVAL: // The specified time limit is invalid. One of its components 2497b9c1b51eSKate Stone // is negative or too large. 2498a332978bSJason Molenda default: // Other unknown error 2499a332978bSJason Molenda break; 2500a332978bSJason Molenda } 2501b9c1b51eSKate Stone } else if (num_set_fds == 0) { 2502b9c1b51eSKate Stone } else { 2503a332978bSJason Molenda char s[1024]; 2504a332978bSJason Molenda s[sizeof(s) - 1] = '\0'; // Ensure we have NULL termination 2505ee2ed525SGreg Clayton ssize_t bytes_read = 0; 2506b9c1b51eSKate Stone if (stdout_fd >= 0 && FD_ISSET(stdout_fd, &read_fds)) { 2507b9c1b51eSKate Stone do { 2508a332978bSJason Molenda bytes_read = ::read(stdout_fd, s, sizeof(s) - 1); 2509b9c1b51eSKate Stone if (bytes_read < 0) { 2510a332978bSJason Molenda int read_errno = errno; 2511b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 2512b9c1b51eSKate Stone "read (stdout_fd, ) => %zd errno: %d (%s)", 2513b9c1b51eSKate Stone bytes_read, read_errno, strerror(read_errno)); 2514b9c1b51eSKate Stone } else if (bytes_read == 0) { 2515a332978bSJason Molenda // EOF... 2516b9c1b51eSKate Stone DNBLogThreadedIf( 2517b9c1b51eSKate Stone LOG_PROCESS, 2518b9c1b51eSKate Stone "read (stdout_fd, ) => %zd (reached EOF for child STDOUT)", 2519b9c1b51eSKate Stone bytes_read); 2520a332978bSJason Molenda stdout_fd = -1; 2521b9c1b51eSKate Stone } else if (bytes_read > 0) { 2522a332978bSJason Molenda proc->AppendSTDOUT(s, bytes_read); 2523a332978bSJason Molenda } 2524a332978bSJason Molenda 2525a332978bSJason Molenda } while (bytes_read > 0); 2526a332978bSJason Molenda } 2527a332978bSJason Molenda 2528b9c1b51eSKate Stone if (stderr_fd >= 0 && FD_ISSET(stderr_fd, &read_fds)) { 2529b9c1b51eSKate Stone do { 2530a332978bSJason Molenda bytes_read = ::read(stderr_fd, s, sizeof(s) - 1); 2531b9c1b51eSKate Stone if (bytes_read < 0) { 2532a332978bSJason Molenda int read_errno = errno; 2533b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 2534b9c1b51eSKate Stone "read (stderr_fd, ) => %zd errno: %d (%s)", 2535b9c1b51eSKate Stone bytes_read, read_errno, strerror(read_errno)); 2536b9c1b51eSKate Stone } else if (bytes_read == 0) { 2537a332978bSJason Molenda // EOF... 2538b9c1b51eSKate Stone DNBLogThreadedIf( 2539b9c1b51eSKate Stone LOG_PROCESS, 2540b9c1b51eSKate Stone "read (stderr_fd, ) => %zd (reached EOF for child STDERR)", 2541b9c1b51eSKate Stone bytes_read); 2542a332978bSJason Molenda stderr_fd = -1; 2543b9c1b51eSKate Stone } else if (bytes_read > 0) { 2544a332978bSJason Molenda proc->AppendSTDOUT(s, bytes_read); 2545a332978bSJason Molenda } 2546a332978bSJason Molenda 2547a332978bSJason Molenda } while (bytes_read > 0); 2548a332978bSJason Molenda } 2549a332978bSJason Molenda } 2550a332978bSJason Molenda } 2551b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%p): thread exiting...", 2552b9c1b51eSKate Stone __FUNCTION__, arg); 2553a332978bSJason Molenda return NULL; 2554a332978bSJason Molenda} 2555a332978bSJason Molenda 2556b9c1b51eSKate Stonevoid MachProcess::SignalAsyncProfileData(const char *info) { 2557a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%s) ...", __FUNCTION__, info); 2558a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_profile_data_mutex); 2559a332978bSJason Molenda m_profile_data.push_back(info); 2560a332978bSJason Molenda m_events.SetEvents(eEventProfileDataAvailable); 2561a332978bSJason Molenda 2562a332978bSJason Molenda // Wait for the event bit to reset if a reset ACK is requested 2563a332978bSJason Molenda m_events.WaitForResetAck(eEventProfileDataAvailable); 2564a332978bSJason Molenda} 2565a332978bSJason Molenda 2566b9c1b51eSKate Stonesize_t MachProcess::GetAsyncProfileData(char *buf, size_t buf_size) { 2567b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (&%p[%llu]) ...", __FUNCTION__, 256865fdb342SRaphael Isemann static_cast<void *>(buf), (uint64_t)buf_size); 2569a332978bSJason Molenda PTHREAD_MUTEX_LOCKER(locker, m_profile_data_mutex); 2570a332978bSJason Molenda if (m_profile_data.empty()) 2571a332978bSJason Molenda return 0; 2572a332978bSJason Molenda 2573a332978bSJason Molenda size_t bytes_available = m_profile_data.front().size(); 2574b9c1b51eSKate Stone if (bytes_available > 0) { 2575b9c1b51eSKate Stone if (bytes_available > buf_size) { 2576a332978bSJason Molenda memcpy(buf, m_profile_data.front().data(), buf_size); 2577a332978bSJason Molenda m_profile_data.front().erase(0, buf_size); 2578a332978bSJason Molenda bytes_available = buf_size; 2579b9c1b51eSKate Stone } else { 2580a332978bSJason Molenda memcpy(buf, m_profile_data.front().data(), bytes_available); 2581a332978bSJason Molenda m_profile_data.erase(m_profile_data.begin()); 2582a332978bSJason Molenda } 2583a332978bSJason Molenda } 2584a332978bSJason Molenda return bytes_available; 2585a332978bSJason Molenda} 2586a332978bSJason Molenda 2587b9c1b51eSKate Stonevoid *MachProcess::ProfileThread(void *arg) { 2588a332978bSJason Molenda MachProcess *proc = (MachProcess *)arg; 2589b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 2590b9c1b51eSKate Stone "MachProcess::%s ( arg = %p ) thread starting...", 2591b9c1b51eSKate Stone __FUNCTION__, arg); 2592a332978bSJason Molenda 259336a216eeSJason Molenda#if defined(__APPLE__) 259436a216eeSJason Molenda pthread_setname_np("performance profiling thread"); 259536a216eeSJason Molenda#endif 259636a216eeSJason Molenda 2597b9c1b51eSKate Stone while (proc->IsProfilingEnabled()) { 2598a332978bSJason Molenda nub_state_t state = proc->GetState(); 2599b9c1b51eSKate Stone if (state == eStateRunning) { 2600b9c1b51eSKate Stone std::string data = 2601b9c1b51eSKate Stone proc->Task().GetProfileData(proc->GetProfileScanType()); 2602b9c1b51eSKate Stone if (!data.empty()) { 2603a332978bSJason Molenda proc->SignalAsyncProfileData(data.c_str()); 2604a332978bSJason Molenda } 2605b9c1b51eSKate Stone } else if ((state == eStateUnloaded) || (state == eStateDetached) || 2606b9c1b51eSKate Stone (state == eStateUnloaded)) { 2607a332978bSJason Molenda // Done. Get out of this thread. 2608a332978bSJason Molenda break; 2609a332978bSJason Molenda } 26103cd13c46SJim Ingham timespec ts; 26113cd13c46SJim Ingham { 26123cd13c46SJim Ingham using namespace std::chrono; 26133cd13c46SJim Ingham std::chrono::microseconds dur(proc->ProfileInterval()); 26143cd13c46SJim Ingham const auto dur_secs = duration_cast<seconds>(dur); 26153cd13c46SJim Ingham const auto dur_usecs = dur % std::chrono::seconds(1); 26163cd13c46SJim Ingham DNBTimer::OffsetTimeOfDay(&ts, dur_secs.count(), 26173cd13c46SJim Ingham dur_usecs.count()); 26183cd13c46SJim Ingham } 26193cd13c46SJim Ingham uint32_t bits_set = 26203cd13c46SJim Ingham proc->m_profile_events.WaitForSetEvents(eMachProcessProfileCancel, &ts); 26213cd13c46SJim Ingham // If we got bits back, we were told to exit. Do so. 26223cd13c46SJim Ingham if (bits_set & eMachProcessProfileCancel) 26233cd13c46SJim Ingham break; 2624a332978bSJason Molenda } 2625a332978bSJason Molenda return NULL; 2626a332978bSJason Molenda} 2627a332978bSJason Molenda 2628bff4673bSJim Inghampid_t MachProcess::AttachForDebug( 2629bff4673bSJim Ingham pid_t pid, 2630bff4673bSJim Ingham const RNBContext::IgnoredExceptions &ignored_exceptions, 2631bff4673bSJim Ingham char *err_str, 263227012c0fSAlessandro Arzilli size_t err_len) { 2633a332978bSJason Molenda // Clear out and clean up from any current state 2634a332978bSJason Molenda Clear(); 2635b9c1b51eSKate Stone if (pid != 0) { 2636a332978bSJason Molenda DNBError err; 2637a332978bSJason Molenda // Make sure the process exists... 2638b9c1b51eSKate Stone if (::getpgid(pid) < 0) { 2639a332978bSJason Molenda err.SetErrorToErrno(); 2640a332978bSJason Molenda const char *err_cstr = err.AsString(); 2641b9c1b51eSKate Stone ::snprintf(err_str, err_len, "%s", 2642b9c1b51eSKate Stone err_cstr ? err_cstr : "No such process"); 26433bf883eaSJason Molenda DNBLogError ("MachProcess::AttachForDebug pid %d does not exist", pid); 2644a332978bSJason Molenda return INVALID_NUB_PROCESS; 2645a332978bSJason Molenda } 2646a332978bSJason Molenda 2647a332978bSJason Molenda SetState(eStateAttaching); 2648a332978bSJason Molenda m_pid = pid; 2649bff4673bSJim Ingham if (!m_task.StartExceptionThread(ignored_exceptions, err)) { 2650a332978bSJason Molenda const char *err_cstr = err.AsString(); 2651b9c1b51eSKate Stone ::snprintf(err_str, err_len, "%s", 2652b9c1b51eSKate Stone err_cstr ? err_cstr : "unable to start the exception thread"); 2653a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid); 2654edde2eb1SJason Molenda DNBLogError( 2655edde2eb1SJason Molenda "[LaunchAttach] END (%d) MachProcess::AttachForDebug failed to start " 2656edde2eb1SJason Molenda "exception thread attaching to pid %i: %s", 2657edde2eb1SJason Molenda getpid(), pid, err_str); 2658a332978bSJason Molenda m_pid = INVALID_NUB_PROCESS; 2659a332978bSJason Molenda return INVALID_NUB_PROCESS; 2660a332978bSJason Molenda } 2661a332978bSJason Molenda 2662edde2eb1SJason Molenda DNBLog("[LaunchAttach] (%d) About to ptrace(PT_ATTACHEXC, %d)...", getpid(), 2663edde2eb1SJason Molenda pid); 2664a332978bSJason Molenda errno = 0; 2665edde2eb1SJason Molenda int ptrace_result = ::ptrace(PT_ATTACHEXC, pid, 0, 0); 2666edde2eb1SJason Molenda int ptrace_errno = errno; 2667edde2eb1SJason Molenda DNBLog("[LaunchAttach] (%d) Completed ptrace(PT_ATTACHEXC, %d) == %d", 2668edde2eb1SJason Molenda getpid(), pid, ptrace_result); 2669edde2eb1SJason Molenda if (ptrace_result != 0) { 2670edde2eb1SJason Molenda err.SetError(ptrace_errno); 2671edde2eb1SJason Molenda DNBLogError("MachProcess::AttachForDebug failed to ptrace(PT_ATTACHEXC) " 2672edde2eb1SJason Molenda "pid %i: %s", 2673edde2eb1SJason Molenda pid, err.AsString()); 26743bf883eaSJason Molenda } else { 2675a332978bSJason Molenda err.Clear(); 26763bf883eaSJason Molenda } 2677a332978bSJason Molenda 2678b9c1b51eSKate Stone if (err.Success()) { 2679a332978bSJason Molenda m_flags |= eMachProcessFlagsAttached; 2680b9c1b51eSKate Stone // Sleep a bit to let the exception get received and set our process 2681b9c1b51eSKate Stone // status 2682a332978bSJason Molenda // to stopped. 2683a332978bSJason Molenda ::usleep(250000); 2684edde2eb1SJason Molenda DNBLog("[LaunchAttach] (%d) Done napping after ptrace(PT_ATTACHEXC)'ing", 2685edde2eb1SJason Molenda getpid()); 2686a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", pid); 2687a332978bSJason Molenda return m_pid; 2688b9c1b51eSKate Stone } else { 2689a332978bSJason Molenda ::snprintf(err_str, err_len, "%s", err.AsString()); 2690edde2eb1SJason Molenda DNBLogError( 2691edde2eb1SJason Molenda "[LaunchAttach] (%d) MachProcess::AttachForDebug error: failed to " 2692edde2eb1SJason Molenda "attach to pid %d", 2693edde2eb1SJason Molenda getpid(), pid); 26943bf883eaSJason Molenda 26953bf883eaSJason Molenda struct kinfo_proc kinfo; 26963bf883eaSJason Molenda int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; 26973bf883eaSJason Molenda size_t len = sizeof(struct kinfo_proc); 26983bf883eaSJason Molenda if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &kinfo, &len, NULL, 0) == 0 && len > 0) { 26993bf883eaSJason Molenda if (kinfo.kp_proc.p_flag & P_TRACED) { 27003bf883eaSJason Molenda ::snprintf(err_str, err_len, "%s - process %d is already being debugged", err.AsString(), pid); 2701edde2eb1SJason Molenda DNBLogError( 2702edde2eb1SJason Molenda "[LaunchAttach] (%d) MachProcess::AttachForDebug pid %d is " 2703edde2eb1SJason Molenda "already being debugged", 2704edde2eb1SJason Molenda getpid(), pid); 27053bf883eaSJason Molenda } 27063bf883eaSJason Molenda } 2707a332978bSJason Molenda } 2708a332978bSJason Molenda } 2709a332978bSJason Molenda return INVALID_NUB_PROCESS; 2710a332978bSJason Molenda} 2711a332978bSJason Molenda 2712705b1809SJason MolendaGenealogy::ThreadActivitySP 2713b9c1b51eSKate StoneMachProcess::GetGenealogyInfoForThread(nub_thread_t tid, bool &timed_out) { 2714b9c1b51eSKate Stone return m_activities.GetGenealogyInfoForThread(m_pid, tid, m_thread_list, 2715b9c1b51eSKate Stone m_task.TaskPort(), timed_out); 2716705b1809SJason Molenda} 2717705b1809SJason Molenda 2718705b1809SJason MolendaGenealogy::ProcessExecutableInfoSP 2719b9c1b51eSKate StoneMachProcess::GetGenealogyImageInfo(size_t idx) { 2720705b1809SJason Molenda return m_activities.GetProcessExecutableInfosAtIndex(idx); 2721705b1809SJason Molenda} 2722705b1809SJason Molenda 2723b9c1b51eSKate Stonebool MachProcess::GetOSVersionNumbers(uint64_t *major, uint64_t *minor, 2724b9c1b51eSKate Stone uint64_t *patch) { 27256acc86c3SJason Molenda NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 27266acc86c3SJason Molenda 2727b9c1b51eSKate Stone NSOperatingSystemVersion vers = 2728b9c1b51eSKate Stone [[NSProcessInfo processInfo] operatingSystemVersion]; 27296acc86c3SJason Molenda if (major) 27306acc86c3SJason Molenda *major = vers.majorVersion; 27316acc86c3SJason Molenda if (minor) 27326acc86c3SJason Molenda *minor = vers.minorVersion; 27336acc86c3SJason Molenda if (patch) 27346acc86c3SJason Molenda *patch = vers.patchVersion; 27356acc86c3SJason Molenda 27366acc86c3SJason Molenda [pool drain]; 27376acc86c3SJason Molenda 2738109dd2e2SEnrico Granata return true; 27396acc86c3SJason Molenda} 27406acc86c3SJason Molenda 27416cebeafaSJason Molendastd::string MachProcess::GetMacCatalystVersionString() { 27426cebeafaSJason Molenda @autoreleasepool { 27436cebeafaSJason Molenda NSDictionary *version_info = 27446cebeafaSJason Molenda [NSDictionary dictionaryWithContentsOfFile: 27456cebeafaSJason Molenda @"/System/Library/CoreServices/SystemVersion.plist"]; 27466cebeafaSJason Molenda NSString *version_value = [version_info objectForKey: @"iOSSupportVersion"]; 27476cebeafaSJason Molenda if (const char *version_str = [version_value UTF8String]) 27486cebeafaSJason Molenda return version_str; 27496cebeafaSJason Molenda } 27506cebeafaSJason Molenda return {}; 27516cebeafaSJason Molenda} 27526cebeafaSJason Molenda 2753011a8e21SJonas Devlieghere#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) || defined(WITH_FBS) 2754011a8e21SJonas Devlieghere/// Get the app bundle from the given path. Returns the empty string if the 2755011a8e21SJonas Devlieghere/// path doesn't appear to be an app bundle. 2756011a8e21SJonas Devliegherestatic std::string GetAppBundle(std::string path) { 2757011a8e21SJonas Devlieghere auto pos = path.rfind(".app"); 2758011a8e21SJonas Devlieghere // Path doesn't contain `.app`. 2759011a8e21SJonas Devlieghere if (pos == std::string::npos) 2760011a8e21SJonas Devlieghere return {}; 2761011a8e21SJonas Devlieghere // Path has `.app` extension. 2762011a8e21SJonas Devlieghere if (pos == path.size() - 4) 2763011a8e21SJonas Devlieghere return path.substr(0, pos + 4); 2764011a8e21SJonas Devlieghere 2765011a8e21SJonas Devlieghere // Look for `.app` before a path separator. 2766011a8e21SJonas Devlieghere do { 2767011a8e21SJonas Devlieghere if (path[pos + 4] == '/') 2768011a8e21SJonas Devlieghere return path.substr(0, pos + 4); 2769011a8e21SJonas Devlieghere path = path.substr(0, pos); 2770011a8e21SJonas Devlieghere pos = path.rfind(".app"); 2771011a8e21SJonas Devlieghere } while (pos != std::string::npos); 2772011a8e21SJonas Devlieghere 2773011a8e21SJonas Devlieghere return {}; 2774011a8e21SJonas Devlieghere} 2775011a8e21SJonas Devlieghere#endif 2776011a8e21SJonas Devlieghere 2777b9c1b51eSKate Stone// Do the process specific setup for attach. If this returns NULL, then there's 2778b9c1b51eSKate Stone// no 2779b9c1b51eSKate Stone// platform specific stuff to be done to wait for the attach. If you get 2780b9c1b51eSKate Stone// non-null, 2781b9c1b51eSKate Stone// pass that token to the CheckForProcess method, and then to 2782b9c1b51eSKate Stone// CleanupAfterAttach. 2783a332978bSJason Molenda 2784b9c1b51eSKate Stone// Call PrepareForAttach before attaching to a process that has not yet 2785b9c1b51eSKate Stone// launched 2786b9c1b51eSKate Stone// This returns a token that can be passed to CheckForProcess, and to 2787b9c1b51eSKate Stone// CleanupAfterAttach. 2788a332978bSJason Molenda// You should call CleanupAfterAttach to free the token, and do whatever other 2789a332978bSJason Molenda// cleanup seems good. 2790a332978bSJason Molenda 2791b9c1b51eSKate Stoneconst void *MachProcess::PrepareForAttach(const char *path, 2792b9c1b51eSKate Stone nub_launch_flavor_t launch_flavor, 2793b9c1b51eSKate Stone bool waitfor, DNBError &attach_err) { 2794c611a740SJason Molenda#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) || defined(WITH_FBS) 2795a332978bSJason Molenda // Tell SpringBoard to halt the next launch of this application on startup. 2796a332978bSJason Molenda 2797a332978bSJason Molenda if (!waitfor) 2798a332978bSJason Molenda return NULL; 2799a332978bSJason Molenda 2800011a8e21SJonas Devlieghere std::string app_bundle_path = GetAppBundle(path); 2801011a8e21SJonas Devlieghere if (app_bundle_path.empty()) { 2802b9c1b51eSKate Stone DNBLogThreadedIf( 2803b9c1b51eSKate Stone LOG_PROCESS, 2804b9c1b51eSKate Stone "MachProcess::PrepareForAttach(): path '%s' doesn't contain .app, " 2805a332978bSJason Molenda "we can't tell springboard to wait for launch...", 2806a332978bSJason Molenda path); 2807a332978bSJason Molenda return NULL; 2808a332978bSJason Molenda } 2809a332978bSJason Molenda 2810c611a740SJason Molenda#if defined(WITH_FBS) 2811c611a740SJason Molenda if (launch_flavor == eLaunchFlavorDefault) 2812c611a740SJason Molenda launch_flavor = eLaunchFlavorFBS; 2813c611a740SJason Molenda if (launch_flavor != eLaunchFlavorFBS) 2814c611a740SJason Molenda return NULL; 2815c611a740SJason Molenda#elif defined(WITH_BKS) 2816a332978bSJason Molenda if (launch_flavor == eLaunchFlavorDefault) 2817a332978bSJason Molenda launch_flavor = eLaunchFlavorBKS; 2818a332978bSJason Molenda if (launch_flavor != eLaunchFlavorBKS) 2819a332978bSJason Molenda return NULL; 2820a332978bSJason Molenda#elif defined(WITH_SPRINGBOARD) 2821a332978bSJason Molenda if (launch_flavor == eLaunchFlavorDefault) 2822a332978bSJason Molenda launch_flavor = eLaunchFlavorSpringBoard; 2823a332978bSJason Molenda if (launch_flavor != eLaunchFlavorSpringBoard) 2824a332978bSJason Molenda return NULL; 2825a332978bSJason Molenda#endif 2826a332978bSJason Molenda 2827b9c1b51eSKate Stone CFStringRef bundleIDCFStr = 2828b9c1b51eSKate Stone CopyBundleIDForPath(app_bundle_path.c_str(), attach_err); 2829a332978bSJason Molenda std::string bundleIDStr; 2830a332978bSJason Molenda CFString::UTF8(bundleIDCFStr, bundleIDStr); 2831a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, 2832a332978bSJason Molenda "CopyBundleIDForPath (%s, err_str) returned @\"%s\"", 2833b9c1b51eSKate Stone app_bundle_path.c_str(), bundleIDStr.c_str()); 2834a332978bSJason Molenda 2835b9c1b51eSKate Stone if (bundleIDCFStr == NULL) { 2836a332978bSJason Molenda return NULL; 2837a332978bSJason Molenda } 2838a332978bSJason Molenda 2839c611a740SJason Molenda#if defined(WITH_FBS) 2840b9c1b51eSKate Stone if (launch_flavor == eLaunchFlavorFBS) { 2841c611a740SJason Molenda NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 2842c611a740SJason Molenda 2843c611a740SJason Molenda NSString *stdio_path = nil; 2844c611a740SJason Molenda NSFileManager *file_manager = [NSFileManager defaultManager]; 2845c611a740SJason Molenda const char *null_path = "/dev/null"; 2846b9c1b51eSKate Stone stdio_path = 2847b9c1b51eSKate Stone [file_manager stringWithFileSystemRepresentation:null_path 2848b9c1b51eSKate Stone length:strlen(null_path)]; 2849c611a740SJason Molenda 2850c611a740SJason Molenda NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; 2851c611a740SJason Molenda NSMutableDictionary *options = [NSMutableDictionary dictionary]; 2852c611a740SJason Molenda 2853b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "Calling BKSSystemService openApplication: " 2854b9c1b51eSKate Stone "@\"%s\",options include stdio path: \"%s\", " 2855b9c1b51eSKate Stone "BKSDebugOptionKeyDebugOnNextLaunch & " 2856b9c1b51eSKate Stone "BKSDebugOptionKeyWaitForDebugger )", 2857b9c1b51eSKate Stone bundleIDStr.c_str(), null_path); 2858c611a740SJason Molenda 2859b9c1b51eSKate Stone [debug_options setObject:stdio_path 2860b9c1b51eSKate Stone forKey:FBSDebugOptionKeyStandardOutPath]; 2861b9c1b51eSKate Stone [debug_options setObject:stdio_path 2862b9c1b51eSKate Stone forKey:FBSDebugOptionKeyStandardErrorPath]; 2863b9c1b51eSKate Stone [debug_options setObject:[NSNumber numberWithBool:YES] 2864b9c1b51eSKate Stone forKey:FBSDebugOptionKeyWaitForDebugger]; 2865b9c1b51eSKate Stone [debug_options setObject:[NSNumber numberWithBool:YES] 2866b9c1b51eSKate Stone forKey:FBSDebugOptionKeyDebugOnNextLaunch]; 2867c611a740SJason Molenda 2868b9c1b51eSKate Stone [options setObject:debug_options 2869b9c1b51eSKate Stone forKey:FBSOpenApplicationOptionKeyDebuggingOptions]; 2870c611a740SJason Molenda 2871c611a740SJason Molenda FBSSystemService *system_service = [[FBSSystemService alloc] init]; 2872c611a740SJason Molenda 2873c611a740SJason Molenda mach_port_t client_port = [system_service createClientPort]; 2874c611a740SJason Molenda __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 2875b9c1b51eSKate Stone __block FBSOpenApplicationErrorCode attach_error_code = 2876b9c1b51eSKate Stone FBSOpenApplicationErrorCodeNone; 2877c611a740SJason Molenda 2878c611a740SJason Molenda NSString *bundleIDNSStr = (NSString *)bundleIDCFStr; 2879c611a740SJason Molenda 2880edde2eb1SJason Molenda DNBLog("[LaunchAttach] START (%d) requesting FBS launch of app with bundle " 2881edde2eb1SJason Molenda "ID '%s'", 2882edde2eb1SJason Molenda getpid(), bundleIDStr.c_str()); 2883c611a740SJason Molenda [system_service openApplication:bundleIDNSStr 2884c611a740SJason Molenda options:options 2885c611a740SJason Molenda clientPort:client_port 2886b9c1b51eSKate Stone withResult:^(NSError *error) { 2887b9c1b51eSKate Stone // The system service will cleanup the client port we 2888b9c1b51eSKate Stone // created for us. 2889c611a740SJason Molenda if (error) 2890b9c1b51eSKate Stone attach_error_code = 2891b9c1b51eSKate Stone (FBSOpenApplicationErrorCode)[error code]; 2892c611a740SJason Molenda 2893c611a740SJason Molenda [system_service release]; 2894c611a740SJason Molenda dispatch_semaphore_signal(semaphore); 2895b9c1b51eSKate Stone }]; 2896c611a740SJason Molenda 2897c611a740SJason Molenda const uint32_t timeout_secs = 9; 2898c611a740SJason Molenda 2899b9c1b51eSKate Stone dispatch_time_t timeout = 2900b9c1b51eSKate Stone dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); 2901c611a740SJason Molenda 2902c611a740SJason Molenda long success = dispatch_semaphore_wait(semaphore, timeout) == 0; 2903c611a740SJason Molenda 2904b9c1b51eSKate Stone if (!success) { 2905c611a740SJason Molenda DNBLogError("timed out trying to launch %s.", bundleIDStr.c_str()); 2906b9c1b51eSKate Stone attach_err.SetErrorString( 2907b9c1b51eSKate Stone "debugserver timed out waiting for openApplication to complete."); 2908c611a740SJason Molenda attach_err.SetError(OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); 2909b9c1b51eSKate Stone } else if (attach_error_code != FBSOpenApplicationErrorCodeNone) { 2910d44a0743SJason Molenda std::string empty_str; 2911d44a0743SJason Molenda SetFBSError(attach_error_code, empty_str, attach_err); 2912b9c1b51eSKate Stone DNBLogError("unable to launch the application with CFBundleIdentifier " 2913b9c1b51eSKate Stone "'%s' bks_error = %ld", 2914b9c1b51eSKate Stone bundleIDStr.c_str(), (NSInteger)attach_error_code); 2915c611a740SJason Molenda } 2916c611a740SJason Molenda dispatch_release(semaphore); 2917c611a740SJason Molenda [pool drain]; 2918c611a740SJason Molenda } 2919c611a740SJason Molenda#endif 2920a332978bSJason Molenda#if defined(WITH_BKS) 2921b9c1b51eSKate Stone if (launch_flavor == eLaunchFlavorBKS) { 2922a332978bSJason Molenda NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 2923a332978bSJason Molenda 2924a332978bSJason Molenda NSString *stdio_path = nil; 2925a332978bSJason Molenda NSFileManager *file_manager = [NSFileManager defaultManager]; 2926a332978bSJason Molenda const char *null_path = "/dev/null"; 2927b9c1b51eSKate Stone stdio_path = 2928b9c1b51eSKate Stone [file_manager stringWithFileSystemRepresentation:null_path 2929b9c1b51eSKate Stone length:strlen(null_path)]; 2930a332978bSJason Molenda 2931a332978bSJason Molenda NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; 2932a332978bSJason Molenda NSMutableDictionary *options = [NSMutableDictionary dictionary]; 2933a332978bSJason Molenda 2934b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "Calling BKSSystemService openApplication: " 2935b9c1b51eSKate Stone "@\"%s\",options include stdio path: \"%s\", " 2936b9c1b51eSKate Stone "BKSDebugOptionKeyDebugOnNextLaunch & " 2937b9c1b51eSKate Stone "BKSDebugOptionKeyWaitForDebugger )", 2938b9c1b51eSKate Stone bundleIDStr.c_str(), null_path); 2939a332978bSJason Molenda 2940b9c1b51eSKate Stone [debug_options setObject:stdio_path 2941b9c1b51eSKate Stone forKey:BKSDebugOptionKeyStandardOutPath]; 2942b9c1b51eSKate Stone [debug_options setObject:stdio_path 2943b9c1b51eSKate Stone forKey:BKSDebugOptionKeyStandardErrorPath]; 2944b9c1b51eSKate Stone [debug_options setObject:[NSNumber numberWithBool:YES] 2945b9c1b51eSKate Stone forKey:BKSDebugOptionKeyWaitForDebugger]; 2946b9c1b51eSKate Stone [debug_options setObject:[NSNumber numberWithBool:YES] 2947b9c1b51eSKate Stone forKey:BKSDebugOptionKeyDebugOnNextLaunch]; 2948a332978bSJason Molenda 2949b9c1b51eSKate Stone [options setObject:debug_options 2950b9c1b51eSKate Stone forKey:BKSOpenApplicationOptionKeyDebuggingOptions]; 2951a332978bSJason Molenda 2952a332978bSJason Molenda BKSSystemService *system_service = [[BKSSystemService alloc] init]; 2953a332978bSJason Molenda 2954a332978bSJason Molenda mach_port_t client_port = [system_service createClientPort]; 2955a332978bSJason Molenda __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 2956b9c1b51eSKate Stone __block BKSOpenApplicationErrorCode attach_error_code = 2957b9c1b51eSKate Stone BKSOpenApplicationErrorCodeNone; 2958a332978bSJason Molenda 2959a332978bSJason Molenda NSString *bundleIDNSStr = (NSString *)bundleIDCFStr; 2960a332978bSJason Molenda 2961edde2eb1SJason Molenda DNBLog("[LaunchAttach] START (%d) requesting BKS launch of app with bundle " 2962edde2eb1SJason Molenda "ID '%s'", 2963edde2eb1SJason Molenda getpid(), bundleIDStr.c_str()); 2964a332978bSJason Molenda [system_service openApplication:bundleIDNSStr 2965a332978bSJason Molenda options:options 2966a332978bSJason Molenda clientPort:client_port 2967b9c1b51eSKate Stone withResult:^(NSError *error) { 2968b9c1b51eSKate Stone // The system service will cleanup the client port we 2969b9c1b51eSKate Stone // created for us. 2970a332978bSJason Molenda if (error) 2971b9c1b51eSKate Stone attach_error_code = 2972b9c1b51eSKate Stone (BKSOpenApplicationErrorCode)[error code]; 2973a332978bSJason Molenda 2974a332978bSJason Molenda [system_service release]; 2975a332978bSJason Molenda dispatch_semaphore_signal(semaphore); 2976b9c1b51eSKate Stone }]; 2977a332978bSJason Molenda 2978a332978bSJason Molenda const uint32_t timeout_secs = 9; 2979a332978bSJason Molenda 2980b9c1b51eSKate Stone dispatch_time_t timeout = 2981b9c1b51eSKate Stone dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); 2982a332978bSJason Molenda 2983a332978bSJason Molenda long success = dispatch_semaphore_wait(semaphore, timeout) == 0; 2984a332978bSJason Molenda 2985b9c1b51eSKate Stone if (!success) { 2986a332978bSJason Molenda DNBLogError("timed out trying to launch %s.", bundleIDStr.c_str()); 2987b9c1b51eSKate Stone attach_err.SetErrorString( 2988b9c1b51eSKate Stone "debugserver timed out waiting for openApplication to complete."); 2989c611a740SJason Molenda attach_err.SetError(OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); 2990b9c1b51eSKate Stone } else if (attach_error_code != BKSOpenApplicationErrorCodeNone) { 2991d44a0743SJason Molenda std::string empty_str; 2992d44a0743SJason Molenda SetBKSError(attach_error_code, empty_str, attach_err); 2993b9c1b51eSKate Stone DNBLogError("unable to launch the application with CFBundleIdentifier " 2994edde2eb1SJason Molenda "'%s' bks_error = %d", 2995b9c1b51eSKate Stone bundleIDStr.c_str(), attach_error_code); 2996a332978bSJason Molenda } 2997a332978bSJason Molenda dispatch_release(semaphore); 2998a332978bSJason Molenda [pool drain]; 2999a332978bSJason Molenda } 3000c611a740SJason Molenda#endif 3001c611a740SJason Molenda 3002c611a740SJason Molenda#if defined(WITH_SPRINGBOARD) 3003b9c1b51eSKate Stone if (launch_flavor == eLaunchFlavorSpringBoard) { 3004a332978bSJason Molenda SBSApplicationLaunchError sbs_error = 0; 3005a332978bSJason Molenda 3006a332978bSJason Molenda const char *stdout_err = "/dev/null"; 3007a332978bSJason Molenda CFString stdio_path; 3008a332978bSJason Molenda stdio_path.SetFileSystemRepresentation(stdout_err); 3009a332978bSJason Molenda 3010b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "SBSLaunchApplicationForDebugging ( @\"%s\" " 3011b9c1b51eSKate Stone ", NULL, NULL, NULL, @\"%s\", @\"%s\", " 3012b9c1b51eSKate Stone "SBSApplicationDebugOnNextLaunch | " 3013b9c1b51eSKate Stone "SBSApplicationLaunchWaitForDebugger )", 3014b9c1b51eSKate Stone bundleIDStr.c_str(), stdout_err, stdout_err); 3015a332978bSJason Molenda 3016edde2eb1SJason Molenda DNBLog("[LaunchAttach] START (%d) requesting SpringBoard launch of app " 3017edde2eb1SJason Molenda "with bundle " 3018edde2eb1SJason Molenda "ID '%s'", 3019edde2eb1SJason Molenda getpid(), bundleIDStr.c_str()); 3020b9c1b51eSKate Stone sbs_error = SBSLaunchApplicationForDebugging( 3021b9c1b51eSKate Stone bundleIDCFStr, 3022a332978bSJason Molenda (CFURLRef)NULL, // openURL 3023a332978bSJason Molenda NULL, // launch_argv.get(), 3024a332978bSJason Molenda NULL, // launch_envp.get(), // CFDictionaryRef environment 3025b9c1b51eSKate Stone stdio_path.get(), stdio_path.get(), 3026a332978bSJason Molenda SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger); 3027a332978bSJason Molenda 3028b9c1b51eSKate Stone if (sbs_error != SBSApplicationLaunchErrorSuccess) { 3029a332978bSJason Molenda attach_err.SetError(sbs_error, DNBError::SpringBoard); 3030a332978bSJason Molenda return NULL; 3031a332978bSJason Molenda } 3032a332978bSJason Molenda } 3033a332978bSJason Molenda#endif // WITH_SPRINGBOARD 3034a332978bSJason Molenda 3035a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "Successfully set DebugOnNextLaunch."); 3036a332978bSJason Molenda return bundleIDCFStr; 3037b9c1b51eSKate Stone#else // !(defined (WITH_SPRINGBOARD) || defined (WITH_BKS) || defined 3038b9c1b51eSKate Stone // (WITH_FBS)) 3039a332978bSJason Molenda return NULL; 3040a332978bSJason Molenda#endif 3041a332978bSJason Molenda} 3042a332978bSJason Molenda 3043a332978bSJason Molenda// Pass in the token you got from PrepareForAttach. If there is a process 3044a332978bSJason Molenda// for that token, then the pid will be returned, otherwise INVALID_NUB_PROCESS 3045a332978bSJason Molenda// will be returned. 3046a332978bSJason Molenda 3047b9c1b51eSKate Stonenub_process_t MachProcess::CheckForProcess(const void *attach_token, 3048b9c1b51eSKate Stone nub_launch_flavor_t launch_flavor) { 3049a332978bSJason Molenda if (attach_token == NULL) 3050a332978bSJason Molenda return INVALID_NUB_PROCESS; 3051a332978bSJason Molenda 3052c611a740SJason Molenda#if defined(WITH_FBS) 3053b9c1b51eSKate Stone if (launch_flavor == eLaunchFlavorFBS) { 3054c611a740SJason Molenda NSString *bundleIDNSStr = (NSString *)attach_token; 3055c611a740SJason Molenda FBSSystemService *systemService = [[FBSSystemService alloc] init]; 3056c611a740SJason Molenda pid_t pid = [systemService pidForApplication:bundleIDNSStr]; 3057c611a740SJason Molenda [systemService release]; 3058c611a740SJason Molenda if (pid == 0) 3059c611a740SJason Molenda return INVALID_NUB_PROCESS; 3060c611a740SJason Molenda else 3061c611a740SJason Molenda return pid; 3062c611a740SJason Molenda } 3063c611a740SJason Molenda#endif 3064c611a740SJason Molenda 3065a332978bSJason Molenda#if defined(WITH_BKS) 3066b9c1b51eSKate Stone if (launch_flavor == eLaunchFlavorBKS) { 3067a332978bSJason Molenda NSString *bundleIDNSStr = (NSString *)attach_token; 3068a332978bSJason Molenda BKSSystemService *systemService = [[BKSSystemService alloc] init]; 3069a332978bSJason Molenda pid_t pid = [systemService pidForApplication:bundleIDNSStr]; 3070a332978bSJason Molenda [systemService release]; 3071a332978bSJason Molenda if (pid == 0) 3072a332978bSJason Molenda return INVALID_NUB_PROCESS; 3073a332978bSJason Molenda else 3074a332978bSJason Molenda return pid; 3075c611a740SJason Molenda } 3076c611a740SJason Molenda#endif 3077c611a740SJason Molenda 3078c611a740SJason Molenda#if defined(WITH_SPRINGBOARD) 3079b9c1b51eSKate Stone if (launch_flavor == eLaunchFlavorSpringBoard) { 3080a332978bSJason Molenda CFStringRef bundleIDCFStr = (CFStringRef)attach_token; 3081a332978bSJason Molenda Boolean got_it; 3082a332978bSJason Molenda nub_process_t attach_pid; 3083a332978bSJason Molenda got_it = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &attach_pid); 3084a332978bSJason Molenda if (got_it) 3085a332978bSJason Molenda return attach_pid; 3086a332978bSJason Molenda else 3087a332978bSJason Molenda return INVALID_NUB_PROCESS; 3088c611a740SJason Molenda } 3089a332978bSJason Molenda#endif 3090c611a740SJason Molenda return INVALID_NUB_PROCESS; 3091a332978bSJason Molenda} 3092a332978bSJason Molenda 3093b9c1b51eSKate Stone// Call this to clean up after you have either attached or given up on the 3094b9c1b51eSKate Stone// attach. 3095a332978bSJason Molenda// Pass true for success if you have attached, false if you have not. 3096a332978bSJason Molenda// The token will also be freed at this point, so you can't use it after calling 3097a332978bSJason Molenda// this method. 3098a332978bSJason Molenda 3099b9c1b51eSKate Stonevoid MachProcess::CleanupAfterAttach(const void *attach_token, 3100b9c1b51eSKate Stone nub_launch_flavor_t launch_flavor, 3101b9c1b51eSKate Stone bool success, DNBError &err_str) { 3102a332978bSJason Molenda if (attach_token == NULL) 3103a332978bSJason Molenda return; 3104a332978bSJason Molenda 3105c611a740SJason Molenda#if defined(WITH_FBS) 3106b9c1b51eSKate Stone if (launch_flavor == eLaunchFlavorFBS) { 3107b9c1b51eSKate Stone if (!success) { 3108c611a740SJason Molenda FBSCleanupAfterAttach(attach_token, err_str); 3109c611a740SJason Molenda } 3110c611a740SJason Molenda CFRelease((CFStringRef)attach_token); 3111c611a740SJason Molenda } 3112c611a740SJason Molenda#endif 3113c611a740SJason Molenda 3114a332978bSJason Molenda#if defined(WITH_BKS) 3115a332978bSJason Molenda 3116b9c1b51eSKate Stone if (launch_flavor == eLaunchFlavorBKS) { 3117b9c1b51eSKate Stone if (!success) { 3118a332978bSJason Molenda BKSCleanupAfterAttach(attach_token, err_str); 3119a332978bSJason Molenda } 3120a332978bSJason Molenda CFRelease((CFStringRef)attach_token); 3121c611a740SJason Molenda } 3122c611a740SJason Molenda#endif 3123a332978bSJason Molenda 3124c611a740SJason Molenda#if defined(WITH_SPRINGBOARD) 3125a332978bSJason Molenda // Tell SpringBoard to cancel the debug on next launch of this application 3126a332978bSJason Molenda // if we failed to attach 3127b9c1b51eSKate Stone if (launch_flavor == eMachProcessFlagsUsingSpringBoard) { 3128b9c1b51eSKate Stone if (!success) { 3129a332978bSJason Molenda SBSApplicationLaunchError sbs_error = 0; 3130a332978bSJason Molenda CFStringRef bundleIDCFStr = (CFStringRef)attach_token; 3131a332978bSJason Molenda 3132b9c1b51eSKate Stone sbs_error = SBSLaunchApplicationForDebugging( 3133b9c1b51eSKate Stone bundleIDCFStr, (CFURLRef)NULL, NULL, NULL, NULL, NULL, 3134a332978bSJason Molenda SBSApplicationCancelDebugOnNextLaunch); 3135a332978bSJason Molenda 3136b9c1b51eSKate Stone if (sbs_error != SBSApplicationLaunchErrorSuccess) { 3137a332978bSJason Molenda err_str.SetError(sbs_error, DNBError::SpringBoard); 3138a332978bSJason Molenda return; 3139a332978bSJason Molenda } 3140a332978bSJason Molenda } 3141a332978bSJason Molenda 3142a332978bSJason Molenda CFRelease((CFStringRef)attach_token); 3143c611a740SJason Molenda } 3144a332978bSJason Molenda#endif 3145a332978bSJason Molenda} 3146a332978bSJason Molenda 3147b9c1b51eSKate Stonepid_t MachProcess::LaunchForDebug( 3148b9c1b51eSKate Stone const char *path, char const *argv[], char const *envp[], 3149b9c1b51eSKate Stone const char *working_directory, // NULL => don't change, non-NULL => set 3150b9c1b51eSKate Stone // working directory for inferior to this 3151b9c1b51eSKate Stone const char *stdin_path, const char *stdout_path, const char *stderr_path, 3152b9c1b51eSKate Stone bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, 3153bff4673bSJim Ingham const char *event_data, 3154bff4673bSJim Ingham const RNBContext::IgnoredExceptions &ignored_exceptions, 3155bff4673bSJim Ingham DNBError &launch_err) { 3156a332978bSJason Molenda // Clear out and clean up from any current state 3157a332978bSJason Molenda Clear(); 3158a332978bSJason Molenda 3159a64fafc7STim Hammerquist DNBLogThreadedIf(LOG_PROCESS, 3160a64fafc7STim Hammerquist "%s( path = '%s', argv = %p, envp = %p, " 3161b9c1b51eSKate Stone "launch_flavor = %u, disable_aslr = %d )", 316265fdb342SRaphael Isemann __FUNCTION__, path, static_cast<const void *>(argv), 316365fdb342SRaphael Isemann static_cast<const void *>(envp), launch_flavor, 3164a64fafc7STim Hammerquist disable_aslr); 3165a332978bSJason Molenda 3166a332978bSJason Molenda // Fork a child process for debugging 3167a332978bSJason Molenda SetState(eStateLaunching); 3168a332978bSJason Molenda 3169b9c1b51eSKate Stone switch (launch_flavor) { 3170a332978bSJason Molenda case eLaunchFlavorForkExec: 3171b9c1b51eSKate Stone m_pid = MachProcess::ForkChildForPTraceDebugging(path, argv, envp, this, 3172b9c1b51eSKate Stone launch_err); 3173a332978bSJason Molenda break; 3174c611a740SJason Molenda#ifdef WITH_FBS 3175b9c1b51eSKate Stone case eLaunchFlavorFBS: { 3176011a8e21SJonas Devlieghere std::string app_bundle_path = GetAppBundle(path); 3177011a8e21SJonas Devlieghere if (!app_bundle_path.empty()) { 31783bf883eaSJason Molenda m_flags |= (eMachProcessFlagsUsingFBS | eMachProcessFlagsBoardCalculated); 3179b9c1b51eSKate Stone if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, 3180b9c1b51eSKate Stone no_stdio, disable_aslr, event_data, 3181bff4673bSJim Ingham ignored_exceptions, launch_err) != 0) 3182b9c1b51eSKate Stone return m_pid; // A successful SBLaunchForDebug() returns and assigns a 3183b9c1b51eSKate Stone // non-zero m_pid. 3184c611a740SJason Molenda } 3185011a8e21SJonas Devlieghere DNBLog("Failed to launch '%s' with FBS", app_bundle_path); 3186b9c1b51eSKate Stone } break; 3187c611a740SJason Molenda#endif 3188a332978bSJason Molenda#ifdef WITH_BKS 3189b9c1b51eSKate Stone case eLaunchFlavorBKS: { 3190011a8e21SJonas Devlieghere std::string app_bundle_path = GetAppBundle(path); 3191011a8e21SJonas Devlieghere if (!app_bundle_path.empty()) { 31923bf883eaSJason Molenda m_flags |= (eMachProcessFlagsUsingBKS | eMachProcessFlagsBoardCalculated); 3193b9c1b51eSKate Stone if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, 3194b9c1b51eSKate Stone no_stdio, disable_aslr, event_data, 3195bff4673bSJim Ingham ignored_exceptions, launch_err) != 0) 3196b9c1b51eSKate Stone return m_pid; // A successful SBLaunchForDebug() returns and assigns a 3197b9c1b51eSKate Stone // non-zero m_pid. 3198a332978bSJason Molenda } 3199011a8e21SJonas Devlieghere DNBLog("Failed to launch '%s' with BKS", app_bundle_path); 3200b9c1b51eSKate Stone } break; 3201a332978bSJason Molenda#endif 3202a332978bSJason Molenda#ifdef WITH_SPRINGBOARD 3203b9c1b51eSKate Stone case eLaunchFlavorSpringBoard: { 3204011a8e21SJonas Devlieghere std::string app_bundle_path = GetAppBundle(path); 3205011a8e21SJonas Devlieghere if (!app_bundle_path.empty()) { 3206b9c1b51eSKate Stone if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio, 3207bff4673bSJim Ingham disable_aslr, ignored_exceptions, launch_err) != 0) 3208b9c1b51eSKate Stone return m_pid; // A successful SBLaunchForDebug() returns and assigns a 3209b9c1b51eSKate Stone // non-zero m_pid. 3210a332978bSJason Molenda } 3211011a8e21SJonas Devlieghere DNBLog("Failed to launch '%s' with SpringBoard", app_bundle_path); 3212b9c1b51eSKate Stone } break; 3213a332978bSJason Molenda 3214a332978bSJason Molenda#endif 3215a332978bSJason Molenda 3216a332978bSJason Molenda case eLaunchFlavorPosixSpawn: 3217b9c1b51eSKate Stone m_pid = MachProcess::PosixSpawnChildForPTraceDebugging( 32180db37576SJonas Devlieghere path, DNBArchProtocol::GetCPUType(), DNBArchProtocol::GetCPUSubType(), 32190db37576SJonas Devlieghere argv, envp, working_directory, stdin_path, stdout_path, stderr_path, 32200db37576SJonas Devlieghere no_stdio, this, disable_aslr, launch_err); 3221a332978bSJason Molenda break; 3222a332978bSJason Molenda 3223a332978bSJason Molenda default: 3224011a8e21SJonas Devlieghere DNBLog("Failed to launch: invalid launch flavor: %d", launch_flavor); 3225a332978bSJason Molenda launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic); 3226a332978bSJason Molenda return INVALID_NUB_PROCESS; 3227a332978bSJason Molenda } 3228a332978bSJason Molenda 3229b9c1b51eSKate Stone if (m_pid == INVALID_NUB_PROCESS) { 3230a332978bSJason Molenda // If we don't have a valid process ID and no one has set the error, 3231a332978bSJason Molenda // then return a generic error 3232a332978bSJason Molenda if (launch_err.Success()) 3233a332978bSJason Molenda launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic); 3234b9c1b51eSKate Stone } else { 3235a332978bSJason Molenda m_path = path; 3236a332978bSJason Molenda size_t i; 3237a332978bSJason Molenda char const *arg; 3238a332978bSJason Molenda for (i = 0; (arg = argv[i]) != NULL; i++) 3239a332978bSJason Molenda m_args.push_back(arg); 3240a332978bSJason Molenda 3241bff4673bSJim Ingham m_task.StartExceptionThread(ignored_exceptions, launch_err); 3242b9c1b51eSKate Stone if (launch_err.Fail()) { 3243a332978bSJason Molenda if (launch_err.AsString() == NULL) 3244a332978bSJason Molenda launch_err.SetErrorString("unable to start the exception thread"); 3245b9c1b51eSKate Stone DNBLog("Could not get inferior's Mach exception port, sending ptrace " 3246b9c1b51eSKate Stone "PT_KILL and exiting."); 3247a332978bSJason Molenda ::ptrace(PT_KILL, m_pid, 0, 0); 3248a332978bSJason Molenda m_pid = INVALID_NUB_PROCESS; 3249a332978bSJason Molenda return INVALID_NUB_PROCESS; 3250a332978bSJason Molenda } 3251a332978bSJason Molenda 3252a332978bSJason Molenda StartSTDIOThread(); 3253a332978bSJason Molenda 3254b9c1b51eSKate Stone if (launch_flavor == eLaunchFlavorPosixSpawn) { 3255a332978bSJason Molenda 3256a332978bSJason Molenda SetState(eStateAttaching); 3257a332978bSJason Molenda errno = 0; 3258edde2eb1SJason Molenda DNBLog("[LaunchAttach] (%d) About to ptrace(PT_ATTACHEXC, %d)...", 3259edde2eb1SJason Molenda getpid(), m_pid); 3260a332978bSJason Molenda int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); 3261edde2eb1SJason Molenda int ptrace_errno = errno; 3262edde2eb1SJason Molenda DNBLog("[LaunchAttach] (%d) Completed ptrace(PT_ATTACHEXC, %d) == %d", 3263edde2eb1SJason Molenda getpid(), m_pid, err); 3264b9c1b51eSKate Stone if (err == 0) { 3265a332978bSJason Molenda m_flags |= eMachProcessFlagsAttached; 3266a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "successfully spawned pid %d", m_pid); 3267a332978bSJason Molenda launch_err.Clear(); 3268b9c1b51eSKate Stone } else { 3269a332978bSJason Molenda SetState(eStateExited); 3270edde2eb1SJason Molenda DNBError ptrace_err(ptrace_errno, DNBError::POSIX); 3271b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to spawned pid " 3272b9c1b51eSKate Stone "%d (err = %i, errno = %i (%s))", 327397206d57SZachary Turner m_pid, err, ptrace_err.Status(), 327497206d57SZachary Turner ptrace_err.AsString()); 3275a332978bSJason Molenda launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic); 3276a332978bSJason Molenda } 3277b9c1b51eSKate Stone } else { 3278a332978bSJason Molenda launch_err.Clear(); 3279a332978bSJason Molenda } 3280a332978bSJason Molenda } 3281a332978bSJason Molenda return m_pid; 3282a332978bSJason Molenda} 3283a332978bSJason Molenda 3284b9c1b51eSKate Stonepid_t MachProcess::PosixSpawnChildForPTraceDebugging( 32850db37576SJonas Devlieghere const char *path, cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, 32860db37576SJonas Devlieghere char const *argv[], char const *envp[], const char *working_directory, 32870db37576SJonas Devlieghere const char *stdin_path, const char *stdout_path, const char *stderr_path, 32880db37576SJonas Devlieghere bool no_stdio, MachProcess *process, int disable_aslr, DNBError &err) { 3289a332978bSJason Molenda posix_spawnattr_t attr; 3290a332978bSJason Molenda short flags; 329165fdb342SRaphael Isemann DNBLogThreadedIf(LOG_PROCESS, 329265fdb342SRaphael Isemann "%s ( path='%s', argv=%p, envp=%p, " 3293b9c1b51eSKate Stone "working_dir=%s, stdin=%s, stdout=%s " 3294b9c1b51eSKate Stone "stderr=%s, no-stdio=%i)", 329565fdb342SRaphael Isemann __FUNCTION__, path, static_cast<const void *>(argv), 329665fdb342SRaphael Isemann static_cast<const void *>(envp), working_directory, 3297b9c1b51eSKate Stone stdin_path, stdout_path, stderr_path, no_stdio); 3298a332978bSJason Molenda 3299a332978bSJason Molenda err.SetError(::posix_spawnattr_init(&attr), DNBError::POSIX); 3300a332978bSJason Molenda if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) 3301a332978bSJason Molenda err.LogThreaded("::posix_spawnattr_init ( &attr )"); 3302a332978bSJason Molenda if (err.Fail()) 3303a332978bSJason Molenda return INVALID_NUB_PROCESS; 3304a332978bSJason Molenda 3305b9c1b51eSKate Stone flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF | 3306b9c1b51eSKate Stone POSIX_SPAWN_SETSIGMASK; 3307a332978bSJason Molenda if (disable_aslr) 3308a332978bSJason Molenda flags |= _POSIX_SPAWN_DISABLE_ASLR; 3309a332978bSJason Molenda 3310a332978bSJason Molenda sigset_t no_signals; 3311a332978bSJason Molenda sigset_t all_signals; 3312a332978bSJason Molenda sigemptyset(&no_signals); 3313a332978bSJason Molenda sigfillset(&all_signals); 3314a332978bSJason Molenda ::posix_spawnattr_setsigmask(&attr, &no_signals); 3315a332978bSJason Molenda ::posix_spawnattr_setsigdefault(&attr, &all_signals); 3316a332978bSJason Molenda 3317a332978bSJason Molenda err.SetError(::posix_spawnattr_setflags(&attr, flags), DNBError::POSIX); 3318a332978bSJason Molenda if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) 3319b9c1b51eSKate Stone err.LogThreaded( 3320b9c1b51eSKate Stone "::posix_spawnattr_setflags ( &attr, POSIX_SPAWN_START_SUSPENDED%s )", 3321b9c1b51eSKate Stone flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR" 3322b9c1b51eSKate Stone : ""); 3323a332978bSJason Molenda if (err.Fail()) 3324a332978bSJason Molenda return INVALID_NUB_PROCESS; 3325a332978bSJason Molenda 3326a332978bSJason Molenda// Don't do this on SnowLeopard, _sometimes_ the TASK_BASIC_INFO will fail 3327a332978bSJason Molenda// and we will fail to continue with our process... 3328a332978bSJason Molenda 3329a332978bSJason Molenda// On SnowLeopard we should set "DYLD_NO_PIE" in the inferior environment.... 3330a332978bSJason Molenda 3331b9c1b51eSKate Stone if (cpu_type != 0) { 3332a332978bSJason Molenda size_t ocount = 0; 33330db37576SJonas Devlieghere bool slice_preference_set = false; 33340db37576SJonas Devlieghere 33350db37576SJonas Devlieghere if (cpu_subtype != 0) { 333613ee00d0SJonas Devlieghere typedef int (*posix_spawnattr_setarchpref_np_t)( 333713ee00d0SJonas Devlieghere posix_spawnattr_t *, size_t, cpu_type_t *, cpu_subtype_t *, size_t *); 333813ee00d0SJonas Devlieghere posix_spawnattr_setarchpref_np_t posix_spawnattr_setarchpref_np_fn = 333913ee00d0SJonas Devlieghere (posix_spawnattr_setarchpref_np_t)dlsym( 334013ee00d0SJonas Devlieghere RTLD_DEFAULT, "posix_spawnattr_setarchpref_np"); 334113ee00d0SJonas Devlieghere if (posix_spawnattr_setarchpref_np_fn) { 3342ee607ed5SJonas Devlieghere err.SetError((*posix_spawnattr_setarchpref_np_fn)( 3343ee607ed5SJonas Devlieghere &attr, 1, &cpu_type, &cpu_subtype, &ocount)); 33440db37576SJonas Devlieghere slice_preference_set = err.Success(); 33450db37576SJonas Devlieghere if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) 33460db37576SJonas Devlieghere err.LogThreaded( 33470db37576SJonas Devlieghere "::posix_spawnattr_setarchpref_np ( &attr, 1, cpu_type = " 33480db37576SJonas Devlieghere "0x%8.8x, cpu_subtype = 0x%8.8x, count => %llu )", 33490db37576SJonas Devlieghere cpu_type, cpu_subtype, (uint64_t)ocount); 33500db37576SJonas Devlieghere if (err.Fail() != 0 || ocount != 1) 33510db37576SJonas Devlieghere return INVALID_NUB_PROCESS; 33520db37576SJonas Devlieghere } 33530db37576SJonas Devlieghere } 33540db37576SJonas Devlieghere 33550db37576SJonas Devlieghere if (!slice_preference_set) { 33560db37576SJonas Devlieghere err.SetError( 33570db37576SJonas Devlieghere ::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount), 3358b9c1b51eSKate Stone DNBError::POSIX); 3359a332978bSJason Molenda if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) 33600db37576SJonas Devlieghere err.LogThreaded( 33610db37576SJonas Devlieghere "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = " 3362b9c1b51eSKate Stone "0x%8.8x, count => %llu )", 3363b9c1b51eSKate Stone cpu_type, (uint64_t)ocount); 3364a332978bSJason Molenda 3365a332978bSJason Molenda if (err.Fail() != 0 || ocount != 1) 3366a332978bSJason Molenda return INVALID_NUB_PROCESS; 3367a332978bSJason Molenda } 33680db37576SJonas Devlieghere } 3369a332978bSJason Molenda 3370a332978bSJason Molenda PseudoTerminal pty; 3371a332978bSJason Molenda 3372a332978bSJason Molenda posix_spawn_file_actions_t file_actions; 3373a332978bSJason Molenda err.SetError(::posix_spawn_file_actions_init(&file_actions), DNBError::POSIX); 3374a332978bSJason Molenda int file_actions_valid = err.Success(); 3375a332978bSJason Molenda if (!file_actions_valid || DNBLogCheckLogBit(LOG_PROCESS)) 3376a332978bSJason Molenda err.LogThreaded("::posix_spawn_file_actions_init ( &file_actions )"); 3377a332978bSJason Molenda int pty_error = -1; 3378a332978bSJason Molenda pid_t pid = INVALID_NUB_PROCESS; 3379b9c1b51eSKate Stone if (file_actions_valid) { 3380b9c1b51eSKate Stone if (stdin_path == NULL && stdout_path == NULL && stderr_path == NULL && 3381b9c1b51eSKate Stone !no_stdio) { 33820965b59bSJonas Devlieghere pty_error = pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY); 3383b9c1b51eSKate Stone if (pty_error == PseudoTerminal::success) { 33840965b59bSJonas Devlieghere stdin_path = stdout_path = stderr_path = pty.SecondaryName(); 3385a332978bSJason Molenda } 3386a332978bSJason Molenda } 3387a332978bSJason Molenda 3388a332978bSJason Molenda // if no_stdio or std paths not supplied, then route to "/dev/null". 3389a332978bSJason Molenda if (no_stdio || stdin_path == NULL || stdin_path[0] == '\0') 3390a332978bSJason Molenda stdin_path = "/dev/null"; 3391a332978bSJason Molenda if (no_stdio || stdout_path == NULL || stdout_path[0] == '\0') 3392a332978bSJason Molenda stdout_path = "/dev/null"; 3393a332978bSJason Molenda if (no_stdio || stderr_path == NULL || stderr_path[0] == '\0') 3394a332978bSJason Molenda stderr_path = "/dev/null"; 3395a332978bSJason Molenda 3396b9c1b51eSKate Stone err.SetError(::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, 3397a332978bSJason Molenda stdin_path, 3398b9c1b51eSKate Stone O_RDONLY | O_NOCTTY, 0), 3399a332978bSJason Molenda DNBError::POSIX); 3400a332978bSJason Molenda if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) 3401b9c1b51eSKate Stone err.LogThreaded("::posix_spawn_file_actions_addopen (&file_actions, " 3402b9c1b51eSKate Stone "filedes=STDIN_FILENO, path='%s')", 3403b9c1b51eSKate Stone stdin_path); 3404a332978bSJason Molenda 3405b9c1b51eSKate Stone err.SetError(::posix_spawn_file_actions_addopen( 3406b9c1b51eSKate Stone &file_actions, STDOUT_FILENO, stdout_path, 3407b9c1b51eSKate Stone O_WRONLY | O_NOCTTY | O_CREAT, 0640), 3408a332978bSJason Molenda DNBError::POSIX); 3409a332978bSJason Molenda if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) 3410b9c1b51eSKate Stone err.LogThreaded("::posix_spawn_file_actions_addopen (&file_actions, " 3411b9c1b51eSKate Stone "filedes=STDOUT_FILENO, path='%s')", 3412b9c1b51eSKate Stone stdout_path); 3413a332978bSJason Molenda 3414b9c1b51eSKate Stone err.SetError(::posix_spawn_file_actions_addopen( 3415b9c1b51eSKate Stone &file_actions, STDERR_FILENO, stderr_path, 3416b9c1b51eSKate Stone O_WRONLY | O_NOCTTY | O_CREAT, 0640), 3417a332978bSJason Molenda DNBError::POSIX); 3418a332978bSJason Molenda if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) 3419b9c1b51eSKate Stone err.LogThreaded("::posix_spawn_file_actions_addopen (&file_actions, " 3420b9c1b51eSKate Stone "filedes=STDERR_FILENO, path='%s')", 3421b9c1b51eSKate Stone stderr_path); 3422a332978bSJason Molenda 3423a332978bSJason Molenda // TODO: Verify if we can set the working directory back immediately 3424a332978bSJason Molenda // after the posix_spawnp call without creating a race condition??? 3425a332978bSJason Molenda if (working_directory) 3426a332978bSJason Molenda ::chdir(working_directory); 3427a332978bSJason Molenda 3428b9c1b51eSKate Stone err.SetError(::posix_spawnp(&pid, path, &file_actions, &attr, 342907d95614SVedant Kumar const_cast<char *const *>(argv), 343007d95614SVedant Kumar const_cast<char *const *>(envp)), 3431b9c1b51eSKate Stone DNBError::POSIX); 3432a332978bSJason Molenda if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) 3433b9c1b51eSKate Stone err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = " 3434b9c1b51eSKate Stone "%p, attr = %p, argv = %p, envp = %p )", 3435b9c1b51eSKate Stone pid, path, &file_actions, &attr, argv, envp); 3436b9c1b51eSKate Stone } else { 3437a332978bSJason Molenda // TODO: Verify if we can set the working directory back immediately 3438a332978bSJason Molenda // after the posix_spawnp call without creating a race condition??? 3439a332978bSJason Molenda if (working_directory) 3440a332978bSJason Molenda ::chdir(working_directory); 3441a332978bSJason Molenda 344207d95614SVedant Kumar err.SetError(::posix_spawnp(&pid, path, NULL, &attr, 344307d95614SVedant Kumar const_cast<char *const *>(argv), 344407d95614SVedant Kumar const_cast<char *const *>(envp)), 3445b9c1b51eSKate Stone DNBError::POSIX); 3446a332978bSJason Molenda if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) 3447b9c1b51eSKate Stone err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = " 3448b9c1b51eSKate Stone "%p, attr = %p, argv = %p, envp = %p )", 3449b9c1b51eSKate Stone pid, path, NULL, &attr, argv, envp); 3450a332978bSJason Molenda } 3451a332978bSJason Molenda 3452a332978bSJason Molenda // We have seen some cases where posix_spawnp was returning a valid 3453a332978bSJason Molenda // looking pid even when an error was returned, so clear it out 3454a332978bSJason Molenda if (err.Fail()) 3455a332978bSJason Molenda pid = INVALID_NUB_PROCESS; 3456a332978bSJason Molenda 3457b9c1b51eSKate Stone if (pty_error == 0) { 3458b9c1b51eSKate Stone if (process != NULL) { 34590965b59bSJonas Devlieghere int primary_fd = pty.ReleasePrimaryFD(); 34600965b59bSJonas Devlieghere process->SetChildFileDescriptors(primary_fd, primary_fd, primary_fd); 3461a332978bSJason Molenda } 3462a332978bSJason Molenda } 3463a332978bSJason Molenda ::posix_spawnattr_destroy(&attr); 3464a332978bSJason Molenda 3465b9c1b51eSKate Stone if (pid != INVALID_NUB_PROCESS) { 3466a332978bSJason Molenda cpu_type_t pid_cpu_type = MachProcess::GetCPUTypeForLocalProcess(pid); 3467b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 3468b9c1b51eSKate Stone "MachProcess::%s ( ) pid=%i, cpu_type=0x%8.8x", 3469b9c1b51eSKate Stone __FUNCTION__, pid, pid_cpu_type); 3470a332978bSJason Molenda if (pid_cpu_type) 3471a332978bSJason Molenda DNBArchProtocol::SetArchitecture(pid_cpu_type); 3472a332978bSJason Molenda } 3473a332978bSJason Molenda 3474b9c1b51eSKate Stone if (file_actions_valid) { 3475a332978bSJason Molenda DNBError err2; 3476b9c1b51eSKate Stone err2.SetError(::posix_spawn_file_actions_destroy(&file_actions), 3477b9c1b51eSKate Stone DNBError::POSIX); 3478a332978bSJason Molenda if (err2.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) 3479a332978bSJason Molenda err2.LogThreaded("::posix_spawn_file_actions_destroy ( &file_actions )"); 3480a332978bSJason Molenda } 3481a332978bSJason Molenda 3482a332978bSJason Molenda return pid; 3483a332978bSJason Molenda} 3484a332978bSJason Molenda 3485b9c1b51eSKate Stoneuint32_t MachProcess::GetCPUTypeForLocalProcess(pid_t pid) { 3486b9c1b51eSKate Stone int mib[CTL_MAXNAME] = { 3487b9c1b51eSKate Stone 0, 3488b9c1b51eSKate Stone }; 3489a332978bSJason Molenda size_t len = CTL_MAXNAME; 3490a332978bSJason Molenda if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) 3491a332978bSJason Molenda return 0; 3492a332978bSJason Molenda 3493a332978bSJason Molenda mib[len] = pid; 3494a332978bSJason Molenda len++; 3495a332978bSJason Molenda 3496a332978bSJason Molenda cpu_type_t cpu; 3497a332978bSJason Molenda size_t cpu_len = sizeof(cpu); 3498ee2ed525SGreg Clayton if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0)) 3499a332978bSJason Molenda cpu = 0; 3500a332978bSJason Molenda return cpu; 3501a332978bSJason Molenda} 3502a332978bSJason Molenda 3503b9c1b51eSKate Stonepid_t MachProcess::ForkChildForPTraceDebugging(const char *path, 3504a332978bSJason Molenda char const *argv[], 3505a332978bSJason Molenda char const *envp[], 3506a332978bSJason Molenda MachProcess *process, 3507b9c1b51eSKate Stone DNBError &launch_err) { 350897206d57SZachary Turner PseudoTerminal::Status pty_error = PseudoTerminal::success; 3509a332978bSJason Molenda 3510a332978bSJason Molenda // Use a fork that ties the child process's stdin/out/err to a pseudo 3511a332978bSJason Molenda // terminal so we can read it in our MachProcess::STDIOThread 3512a332978bSJason Molenda // as unbuffered io. 3513a332978bSJason Molenda PseudoTerminal pty; 3514a332978bSJason Molenda pid_t pid = pty.Fork(pty_error); 3515a332978bSJason Molenda 3516b9c1b51eSKate Stone if (pid < 0) { 3517a332978bSJason Molenda //-------------------------------------------------------------- 351897206d57SZachary Turner // Status during fork. 3519a332978bSJason Molenda //-------------------------------------------------------------- 3520a332978bSJason Molenda return pid; 3521b9c1b51eSKate Stone } else if (pid == 0) { 3522a332978bSJason Molenda //-------------------------------------------------------------- 3523a332978bSJason Molenda // Child process 3524a332978bSJason Molenda //-------------------------------------------------------------- 3525a332978bSJason Molenda ::ptrace(PT_TRACE_ME, 0, 0, 0); // Debug this process 3526a332978bSJason Molenda ::ptrace(PT_SIGEXC, 0, 0, 0); // Get BSD signals as mach exceptions 3527a332978bSJason Molenda 3528a332978bSJason Molenda // If our parent is setgid, lets make sure we don't inherit those 3529a332978bSJason Molenda // extra powers due to nepotism. 3530b9c1b51eSKate Stone if (::setgid(getgid()) == 0) { 3531a332978bSJason Molenda 3532a332978bSJason Molenda // Let the child have its own process group. We need to execute 3533a332978bSJason Molenda // this call in both the child and parent to avoid a race condition 3534a332978bSJason Molenda // between the two processes. 3535a332978bSJason Molenda ::setpgid(0, 0); // Set the child process group to match its pid 3536a332978bSJason Molenda 3537a332978bSJason Molenda // Sleep a bit to before the exec call 3538a332978bSJason Molenda ::sleep(1); 3539a332978bSJason Molenda 3540a332978bSJason Molenda // Turn this process into 354107d95614SVedant Kumar ::execv(path, const_cast<char *const *>(argv)); 3542a332978bSJason Molenda } 3543a332978bSJason Molenda // Exit with error code. Child process should have taken 3544a332978bSJason Molenda // over in above exec call and if the exec fails it will 3545a332978bSJason Molenda // exit the child process below. 3546a332978bSJason Molenda ::exit(127); 3547b9c1b51eSKate Stone } else { 3548a332978bSJason Molenda //-------------------------------------------------------------- 3549a332978bSJason Molenda // Parent process 3550a332978bSJason Molenda //-------------------------------------------------------------- 3551a332978bSJason Molenda // Let the child have its own process group. We need to execute 3552a332978bSJason Molenda // this call in both the child and parent to avoid a race condition 3553a332978bSJason Molenda // between the two processes. 3554a332978bSJason Molenda ::setpgid(pid, pid); // Set the child process group to match its pid 3555a332978bSJason Molenda 3556b9c1b51eSKate Stone if (process != NULL) { 35570965b59bSJonas Devlieghere // Release our primary pty file descriptor so the pty class doesn't 3558a332978bSJason Molenda // close it and so we can continue to use it in our STDIO thread 35590965b59bSJonas Devlieghere int primary_fd = pty.ReleasePrimaryFD(); 35600965b59bSJonas Devlieghere process->SetChildFileDescriptors(primary_fd, primary_fd, primary_fd); 3561a332978bSJason Molenda } 3562a332978bSJason Molenda } 3563a332978bSJason Molenda return pid; 3564a332978bSJason Molenda} 3565a332978bSJason Molenda 3566c611a740SJason Molenda#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) || defined(WITH_FBS) 3567c611a740SJason Molenda// This returns a CFRetained pointer to the Bundle ID for app_bundle_path, 3568c611a740SJason Molenda// or NULL if there was some problem getting the bundle id. 3569b9c1b51eSKate Stonestatic CFStringRef CopyBundleIDForPath(const char *app_bundle_path, 3570b9c1b51eSKate Stone DNBError &err_str) { 3571c611a740SJason Molenda CFBundle bundle(app_bundle_path); 3572c611a740SJason Molenda CFStringRef bundleIDCFStr = bundle.GetIdentifier(); 3573c611a740SJason Molenda std::string bundleID; 3574b9c1b51eSKate Stone if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL) { 3575c611a740SJason Molenda struct stat app_bundle_stat; 3576c611a740SJason Molenda char err_msg[PATH_MAX]; 3577c611a740SJason Molenda 3578b9c1b51eSKate Stone if (::stat(app_bundle_path, &app_bundle_stat) < 0) { 3579c611a740SJason Molenda err_str.SetError(errno, DNBError::POSIX); 3580b9c1b51eSKate Stone snprintf(err_msg, sizeof(err_msg), "%s: \"%s\"", err_str.AsString(), 3581b9c1b51eSKate Stone app_bundle_path); 3582c611a740SJason Molenda err_str.SetErrorString(err_msg); 3583c611a740SJason Molenda DNBLogThreadedIf(LOG_PROCESS, "%s() error: %s", __FUNCTION__, err_msg); 3584b9c1b51eSKate Stone } else { 3585c611a740SJason Molenda err_str.SetError(-1, DNBError::Generic); 3586b9c1b51eSKate Stone snprintf(err_msg, sizeof(err_msg), 3587b9c1b51eSKate Stone "failed to extract CFBundleIdentifier from %s", app_bundle_path); 3588c611a740SJason Molenda err_str.SetErrorString(err_msg); 3589b9c1b51eSKate Stone DNBLogThreadedIf( 3590b9c1b51eSKate Stone LOG_PROCESS, 3591b9c1b51eSKate Stone "%s() error: failed to extract CFBundleIdentifier from '%s'", 3592b9c1b51eSKate Stone __FUNCTION__, app_bundle_path); 3593c611a740SJason Molenda } 3594c611a740SJason Molenda return NULL; 3595c611a740SJason Molenda } 3596c611a740SJason Molenda 3597b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", 3598b9c1b51eSKate Stone __FUNCTION__, bundleID.c_str()); 3599c611a740SJason Molenda CFRetain(bundleIDCFStr); 3600c611a740SJason Molenda 3601c611a740SJason Molenda return bundleIDCFStr; 3602c611a740SJason Molenda} 3603b9c1b51eSKate Stone#endif // #if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) || defined 3604b9c1b51eSKate Stone // (WITH_FBS) 3605a332978bSJason Molenda#ifdef WITH_SPRINGBOARD 3606a332978bSJason Molenda 3607b9c1b51eSKate Stonepid_t MachProcess::SBLaunchForDebug(const char *path, char const *argv[], 3608b9c1b51eSKate Stone char const *envp[], bool no_stdio, 3609bff4673bSJim Ingham bool disable_aslr, 3610bff4673bSJim Ingham const RNBContext::IgnoredExceptions 3611bff4673bSJim Ingham &ignored_exceptions, 361227012c0fSAlessandro Arzilli DNBError &launch_err) { 3613a332978bSJason Molenda // Clear out and clean up from any current state 3614a332978bSJason Molenda Clear(); 3615a332978bSJason Molenda 3616a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path); 3617a332978bSJason Molenda 3618a332978bSJason Molenda // Fork a child process for debugging 3619a332978bSJason Molenda SetState(eStateLaunching); 3620b9c1b51eSKate Stone m_pid = MachProcess::SBForkChildForPTraceDebugging(path, argv, envp, no_stdio, 3621b9c1b51eSKate Stone this, launch_err); 3622b9c1b51eSKate Stone if (m_pid != 0) { 3623a332978bSJason Molenda m_path = path; 3624a332978bSJason Molenda size_t i; 3625a332978bSJason Molenda char const *arg; 3626a332978bSJason Molenda for (i = 0; (arg = argv[i]) != NULL; i++) 3627a332978bSJason Molenda m_args.push_back(arg); 3628bff4673bSJim Ingham m_task.StartExceptionThread(ignored_exceptions, launch_err); 3629a332978bSJason Molenda 3630b9c1b51eSKate Stone if (launch_err.Fail()) { 3631a332978bSJason Molenda if (launch_err.AsString() == NULL) 3632a332978bSJason Molenda launch_err.SetErrorString("unable to start the exception thread"); 3633b9c1b51eSKate Stone DNBLog("Could not get inferior's Mach exception port, sending ptrace " 3634b9c1b51eSKate Stone "PT_KILL and exiting."); 3635a332978bSJason Molenda ::ptrace(PT_KILL, m_pid, 0, 0); 3636a332978bSJason Molenda m_pid = INVALID_NUB_PROCESS; 3637a332978bSJason Molenda return INVALID_NUB_PROCESS; 3638a332978bSJason Molenda } 3639a332978bSJason Molenda 3640a332978bSJason Molenda StartSTDIOThread(); 3641a332978bSJason Molenda SetState(eStateAttaching); 3642edde2eb1SJason Molenda DNBLog("[LaunchAttach] (%d) About to ptrace(PT_ATTACHEXC, %d)...", getpid(), 3643edde2eb1SJason Molenda m_pid); 3644a332978bSJason Molenda int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); 3645edde2eb1SJason Molenda DNBLog("[LaunchAttach] (%d) Completed ptrace(PT_ATTACHEXC, %d) == %d", 3646edde2eb1SJason Molenda getpid(), m_pid, err); 3647b9c1b51eSKate Stone if (err == 0) { 3648a332978bSJason Molenda m_flags |= eMachProcessFlagsAttached; 3649a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid); 3650b9c1b51eSKate Stone } else { 3651a332978bSJason Molenda SetState(eStateExited); 3652a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", m_pid); 3653a332978bSJason Molenda } 3654a332978bSJason Molenda } 3655a332978bSJason Molenda return m_pid; 3656a332978bSJason Molenda} 3657a332978bSJason Molenda 3658a332978bSJason Molenda#include <servers/bootstrap.h> 3659a332978bSJason Molenda 3660b9c1b51eSKate Stonepid_t MachProcess::SBForkChildForPTraceDebugging( 3661b9c1b51eSKate Stone const char *app_bundle_path, char const *argv[], char const *envp[], 3662b9c1b51eSKate Stone bool no_stdio, MachProcess *process, DNBError &launch_err) { 3663b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, 3664b9c1b51eSKate Stone app_bundle_path, process); 3665a332978bSJason Molenda CFAllocatorRef alloc = kCFAllocatorDefault; 3666a332978bSJason Molenda 3667a332978bSJason Molenda if (argv[0] == NULL) 3668a332978bSJason Molenda return INVALID_NUB_PROCESS; 3669a332978bSJason Molenda 3670a332978bSJason Molenda size_t argc = 0; 3671a332978bSJason Molenda // Count the number of arguments 3672a332978bSJason Molenda while (argv[argc] != NULL) 3673a332978bSJason Molenda argc++; 3674a332978bSJason Molenda 3675a332978bSJason Molenda // Enumerate the arguments 3676a332978bSJason Molenda size_t first_launch_arg_idx = 1; 3677a332978bSJason Molenda CFReleaser<CFMutableArrayRef> launch_argv; 3678a332978bSJason Molenda 3679b9c1b51eSKate Stone if (argv[first_launch_arg_idx]) { 3680a332978bSJason Molenda size_t launch_argc = argc > 0 ? argc - 1 : 0; 3681b9c1b51eSKate Stone launch_argv.reset( 3682b9c1b51eSKate Stone ::CFArrayCreateMutable(alloc, launch_argc, &kCFTypeArrayCallBacks)); 3683a332978bSJason Molenda size_t i; 3684a332978bSJason Molenda char const *arg; 3685a332978bSJason Molenda CFString launch_arg; 3686b9c1b51eSKate Stone for (i = first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); 3687b9c1b51eSKate Stone i++) { 3688b9c1b51eSKate Stone launch_arg.reset( 3689b9c1b51eSKate Stone ::CFStringCreateWithCString(alloc, arg, kCFStringEncodingUTF8)); 3690a332978bSJason Molenda if (launch_arg.get() != NULL) 3691a332978bSJason Molenda CFArrayAppendValue(launch_argv.get(), launch_arg.get()); 3692a332978bSJason Molenda else 3693a332978bSJason Molenda break; 3694a332978bSJason Molenda } 3695a332978bSJason Molenda } 3696a332978bSJason Molenda 3697a332978bSJason Molenda // Next fill in the arguments dictionary. Note, the envp array is of the form 3698b9c1b51eSKate Stone // Variable=value but SpringBoard wants a CF dictionary. So we have to 3699b9c1b51eSKate Stone // convert 3700a332978bSJason Molenda // this here. 3701a332978bSJason Molenda 3702a332978bSJason Molenda CFReleaser<CFMutableDictionaryRef> launch_envp; 3703a332978bSJason Molenda 3704b9c1b51eSKate Stone if (envp[0]) { 3705b9c1b51eSKate Stone launch_envp.reset( 3706b9c1b51eSKate Stone ::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, 3707b9c1b51eSKate Stone &kCFTypeDictionaryValueCallBacks)); 3708a332978bSJason Molenda const char *value; 3709a332978bSJason Molenda int name_len; 3710a332978bSJason Molenda CFString name_string, value_string; 3711a332978bSJason Molenda 3712b9c1b51eSKate Stone for (int i = 0; envp[i] != NULL; i++) { 3713a332978bSJason Molenda value = strstr(envp[i], "="); 3714a332978bSJason Molenda 3715b9c1b51eSKate Stone // If the name field is empty or there's no =, skip it. Somebody's 3716b9c1b51eSKate Stone // messing with us. 3717a332978bSJason Molenda if (value == NULL || value == envp[i]) 3718a332978bSJason Molenda continue; 3719a332978bSJason Molenda 3720a332978bSJason Molenda name_len = value - envp[i]; 3721a332978bSJason Molenda 3722a332978bSJason Molenda // Now move value over the "=" 3723a332978bSJason Molenda value++; 3724a332978bSJason Molenda 3725b9c1b51eSKate Stone name_string.reset( 3726b9c1b51eSKate Stone ::CFStringCreateWithBytes(alloc, (const UInt8 *)envp[i], name_len, 3727b9c1b51eSKate Stone kCFStringEncodingUTF8, false)); 3728b9c1b51eSKate Stone value_string.reset( 3729b9c1b51eSKate Stone ::CFStringCreateWithCString(alloc, value, kCFStringEncodingUTF8)); 3730b9c1b51eSKate Stone CFDictionarySetValue(launch_envp.get(), name_string.get(), 3731b9c1b51eSKate Stone value_string.get()); 3732a332978bSJason Molenda } 3733a332978bSJason Molenda } 3734a332978bSJason Molenda 3735a332978bSJason Molenda CFString stdio_path; 3736a332978bSJason Molenda 3737a332978bSJason Molenda PseudoTerminal pty; 3738b9c1b51eSKate Stone if (!no_stdio) { 373997206d57SZachary Turner PseudoTerminal::Status pty_err = 37400965b59bSJonas Devlieghere pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY); 3741b9c1b51eSKate Stone if (pty_err == PseudoTerminal::success) { 37420965b59bSJonas Devlieghere const char *secondary_name = pty.SecondaryName(); 3743b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 37440965b59bSJonas Devlieghere "%s() successfully opened primary pty, secondary is %s", 37450965b59bSJonas Devlieghere __FUNCTION__, secondary_name); 37460965b59bSJonas Devlieghere if (secondary_name && secondary_name[0]) { 37470965b59bSJonas Devlieghere ::chmod(secondary_name, S_IRWXU | S_IRWXG | S_IRWXO); 37480965b59bSJonas Devlieghere stdio_path.SetFileSystemRepresentation(secondary_name); 3749a332978bSJason Molenda } 3750a332978bSJason Molenda } 3751a332978bSJason Molenda } 3752a332978bSJason Molenda 3753b9c1b51eSKate Stone if (stdio_path.get() == NULL) { 3754a332978bSJason Molenda stdio_path.SetFileSystemRepresentation("/dev/null"); 3755a332978bSJason Molenda } 3756a332978bSJason Molenda 3757a332978bSJason Molenda CFStringRef bundleIDCFStr = CopyBundleIDForPath(app_bundle_path, launch_err); 3758a332978bSJason Molenda if (bundleIDCFStr == NULL) 3759a332978bSJason Molenda return INVALID_NUB_PROCESS; 3760a332978bSJason Molenda 3761a332978bSJason Molenda // This is just for logging: 3762a332978bSJason Molenda std::string bundleID; 3763a332978bSJason Molenda CFString::UTF8(bundleIDCFStr, bundleID); 3764a332978bSJason Molenda 3765b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "%s() serialized launch arg array", 3766b9c1b51eSKate Stone __FUNCTION__); 3767a332978bSJason Molenda 3768a332978bSJason Molenda // Find SpringBoard 3769a332978bSJason Molenda SBSApplicationLaunchError sbs_error = 0; 3770b9c1b51eSKate Stone sbs_error = SBSLaunchApplicationForDebugging( 3771b9c1b51eSKate Stone bundleIDCFStr, 3772a332978bSJason Molenda (CFURLRef)NULL, // openURL 3773a332978bSJason Molenda launch_argv.get(), 3774a332978bSJason Molenda launch_envp.get(), // CFDictionaryRef environment 3775b9c1b51eSKate Stone stdio_path.get(), stdio_path.get(), 3776a332978bSJason Molenda SBSApplicationLaunchWaitForDebugger | SBSApplicationLaunchUnlockDevice); 3777a332978bSJason Molenda 3778a332978bSJason Molenda launch_err.SetError(sbs_error, DNBError::SpringBoard); 3779a332978bSJason Molenda 3780b9c1b51eSKate Stone if (sbs_error == SBSApplicationLaunchErrorSuccess) { 3781a332978bSJason Molenda static const useconds_t pid_poll_interval = 200000; 3782a332978bSJason Molenda static const useconds_t pid_poll_timeout = 30000000; 3783a332978bSJason Molenda 3784a332978bSJason Molenda useconds_t pid_poll_total = 0; 3785a332978bSJason Molenda 3786a332978bSJason Molenda nub_process_t pid = INVALID_NUB_PROCESS; 3787a332978bSJason Molenda Boolean pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid); 3788b9c1b51eSKate Stone // Poll until the process is running, as long as we are getting valid 3789b9c1b51eSKate Stone // responses and the timeout hasn't expired 3790b9c1b51eSKate Stone // A return PID of 0 means the process is not running, which may be because 3791b9c1b51eSKate Stone // it hasn't been (asynchronously) started 3792a332978bSJason Molenda // yet, or that it died very quickly (if you weren't using waitForDebugger). 3793b9c1b51eSKate Stone while (!pid_found && pid_poll_total < pid_poll_timeout) { 3794a332978bSJason Molenda usleep(pid_poll_interval); 3795a332978bSJason Molenda pid_poll_total += pid_poll_interval; 3796b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 3797b9c1b51eSKate Stone "%s() polling Springboard for pid for %s...", 3798b9c1b51eSKate Stone __FUNCTION__, bundleID.c_str()); 3799a332978bSJason Molenda pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid); 3800a332978bSJason Molenda } 3801a332978bSJason Molenda 3802a332978bSJason Molenda CFRelease(bundleIDCFStr); 3803b9c1b51eSKate Stone if (pid_found) { 3804b9c1b51eSKate Stone if (process != NULL) { 38050965b59bSJonas Devlieghere // Release our primary pty file descriptor so the pty class doesn't 3806a332978bSJason Molenda // close it and so we can continue to use it in our STDIO thread 38070965b59bSJonas Devlieghere int primary_fd = pty.ReleasePrimaryFD(); 38080965b59bSJonas Devlieghere process->SetChildFileDescriptors(primary_fd, primary_fd, primary_fd); 3809a332978bSJason Molenda } 3810a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "%s() => pid = %4.4x", __FUNCTION__, pid); 3811b9c1b51eSKate Stone } else { 3812b9c1b51eSKate Stone DNBLogError("failed to lookup the process ID for CFBundleIdentifier %s.", 3813b9c1b51eSKate Stone bundleID.c_str()); 3814a332978bSJason Molenda } 3815a332978bSJason Molenda return pid; 3816a332978bSJason Molenda } 3817a332978bSJason Molenda 3818b9c1b51eSKate Stone DNBLogError("unable to launch the application with CFBundleIdentifier '%s' " 3819b9c1b51eSKate Stone "sbs_error = %u", 3820b9c1b51eSKate Stone bundleID.c_str(), sbs_error); 3821a332978bSJason Molenda return INVALID_NUB_PROCESS; 3822a332978bSJason Molenda} 3823a332978bSJason Molenda 3824a332978bSJason Molenda#endif // #ifdef WITH_SPRINGBOARD 3825a332978bSJason Molenda 3826c611a740SJason Molenda#if defined(WITH_BKS) || defined(WITH_FBS) 3827b9c1b51eSKate Stonepid_t MachProcess::BoardServiceLaunchForDebug( 3828b9c1b51eSKate Stone const char *path, char const *argv[], char const *envp[], bool no_stdio, 3829bff4673bSJim Ingham bool disable_aslr, const char *event_data, 3830bff4673bSJim Ingham const RNBContext::IgnoredExceptions &ignored_exceptions, 383127012c0fSAlessandro Arzilli DNBError &launch_err) { 3832a332978bSJason Molenda DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path); 3833a332978bSJason Molenda 3834a332978bSJason Molenda // Fork a child process for debugging 3835a332978bSJason Molenda SetState(eStateLaunching); 3836b9c1b51eSKate Stone m_pid = BoardServiceForkChildForPTraceDebugging( 3837b9c1b51eSKate Stone path, argv, envp, no_stdio, disable_aslr, event_data, launch_err); 3838b9c1b51eSKate Stone if (m_pid != 0) { 3839a332978bSJason Molenda m_path = path; 3840a332978bSJason Molenda size_t i; 3841a332978bSJason Molenda char const *arg; 3842a332978bSJason Molenda for (i = 0; (arg = argv[i]) != NULL; i++) 3843a332978bSJason Molenda m_args.push_back(arg); 3844bff4673bSJim Ingham m_task.StartExceptionThread(ignored_exceptions, launch_err); 3845a332978bSJason Molenda 3846b9c1b51eSKate Stone if (launch_err.Fail()) { 3847a332978bSJason Molenda if (launch_err.AsString() == NULL) 3848a332978bSJason Molenda launch_err.SetErrorString("unable to start the exception thread"); 3849edde2eb1SJason Molenda DNBLog("[LaunchAttach] END (%d) Could not get inferior's Mach exception " 3850edde2eb1SJason Molenda "port, " 3851edde2eb1SJason Molenda "sending ptrace " 3852edde2eb1SJason Molenda "PT_KILL to pid %i and exiting.", 3853edde2eb1SJason Molenda getpid(), m_pid); 3854a332978bSJason Molenda ::ptrace(PT_KILL, m_pid, 0, 0); 3855a332978bSJason Molenda m_pid = INVALID_NUB_PROCESS; 3856a332978bSJason Molenda return INVALID_NUB_PROCESS; 3857a332978bSJason Molenda } 3858a332978bSJason Molenda 3859a332978bSJason Molenda StartSTDIOThread(); 3860a332978bSJason Molenda SetState(eStateAttaching); 3861edde2eb1SJason Molenda DNBLog("[LaunchAttach] (%d) About to ptrace(PT_ATTACHEXC, %d)...", getpid(), 3862edde2eb1SJason Molenda m_pid); 3863a332978bSJason Molenda int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); 3864edde2eb1SJason Molenda DNBLog("[LaunchAttach] (%d) Completed ptrace(PT_ATTACHEXC, %d) == %d", 3865edde2eb1SJason Molenda getpid(), m_pid, err); 3866b9c1b51eSKate Stone if (err == 0) { 3867a332978bSJason Molenda m_flags |= eMachProcessFlagsAttached; 3868edde2eb1SJason Molenda DNBLog("[LaunchAttach] successfully attached to pid %d", m_pid); 3869b9c1b51eSKate Stone } else { 3870a332978bSJason Molenda SetState(eStateExited); 3871edde2eb1SJason Molenda DNBLog("[LaunchAttach] END (%d) error: failed to attach to pid %d", 3872edde2eb1SJason Molenda getpid(), m_pid); 3873a332978bSJason Molenda } 3874a332978bSJason Molenda } 3875a332978bSJason Molenda return m_pid; 3876a332978bSJason Molenda} 3877a332978bSJason Molenda 3878b9c1b51eSKate Stonepid_t MachProcess::BoardServiceForkChildForPTraceDebugging( 3879b9c1b51eSKate Stone const char *app_bundle_path, char const *argv[], char const *envp[], 3880b9c1b51eSKate Stone bool no_stdio, bool disable_aslr, const char *event_data, 3881b9c1b51eSKate Stone DNBError &launch_err) { 3882a332978bSJason Molenda if (argv[0] == NULL) 3883a332978bSJason Molenda return INVALID_NUB_PROCESS; 3884a332978bSJason Molenda 3885b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, 3886b9c1b51eSKate Stone app_bundle_path, this); 3887a332978bSJason Molenda 3888a332978bSJason Molenda NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 3889a332978bSJason Molenda 3890a332978bSJason Molenda size_t argc = 0; 3891a332978bSJason Molenda // Count the number of arguments 3892a332978bSJason Molenda while (argv[argc] != NULL) 3893a332978bSJason Molenda argc++; 3894a332978bSJason Molenda 3895a332978bSJason Molenda // Enumerate the arguments 3896a332978bSJason Molenda size_t first_launch_arg_idx = 1; 3897a332978bSJason Molenda 3898a332978bSJason Molenda NSMutableArray *launch_argv = nil; 3899a332978bSJason Molenda 3900b9c1b51eSKate Stone if (argv[first_launch_arg_idx]) { 3901a332978bSJason Molenda size_t launch_argc = argc > 0 ? argc - 1 : 0; 3902a332978bSJason Molenda launch_argv = [NSMutableArray arrayWithCapacity:launch_argc]; 3903a332978bSJason Molenda size_t i; 3904a332978bSJason Molenda char const *arg; 3905a332978bSJason Molenda NSString *launch_arg; 3906b9c1b51eSKate Stone for (i = first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); 3907b9c1b51eSKate Stone i++) { 3908a332978bSJason Molenda launch_arg = [NSString stringWithUTF8String:arg]; 3909b9c1b51eSKate Stone // FIXME: Should we silently eat an argument that we can't convert into a 3910b9c1b51eSKate Stone // UTF8 string? 3911a332978bSJason Molenda if (launch_arg != nil) 3912a332978bSJason Molenda [launch_argv addObject:launch_arg]; 3913a332978bSJason Molenda else 3914a332978bSJason Molenda break; 3915a332978bSJason Molenda } 3916a332978bSJason Molenda } 3917a332978bSJason Molenda 3918a332978bSJason Molenda NSMutableDictionary *launch_envp = nil; 3919b9c1b51eSKate Stone if (envp[0]) { 3920a332978bSJason Molenda launch_envp = [[NSMutableDictionary alloc] init]; 3921a332978bSJason Molenda const char *value; 3922a332978bSJason Molenda int name_len; 3923a332978bSJason Molenda NSString *name_string, *value_string; 3924a332978bSJason Molenda 3925b9c1b51eSKate Stone for (int i = 0; envp[i] != NULL; i++) { 3926a332978bSJason Molenda value = strstr(envp[i], "="); 3927a332978bSJason Molenda 3928b9c1b51eSKate Stone // If the name field is empty or there's no =, skip it. Somebody's 3929b9c1b51eSKate Stone // messing with us. 3930a332978bSJason Molenda if (value == NULL || value == envp[i]) 3931a332978bSJason Molenda continue; 3932a332978bSJason Molenda 3933a332978bSJason Molenda name_len = value - envp[i]; 3934a332978bSJason Molenda 3935a332978bSJason Molenda // Now move value over the "=" 3936a332978bSJason Molenda value++; 3937b9c1b51eSKate Stone name_string = [[NSString alloc] initWithBytes:envp[i] 3938b9c1b51eSKate Stone length:name_len 3939b9c1b51eSKate Stone encoding:NSUTF8StringEncoding]; 3940a332978bSJason Molenda value_string = [NSString stringWithUTF8String:value]; 3941a332978bSJason Molenda [launch_envp setObject:value_string forKey:name_string]; 3942a332978bSJason Molenda } 3943a332978bSJason Molenda } 3944a332978bSJason Molenda 3945a332978bSJason Molenda NSString *stdio_path = nil; 3946a332978bSJason Molenda NSFileManager *file_manager = [NSFileManager defaultManager]; 3947a332978bSJason Molenda 3948a332978bSJason Molenda PseudoTerminal pty; 3949b9c1b51eSKate Stone if (!no_stdio) { 395097206d57SZachary Turner PseudoTerminal::Status pty_err = 39510965b59bSJonas Devlieghere pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY); 3952b9c1b51eSKate Stone if (pty_err == PseudoTerminal::success) { 39530965b59bSJonas Devlieghere const char *secondary_name = pty.SecondaryName(); 3954b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 39550965b59bSJonas Devlieghere "%s() successfully opened primary pty, secondary is %s", 39560965b59bSJonas Devlieghere __FUNCTION__, secondary_name); 39570965b59bSJonas Devlieghere if (secondary_name && secondary_name[0]) { 39580965b59bSJonas Devlieghere ::chmod(secondary_name, S_IRWXU | S_IRWXG | S_IRWXO); 3959b9c1b51eSKate Stone stdio_path = [file_manager 39600965b59bSJonas Devlieghere stringWithFileSystemRepresentation:secondary_name 39610965b59bSJonas Devlieghere length:strlen(secondary_name)]; 3962a332978bSJason Molenda } 3963a332978bSJason Molenda } 3964a332978bSJason Molenda } 3965a332978bSJason Molenda 3966b9c1b51eSKate Stone if (stdio_path == nil) { 3967a332978bSJason Molenda const char *null_path = "/dev/null"; 3968b9c1b51eSKate Stone stdio_path = 3969b9c1b51eSKate Stone [file_manager stringWithFileSystemRepresentation:null_path 3970b9c1b51eSKate Stone length:strlen(null_path)]; 3971a332978bSJason Molenda } 3972a332978bSJason Molenda 3973a332978bSJason Molenda CFStringRef bundleIDCFStr = CopyBundleIDForPath(app_bundle_path, launch_err); 3974b9c1b51eSKate Stone if (bundleIDCFStr == NULL) { 3975a332978bSJason Molenda [pool drain]; 3976a332978bSJason Molenda return INVALID_NUB_PROCESS; 3977a332978bSJason Molenda } 3978a332978bSJason Molenda 3979b9c1b51eSKate Stone // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use 3980b9c1b51eSKate Stone // toll-free bridging here: 3981a332978bSJason Molenda NSString *bundleIDNSStr = (NSString *)bundleIDCFStr; 3982a332978bSJason Molenda 3983b9c1b51eSKate Stone // Okay, now let's assemble all these goodies into the BackBoardServices 3984b9c1b51eSKate Stone // options mega-dictionary: 3985a332978bSJason Molenda 3986c611a740SJason Molenda NSMutableDictionary *options = nullptr; 3987a332978bSJason Molenda pid_t return_pid = INVALID_NUB_PROCESS; 3988c611a740SJason Molenda bool success = false; 3989c611a740SJason Molenda 3990c611a740SJason Molenda#ifdef WITH_BKS 39913bf883eaSJason Molenda if (ProcessUsingBackBoard()) { 3992b9c1b51eSKate Stone options = 3993b9c1b51eSKate Stone BKSCreateOptionsDictionary(app_bundle_path, launch_argv, launch_envp, 3994b9c1b51eSKate Stone stdio_path, disable_aslr, event_data); 3995b9c1b51eSKate Stone success = BKSCallOpenApplicationFunction(bundleIDNSStr, options, launch_err, 3996b9c1b51eSKate Stone &return_pid); 3997c611a740SJason Molenda } 3998c611a740SJason Molenda#endif 3999c611a740SJason Molenda#ifdef WITH_FBS 40003bf883eaSJason Molenda if (ProcessUsingFrontBoard()) { 4001b9c1b51eSKate Stone options = 4002b9c1b51eSKate Stone FBSCreateOptionsDictionary(app_bundle_path, launch_argv, launch_envp, 4003b9c1b51eSKate Stone stdio_path, disable_aslr, event_data); 4004b9c1b51eSKate Stone success = FBSCallOpenApplicationFunction(bundleIDNSStr, options, launch_err, 4005b9c1b51eSKate Stone &return_pid); 4006c611a740SJason Molenda } 4007c611a740SJason Molenda#endif 4008a332978bSJason Molenda 4009b9c1b51eSKate Stone if (success) { 40100965b59bSJonas Devlieghere int primary_fd = pty.ReleasePrimaryFD(); 40110965b59bSJonas Devlieghere SetChildFileDescriptors(primary_fd, primary_fd, primary_fd); 4012a332978bSJason Molenda CFString::UTF8(bundleIDCFStr, m_bundle_id); 4013a332978bSJason Molenda } 4014a332978bSJason Molenda 4015a332978bSJason Molenda [pool drain]; 4016a332978bSJason Molenda 4017a332978bSJason Molenda return return_pid; 4018a332978bSJason Molenda} 4019a332978bSJason Molenda 4020b9c1b51eSKate Stonebool MachProcess::BoardServiceSendEvent(const char *event_data, 4021b9c1b51eSKate Stone DNBError &send_err) { 4022a332978bSJason Molenda bool return_value = true; 4023a332978bSJason Molenda 4024b9c1b51eSKate Stone if (event_data == NULL || *event_data == '\0') { 4025a332978bSJason Molenda DNBLogError("SendEvent called with NULL event data."); 4026a332978bSJason Molenda send_err.SetErrorString("SendEvent called with empty event data"); 4027a332978bSJason Molenda return false; 4028a332978bSJason Molenda } 4029a332978bSJason Molenda 4030a332978bSJason Molenda NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 4031a332978bSJason Molenda 4032b9c1b51eSKate Stone if (strcmp(event_data, "BackgroundApplication") == 0) { 4033b9c1b51eSKate Stone// This is an event I cooked up. What you actually do is foreground the system 4034b9c1b51eSKate Stone// app, so: 4035c611a740SJason Molenda#ifdef WITH_BKS 40363bf883eaSJason Molenda if (ProcessUsingBackBoard()) { 4037c611a740SJason Molenda return_value = BKSCallOpenApplicationFunction(nil, nil, send_err, NULL); 4038c611a740SJason Molenda } 4039c611a740SJason Molenda#endif 4040c611a740SJason Molenda#ifdef WITH_FBS 40413bf883eaSJason Molenda if (ProcessUsingFrontBoard()) { 4042c611a740SJason Molenda return_value = FBSCallOpenApplicationFunction(nil, nil, send_err, NULL); 4043c611a740SJason Molenda } 4044c611a740SJason Molenda#endif 4045b9c1b51eSKate Stone if (!return_value) { 4046b9c1b51eSKate Stone DNBLogError("Failed to background application, error: %s.", 4047b9c1b51eSKate Stone send_err.AsString()); 4048a332978bSJason Molenda } 4049b9c1b51eSKate Stone } else { 4050b9c1b51eSKate Stone if (m_bundle_id.empty()) { 4051a332978bSJason Molenda // See if we can figure out the bundle ID for this PID: 4052a332978bSJason Molenda 4053b9c1b51eSKate Stone DNBLogError( 4054b9c1b51eSKate Stone "Tried to send event \"%s\" to a process that has no bundle ID.", 4055b9c1b51eSKate Stone event_data); 4056a332978bSJason Molenda return false; 4057a332978bSJason Molenda } 4058a332978bSJason Molenda 4059b9c1b51eSKate Stone NSString *bundleIDNSStr = 4060b9c1b51eSKate Stone [NSString stringWithUTF8String:m_bundle_id.c_str()]; 4061a332978bSJason Molenda 4062a332978bSJason Molenda NSMutableDictionary *options = [NSMutableDictionary dictionary]; 4063a332978bSJason Molenda 4064c611a740SJason Molenda#ifdef WITH_BKS 40653bf883eaSJason Molenda if (ProcessUsingBackBoard()) { 4066b9c1b51eSKate Stone if (!BKSAddEventDataToOptions(options, event_data, send_err)) { 4067a332978bSJason Molenda [pool drain]; 4068a332978bSJason Molenda return false; 4069a332978bSJason Molenda } 4070b9c1b51eSKate Stone return_value = BKSCallOpenApplicationFunction(bundleIDNSStr, options, 4071b9c1b51eSKate Stone send_err, NULL); 4072b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 4073b9c1b51eSKate Stone "Called BKSCallOpenApplicationFunction to send event."); 4074c611a740SJason Molenda } 4075c611a740SJason Molenda#endif 4076c611a740SJason Molenda#ifdef WITH_FBS 40773bf883eaSJason Molenda if (ProcessUsingFrontBoard()) { 4078b9c1b51eSKate Stone if (!FBSAddEventDataToOptions(options, event_data, send_err)) { 4079c611a740SJason Molenda [pool drain]; 4080c611a740SJason Molenda return false; 4081c611a740SJason Molenda } 4082b9c1b51eSKate Stone return_value = FBSCallOpenApplicationFunction(bundleIDNSStr, options, 4083b9c1b51eSKate Stone send_err, NULL); 4084b9c1b51eSKate Stone DNBLogThreadedIf(LOG_PROCESS, 4085b9c1b51eSKate Stone "Called FBSCallOpenApplicationFunction to send event."); 4086c611a740SJason Molenda } 4087c611a740SJason Molenda#endif 4088a332978bSJason Molenda 4089b9c1b51eSKate Stone if (!return_value) { 4090b9c1b51eSKate Stone DNBLogError("Failed to send event: %s, error: %s.", event_data, 4091b9c1b51eSKate Stone send_err.AsString()); 4092a332978bSJason Molenda } 4093a332978bSJason Molenda } 4094a332978bSJason Molenda 4095a332978bSJason Molenda [pool drain]; 4096a332978bSJason Molenda return return_value; 4097a332978bSJason Molenda} 4098c611a740SJason Molenda#endif // defined(WITH_BKS) || defined (WITH_FBS) 4099c611a740SJason Molenda 4100c611a740SJason Molenda#ifdef WITH_BKS 4101b9c1b51eSKate Stonevoid MachProcess::BKSCleanupAfterAttach(const void *attach_token, 4102b9c1b51eSKate Stone DNBError &err_str) { 4103c611a740SJason Molenda bool success; 4104c611a740SJason Molenda 4105c611a740SJason Molenda NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 4106c611a740SJason Molenda 4107b9c1b51eSKate Stone // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use 4108b9c1b51eSKate Stone // toll-free bridging here: 4109c611a740SJason Molenda NSString *bundleIDNSStr = (NSString *)attach_token; 4110c611a740SJason Molenda 4111b9c1b51eSKate Stone // Okay, now let's assemble all these goodies into the BackBoardServices 4112b9c1b51eSKate Stone // options mega-dictionary: 4113c611a740SJason Molenda 4114c611a740SJason Molenda // First we have the debug sub-dictionary: 4115c611a740SJason Molenda NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; 4116b9c1b51eSKate Stone [debug_options setObject:[NSNumber numberWithBool:YES] 4117b9c1b51eSKate Stone forKey:BKSDebugOptionKeyCancelDebugOnNextLaunch]; 4118c611a740SJason Molenda 4119c611a740SJason Molenda // That will go in the overall dictionary: 4120c611a740SJason Molenda 4121c611a740SJason Molenda NSMutableDictionary *options = [NSMutableDictionary dictionary]; 4122b9c1b51eSKate Stone [options setObject:debug_options 4123b9c1b51eSKate Stone forKey:BKSOpenApplicationOptionKeyDebuggingOptions]; 4124c611a740SJason Molenda 4125b9c1b51eSKate Stone success = 4126b9c1b51eSKate Stone BKSCallOpenApplicationFunction(bundleIDNSStr, options, err_str, NULL); 4127c611a740SJason Molenda 4128b9c1b51eSKate Stone if (!success) { 4129b9c1b51eSKate Stone DNBLogError("error trying to cancel debug on next launch for %s: %s", 4130b9c1b51eSKate Stone [bundleIDNSStr UTF8String], err_str.AsString()); 4131c611a740SJason Molenda } 4132c611a740SJason Molenda 4133c611a740SJason Molenda [pool drain]; 4134c611a740SJason Molenda} 4135a332978bSJason Molenda#endif // WITH_BKS 4136c611a740SJason Molenda 4137c611a740SJason Molenda#ifdef WITH_FBS 4138b9c1b51eSKate Stonevoid MachProcess::FBSCleanupAfterAttach(const void *attach_token, 4139b9c1b51eSKate Stone DNBError &err_str) { 4140c611a740SJason Molenda bool success; 4141c611a740SJason Molenda 4142c611a740SJason Molenda NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 4143c611a740SJason Molenda 4144b9c1b51eSKate Stone // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use 4145b9c1b51eSKate Stone // toll-free bridging here: 4146c611a740SJason Molenda NSString *bundleIDNSStr = (NSString *)attach_token; 4147c611a740SJason Molenda 4148b9c1b51eSKate Stone // Okay, now let's assemble all these goodies into the BackBoardServices 4149b9c1b51eSKate Stone // options mega-dictionary: 4150c611a740SJason Molenda 4151c611a740SJason Molenda // First we have the debug sub-dictionary: 4152c611a740SJason Molenda NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; 4153b9c1b51eSKate Stone [debug_options setObject:[NSNumber numberWithBool:YES] 4154b9c1b51eSKate Stone forKey:FBSDebugOptionKeyCancelDebugOnNextLaunch]; 4155c611a740SJason Molenda 4156c611a740SJason Molenda // That will go in the overall dictionary: 4157c611a740SJason Molenda 4158c611a740SJason Molenda NSMutableDictionary *options = [NSMutableDictionary dictionary]; 4159b9c1b51eSKate Stone [options setObject:debug_options 4160b9c1b51eSKate Stone forKey:FBSOpenApplicationOptionKeyDebuggingOptions]; 4161c611a740SJason Molenda 4162b9c1b51eSKate Stone success = 4163b9c1b51eSKate Stone FBSCallOpenApplicationFunction(bundleIDNSStr, options, err_str, NULL); 4164c611a740SJason Molenda 4165b9c1b51eSKate Stone if (!success) { 4166b9c1b51eSKate Stone DNBLogError("error trying to cancel debug on next launch for %s: %s", 4167b9c1b51eSKate Stone [bundleIDNSStr UTF8String], err_str.AsString()); 4168c611a740SJason Molenda } 4169c611a740SJason Molenda 4170c611a740SJason Molenda [pool drain]; 4171c611a740SJason Molenda} 4172c611a740SJason Molenda#endif // WITH_FBS 41733bf883eaSJason Molenda 41743bf883eaSJason Molenda 41753bf883eaSJason Molendavoid MachProcess::CalculateBoardStatus() 41763bf883eaSJason Molenda{ 41773bf883eaSJason Molenda if (m_flags & eMachProcessFlagsBoardCalculated) 41783bf883eaSJason Molenda return; 41793bf883eaSJason Molenda if (m_pid == 0) 41803bf883eaSJason Molenda return; 41813bf883eaSJason Molenda 41825044316dSJason Molenda#if defined (WITH_FBS) || defined (WITH_BKS) 41833bf883eaSJason Molenda bool found_app_flavor = false; 41845044316dSJason Molenda#endif 41855044316dSJason Molenda 41863bf883eaSJason Molenda#if defined(WITH_FBS) 41873bf883eaSJason Molenda if (!found_app_flavor && IsFBSProcess(m_pid)) { 41883bf883eaSJason Molenda found_app_flavor = true; 41893bf883eaSJason Molenda m_flags |= eMachProcessFlagsUsingFBS; 41903bf883eaSJason Molenda } 4191870c0a64SJason Molenda#endif 4192870c0a64SJason Molenda#if defined(WITH_BKS) 41933bf883eaSJason Molenda if (!found_app_flavor && IsBKSProcess(m_pid)) { 41943bf883eaSJason Molenda found_app_flavor = true; 41953bf883eaSJason Molenda m_flags |= eMachProcessFlagsUsingBKS; 41963bf883eaSJason Molenda } 41973bf883eaSJason Molenda#endif 41985044316dSJason Molenda 41993bf883eaSJason Molenda m_flags |= eMachProcessFlagsBoardCalculated; 42003bf883eaSJason Molenda} 42013bf883eaSJason Molenda 42023bf883eaSJason Molendabool MachProcess::ProcessUsingBackBoard() { 42033bf883eaSJason Molenda CalculateBoardStatus(); 42043bf883eaSJason Molenda return (m_flags & eMachProcessFlagsUsingBKS) != 0; 42053bf883eaSJason Molenda} 42063bf883eaSJason Molenda 42073bf883eaSJason Molendabool MachProcess::ProcessUsingFrontBoard() { 42083bf883eaSJason Molenda CalculateBoardStatus(); 42093bf883eaSJason Molenda return (m_flags & eMachProcessFlagsUsingFBS) != 0; 42103bf883eaSJason Molenda} 4211afee0975SJason Molenda 4212afee0975SJason Molendaint MachProcess::GetInferiorAddrSize(pid_t pid) { 4213afee0975SJason Molenda int pointer_size = 8; 4214afee0975SJason Molenda int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; 4215afee0975SJason Molenda struct kinfo_proc processInfo; 4216afee0975SJason Molenda size_t bufsize = sizeof(processInfo); 4217afee0975SJason Molenda if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, &bufsize, 4218afee0975SJason Molenda NULL, 0) == 0 && 4219afee0975SJason Molenda bufsize > 0) { 4220afee0975SJason Molenda if ((processInfo.kp_proc.p_flag & P_LP64) == 0) 4221afee0975SJason Molenda pointer_size = 4; 4222afee0975SJason Molenda } 4223afee0975SJason Molenda return pointer_size; 4224afee0975SJason Molenda} 4225