blob: e3379d07ccad82b84323842bafe1d0dcf1c949bf [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- Host.mm -------------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Greg Clayton8f3b21d2010-09-07 20:11:56 +000010#include "lldb/Host/Host.h"
11#include "lldb/Core/FileSpec.h"
12#include "lldb/Core/Log.h"
Chris Lattner24943d22010-06-08 16:52:24 +000013
Greg Clayton54e7afa2010-07-09 20:39:50 +000014#include "cfcpp/CFCBundle.h"
Greg Clayton4b407112010-09-30 21:49:03 +000015#include "cfcpp/CFCMutableDictionary.h"
Greg Clayton54e7afa2010-07-09 20:39:50 +000016#include "cfcpp/CFCReleaser.h"
17#include "cfcpp/CFCString.h"
Chris Lattner24943d22010-06-08 16:52:24 +000018
Greg Clayton8f3b21d2010-09-07 20:11:56 +000019#include <objc/objc-auto.h>
20
Greg Clayton4b407112010-09-30 21:49:03 +000021#include <ApplicationServices/ApplicationServices.h>
Greg Clayton8f3b21d2010-09-07 20:11:56 +000022#include <Carbon/Carbon.h>
23#include <Foundation/Foundation.h>
Chris Lattner24943d22010-06-08 16:52:24 +000024
25using namespace lldb;
26using namespace lldb_private;
27
Chris Lattner24943d22010-06-08 16:52:24 +000028class MacOSXDarwinThread
29{
30public:
31 MacOSXDarwinThread(const char *thread_name) :
32 m_pool (nil)
33 {
34 // Register our thread with the collector if garbage collection is enabled.
35 if (objc_collectingEnabled())
36 {
37#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
38 // On Leopard and earlier there is no way objc_registerThreadWithCollector
39 // function, so we do it manually.
40 auto_zone_register_thread(auto_zone());
41#else
42 // On SnowLoepard and later we just call the thread registration function.
43 objc_registerThreadWithCollector();
44#endif
45 }
46 else
47 {
48 m_pool = [[NSAutoreleasePool alloc] init];
49 }
50
51
52 Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
53 }
54
55 ~MacOSXDarwinThread()
56 {
57 if (m_pool)
58 [m_pool release];
59 }
60
61 static void PThreadDestructor (void *v)
62 {
63 delete (MacOSXDarwinThread*)v;
64 }
65
66protected:
67 NSAutoreleasePool * m_pool;
68private:
69 DISALLOW_COPY_AND_ASSIGN (MacOSXDarwinThread);
70};
71
72static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
73static pthread_key_t g_thread_create_key = 0;
74
75static void
76InitThreadCreated()
77{
78 ::pthread_key_create (&g_thread_create_key, MacOSXDarwinThread::PThreadDestructor);
79}
80
Chris Lattner24943d22010-06-08 16:52:24 +000081void
82Host::ThreadCreated (const char *thread_name)
83{
84 ::pthread_once (&g_thread_create_once, InitThreadCreated);
85 if (g_thread_create_key)
86 {
87 ::pthread_setspecific (g_thread_create_key, new MacOSXDarwinThread(thread_name));
88 }
89}
90
Chris Lattner24943d22010-06-08 16:52:24 +000091
92bool
93Host::ResolveExecutableInBundle (FileSpec *file)
94{
Greg Clayton8f3b21d2010-09-07 20:11:56 +000095#if defined (__APPLE__)
96 if (file->GetFileType () == FileSpec::eFileTypeDirectory)
97 {
98 char path[PATH_MAX];
99 if (file->GetPath(path, sizeof(path)))
Chris Lattner24943d22010-06-08 16:52:24 +0000100 {
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000101 CFCBundle bundle (path);
102 CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
103 if (url.get())
104 {
105 if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
Chris Lattner24943d22010-06-08 16:52:24 +0000106 {
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000107 file->SetFile(path);
108 return true;
Chris Lattner24943d22010-06-08 16:52:24 +0000109 }
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000110 }
Chris Lattner24943d22010-06-08 16:52:24 +0000111 }
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000112 }
113#endif
114 return false;
Jim Ingham7508e732010-08-09 23:31:02 +0000115}
Jim Ingham74989e82010-08-30 19:44:40 +0000116
Greg Clayton4b407112010-09-30 21:49:03 +0000117lldb::pid_t
118Host::LaunchApplication (const FileSpec &app_file_spec)
119{
120 char app_path[PATH_MAX];
121 app_file_spec.GetPath(app_path, sizeof(app_path));
122
123 LSApplicationParameters app_params;
124 ::bzero (&app_params, sizeof (app_params));
125 app_params.flags = kLSLaunchDefaults |
126 kLSLaunchDontAddToRecents |
127 kLSLaunchDontSwitch |
128 kLSLaunchNewInstance;// | 0x00001000;
129
130 FSRef app_fsref;
131 CFCString app_cfstr (app_path, kCFStringEncodingUTF8);
132
133 OSStatus error = ::FSPathMakeRef ((const UInt8 *)app_path, &app_fsref, false);
134
135 // If we found the app, then store away the name so we don't have to re-look it up.
136 if (error != noErr)
137 return LLDB_INVALID_PROCESS_ID;
138
139 app_params.application = &app_fsref;
140
141 ProcessSerialNumber psn;
142
143 error = ::LSOpenApplication (&app_params, &psn);
144
145 if (error != noErr)
146 return LLDB_INVALID_PROCESS_ID;
147
148 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
149 error = ::GetProcessPID(&psn, &pid);
150 return pid;
151}
152
Jim Ingham74989e82010-08-30 19:44:40 +0000153bool
Greg Clayton4b407112010-09-30 21:49:03 +0000154Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
Jim Ingham74989e82010-08-30 19:44:40 +0000155{
156 // We attach this to an 'odoc' event to specify a particular selection
157 typedef struct {
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000158 int16_t reserved0; // must be zero
159 int16_t fLineNumber;
160 int32_t fSelStart;
161 int32_t fSelEnd;
162 uint32_t reserved1; // must be zero
163 uint32_t reserved2; // must be zero
Jim Ingham74989e82010-08-30 19:44:40 +0000164 } BabelAESelInfo;
165
Jim Inghamb0fff352010-08-31 18:05:13 +0000166 Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST);
Jim Ingham74989e82010-08-30 19:44:40 +0000167 char file_path[PATH_MAX];
168 file_spec.GetPath(file_path, PATH_MAX);
169 CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000170 CFCReleaser<CFURLRef> file_URL (::CFURLCreateWithFileSystemPath (NULL,
171 file_cfstr.get(),
172 kCFURLPOSIXPathStyle,
173 false));
Jim Inghamb0fff352010-08-31 18:05:13 +0000174
175 if (log)
176 log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000177
Jim Ingham74989e82010-08-30 19:44:40 +0000178 OSStatus error;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000179 BabelAESelInfo file_and_line_info =
180 {
181 0, // reserved0
182 line_no - 1, // fLineNumber (zero based line number)
183 1, // fSelStart
184 1024, // fSelEnd
185 0, // reserved1
186 0 // reserved2
187 };
Jim Ingham74989e82010-08-30 19:44:40 +0000188
189 AEKeyDesc file_and_line_desc;
190
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000191 error = ::AECreateDesc (typeUTF8Text,
192 &file_and_line_info,
193 sizeof (file_and_line_info),
194 &(file_and_line_desc.descContent));
Jim Ingham74989e82010-08-30 19:44:40 +0000195
Jim Ingham74989e82010-08-30 19:44:40 +0000196 if (error != noErr)
197 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000198 if (log)
199 log->Printf("Error creating AEDesc: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000200 return false;
201 }
202
203 file_and_line_desc.descKey = keyAEPosition;
204
Greg Claytoncb0989a2010-08-31 18:56:24 +0000205 static std::string g_app_name;
Greg Clayton452bf612010-08-31 18:35:14 +0000206 static FSRef g_app_fsref;
207
Jim Ingham74989e82010-08-30 19:44:40 +0000208 LSApplicationParameters app_params;
Greg Clayton452bf612010-08-31 18:35:14 +0000209 ::bzero (&app_params, sizeof (app_params));
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000210 app_params.flags = kLSLaunchDefaults |
211 kLSLaunchDontAddToRecents |
212 kLSLaunchDontSwitch;
Greg Clayton452bf612010-08-31 18:35:14 +0000213
Jim Ingham363180d2010-08-30 23:48:25 +0000214 char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR");
215
Greg Clayton452bf612010-08-31 18:35:14 +0000216 if (external_editor)
Jim Ingham363180d2010-08-30 23:48:25 +0000217 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000218 if (log)
219 log->Printf("Looking for external editor \"%s\".\n", external_editor);
220
Greg Claytoncb0989a2010-08-31 18:56:24 +0000221 if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0)
Jim Ingham363180d2010-08-30 23:48:25 +0000222 {
Jim Ingham363180d2010-08-30 23:48:25 +0000223 CFCString editor_name (external_editor, kCFStringEncodingUTF8);
Greg Clayton452bf612010-08-31 18:35:14 +0000224 error = ::LSFindApplicationForInfo (kLSUnknownCreator,
225 NULL,
226 editor_name.get(),
227 &g_app_fsref,
228 NULL);
Jim Ingham363180d2010-08-30 23:48:25 +0000229
230 // If we found the app, then store away the name so we don't have to re-look it up.
Greg Clayton452bf612010-08-31 18:35:14 +0000231 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000232 {
233 if (log)
234 log->Printf("Could not find External Editor application, error: %d.\n", error);
Jim Ingham363180d2010-08-30 23:48:25 +0000235 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000236 }
Jim Ingham363180d2010-08-30 23:48:25 +0000237
238 }
Greg Clayton452bf612010-08-31 18:35:14 +0000239 app_params.application = &g_app_fsref;
Jim Ingham363180d2010-08-30 23:48:25 +0000240 }
241
Jim Ingham74989e82010-08-30 19:44:40 +0000242 ProcessSerialNumber psn;
243 CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000244 error = ::LSOpenURLsWithRole (file_array.get(),
Jim Ingham363180d2010-08-30 23:48:25 +0000245 kLSRolesAll,
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000246 &file_and_line_desc,
247 &app_params,
248 &psn,
249 1);
250
Jim Ingham74989e82010-08-30 19:44:40 +0000251 AEDisposeDesc (&(file_and_line_desc.descContent));
252
253 if (error != noErr)
254 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000255 if (log)
256 log->Printf("LSOpenURLsWithRole failed, error: %d.\n", error);
257
Jim Ingham74989e82010-08-30 19:44:40 +0000258 return false;
259 }
260
261 ProcessInfoRec which_process;
262 bzero(&which_process, sizeof(which_process));
263 unsigned char ap_name[PATH_MAX];
264 which_process.processName = ap_name;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000265 error = ::GetProcessInformation (&psn, &which_process);
Jim Ingham74989e82010-08-30 19:44:40 +0000266
Jim Inghamb0fff352010-08-31 18:05:13 +0000267 bool using_xcode;
268 if (error != noErr)
269 {
270 if (log)
271 log->Printf("GetProcessInformation failed, error: %d.\n", error);
272 using_xcode = false;
273 }
274 else
275 using_xcode = strncmp((char *) ap_name+1, "Xcode", (int) ap_name[0]) == 0;
Jim Ingham74989e82010-08-30 19:44:40 +0000276
277 // Xcode doesn't obey the line number in the Open Apple Event. So I have to send
278 // it an AppleScript to focus on the right line.
279
280 if (using_xcode)
281 {
282 static ComponentInstance osa_component = NULL;
283 static const char *as_template = "tell application \"Xcode\"\n"
284 "set doc to the first document whose path is \"%s\"\n"
285 "set the selection to paragraph %d of doc\n"
286 "--- set the selected paragraph range to {%d, %d} of doc\n"
287 "end tell\n";
288 const int chars_for_int = 32;
289 static int as_template_len = strlen (as_template);
290
291
292 char *as_str;
293 AEDesc as_desc;
294
295 if (osa_component == NULL)
296 {
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000297 osa_component = ::OpenDefaultComponent (kOSAComponentType,
298 kAppleScriptSubtype);
Jim Ingham74989e82010-08-30 19:44:40 +0000299 }
300
301 if (osa_component == NULL)
302 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000303 if (log)
304 log->Printf("Could not get default AppleScript component.\n");
Jim Ingham74989e82010-08-30 19:44:40 +0000305 return false;
306 }
307
308 uint32_t as_str_size = as_template_len + strlen (file_path) + 3 * chars_for_int + 1;
309 as_str = (char *) malloc (as_str_size);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000310 ::snprintf (as_str,
311 as_str_size - 1,
312 as_template,
313 file_path,
314 line_no,
315 line_no,
316 line_no);
Jim Ingham74989e82010-08-30 19:44:40 +0000317
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000318 error = ::AECreateDesc (typeChar,
319 as_str,
320 strlen (as_str),
321 &as_desc);
322
323 ::free (as_str);
Jim Ingham74989e82010-08-30 19:44:40 +0000324
325 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000326 {
327 if (log)
328 log->Printf("Failed to create AEDesc for Xcode AppleEvent: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000329 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000330 }
Jim Ingham74989e82010-08-30 19:44:40 +0000331
332 OSAID ret_OSAID;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000333 error = ::OSACompileExecute (osa_component,
334 &as_desc,
335 kOSANullScript,
336 kOSAModeNeverInteract,
337 &ret_OSAID);
338
339 ::OSADispose (osa_component, ret_OSAID);
Jim Ingham74989e82010-08-30 19:44:40 +0000340
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000341 ::AEDisposeDesc (&as_desc);
Jim Ingham74989e82010-08-30 19:44:40 +0000342
343 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000344 {
345 if (log)
346 log->Printf("Sending AppleEvent to Xcode failed, error: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000347 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000348 }
Jim Ingham74989e82010-08-30 19:44:40 +0000349 }
350
351 return true;
352}