2010-06-09 00:52:24 +08:00
|
|
|
//===-- Host.mm -------------------------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-09-08 04:11:56 +08:00
|
|
|
#include "lldb/Host/Host.h"
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-18 06:03:32 +08:00
|
|
|
|
2012-02-25 09:07:38 +08:00
|
|
|
#include <AvailabilityMacros.h>
|
|
|
|
|
|
|
|
#if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
|
2012-03-08 12:03:25 +08:00
|
|
|
#define NO_XPC_SERVICES 1
|
2012-02-25 09:07:38 +08:00
|
|
|
#endif
|
|
|
|
|
2012-03-08 12:03:25 +08:00
|
|
|
#if !defined(NO_XPC_SERVICES)
|
2012-02-25 14:56:35 +08:00
|
|
|
#define __XPC_PRIVATE_H__
|
2012-02-25 09:07:38 +08:00
|
|
|
#include <xpc/xpc.h>
|
2012-04-03 15:51:16 +08:00
|
|
|
#include "launcherXPCService/LauncherXPCService.h"
|
2012-02-25 09:07:38 +08:00
|
|
|
#endif
|
|
|
|
|
2013-08-27 13:04:57 +08:00
|
|
|
#include "llvm/Support/Host.h"
|
|
|
|
|
2012-01-05 11:57:59 +08:00
|
|
|
#include <asl.h>
|
2010-12-04 08:10:17 +08:00
|
|
|
#include <crt_externs.h>
|
2010-12-03 14:02:24 +08:00
|
|
|
#include <execinfo.h>
|
2011-03-22 05:25:07 +08:00
|
|
|
#include <grp.h>
|
2010-10-20 02:15:50 +08:00
|
|
|
#include <libproc.h>
|
2011-03-22 05:25:07 +08:00
|
|
|
#include <pwd.h>
|
2011-04-12 13:54:46 +08:00
|
|
|
#include <spawn.h>
|
2010-12-03 14:02:24 +08:00
|
|
|
#include <stdio.h>
|
2010-10-20 02:15:50 +08:00
|
|
|
#include <sys/proc.h>
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-18 06:03:32 +08:00
|
|
|
#include <sys/stat.h>
|
2011-03-22 05:25:07 +08:00
|
|
|
#include <sys/sysctl.h>
|
2010-10-20 02:15:50 +08:00
|
|
|
#include <sys/types.h>
|
2010-12-03 14:02:24 +08:00
|
|
|
#include <unistd.h>
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-18 06:03:32 +08:00
|
|
|
|
|
|
|
#include "lldb/Core/ArchSpec.h"
|
2010-10-19 11:25:40 +08:00
|
|
|
#include "lldb/Core/Communication.h"
|
2011-04-01 08:29:43 +08:00
|
|
|
#include "lldb/Core/DataExtractor.h"
|
2010-09-08 04:11:56 +08:00
|
|
|
#include "lldb/Core/Log.h"
|
2011-04-12 13:54:46 +08:00
|
|
|
#include "lldb/Core/Module.h"
|
2014-11-18 03:39:20 +08:00
|
|
|
#include "lldb/Core/ModuleSpec.h"
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-18 06:03:32 +08:00
|
|
|
#include "lldb/Core/StreamFile.h"
|
|
|
|
#include "lldb/Core/StreamString.h"
|
2015-02-21 05:48:38 +08:00
|
|
|
#include "lldb/Core/StructuredData.h"
|
2014-10-07 05:22:36 +08:00
|
|
|
#include "lldb/Host/ConnectionFileDescriptor.h"
|
2011-04-12 13:54:46 +08:00
|
|
|
#include "lldb/Host/Endian.h"
|
|
|
|
#include "lldb/Host/FileSpec.h"
|
2014-09-10 04:54:56 +08:00
|
|
|
#include "lldb/Host/FileSystem.h"
|
2014-08-22 01:29:12 +08:00
|
|
|
#include "lldb/Host/HostInfo.h"
|
2014-09-10 04:54:56 +08:00
|
|
|
#include "lldb/Host/ThreadLauncher.h"
|
2011-04-12 13:54:46 +08:00
|
|
|
#include "lldb/Target/Platform.h"
|
2011-03-22 05:25:07 +08:00
|
|
|
#include "lldb/Target/Process.h"
|
2011-04-12 13:54:46 +08:00
|
|
|
#include "lldb/Utility/CleanUp.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2010-07-10 04:39:50 +08:00
|
|
|
#include "cfcpp/CFCBundle.h"
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-18 06:03:32 +08:00
|
|
|
#include "cfcpp/CFCMutableArray.h"
|
2010-10-01 05:49:03 +08:00
|
|
|
#include "cfcpp/CFCMutableDictionary.h"
|
2010-07-10 04:39:50 +08:00
|
|
|
#include "cfcpp/CFCReleaser.h"
|
|
|
|
#include "cfcpp/CFCString.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2014-03-30 02:54:20 +08:00
|
|
|
|
2010-09-08 04:11:56 +08:00
|
|
|
#include <objc/objc-auto.h>
|
|
|
|
|
2012-07-13 07:16:43 +08:00
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
#include <Foundation/Foundation.h>
|
|
|
|
|
2011-04-12 13:54:46 +08:00
|
|
|
#ifndef _POSIX_SPAWN_DISABLE_ASLR
|
|
|
|
#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
|
|
|
|
#endif
|
|
|
|
|
2011-11-15 11:53:30 +08:00
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
int __pthread_chdir(const char *path);
|
|
|
|
int __pthread_fchdir (int fildes);
|
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
2012-02-14 07:10:39 +08:00
|
|
|
bool
|
|
|
|
Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle_directory)
|
|
|
|
{
|
|
|
|
#if defined (__APPLE__)
|
|
|
|
if (file.GetFileType () == FileSpec::eFileTypeDirectory)
|
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
if (file.GetPath(path, sizeof(path)))
|
|
|
|
{
|
|
|
|
CFCBundle bundle (path);
|
|
|
|
if (bundle.GetPath (path, sizeof(path)))
|
|
|
|
{
|
|
|
|
bundle_directory.SetFile (path, false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
bundle_directory.Clear();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
bool
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-18 06:03:32 +08:00
|
|
|
Host::ResolveExecutableInBundle (FileSpec &file)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-09-08 04:11:56 +08:00
|
|
|
#if defined (__APPLE__)
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-18 06:03:32 +08:00
|
|
|
if (file.GetFileType () == FileSpec::eFileTypeDirectory)
|
2010-09-08 04:11:56 +08:00
|
|
|
{
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-18 06:03:32 +08:00
|
|
|
char path[PATH_MAX];
|
|
|
|
if (file.GetPath(path, sizeof(path)))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-18 06:03:32 +08:00
|
|
|
CFCBundle bundle (path);
|
|
|
|
CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
|
|
|
|
if (url.get())
|
|
|
|
{
|
|
|
|
if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
|
|
|
|
{
|
2010-10-21 04:54:39 +08:00
|
|
|
file.SetFile(path, false);
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-18 06:03:32 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
}
|
2010-09-08 04:11:56 +08:00
|
|
|
#endif
|
|
|
|
return false;
|
2010-08-10 07:31:02 +08:00
|
|
|
}
|
2010-08-31 03:44:40 +08:00
|
|
|
|
2010-10-20 02:15:50 +08:00
|
|
|
static void *
|
|
|
|
AcceptPIDFromInferior (void *arg)
|
|
|
|
{
|
|
|
|
const char *connect_url = (const char *)arg;
|
2010-10-20 01:03:58 +08:00
|
|
|
ConnectionFileDescriptor file_conn;
|
2010-10-20 02:15:50 +08:00
|
|
|
Error error;
|
|
|
|
if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
|
2010-10-20 01:03:58 +08:00
|
|
|
{
|
|
|
|
char pid_str[256];
|
2011-02-05 05:13:05 +08:00
|
|
|
::memset (pid_str, 0, sizeof(pid_str));
|
2010-10-20 01:03:58 +08:00
|
|
|
ConnectionStatus status;
|
2012-04-03 15:51:16 +08:00
|
|
|
const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL);
|
2010-10-20 01:03:58 +08:00
|
|
|
if (pid_str_len > 0)
|
|
|
|
{
|
2010-10-20 02:15:50 +08:00
|
|
|
int pid = atoi (pid_str);
|
|
|
|
return (void *)(intptr_t)pid;
|
2010-10-20 01:03:58 +08:00
|
|
|
}
|
|
|
|
}
|
2010-10-20 02:15:50 +08:00
|
|
|
return NULL;
|
2010-10-20 01:03:58 +08:00
|
|
|
}
|
|
|
|
|
2010-10-20 02:15:50 +08:00
|
|
|
static bool
|
|
|
|
WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
|
|
|
|
{
|
|
|
|
const int time_delta_usecs = 100000;
|
|
|
|
const int num_retries = timeout_in_seconds/time_delta_usecs;
|
|
|
|
for (int i=0; i<num_retries; i++)
|
|
|
|
{
|
|
|
|
struct proc_bsdinfo bsd_info;
|
|
|
|
int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
|
|
|
|
(uint64_t) 0,
|
|
|
|
&bsd_info,
|
|
|
|
PROC_PIDTBSDINFO_SIZE);
|
|
|
|
|
|
|
|
switch (error)
|
|
|
|
{
|
|
|
|
case EINVAL:
|
|
|
|
case ENOTSUP:
|
|
|
|
case ESRCH:
|
|
|
|
case EPERM:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
if (bsd_info.pbi_status == SSTOP)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
::usleep (time_delta_usecs);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-09 09:29:05 +08:00
|
|
|
#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
|
2010-10-20 02:15:50 +08:00
|
|
|
|
2012-07-17 11:23:13 +08:00
|
|
|
//static lldb::pid_t
|
|
|
|
//LaunchInNewTerminalWithCommandFile
|
|
|
|
//(
|
|
|
|
// const char **argv,
|
|
|
|
// const char **envp,
|
|
|
|
// const char *working_dir,
|
|
|
|
// const ArchSpec *arch_spec,
|
|
|
|
// bool stop_at_entry,
|
|
|
|
// bool disable_aslr
|
|
|
|
//)
|
|
|
|
//{
|
|
|
|
// if (!argv || !argv[0])
|
|
|
|
// return LLDB_INVALID_PROCESS_ID;
|
|
|
|
//
|
|
|
|
// OSStatus error = 0;
|
|
|
|
//
|
|
|
|
// FileSpec program (argv[0], false);
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// std::string unix_socket_name;
|
|
|
|
//
|
|
|
|
// char temp_file_path[PATH_MAX];
|
|
|
|
// const char *tmpdir = ::getenv ("TMPDIR");
|
|
|
|
// if (tmpdir == NULL)
|
|
|
|
// tmpdir = "/tmp/";
|
|
|
|
// ::snprintf (temp_file_path, sizeof(temp_file_path), "%s%s-XXXXXX", tmpdir, program.GetFilename().AsCString());
|
|
|
|
//
|
|
|
|
// if (::mktemp (temp_file_path) == NULL)
|
|
|
|
// return LLDB_INVALID_PROCESS_ID;
|
|
|
|
//
|
|
|
|
// unix_socket_name.assign (temp_file_path);
|
|
|
|
//
|
|
|
|
// ::strlcat (temp_file_path, ".command", sizeof (temp_file_path));
|
|
|
|
//
|
|
|
|
// StreamFile command_file;
|
|
|
|
// command_file.GetFile().Open (temp_file_path,
|
|
|
|
// File::eOpenOptionWrite | File::eOpenOptionCanCreate,
|
2013-11-21 05:07:01 +08:00
|
|
|
// lldb::eFilePermissionsDefault);
|
2012-07-17 11:23:13 +08:00
|
|
|
//
|
|
|
|
// if (!command_file.GetFile().IsValid())
|
|
|
|
// return LLDB_INVALID_PROCESS_ID;
|
|
|
|
//
|
|
|
|
// FileSpec darwin_debug_file_spec;
|
2014-08-22 01:29:12 +08:00
|
|
|
// if (!HostInfo::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec))
|
2012-07-17 11:23:13 +08:00
|
|
|
// return LLDB_INVALID_PROCESS_ID;
|
|
|
|
// darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// if (!darwin_debug_file_spec.Exists())
|
|
|
|
// return LLDB_INVALID_PROCESS_ID;
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// char launcher_path[PATH_MAX];
|
|
|
|
// darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
|
|
|
|
// command_file.Printf("\"%s\" ", launcher_path);
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// command_file.Printf("--unix-socket=%s ", unix_socket_name.c_str());
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// if (arch_spec && arch_spec->IsValid())
|
|
|
|
// {
|
|
|
|
// command_file.Printf("--arch=%s ", arch_spec->GetArchitectureName());
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if (disable_aslr)
|
|
|
|
// {
|
|
|
|
// command_file.PutCString("--disable-aslr ");
|
|
|
|
// }
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// command_file.PutCString("-- ");
|
|
|
|
//
|
|
|
|
// if (argv)
|
|
|
|
// {
|
|
|
|
// for (size_t i=0; argv[i] != NULL; ++i)
|
|
|
|
// {
|
|
|
|
// command_file.Printf("\"%s\" ", argv[i]);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// command_file.PutCString("\necho Process exited with status $?\n");
|
|
|
|
// command_file.GetFile().Close();
|
|
|
|
// if (::chmod (temp_file_path, S_IRWXU | S_IRWXG) != 0)
|
|
|
|
// return LLDB_INVALID_PROCESS_ID;
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// CFCMutableDictionary cf_env_dict;
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// const bool can_create = true;
|
|
|
|
// if (envp)
|
|
|
|
// {
|
|
|
|
// for (size_t i=0; envp[i] != NULL; ++i)
|
|
|
|
// {
|
2014-08-22 01:29:12 +08:00
|
|
|
// const char *env_entry = envp[i];
|
2012-07-17 11:23:13 +08:00
|
|
|
// const char *equal_pos = strchr(env_entry, '=');
|
|
|
|
// if (equal_pos)
|
|
|
|
// {
|
|
|
|
// std::string env_key (env_entry, equal_pos);
|
|
|
|
// std::string env_val (equal_pos + 1);
|
|
|
|
// CFCString cf_env_key (env_key.c_str(), kCFStringEncodingUTF8);
|
|
|
|
// CFCString cf_env_val (env_val.c_str(), kCFStringEncodingUTF8);
|
|
|
|
// cf_env_dict.AddValue (cf_env_key.get(), cf_env_val.get(), can_create);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// LSApplicationParameters app_params;
|
|
|
|
// ::memset (&app_params, 0, sizeof (app_params));
|
|
|
|
// app_params.flags = kLSLaunchDontAddToRecents | kLSLaunchAsync;
|
|
|
|
// app_params.argv = NULL;
|
|
|
|
// app_params.environment = (CFDictionaryRef)cf_env_dict.get();
|
|
|
|
//
|
2014-08-22 01:29:12 +08:00
|
|
|
// CFCReleaser<CFURLRef> command_file_url (::CFURLCreateFromFileSystemRepresentation (NULL,
|
|
|
|
// (const UInt8 *)temp_file_path,
|
2012-07-17 11:23:13 +08:00
|
|
|
// strlen(temp_file_path),
|
|
|
|
// false));
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// CFCMutableArray urls;
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// // Terminal.app will open the ".command" file we have created
|
|
|
|
// // and run our process inside it which will wait at the entry point
|
|
|
|
// // for us to attach.
|
|
|
|
// urls.AppendValue(command_file_url.get());
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
|
|
|
|
//
|
|
|
|
// Error lldb_error;
|
|
|
|
// // Sleep and wait a bit for debugserver to start to listen...
|
|
|
|
// char connect_url[128];
|
|
|
|
// ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name.c_str());
|
|
|
|
//
|
|
|
|
// // Spawn a new thread to accept incoming connection on the connect_url
|
|
|
|
// // so we can grab the pid from the inferior
|
|
|
|
// lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name.c_str(),
|
|
|
|
// AcceptPIDFromInferior,
|
|
|
|
// connect_url,
|
|
|
|
// &lldb_error);
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// ProcessSerialNumber psn;
|
|
|
|
// error = LSOpenURLsWithRole(urls.get(), kLSRolesShell, NULL, &app_params, &psn, 1);
|
|
|
|
// if (error == noErr)
|
|
|
|
// {
|
|
|
|
// thread_result_t accept_thread_result = NULL;
|
|
|
|
// if (Host::ThreadJoin (accept_thread, &accept_thread_result, &lldb_error))
|
|
|
|
// {
|
|
|
|
// if (accept_thread_result)
|
|
|
|
// {
|
|
|
|
// pid = (intptr_t)accept_thread_result;
|
2014-08-22 01:29:12 +08:00
|
|
|
//
|
2012-07-17 11:23:13 +08:00
|
|
|
// // Wait for process to be stopped the the entry point by watching
|
|
|
|
// // for the process status to be set to SSTOP which indicates it it
|
|
|
|
// // SIGSTOP'ed at the entry point
|
|
|
|
// WaitForProcessToSIGSTOP (pid, 5);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// else
|
|
|
|
// {
|
|
|
|
// Host::ThreadCancel (accept_thread, &lldb_error);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// return pid;
|
|
|
|
//}
|
2010-10-20 02:15:50 +08:00
|
|
|
|
2010-10-20 07:16:00 +08:00
|
|
|
const char *applscript_in_new_tty =
|
|
|
|
"tell application \"Terminal\"\n"
|
|
|
|
" do script \"%s\"\n"
|
|
|
|
"end tell\n";
|
|
|
|
|
|
|
|
|
|
|
|
const char *applscript_in_existing_tty = "\
|
|
|
|
set the_shell_script to \"%s\"\n\
|
|
|
|
tell application \"Terminal\"\n\
|
|
|
|
repeat with the_window in (get windows)\n\
|
|
|
|
repeat with the_tab in tabs of the_window\n\
|
|
|
|
set the_tty to tty in the_tab\n\
|
|
|
|
if the_tty contains \"%s\" then\n\
|
|
|
|
if the_tab is not busy then\n\
|
|
|
|
set selected of the_tab to true\n\
|
|
|
|
set frontmost of the_window to true\n\
|
|
|
|
do script the_shell_script in the_tab\n\
|
|
|
|
return\n\
|
|
|
|
end if\n\
|
|
|
|
end if\n\
|
|
|
|
end repeat\n\
|
|
|
|
end repeat\n\
|
|
|
|
do script the_shell_script\n\
|
|
|
|
end tell\n";
|
2010-10-20 02:15:50 +08:00
|
|
|
|
2011-11-08 10:43:13 +08:00
|
|
|
|
|
|
|
static Error
|
|
|
|
LaunchInNewTerminalWithAppleScript (const char *exe_path, ProcessLaunchInfo &launch_info)
|
|
|
|
{
|
|
|
|
Error error;
|
2011-04-12 13:54:46 +08:00
|
|
|
char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
|
|
|
|
if (::mktemp (unix_socket_name) == NULL)
|
|
|
|
{
|
|
|
|
error.SetErrorString ("failed to make temporary path for a unix socket");
|
|
|
|
return error;
|
|
|
|
}
|
2010-10-20 02:15:50 +08:00
|
|
|
|
|
|
|
StreamString command;
|
|
|
|
FileSpec darwin_debug_file_spec;
|
2014-08-22 01:29:12 +08:00
|
|
|
if (!HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, darwin_debug_file_spec))
|
2011-04-12 13:54:46 +08:00
|
|
|
{
|
|
|
|
error.SetErrorString ("can't locate the 'darwin-debug' executable");
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2010-10-20 02:15:50 +08:00
|
|
|
darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
|
|
|
|
|
|
|
|
if (!darwin_debug_file_spec.Exists())
|
2011-04-12 13:54:46 +08:00
|
|
|
{
|
2013-04-30 01:25:54 +08:00
|
|
|
error.SetErrorStringWithFormat ("the 'darwin-debug' executable doesn't exists at '%s'",
|
|
|
|
darwin_debug_file_spec.GetPath().c_str());
|
2011-04-12 13:54:46 +08:00
|
|
|
return error;
|
|
|
|
}
|
2010-10-20 02:15:50 +08:00
|
|
|
|
|
|
|
char launcher_path[PATH_MAX];
|
|
|
|
darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
|
2010-10-20 07:16:00 +08:00
|
|
|
|
2011-04-12 13:54:46 +08:00
|
|
|
const ArchSpec &arch_spec = launch_info.GetArchitecture();
|
2015-01-06 08:25:18 +08:00
|
|
|
// Only set the architecture if it is valid and if it isn't Haswell (x86_64h).
|
|
|
|
if (arch_spec.IsValid() && arch_spec.GetCore() != ArchSpec::eCore_x86_64_x86_64h)
|
2011-04-12 13:54:46 +08:00
|
|
|
command.Printf("arch -arch %s ", arch_spec.GetArchitectureName());
|
2010-11-08 11:06:10 +08:00
|
|
|
|
2011-04-12 13:54:46 +08:00
|
|
|
command.Printf("'%s' --unix-socket=%s", launcher_path, unix_socket_name);
|
2010-10-20 02:15:50 +08:00
|
|
|
|
2011-04-12 13:54:46 +08:00
|
|
|
if (arch_spec.IsValid())
|
|
|
|
command.Printf(" --arch=%s", arch_spec.GetArchitectureName());
|
2010-10-20 02:15:50 +08:00
|
|
|
|
2011-04-12 13:54:46 +08:00
|
|
|
const char *working_dir = launch_info.GetWorkingDirectory();
|
Added a new variant of SBTarget::Launch() that deprectates the old one that
takes separate file handles for stdin, stdout, and stder and also allows for
the working directory to be specified.
Added support to "process launch" to a new option: --working-dir=PATH. We
can now set the working directory. If this is not set, it defaults to that
of the process that has LLDB loaded. Added the working directory to the
host LaunchInNewTerminal function to allows the current working directory
to be set in processes that are spawned in their own terminal. Also hooked this
up to the lldb_private::Process and all mac plug-ins. The linux plug-in had its
API changed, but nothing is making use of it yet. Modfied "debugserver" and
"darwin-debug" to also handle the current working directory options and modified
the code in LLDB that spawns these tools to pass the info along.
Fixed ProcessGDBRemote to properly pass along all file handles for stdin, stdout
and stderr.
After clearing the default values for the stdin/out/err file handles for
process to be NULL, we had a crasher in UserSettingsController::UpdateStringVariable
which is now fixed. Also fixed the setting of boolean values to be able to
be set as "true", "yes", "on", "1" for true (case insensitive) and "false", "no",
"off", or "0" for false.
Fixed debugserver to properly handle files for STDIN, STDOUT and STDERR that are not
already opened. Previous to this fix debugserver would only correctly open and dupe
file handles for the slave side of a pseudo terminal. It now correctly handles
getting STDIN for the inferior from a file, and spitting STDOUT and STDERR out to
files. Also made sure the file handles were correctly opened with the NOCTTY flag
for terminals.
llvm-svn: 124060
2011-01-23 13:56:20 +08:00
|
|
|
if (working_dir)
|
|
|
|
command.Printf(" --working-dir '%s'", working_dir);
|
2013-06-07 06:23:02 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
char cwd[PATH_MAX];
|
|
|
|
if (getcwd(cwd, PATH_MAX))
|
|
|
|
command.Printf(" --working-dir '%s'", cwd);
|
|
|
|
}
|
Added a new variant of SBTarget::Launch() that deprectates the old one that
takes separate file handles for stdin, stdout, and stder and also allows for
the working directory to be specified.
Added support to "process launch" to a new option: --working-dir=PATH. We
can now set the working directory. If this is not set, it defaults to that
of the process that has LLDB loaded. Added the working directory to the
host LaunchInNewTerminal function to allows the current working directory
to be set in processes that are spawned in their own terminal. Also hooked this
up to the lldb_private::Process and all mac plug-ins. The linux plug-in had its
API changed, but nothing is making use of it yet. Modfied "debugserver" and
"darwin-debug" to also handle the current working directory options and modified
the code in LLDB that spawns these tools to pass the info along.
Fixed ProcessGDBRemote to properly pass along all file handles for stdin, stdout
and stderr.
After clearing the default values for the stdin/out/err file handles for
process to be NULL, we had a crasher in UserSettingsController::UpdateStringVariable
which is now fixed. Also fixed the setting of boolean values to be able to
be set as "true", "yes", "on", "1" for true (case insensitive) and "false", "no",
"off", or "0" for false.
Fixed debugserver to properly handle files for STDIN, STDOUT and STDERR that are not
already opened. Previous to this fix debugserver would only correctly open and dupe
file handles for the slave side of a pseudo terminal. It now correctly handles
getting STDIN for the inferior from a file, and spitting STDOUT and STDERR out to
files. Also made sure the file handles were correctly opened with the NOCTTY flag
for terminals.
llvm-svn: 124060
2011-01-23 13:56:20 +08:00
|
|
|
|
2011-04-12 13:54:46 +08:00
|
|
|
if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR))
|
2010-10-20 02:15:50 +08:00
|
|
|
command.PutCString(" --disable-aslr");
|
2011-11-08 10:43:13 +08:00
|
|
|
|
2014-07-02 05:22:11 +08:00
|
|
|
// We are launching on this host in a terminal. So compare the environment on the host
|
|
|
|
// to what is supplied in the launch_info. Any items that aren't in the host environment
|
2013-04-25 01:53:59 +08:00
|
|
|
// need to be sent to darwin-debug. If we send all environment entries, we might blow the
|
|
|
|
// max command line length, so we only send user modified entries.
|
|
|
|
const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector ();
|
2015-01-07 07:33:34 +08:00
|
|
|
|
2013-04-25 01:53:59 +08:00
|
|
|
StringList host_env;
|
|
|
|
const size_t host_env_count = Host::GetEnvironment (host_env);
|
2015-01-07 07:33:34 +08:00
|
|
|
|
|
|
|
if (envp && envp[0])
|
2013-04-25 01:53:59 +08:00
|
|
|
{
|
2015-01-07 07:33:34 +08:00
|
|
|
const char *env_entry;
|
|
|
|
for (size_t env_idx = 0; (env_entry = envp[env_idx]) != NULL; ++env_idx)
|
2013-04-25 01:53:59 +08:00
|
|
|
{
|
2015-01-07 07:33:34 +08:00
|
|
|
bool add_entry = true;
|
|
|
|
for (size_t i=0; i<host_env_count; ++i)
|
|
|
|
{
|
|
|
|
const char *host_env_entry = host_env.GetStringAtIndex(i);
|
|
|
|
if (strcmp(env_entry, host_env_entry) == 0)
|
|
|
|
{
|
|
|
|
add_entry = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (add_entry)
|
2013-04-25 01:53:59 +08:00
|
|
|
{
|
2015-01-07 07:33:34 +08:00
|
|
|
command.Printf(" --env='%s'", env_entry);
|
2013-04-25 01:53:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-15 11:53:30 +08:00
|
|
|
command.PutCString(" -- ");
|
|
|
|
|
|
|
|
const char **argv = launch_info.GetArguments().GetConstArgumentVector ();
|
|
|
|
if (argv)
|
2010-10-20 02:15:50 +08:00
|
|
|
{
|
2011-11-15 11:53:30 +08:00
|
|
|
for (size_t i=0; argv[i] != NULL; ++i)
|
2011-11-08 10:43:13 +08:00
|
|
|
{
|
2011-11-15 11:53:30 +08:00
|
|
|
if (i==0)
|
|
|
|
command.Printf(" '%s'", exe_path);
|
|
|
|
else
|
|
|
|
command.Printf(" '%s'", argv[i]);
|
2011-11-08 10:43:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-11-15 11:53:30 +08:00
|
|
|
command.Printf(" '%s'", exe_path);
|
2010-10-20 02:15:50 +08:00
|
|
|
}
|
2010-10-20 07:16:00 +08:00
|
|
|
command.PutCString (" ; echo Process exited with status $?");
|
2015-02-11 12:51:41 +08:00
|
|
|
if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit))
|
|
|
|
command.PutCString (" ; exit");
|
2010-10-20 07:16:00 +08:00
|
|
|
|
|
|
|
StreamString applescript_source;
|
|
|
|
|
2010-11-08 11:06:10 +08:00
|
|
|
const char *tty_command = command.GetString().c_str();
|
2011-04-12 13:54:46 +08:00
|
|
|
// if (tty_name && tty_name[0])
|
|
|
|
// {
|
|
|
|
// applescript_source.Printf (applscript_in_existing_tty,
|
|
|
|
// tty_command,
|
|
|
|
// tty_name);
|
|
|
|
// }
|
|
|
|
// else
|
|
|
|
// {
|
2010-10-20 07:16:00 +08:00
|
|
|
applescript_source.Printf (applscript_in_new_tty,
|
2010-11-08 11:06:10 +08:00
|
|
|
tty_command);
|
2011-04-12 13:54:46 +08:00
|
|
|
// }
|
2010-10-20 07:16:00 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char *script_source = applescript_source.GetString().c_str();
|
|
|
|
//puts (script_source);
|
2010-10-20 02:15:50 +08:00
|
|
|
NSAppleScript* applescript = [[NSAppleScript alloc] initWithSource:[NSString stringWithCString:script_source encoding:NSUTF8StringEncoding]];
|
|
|
|
|
|
|
|
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
|
|
|
|
|
|
|
|
Error lldb_error;
|
|
|
|
// Sleep and wait a bit for debugserver to start to listen...
|
|
|
|
ConnectionFileDescriptor file_conn;
|
|
|
|
char connect_url[128];
|
2011-04-12 13:54:46 +08:00
|
|
|
::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
|
2010-10-20 02:15:50 +08:00
|
|
|
|
|
|
|
// Spawn a new thread to accept incoming connection on the connect_url
|
2011-04-12 13:54:46 +08:00
|
|
|
// so we can grab the pid from the inferior. We have to do this because we
|
|
|
|
// are sending an AppleScript that will launch a process in Terminal.app,
|
|
|
|
// in a shell and the shell will fork/exec a couple of times before we get
|
|
|
|
// to the process that we wanted to launch. So when our process actually
|
|
|
|
// gets launched, we will handshake with it and get the process ID for it.
|
2014-09-10 04:54:56 +08:00
|
|
|
HostThread accept_thread = ThreadLauncher::LaunchThread(unix_socket_name, AcceptPIDFromInferior, connect_url, &lldb_error);
|
2010-10-20 02:15:50 +08:00
|
|
|
|
|
|
|
[applescript executeAndReturnError:nil];
|
|
|
|
|
|
|
|
thread_result_t accept_thread_result = NULL;
|
2014-09-10 04:54:56 +08:00
|
|
|
lldb_error = accept_thread.Join(&accept_thread_result);
|
|
|
|
if (lldb_error.Success() && accept_thread_result)
|
2010-10-20 02:15:50 +08:00
|
|
|
{
|
2014-09-10 04:54:56 +08:00
|
|
|
pid = (intptr_t)accept_thread_result;
|
|
|
|
|
|
|
|
// Wait for process to be stopped at the entry point by watching
|
|
|
|
// for the process status to be set to SSTOP which indicates it it
|
|
|
|
// SIGSTOP'ed at the entry point
|
|
|
|
WaitForProcessToSIGSTOP(pid, 5);
|
2010-10-20 02:15:50 +08:00
|
|
|
}
|
2014-09-10 04:54:56 +08:00
|
|
|
|
|
|
|
FileSystem::Unlink(unix_socket_name);
|
2010-10-20 02:15:50 +08:00
|
|
|
[applescript release];
|
2011-04-12 13:54:46 +08:00
|
|
|
if (pid != LLDB_INVALID_PROCESS_ID)
|
|
|
|
launch_info.SetProcessID (pid);
|
|
|
|
return error;
|
2010-10-01 05:49:03 +08:00
|
|
|
}
|
2010-10-20 02:15:50 +08:00
|
|
|
|
2014-07-09 09:29:05 +08:00
|
|
|
#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
|
2011-11-04 11:34:56 +08:00
|
|
|
|
2010-10-20 02:15:50 +08:00
|
|
|
|
2010-11-10 12:57:04 +08:00
|
|
|
// On MacOSX CrashReporter will display a string for each shared library if
|
|
|
|
// the shared library has an exported symbol named "__crashreporter_info__".
|
|
|
|
|
|
|
|
static Mutex&
|
|
|
|
GetCrashReporterMutex ()
|
|
|
|
{
|
|
|
|
static Mutex g_mutex;
|
|
|
|
return g_mutex;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
const char *__crashreporter_info__ = NULL;
|
2011-05-20 12:04:17 +08:00
|
|
|
}
|
2010-11-10 12:57:04 +08:00
|
|
|
|
|
|
|
asm(".desc ___crashreporter_info__, 0x10");
|
|
|
|
|
|
|
|
void
|
|
|
|
Host::SetCrashDescriptionWithFormat (const char *format, ...)
|
|
|
|
{
|
|
|
|
static StreamString g_crash_description;
|
|
|
|
Mutex::Locker locker (GetCrashReporterMutex ());
|
|
|
|
|
|
|
|
if (format)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start (args, format);
|
2010-11-11 03:43:40 +08:00
|
|
|
g_crash_description.GetString().clear();
|
2010-11-10 12:57:04 +08:00
|
|
|
g_crash_description.PrintfVarArg(format, args);
|
|
|
|
va_end (args);
|
|
|
|
__crashreporter_info__ = g_crash_description.GetData();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
__crashreporter_info__ = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Host::SetCrashDescription (const char *cstr)
|
|
|
|
{
|
|
|
|
Mutex::Locker locker (GetCrashReporterMutex ());
|
2011-11-11 02:31:53 +08:00
|
|
|
static std::string g_crash_description;
|
|
|
|
if (cstr)
|
|
|
|
{
|
|
|
|
g_crash_description.assign (cstr);
|
|
|
|
__crashreporter_info__ = g_crash_description.c_str();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
__crashreporter_info__ = NULL;
|
|
|
|
}
|
2010-11-10 12:57:04 +08:00
|
|
|
}
|
2010-10-01 05:49:03 +08:00
|
|
|
|
2010-08-31 03:44:40 +08:00
|
|
|
bool
|
2010-10-01 05:49:03 +08:00
|
|
|
Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
|
2010-08-31 03:44:40 +08:00
|
|
|
{
|
2014-07-09 09:29:05 +08:00
|
|
|
#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
|
2011-11-04 11:34:56 +08:00
|
|
|
return false;
|
|
|
|
#else
|
2010-08-31 03:44:40 +08:00
|
|
|
// We attach this to an 'odoc' event to specify a particular selection
|
|
|
|
typedef struct {
|
2010-08-31 06:00:34 +08:00
|
|
|
int16_t reserved0; // must be zero
|
|
|
|
int16_t fLineNumber;
|
|
|
|
int32_t fSelStart;
|
|
|
|
int32_t fSelEnd;
|
|
|
|
uint32_t reserved1; // must be zero
|
|
|
|
uint32_t reserved2; // must be zero
|
2010-08-31 03:44:40 +08:00
|
|
|
} BabelAESelInfo;
|
|
|
|
|
2013-03-28 07:08:40 +08:00
|
|
|
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST));
|
2010-08-31 03:44:40 +08:00
|
|
|
char file_path[PATH_MAX];
|
|
|
|
file_spec.GetPath(file_path, PATH_MAX);
|
|
|
|
CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
|
2010-08-31 06:00:34 +08:00
|
|
|
CFCReleaser<CFURLRef> file_URL (::CFURLCreateWithFileSystemPath (NULL,
|
|
|
|
file_cfstr.get(),
|
|
|
|
kCFURLPOSIXPathStyle,
|
|
|
|
false));
|
2010-09-01 02:05:13 +08:00
|
|
|
|
|
|
|
if (log)
|
|
|
|
log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no);
|
2010-08-31 06:00:34 +08:00
|
|
|
|
2011-12-15 11:14:23 +08:00
|
|
|
long error;
|
2010-08-31 06:00:34 +08:00
|
|
|
BabelAESelInfo file_and_line_info =
|
|
|
|
{
|
2012-02-22 02:37:14 +08:00
|
|
|
0, // reserved0
|
|
|
|
(int16_t)(line_no - 1), // fLineNumber (zero based line number)
|
|
|
|
1, // fSelStart
|
|
|
|
1024, // fSelEnd
|
|
|
|
0, // reserved1
|
|
|
|
0 // reserved2
|
2010-08-31 06:00:34 +08:00
|
|
|
};
|
2010-08-31 03:44:40 +08:00
|
|
|
|
|
|
|
AEKeyDesc file_and_line_desc;
|
|
|
|
|
2010-08-31 06:00:34 +08:00
|
|
|
error = ::AECreateDesc (typeUTF8Text,
|
|
|
|
&file_and_line_info,
|
|
|
|
sizeof (file_and_line_info),
|
|
|
|
&(file_and_line_desc.descContent));
|
2010-08-31 03:44:40 +08:00
|
|
|
|
|
|
|
if (error != noErr)
|
|
|
|
{
|
2010-09-01 02:05:13 +08:00
|
|
|
if (log)
|
2011-12-15 11:14:23 +08:00
|
|
|
log->Printf("Error creating AEDesc: %ld.\n", error);
|
2010-08-31 03:44:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
file_and_line_desc.descKey = keyAEPosition;
|
|
|
|
|
2010-09-01 02:56:24 +08:00
|
|
|
static std::string g_app_name;
|
2010-09-01 02:35:14 +08:00
|
|
|
static FSRef g_app_fsref;
|
|
|
|
|
2010-08-31 03:44:40 +08:00
|
|
|
LSApplicationParameters app_params;
|
2011-02-05 05:13:05 +08:00
|
|
|
::memset (&app_params, 0, sizeof (app_params));
|
2010-08-31 06:00:34 +08:00
|
|
|
app_params.flags = kLSLaunchDefaults |
|
|
|
|
kLSLaunchDontAddToRecents |
|
|
|
|
kLSLaunchDontSwitch;
|
2010-09-01 02:35:14 +08:00
|
|
|
|
2010-08-31 07:48:25 +08:00
|
|
|
char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR");
|
|
|
|
|
2010-09-01 02:35:14 +08:00
|
|
|
if (external_editor)
|
2010-08-31 07:48:25 +08:00
|
|
|
{
|
2010-09-01 02:05:13 +08:00
|
|
|
if (log)
|
|
|
|
log->Printf("Looking for external editor \"%s\".\n", external_editor);
|
|
|
|
|
2010-09-01 02:56:24 +08:00
|
|
|
if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0)
|
2010-08-31 07:48:25 +08:00
|
|
|
{
|
|
|
|
CFCString editor_name (external_editor, kCFStringEncodingUTF8);
|
2010-09-01 02:35:14 +08:00
|
|
|
error = ::LSFindApplicationForInfo (kLSUnknownCreator,
|
|
|
|
NULL,
|
|
|
|
editor_name.get(),
|
|
|
|
&g_app_fsref,
|
|
|
|
NULL);
|
2010-08-31 07:48:25 +08:00
|
|
|
|
|
|
|
// If we found the app, then store away the name so we don't have to re-look it up.
|
2010-09-01 02:35:14 +08:00
|
|
|
if (error != noErr)
|
2010-09-01 02:05:13 +08:00
|
|
|
{
|
|
|
|
if (log)
|
2011-12-15 11:14:23 +08:00
|
|
|
log->Printf("Could not find External Editor application, error: %ld.\n", error);
|
2010-08-31 07:48:25 +08:00
|
|
|
return false;
|
2010-09-01 02:05:13 +08:00
|
|
|
}
|
2010-08-31 07:48:25 +08:00
|
|
|
|
|
|
|
}
|
2010-09-01 02:35:14 +08:00
|
|
|
app_params.application = &g_app_fsref;
|
2010-08-31 07:48:25 +08:00
|
|
|
}
|
|
|
|
|
2010-08-31 03:44:40 +08:00
|
|
|
ProcessSerialNumber psn;
|
|
|
|
CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
|
2010-08-31 06:00:34 +08:00
|
|
|
error = ::LSOpenURLsWithRole (file_array.get(),
|
2010-08-31 07:48:25 +08:00
|
|
|
kLSRolesAll,
|
2010-08-31 06:00:34 +08:00
|
|
|
&file_and_line_desc,
|
|
|
|
&app_params,
|
|
|
|
&psn,
|
|
|
|
1);
|
|
|
|
|
2010-08-31 03:44:40 +08:00
|
|
|
AEDisposeDesc (&(file_and_line_desc.descContent));
|
|
|
|
|
|
|
|
if (error != noErr)
|
|
|
|
{
|
2010-09-01 02:05:13 +08:00
|
|
|
if (log)
|
2011-12-15 11:14:23 +08:00
|
|
|
log->Printf("LSOpenURLsWithRole failed, error: %ld.\n", error);
|
2010-09-01 02:05:13 +08:00
|
|
|
|
2010-08-31 03:44:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2014-07-09 09:29:05 +08:00
|
|
|
#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
|
2010-08-31 03:44:40 +08:00
|
|
|
}
|
2010-12-03 14:02:24 +08:00
|
|
|
|
2010-12-04 08:10:17 +08:00
|
|
|
size_t
|
|
|
|
Host::GetEnvironment (StringList &env)
|
|
|
|
{
|
|
|
|
char **host_env = *_NSGetEnviron();
|
|
|
|
char *env_entry;
|
|
|
|
size_t i;
|
|
|
|
for (i=0; (env_entry = host_env[i]) != NULL; ++i)
|
|
|
|
env.AppendString(env_entry);
|
|
|
|
return i;
|
|
|
|
|
|
|
|
}
|
2011-03-19 09:12:21 +08:00
|
|
|
|
2011-03-22 05:25:07 +08:00
|
|
|
static bool
|
2011-04-12 13:54:46 +08:00
|
|
|
GetMacOSXProcessCPUType (ProcessInstanceInfo &process_info)
|
2011-03-22 05:25:07 +08:00
|
|
|
{
|
|
|
|
if (process_info.ProcessIDIsValid())
|
|
|
|
{
|
|
|
|
// Make a new mib to stay thread safe
|
|
|
|
int mib[CTL_MAXNAME]={0,};
|
|
|
|
size_t mib_len = CTL_MAXNAME;
|
|
|
|
if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
mib[mib_len] = process_info.GetProcessID();
|
|
|
|
mib_len++;
|
2014-03-30 02:54:20 +08:00
|
|
|
|
2011-08-12 08:21:20 +08:00
|
|
|
cpu_type_t cpu, sub = 0;
|
2012-09-14 10:41:36 +08:00
|
|
|
size_t len = sizeof(cpu);
|
|
|
|
if (::sysctl (mib, mib_len, &cpu, &len, 0, 0) == 0)
|
2011-03-22 05:25:07 +08:00
|
|
|
{
|
|
|
|
switch (cpu)
|
|
|
|
{
|
2013-08-27 13:04:57 +08:00
|
|
|
case CPU_TYPE_I386: sub = CPU_SUBTYPE_I386_ALL; break;
|
|
|
|
case CPU_TYPE_X86_64: sub = CPU_SUBTYPE_X86_64_ALL; break;
|
2014-03-30 02:54:20 +08:00
|
|
|
|
|
|
|
#if defined (CPU_TYPE_ARM64) && defined (CPU_SUBTYPE_ARM64_ALL)
|
|
|
|
case CPU_TYPE_ARM64: sub = CPU_SUBTYPE_ARM64_ALL; break;
|
|
|
|
#endif
|
|
|
|
|
2013-08-27 13:04:57 +08:00
|
|
|
case CPU_TYPE_ARM:
|
2012-09-14 10:41:36 +08:00
|
|
|
{
|
2014-03-30 02:54:20 +08:00
|
|
|
// Note that we fetched the cpu type from the PROCESS but we can't get a cpusubtype of the
|
|
|
|
// process -- we can only get the host's cpu subtype.
|
2012-09-14 10:41:36 +08:00
|
|
|
uint32_t cpusubtype = 0;
|
|
|
|
len = sizeof(cpusubtype);
|
|
|
|
if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
|
|
|
|
sub = cpusubtype;
|
2014-03-30 02:54:20 +08:00
|
|
|
|
|
|
|
bool host_cpu_is_64bit;
|
|
|
|
uint32_t is64bit_capable;
|
|
|
|
size_t is64bit_capable_len = sizeof (is64bit_capable);
|
|
|
|
if (sysctlbyname("hw.cpu64bit_capable", &is64bit_capable, &is64bit_capable_len, NULL, 0) == 0)
|
|
|
|
host_cpu_is_64bit = true;
|
|
|
|
else
|
|
|
|
host_cpu_is_64bit = false;
|
|
|
|
|
|
|
|
// if the host is an armv8 device, its cpusubtype will be in CPU_SUBTYPE_ARM64 numbering
|
|
|
|
// and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value instead.
|
|
|
|
|
|
|
|
if (host_cpu_is_64bit)
|
|
|
|
{
|
|
|
|
sub = CPU_SUBTYPE_ARM_V7;
|
|
|
|
}
|
2012-09-14 10:41:36 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2011-03-22 05:25:07 +08:00
|
|
|
}
|
2011-03-25 05:19:54 +08:00
|
|
|
process_info.GetArchitecture ().SetArchitecture (eArchTypeMachO, cpu, sub);
|
2011-03-22 05:25:07 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
process_info.GetArchitecture().Clear();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-04-01 08:29:43 +08:00
|
|
|
static bool
|
2011-04-12 13:54:46 +08:00
|
|
|
GetMacOSXProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
|
|
|
|
ProcessInstanceInfo &process_info)
|
2011-04-01 08:29:43 +08:00
|
|
|
{
|
|
|
|
if (process_info.ProcessIDIsValid())
|
|
|
|
{
|
2012-02-22 02:37:14 +08:00
|
|
|
int proc_args_mib[3] = { CTL_KERN, KERN_PROCARGS2, (int)process_info.GetProcessID() };
|
2011-04-01 08:29:43 +08:00
|
|
|
|
|
|
|
char arg_data[8192];
|
|
|
|
size_t arg_data_size = sizeof(arg_data);
|
|
|
|
if (::sysctl (proc_args_mib, 3, arg_data, &arg_data_size , NULL, 0) == 0)
|
|
|
|
{
|
|
|
|
DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *));
|
2013-01-26 02:06:21 +08:00
|
|
|
lldb::offset_t offset = 0;
|
2011-04-01 08:29:43 +08:00
|
|
|
uint32_t argc = data.GetU32 (&offset);
|
|
|
|
const char *cstr;
|
|
|
|
|
2014-05-30 05:33:45 +08:00
|
|
|
|
|
|
|
llvm::Triple &triple = process_info.GetArchitecture().GetTriple();
|
|
|
|
const llvm::Triple::ArchType triple_arch = triple.getArch();
|
|
|
|
const bool check_for_ios_simulator = (triple_arch == llvm::Triple::x86 || triple_arch == llvm::Triple::x86_64);
|
|
|
|
|
2011-04-01 08:29:43 +08:00
|
|
|
cstr = data.GetCStr (&offset);
|
|
|
|
if (cstr)
|
|
|
|
{
|
|
|
|
process_info.GetExecutableFile().SetFile(cstr, false);
|
|
|
|
|
|
|
|
if (match_info_ptr == NULL ||
|
|
|
|
NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
|
|
|
|
match_info_ptr->GetNameMatchType(),
|
|
|
|
match_info_ptr->GetProcessInfo().GetName()))
|
|
|
|
{
|
|
|
|
// Skip NULLs
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
const uint8_t *p = data.PeekData(offset, 1);
|
|
|
|
if ((p == NULL) || (*p != '\0'))
|
|
|
|
break;
|
|
|
|
++offset;
|
|
|
|
}
|
|
|
|
// Now extract all arguments
|
2011-04-12 13:54:46 +08:00
|
|
|
Args &proc_args = process_info.GetArguments();
|
2014-04-02 11:51:35 +08:00
|
|
|
for (int i=0; i<static_cast<int>(argc); ++i)
|
2011-04-01 08:29:43 +08:00
|
|
|
{
|
|
|
|
cstr = data.GetCStr(&offset);
|
|
|
|
if (cstr)
|
2011-04-12 13:54:46 +08:00
|
|
|
proc_args.AppendArgument(cstr);
|
2011-04-01 08:29:43 +08:00
|
|
|
}
|
2014-05-30 05:33:45 +08:00
|
|
|
|
|
|
|
Args &proc_env = process_info.GetEnvironmentEntries ();
|
|
|
|
while ((cstr = data.GetCStr(&offset)))
|
|
|
|
{
|
|
|
|
if (cstr[0] == '\0')
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (check_for_ios_simulator)
|
|
|
|
{
|
|
|
|
if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) == 0)
|
|
|
|
process_info.GetArchitecture().GetTriple().setOS(llvm::Triple::IOS);
|
2014-08-02 08:15:37 +08:00
|
|
|
else
|
|
|
|
process_info.GetArchitecture().GetTriple().setOS(llvm::Triple::MacOSX);
|
2014-05-30 05:33:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
proc_env.AppendArgument(cstr);
|
|
|
|
}
|
2011-04-01 08:29:43 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-03-22 05:25:07 +08:00
|
|
|
static bool
|
2011-04-12 13:54:46 +08:00
|
|
|
GetMacOSXProcessUserAndGroup (ProcessInstanceInfo &process_info)
|
2011-03-22 05:25:07 +08:00
|
|
|
{
|
|
|
|
if (process_info.ProcessIDIsValid())
|
|
|
|
{
|
|
|
|
int mib[4];
|
|
|
|
mib[0] = CTL_KERN;
|
|
|
|
mib[1] = KERN_PROC;
|
|
|
|
mib[2] = KERN_PROC_PID;
|
|
|
|
mib[3] = process_info.GetProcessID();
|
|
|
|
struct kinfo_proc proc_kinfo;
|
|
|
|
size_t proc_kinfo_size = sizeof(struct kinfo_proc);
|
|
|
|
|
|
|
|
if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
|
|
|
|
{
|
|
|
|
if (proc_kinfo_size > 0)
|
|
|
|
{
|
|
|
|
process_info.SetParentProcessID (proc_kinfo.kp_eproc.e_ppid);
|
2011-04-12 13:54:46 +08:00
|
|
|
process_info.SetUserID (proc_kinfo.kp_eproc.e_pcred.p_ruid);
|
|
|
|
process_info.SetGroupID (proc_kinfo.kp_eproc.e_pcred.p_rgid);
|
2011-03-22 05:25:07 +08:00
|
|
|
process_info.SetEffectiveUserID (proc_kinfo.kp_eproc.e_ucred.cr_uid);
|
|
|
|
if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
|
|
|
|
process_info.SetEffectiveGroupID (proc_kinfo.kp_eproc.e_ucred.cr_groups[0]);
|
|
|
|
else
|
|
|
|
process_info.SetEffectiveGroupID (UINT32_MAX);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
|
2011-04-12 13:54:46 +08:00
|
|
|
process_info.SetUserID (UINT32_MAX);
|
|
|
|
process_info.SetGroupID (UINT32_MAX);
|
2011-03-22 05:25:07 +08:00
|
|
|
process_info.SetEffectiveUserID (UINT32_MAX);
|
|
|
|
process_info.SetEffectiveGroupID (UINT32_MAX);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t
|
2011-04-12 13:54:46 +08:00
|
|
|
Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
|
2011-03-22 05:25:07 +08:00
|
|
|
{
|
2011-04-01 08:29:43 +08:00
|
|
|
std::vector<struct kinfo_proc> kinfos;
|
2011-03-22 05:25:07 +08:00
|
|
|
|
2011-04-01 08:29:43 +08:00
|
|
|
int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
|
2011-03-22 05:25:07 +08:00
|
|
|
|
2011-04-01 08:29:43 +08:00
|
|
|
size_t pid_data_size = 0;
|
|
|
|
if (::sysctl (mib, 4, NULL, &pid_data_size, NULL, 0) != 0)
|
2011-03-22 05:25:07 +08:00
|
|
|
return 0;
|
|
|
|
|
2011-04-01 08:29:43 +08:00
|
|
|
// Add a few extra in case a few more show up
|
|
|
|
const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
|
|
|
|
|
|
|
|
kinfos.resize (estimated_pid_count);
|
|
|
|
pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
|
|
|
|
|
|
|
|
if (::sysctl (mib, 4, &kinfos[0], &pid_data_size, NULL, 0) != 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
|
|
|
|
|
|
|
|
bool all_users = match_info.GetMatchAllUsers();
|
|
|
|
const lldb::pid_t our_pid = getpid();
|
|
|
|
const uid_t our_uid = getuid();
|
2014-04-02 11:51:35 +08:00
|
|
|
for (size_t i = 0; i < actual_pid_count; i++)
|
2011-03-22 05:25:07 +08:00
|
|
|
{
|
2011-04-01 08:29:43 +08:00
|
|
|
const struct kinfo_proc &kinfo = kinfos[i];
|
2011-03-22 05:25:07 +08:00
|
|
|
|
2011-04-01 08:29:43 +08:00
|
|
|
bool kinfo_user_matches = false;
|
|
|
|
if (all_users)
|
|
|
|
kinfo_user_matches = true;
|
|
|
|
else
|
|
|
|
kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;
|
|
|
|
|
2011-09-13 08:52:59 +08:00
|
|
|
// Special case, if lldb is being run as root we can attach to anything.
|
|
|
|
if (our_uid == 0)
|
|
|
|
kinfo_user_matches = true;
|
|
|
|
|
2011-04-01 08:29:43 +08:00
|
|
|
if (kinfo_user_matches == false || // Make sure the user is acceptable
|
2014-04-02 11:51:35 +08:00
|
|
|
static_cast<lldb::pid_t>(kinfo.kp_proc.p_pid) == our_pid || // Skip this process
|
2011-04-01 08:29:43 +08:00
|
|
|
kinfo.kp_proc.p_pid == 0 || // Skip kernel (kernel pid is zero)
|
|
|
|
kinfo.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains...
|
|
|
|
kinfo.kp_proc.p_flag & P_TRACED || // Being debugged?
|
|
|
|
kinfo.kp_proc.p_flag & P_WEXIT || // Working on exiting?
|
|
|
|
kinfo.kp_proc.p_flag & P_TRANSLATED) // Skip translated ppc (Rosetta)
|
|
|
|
continue;
|
|
|
|
|
2011-04-12 13:54:46 +08:00
|
|
|
ProcessInstanceInfo process_info;
|
2011-04-01 08:29:43 +08:00
|
|
|
process_info.SetProcessID (kinfo.kp_proc.p_pid);
|
|
|
|
process_info.SetParentProcessID (kinfo.kp_eproc.e_ppid);
|
2011-04-12 13:54:46 +08:00
|
|
|
process_info.SetUserID (kinfo.kp_eproc.e_pcred.p_ruid);
|
|
|
|
process_info.SetGroupID (kinfo.kp_eproc.e_pcred.p_rgid);
|
2011-04-01 08:29:43 +08:00
|
|
|
process_info.SetEffectiveUserID (kinfo.kp_eproc.e_ucred.cr_uid);
|
|
|
|
if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
|
|
|
|
process_info.SetEffectiveGroupID (kinfo.kp_eproc.e_ucred.cr_groups[0]);
|
|
|
|
else
|
|
|
|
process_info.SetEffectiveGroupID (UINT32_MAX);
|
|
|
|
|
|
|
|
// Make sure our info matches before we go fetch the name and cpu type
|
|
|
|
if (match_info.Matches (process_info))
|
2011-03-22 05:25:07 +08:00
|
|
|
{
|
2014-05-30 05:33:45 +08:00
|
|
|
// Get CPU type first so we can know to look for iOS simulator is we have x86 or x86_64
|
|
|
|
if (GetMacOSXProcessCPUType (process_info))
|
2011-04-01 08:29:43 +08:00
|
|
|
{
|
2014-05-30 05:33:45 +08:00
|
|
|
if (GetMacOSXProcessArgs (&match_info, process_info))
|
|
|
|
{
|
|
|
|
if (match_info.Matches (process_info))
|
|
|
|
process_infos.Append (process_info);
|
|
|
|
}
|
2011-04-01 08:29:43 +08:00
|
|
|
}
|
2011-03-22 05:25:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return process_infos.GetSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2011-04-12 13:54:46 +08:00
|
|
|
Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
|
2011-03-22 05:25:07 +08:00
|
|
|
{
|
|
|
|
process_info.SetProcessID(pid);
|
2012-02-29 08:09:16 +08:00
|
|
|
bool success = false;
|
2014-05-30 05:33:45 +08:00
|
|
|
|
|
|
|
// Get CPU type first so we can know to look for iOS simulator is we have x86 or x86_64
|
|
|
|
if (GetMacOSXProcessCPUType (process_info))
|
2012-02-29 08:09:16 +08:00
|
|
|
success = true;
|
|
|
|
|
2014-05-30 05:33:45 +08:00
|
|
|
if (GetMacOSXProcessArgs (NULL, process_info))
|
2012-02-29 08:09:16 +08:00
|
|
|
success = true;
|
|
|
|
|
|
|
|
if (GetMacOSXProcessUserAndGroup (process_info))
|
|
|
|
success = true;
|
|
|
|
|
|
|
|
if (success)
|
2011-03-22 05:25:07 +08:00
|
|
|
return true;
|
2012-02-29 08:09:16 +08:00
|
|
|
|
2011-03-22 05:25:07 +08:00
|
|
|
process_info.Clear();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-03-08 12:03:25 +08:00
|
|
|
#if !NO_XPC_SERVICES
|
2012-02-25 09:07:38 +08:00
|
|
|
static void
|
|
|
|
PackageXPCArguments (xpc_object_t message, const char *prefix, const Args& args)
|
|
|
|
{
|
|
|
|
size_t count = args.GetArgumentCount();
|
|
|
|
char buf[50]; // long enough for 'argXXX'
|
|
|
|
memset(buf, 0, 50);
|
|
|
|
sprintf(buf, "%sCount", prefix);
|
|
|
|
xpc_dictionary_set_int64(message, buf, count);
|
2014-04-02 11:51:35 +08:00
|
|
|
for (size_t i=0; i<count; i++) {
|
2012-02-25 09:07:38 +08:00
|
|
|
memset(buf, 0, 50);
|
2014-04-02 11:51:35 +08:00
|
|
|
sprintf(buf, "%s%zi", prefix, i);
|
2012-02-25 09:07:38 +08:00
|
|
|
xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i));
|
|
|
|
}
|
|
|
|
}
|
2011-04-12 13:54:46 +08:00
|
|
|
|
2012-05-09 05:32:32 +08:00
|
|
|
/*
|
|
|
|
A valid authorizationRef means that
|
|
|
|
- there is the LaunchUsingXPCRightName rights in the /etc/authorization
|
|
|
|
- we have successfully copied the rights to be send over the XPC wire
|
|
|
|
Once obtained, it will be valid for as long as the process lives.
|
|
|
|
*/
|
2012-02-28 09:18:30 +08:00
|
|
|
static AuthorizationRef authorizationRef = NULL;
|
2012-02-25 09:07:38 +08:00
|
|
|
static Error
|
|
|
|
getXPCAuthorization (ProcessLaunchInfo &launch_info)
|
|
|
|
{
|
|
|
|
Error error;
|
2013-03-28 07:08:40 +08:00
|
|
|
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
|
2011-04-12 13:54:46 +08:00
|
|
|
|
2012-05-09 05:32:32 +08:00
|
|
|
if ((launch_info.GetUserID() == 0) && !authorizationRef)
|
2012-02-25 09:07:38 +08:00
|
|
|
{
|
2012-05-09 05:32:32 +08:00
|
|
|
OSStatus createStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);
|
|
|
|
if (createStatus != errAuthorizationSuccess)
|
2012-02-25 09:07:38 +08:00
|
|
|
{
|
2012-05-09 05:32:32 +08:00
|
|
|
error.SetError(1, eErrorTypeGeneric);
|
|
|
|
error.SetErrorString("Can't create authorizationRef.");
|
|
|
|
if (log)
|
2012-02-25 09:07:38 +08:00
|
|
|
{
|
2013-03-28 07:08:40 +08:00
|
|
|
error.PutToLog(log, "%s", error.AsCString());
|
2012-02-25 09:07:38 +08:00
|
|
|
}
|
2012-05-09 05:32:32 +08:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus rightsStatus = AuthorizationRightGet(LaunchUsingXPCRightName, NULL);
|
|
|
|
if (rightsStatus != errAuthorizationSuccess)
|
|
|
|
{
|
|
|
|
// No rights in the security database, Create it with the right prompt.
|
|
|
|
CFStringRef prompt = CFSTR("Xcode is trying to take control of a root process.");
|
|
|
|
CFStringRef keys[] = { CFSTR("en") };
|
|
|
|
CFTypeRef values[] = { prompt };
|
|
|
|
CFDictionaryRef promptDict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
2012-03-15 23:37:50 +08:00
|
|
|
|
2012-05-09 05:32:32 +08:00
|
|
|
CFStringRef keys1[] = { CFSTR("class"), CFSTR("group"), CFSTR("comment"), CFSTR("default-prompt"), CFSTR("shared") };
|
|
|
|
CFTypeRef values1[] = { CFSTR("user"), CFSTR("admin"), CFSTR(LaunchUsingXPCRightName), promptDict, kCFBooleanFalse };
|
|
|
|
CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
|
|
rightsStatus = AuthorizationRightSet(authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL);
|
|
|
|
CFRelease(promptDict);
|
|
|
|
CFRelease(dict);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus copyRightStatus = errAuthorizationDenied;
|
|
|
|
if (rightsStatus == errAuthorizationSuccess)
|
|
|
|
{
|
|
|
|
AuthorizationItem item1 = { LaunchUsingXPCRightName, 0, NULL, 0 };
|
|
|
|
AuthorizationItem items[] = {item1};
|
|
|
|
AuthorizationRights requestedRights = {1, items };
|
|
|
|
AuthorizationFlags authorizationFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
|
|
|
|
copyRightStatus = AuthorizationCopyRights(authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment, authorizationFlags, NULL);
|
2012-02-25 09:07:38 +08:00
|
|
|
}
|
2012-05-09 05:32:32 +08:00
|
|
|
|
|
|
|
if (copyRightStatus != errAuthorizationSuccess)
|
2012-02-25 09:07:38 +08:00
|
|
|
{
|
|
|
|
// Eventually when the commandline supports running as root and the user is not
|
|
|
|
// logged in in the current audit session, we will need the trick in gdb where
|
|
|
|
// we ask the user to type in the root passwd in the terminal.
|
|
|
|
error.SetError(2, eErrorTypeGeneric);
|
2012-03-15 23:37:50 +08:00
|
|
|
error.SetErrorStringWithFormat("Launching as root needs root authorization.");
|
2012-02-25 09:07:38 +08:00
|
|
|
if (log)
|
|
|
|
{
|
2013-03-28 07:08:40 +08:00
|
|
|
error.PutToLog(log, "%s", error.AsCString());
|
2012-02-25 09:07:38 +08:00
|
|
|
}
|
2012-05-09 05:32:32 +08:00
|
|
|
|
|
|
|
if (authorizationRef)
|
|
|
|
{
|
|
|
|
AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
|
|
|
|
authorizationRef = NULL;
|
|
|
|
}
|
2012-02-25 09:07:38 +08:00
|
|
|
}
|
2011-04-12 13:54:46 +08:00
|
|
|
}
|
2012-02-25 09:07:38 +08:00
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static Error
|
2014-10-15 05:55:08 +08:00
|
|
|
LaunchProcessXPC(const char *exe_path, ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
|
2012-02-25 09:07:38 +08:00
|
|
|
{
|
2012-03-08 12:03:25 +08:00
|
|
|
#if !NO_XPC_SERVICES
|
2012-02-25 09:07:38 +08:00
|
|
|
Error error = getXPCAuthorization(launch_info);
|
|
|
|
if (error.Fail())
|
|
|
|
return error;
|
2011-04-12 13:54:46 +08:00
|
|
|
|
2013-03-28 07:08:40 +08:00
|
|
|
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
|
2012-12-11 07:02:33 +08:00
|
|
|
|
2012-02-25 09:07:38 +08:00
|
|
|
uid_t requested_uid = launch_info.GetUserID();
|
|
|
|
const char *xpc_service = nil;
|
2012-03-15 23:37:50 +08:00
|
|
|
bool send_auth = false;
|
|
|
|
AuthorizationExternalForm extForm;
|
2014-08-22 07:22:33 +08:00
|
|
|
if ((requested_uid == UINT32_MAX) || (requested_uid == HostInfo::GetEffectiveUserID()))
|
2011-04-12 13:54:46 +08:00
|
|
|
{
|
2012-02-25 09:07:38 +08:00
|
|
|
xpc_service = "com.apple.lldb.launcherXPCService";
|
|
|
|
}
|
|
|
|
else if (requested_uid == 0)
|
|
|
|
{
|
2012-03-15 23:37:50 +08:00
|
|
|
if (AuthorizationMakeExternalForm(authorizationRef, &extForm) == errAuthorizationSuccess)
|
|
|
|
{
|
|
|
|
send_auth = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-12-11 07:02:33 +08:00
|
|
|
error.SetError(3, eErrorTypeGeneric);
|
2012-03-15 23:37:50 +08:00
|
|
|
error.SetErrorStringWithFormat("Launching root via XPC needs to externalize authorization reference.");
|
|
|
|
if (log)
|
|
|
|
{
|
2013-03-28 07:08:40 +08:00
|
|
|
error.PutToLog(log, "%s", error.AsCString());
|
2012-03-15 23:37:50 +08:00
|
|
|
}
|
|
|
|
return error;
|
|
|
|
}
|
2012-02-25 09:07:38 +08:00
|
|
|
xpc_service = "com.apple.lldb.launcherRootXPCService";
|
2011-04-12 13:54:46 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-12-11 07:02:33 +08:00
|
|
|
error.SetError(4, eErrorTypeGeneric);
|
2012-03-15 23:37:50 +08:00
|
|
|
error.SetErrorStringWithFormat("Launching via XPC is only currently available for either the login user or root.");
|
2012-02-25 09:07:38 +08:00
|
|
|
if (log)
|
|
|
|
{
|
2013-03-28 07:08:40 +08:00
|
|
|
error.PutToLog(log, "%s", error.AsCString());
|
2012-02-25 09:07:38 +08:00
|
|
|
}
|
2011-04-12 13:54:46 +08:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2012-02-25 09:07:38 +08:00
|
|
|
xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);
|
|
|
|
|
|
|
|
xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
|
|
|
|
xpc_type_t type = xpc_get_type(event);
|
|
|
|
|
|
|
|
if (type == XPC_TYPE_ERROR) {
|
|
|
|
if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
|
2012-12-11 07:02:33 +08:00
|
|
|
// The service has either canceled itself, crashed, or been terminated.
|
2012-02-25 09:07:38 +08:00
|
|
|
// The XPC connection is still valid and sending a message to it will re-launch the service.
|
|
|
|
// If the service is state-full, this is the time to initialize the new service.
|
|
|
|
return;
|
|
|
|
} else if (event == XPC_ERROR_CONNECTION_INVALID) {
|
|
|
|
// The service is invalid. Either the service name supplied to xpc_connection_create() is incorrect
|
2014-07-02 05:22:11 +08:00
|
|
|
// or we (this process) have canceled the service; we can do any cleanup of application state at this point.
|
2012-02-25 09:07:38 +08:00
|
|
|
// printf("Service disconnected");
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
// printf("Unexpected error from service: %s", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
|
|
|
|
}
|
|
|
|
|
2012-12-11 07:02:33 +08:00
|
|
|
} else {
|
2012-02-25 09:07:38 +08:00
|
|
|
// printf("Received unexpected event in handler");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2012-12-11 07:02:33 +08:00
|
|
|
xpc_connection_set_finalizer_f (conn, xpc_finalizer_t(xpc_release));
|
2012-02-25 09:07:38 +08:00
|
|
|
xpc_connection_resume (conn);
|
|
|
|
xpc_object_t message = xpc_dictionary_create (nil, nil, 0);
|
|
|
|
|
2012-03-15 23:37:50 +08:00
|
|
|
if (send_auth)
|
|
|
|
{
|
|
|
|
xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes, sizeof(AuthorizationExternalForm));
|
|
|
|
}
|
|
|
|
|
2012-02-25 09:07:38 +08:00
|
|
|
PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey, launch_info.GetArguments());
|
|
|
|
PackageXPCArguments(message, LauncherXPCServiceEnvPrefxKey, launch_info.GetEnvironmentEntries());
|
|
|
|
|
|
|
|
// Posix spawn stuff.
|
|
|
|
xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey, launch_info.GetArchitecture().GetMachOCPUType());
|
2014-01-23 08:52:28 +08:00
|
|
|
xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey, Host::GetPosixspawnFlags(launch_info));
|
2014-08-15 00:01:25 +08:00
|
|
|
const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
|
2014-02-11 03:23:28 +08:00
|
|
|
if (file_action && file_action->GetPath())
|
|
|
|
{
|
|
|
|
xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey, file_action->GetPath());
|
|
|
|
}
|
|
|
|
file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
|
|
|
|
if (file_action && file_action->GetPath())
|
|
|
|
{
|
|
|
|
xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey, file_action->GetPath());
|
|
|
|
}
|
|
|
|
file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
|
|
|
|
if (file_action && file_action->GetPath())
|
|
|
|
{
|
|
|
|
xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey, file_action->GetPath());
|
|
|
|
}
|
2012-02-25 09:07:38 +08:00
|
|
|
|
|
|
|
xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, message);
|
2012-12-11 07:02:33 +08:00
|
|
|
xpc_type_t returnType = xpc_get_type(reply);
|
|
|
|
if (returnType == XPC_TYPE_DICTIONARY)
|
2011-04-12 13:54:46 +08:00
|
|
|
{
|
2012-12-11 07:02:33 +08:00
|
|
|
pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);
|
|
|
|
if (pid == 0)
|
2012-02-25 09:07:38 +08:00
|
|
|
{
|
2012-12-11 07:02:33 +08:00
|
|
|
int errorType = xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);
|
|
|
|
int errorCode = xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);
|
|
|
|
|
|
|
|
error.SetError(errorCode, eErrorTypeGeneric);
|
|
|
|
error.SetErrorStringWithFormat("Problems with launching via XPC. Error type : %i, code : %i", errorType, errorCode);
|
|
|
|
if (log)
|
|
|
|
{
|
2013-03-28 07:08:40 +08:00
|
|
|
error.PutToLog(log, "%s", error.AsCString());
|
2012-12-11 07:02:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (authorizationRef)
|
|
|
|
{
|
|
|
|
AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
|
|
|
|
authorizationRef = NULL;
|
|
|
|
}
|
2012-02-25 09:07:38 +08:00
|
|
|
}
|
2012-12-11 07:02:33 +08:00
|
|
|
}
|
|
|
|
else if (returnType == XPC_TYPE_ERROR)
|
|
|
|
{
|
|
|
|
error.SetError(5, eErrorTypeGeneric);
|
|
|
|
error.SetErrorStringWithFormat("Problems with launching via XPC. XPC error : %s", xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));
|
|
|
|
if (log)
|
2012-05-09 05:32:32 +08:00
|
|
|
{
|
2013-03-28 07:08:40 +08:00
|
|
|
error.PutToLog(log, "%s", error.AsCString());
|
2012-05-09 05:32:32 +08:00
|
|
|
}
|
2011-04-12 13:54:46 +08:00
|
|
|
}
|
2012-02-25 09:07:38 +08:00
|
|
|
|
2012-07-13 07:16:43 +08:00
|
|
|
return error;
|
|
|
|
#else
|
|
|
|
Error error;
|
2012-02-25 09:07:38 +08:00
|
|
|
return error;
|
2012-03-08 12:03:25 +08:00
|
|
|
#endif
|
2012-02-25 09:07:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2013-12-19 08:35:40 +08:00
|
|
|
ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info)
|
2012-02-25 09:07:38 +08:00
|
|
|
{
|
|
|
|
bool result = false;
|
|
|
|
|
2012-03-08 12:03:25 +08:00
|
|
|
#if !NO_XPC_SERVICES
|
2013-12-19 08:35:40 +08:00
|
|
|
bool launchingAsRoot = launch_info.GetUserID() == 0;
|
2014-08-22 07:22:33 +08:00
|
|
|
bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0;
|
2013-12-19 08:35:40 +08:00
|
|
|
|
|
|
|
if (launchingAsRoot && !currentUserIsRoot)
|
2012-02-25 09:07:38 +08:00
|
|
|
{
|
2013-12-19 08:35:40 +08:00
|
|
|
// If current user is already root, we don't need XPC's help.
|
|
|
|
result = true;
|
2012-02-25 09:07:38 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2011-11-15 11:53:30 +08:00
|
|
|
|
2012-02-25 09:07:38 +08:00
|
|
|
Error
|
|
|
|
Host::LaunchProcess (ProcessLaunchInfo &launch_info)
|
|
|
|
{
|
|
|
|
Error error;
|
|
|
|
char exe_path[PATH_MAX];
|
2014-09-20 04:11:50 +08:00
|
|
|
PlatformSP host_platform_sp (Platform::GetHostPlatform ());
|
2014-11-18 03:39:20 +08:00
|
|
|
|
|
|
|
ModuleSpec exe_module_spec(launch_info.GetExecutableFile(), launch_info.GetArchitecture());
|
|
|
|
|
|
|
|
FileSpec::FileType file_type = exe_module_spec.GetFileSpec().GetFileType();
|
2012-02-25 09:07:38 +08:00
|
|
|
if (file_type != FileSpec::eFileTypeRegular)
|
|
|
|
{
|
|
|
|
lldb::ModuleSP exe_module_sp;
|
2014-11-18 03:39:20 +08:00
|
|
|
error = host_platform_sp->ResolveExecutable (exe_module_spec,
|
2012-02-25 09:07:38 +08:00
|
|
|
exe_module_sp,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (error.Fail())
|
|
|
|
return error;
|
|
|
|
|
|
|
|
if (exe_module_sp)
|
2014-11-18 03:39:20 +08:00
|
|
|
exe_module_spec.GetFileSpec() = exe_module_sp->GetFileSpec();
|
2012-02-25 09:07:38 +08:00
|
|
|
}
|
|
|
|
|
2014-11-18 03:39:20 +08:00
|
|
|
if (exe_module_spec.GetFileSpec().Exists())
|
2012-02-25 09:07:38 +08:00
|
|
|
{
|
2014-11-18 03:39:20 +08:00
|
|
|
exe_module_spec.GetFileSpec().GetPath (exe_path, sizeof(exe_path));
|
2012-02-25 09:07:38 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path));
|
|
|
|
error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
|
|
|
|
{
|
2014-07-09 09:29:05 +08:00
|
|
|
#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
|
2012-02-25 09:07:38 +08:00
|
|
|
return LaunchInNewTerminalWithAppleScript (exe_path, launch_info);
|
|
|
|
#else
|
2014-07-02 05:22:11 +08:00
|
|
|
error.SetErrorString ("launching a process in a new terminal is not supported on iOS devices");
|
2012-02-25 09:07:38 +08:00
|
|
|
return error;
|
|
|
|
#endif
|
|
|
|
}
|
2014-10-15 05:55:08 +08:00
|
|
|
|
|
|
|
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
|
|
|
|
|
2013-12-19 08:35:40 +08:00
|
|
|
if (ShouldLaunchUsingXPC(launch_info))
|
2012-02-25 09:07:38 +08:00
|
|
|
{
|
|
|
|
error = LaunchProcessXPC(exe_path, launch_info, pid);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error = LaunchProcessPosixSpawn(exe_path, launch_info, pid);
|
|
|
|
}
|
|
|
|
|
2011-04-12 13:54:46 +08:00
|
|
|
if (pid != LLDB_INVALID_PROCESS_ID)
|
|
|
|
{
|
|
|
|
// If all went well, then set the process ID into the launch info
|
2011-11-16 13:37:56 +08:00
|
|
|
launch_info.SetProcessID(pid);
|
|
|
|
|
|
|
|
// Make sure we reap any processes we spawn or we will have zombies.
|
|
|
|
if (!launch_info.MonitorProcess())
|
|
|
|
{
|
|
|
|
const bool monitor_signals = false;
|
2014-06-25 05:51:42 +08:00
|
|
|
Host::MonitorChildProcessCallback callback = nullptr;
|
|
|
|
|
2014-06-25 10:32:56 +08:00
|
|
|
if (!launch_info.GetFlags().Test(lldb::eLaunchFlagDontSetExitStatus))
|
2014-06-25 05:51:42 +08:00
|
|
|
callback = Process::SetProcessExitStatus;
|
|
|
|
|
|
|
|
StartMonitoringChildProcess (callback,
|
2011-11-16 13:37:56 +08:00
|
|
|
NULL,
|
|
|
|
pid,
|
|
|
|
monitor_signals);
|
|
|
|
}
|
2011-04-12 13:54:46 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Invalid process ID, something didn't go well
|
|
|
|
if (error.Success())
|
|
|
|
error.SetErrorString ("process launch failed for unknown reasons");
|
|
|
|
}
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2015-02-21 05:48:38 +08:00
|
|
|
Error
|
2015-02-21 06:20:30 +08:00
|
|
|
Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
|
2015-02-21 05:48:38 +08:00
|
|
|
{
|
|
|
|
Error error;
|
2015-02-21 06:20:30 +08:00
|
|
|
if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
|
2015-02-21 05:48:38 +08:00
|
|
|
{
|
2015-02-21 06:20:30 +08:00
|
|
|
FileSpec expand_tool_spec;
|
|
|
|
if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
|
2015-02-21 05:48:38 +08:00
|
|
|
{
|
|
|
|
error.SetErrorString("could not find argdumper tool");
|
|
|
|
return error;
|
|
|
|
}
|
2015-02-21 06:20:30 +08:00
|
|
|
expand_tool_spec.AppendPathComponent("argdumper");
|
|
|
|
if (!expand_tool_spec.Exists())
|
2015-02-21 05:48:38 +08:00
|
|
|
{
|
|
|
|
error.SetErrorString("could not find argdumper tool");
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string quoted_cmd_string;
|
|
|
|
launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string);
|
2015-02-21 06:20:30 +08:00
|
|
|
StreamString expand_command;
|
2015-02-21 05:48:38 +08:00
|
|
|
|
2015-02-21 06:20:30 +08:00
|
|
|
expand_command.Printf("%s %s",
|
|
|
|
expand_tool_spec.GetPath().c_str(),
|
|
|
|
quoted_cmd_string.c_str());
|
2015-02-21 05:48:38 +08:00
|
|
|
|
|
|
|
int status;
|
|
|
|
std::string output;
|
2015-02-21 06:20:30 +08:00
|
|
|
RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), &status, nullptr, &output, 10);
|
2015-02-21 05:48:38 +08:00
|
|
|
|
|
|
|
if (status != 0)
|
|
|
|
{
|
|
|
|
error.SetErrorStringWithFormat("argdumper exited with error %d", status);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto data_sp = StructuredData::ParseJSON(output);
|
|
|
|
if (!data_sp)
|
|
|
|
{
|
|
|
|
error.SetErrorString("invalid JSON");
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto dict_sp = data_sp->GetAsDictionary();
|
|
|
|
if (!data_sp)
|
|
|
|
{
|
|
|
|
error.SetErrorString("invalid JSON");
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
|
|
|
|
if (!args_sp)
|
|
|
|
{
|
|
|
|
error.SetErrorString("invalid JSON");
|
|
|
|
return error;
|
|
|
|
}
|
2015-02-21 06:20:30 +08:00
|
|
|
|
2015-02-21 05:48:38 +08:00
|
|
|
auto args_array_sp = args_sp->GetAsArray();
|
|
|
|
if (!args_array_sp)
|
|
|
|
{
|
|
|
|
error.SetErrorString("invalid JSON");
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
launch_info.GetArguments().Clear();
|
|
|
|
|
|
|
|
for (size_t i = 0;
|
|
|
|
i < args_array_sp->GetSize();
|
|
|
|
i++)
|
|
|
|
{
|
|
|
|
auto item_sp = args_array_sp->GetItemAtIndex(i);
|
|
|
|
if (!item_sp)
|
|
|
|
continue;
|
|
|
|
auto str_sp = item_sp->GetAsString();
|
|
|
|
if (!str_sp)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2014-09-10 04:54:56 +08:00
|
|
|
HostThread
|
|
|
|
Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
|
2011-11-16 13:37:56 +08:00
|
|
|
{
|
|
|
|
unsigned long mask = DISPATCH_PROC_EXIT;
|
|
|
|
if (monitor_signals)
|
|
|
|
mask |= DISPATCH_PROC_SIGNAL;
|
|
|
|
|
2013-03-28 07:08:40 +08:00
|
|
|
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
|
2011-11-18 03:41:57 +08:00
|
|
|
|
2011-11-16 13:37:56 +08:00
|
|
|
|
|
|
|
dispatch_source_t source = ::dispatch_source_create (DISPATCH_SOURCE_TYPE_PROC,
|
|
|
|
pid,
|
|
|
|
mask,
|
|
|
|
::dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT,0));
|
2011-04-12 13:54:46 +08:00
|
|
|
|
2011-11-18 03:41:57 +08:00
|
|
|
if (log)
|
|
|
|
log->Printf ("Host::StartMonitoringChildProcess (callback=%p, baton=%p, pid=%i, monitor_signals=%i) source = %p\n",
|
|
|
|
callback,
|
|
|
|
callback_baton,
|
|
|
|
(int)pid,
|
|
|
|
monitor_signals,
|
|
|
|
source);
|
2011-11-16 13:37:56 +08:00
|
|
|
|
|
|
|
if (source)
|
|
|
|
{
|
|
|
|
::dispatch_source_set_cancel_handler (source, ^{
|
|
|
|
::dispatch_release (source);
|
|
|
|
});
|
|
|
|
::dispatch_source_set_event_handler (source, ^{
|
|
|
|
|
|
|
|
int status= 0;
|
|
|
|
int wait_pid = 0;
|
|
|
|
bool cancel = false;
|
|
|
|
bool exited = false;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
wait_pid = ::waitpid (pid, &status, 0);
|
|
|
|
} while (wait_pid < 0 && errno == EINTR);
|
|
|
|
|
|
|
|
if (wait_pid >= 0)
|
|
|
|
{
|
|
|
|
int signal = 0;
|
|
|
|
int exit_status = 0;
|
|
|
|
const char *status_cstr = NULL;
|
|
|
|
if (WIFSTOPPED(status))
|
|
|
|
{
|
|
|
|
signal = WSTOPSIG(status);
|
|
|
|
status_cstr = "STOPPED";
|
|
|
|
}
|
|
|
|
else if (WIFEXITED(status))
|
|
|
|
{
|
|
|
|
exit_status = WEXITSTATUS(status);
|
|
|
|
status_cstr = "EXITED";
|
|
|
|
exited = true;
|
|
|
|
}
|
|
|
|
else if (WIFSIGNALED(status))
|
|
|
|
{
|
|
|
|
signal = WTERMSIG(status);
|
|
|
|
status_cstr = "SIGNALED";
|
|
|
|
exited = true;
|
|
|
|
exit_status = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status_cstr = "???";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (log)
|
2011-12-02 07:28:38 +08:00
|
|
|
log->Printf ("::waitpid (pid = %llu, &status, 0) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_status = %i",
|
2011-11-16 13:37:56 +08:00
|
|
|
pid,
|
|
|
|
wait_pid,
|
|
|
|
status,
|
|
|
|
status_cstr,
|
|
|
|
signal,
|
|
|
|
exit_status);
|
|
|
|
|
|
|
|
if (callback)
|
|
|
|
cancel = callback (callback_baton, pid, exited, signal, exit_status);
|
|
|
|
|
2012-07-17 11:23:13 +08:00
|
|
|
if (exited || cancel)
|
2011-11-16 13:37:56 +08:00
|
|
|
{
|
|
|
|
::dispatch_source_cancel(source);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
::dispatch_resume (source);
|
|
|
|
}
|
2014-09-10 04:54:56 +08:00
|
|
|
return HostThread();
|
2011-11-16 13:37:56 +08:00
|
|
|
}
|
2012-01-05 11:57:59 +08:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Log to both stderr and to ASL Logging when running on MacOSX.
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void
|
|
|
|
Host::SystemLog (SystemLogType type, const char *format, va_list args)
|
|
|
|
{
|
|
|
|
if (format && format[0])
|
|
|
|
{
|
|
|
|
static aslmsg g_aslmsg = NULL;
|
|
|
|
if (g_aslmsg == NULL)
|
|
|
|
{
|
|
|
|
g_aslmsg = ::asl_new (ASL_TYPE_MSG);
|
|
|
|
char asl_key_sender[PATH_MAX];
|
|
|
|
snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.LLDB.framework");
|
|
|
|
::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the va_list so we can log this message twice
|
|
|
|
va_list copy_args;
|
|
|
|
va_copy (copy_args, args);
|
|
|
|
// Log to stderr
|
|
|
|
::vfprintf (stderr, format, copy_args);
|
|
|
|
va_end (copy_args);
|
|
|
|
|
|
|
|
int asl_level;
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case eSystemLogError:
|
|
|
|
asl_level = ASL_LEVEL_ERR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eSystemLogWarning:
|
|
|
|
asl_level = ASL_LEVEL_WARNING;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log to ASL
|
|
|
|
::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
|
|
|
|
}
|
|
|
|
}
|
2012-02-28 03:00:34 +08:00
|
|
|
|
|
|
|
lldb::DataBufferSP
|
|
|
|
Host::GetAuxvData(lldb_private::Process *process)
|
|
|
|
{
|
|
|
|
return lldb::DataBufferSP();
|
|
|
|
}
|