blob: c7c6e496747cb27de2a6c26d8fdf2bf078e2f25e [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"
Greg Clayton24b48ff2010-10-17 22:03:32 +000011
12#include <sys/types.h>
13#include <sys/stat.h>
14
15#include "lldb/Core/ArchSpec.h"
Greg Clayton8f3b21d2010-09-07 20:11:56 +000016#include "lldb/Core/FileSpec.h"
17#include "lldb/Core/Log.h"
Greg Clayton24b48ff2010-10-17 22:03:32 +000018#include "lldb/Core/StreamFile.h"
19#include "lldb/Core/StreamString.h"
Chris Lattner24943d22010-06-08 16:52:24 +000020
Greg Clayton54e7afa2010-07-09 20:39:50 +000021#include "cfcpp/CFCBundle.h"
Greg Clayton24b48ff2010-10-17 22:03:32 +000022#include "cfcpp/CFCMutableArray.h"
Greg Clayton4b407112010-09-30 21:49:03 +000023#include "cfcpp/CFCMutableDictionary.h"
Greg Clayton54e7afa2010-07-09 20:39:50 +000024#include "cfcpp/CFCReleaser.h"
25#include "cfcpp/CFCString.h"
Chris Lattner24943d22010-06-08 16:52:24 +000026
Greg Clayton8f3b21d2010-09-07 20:11:56 +000027#include <objc/objc-auto.h>
28
Greg Clayton4b407112010-09-30 21:49:03 +000029#include <ApplicationServices/ApplicationServices.h>
Greg Clayton8f3b21d2010-09-07 20:11:56 +000030#include <Carbon/Carbon.h>
31#include <Foundation/Foundation.h>
Chris Lattner24943d22010-06-08 16:52:24 +000032
33using namespace lldb;
34using namespace lldb_private;
35
Chris Lattner24943d22010-06-08 16:52:24 +000036class MacOSXDarwinThread
37{
38public:
39 MacOSXDarwinThread(const char *thread_name) :
40 m_pool (nil)
41 {
42 // Register our thread with the collector if garbage collection is enabled.
43 if (objc_collectingEnabled())
44 {
45#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
46 // On Leopard and earlier there is no way objc_registerThreadWithCollector
47 // function, so we do it manually.
48 auto_zone_register_thread(auto_zone());
49#else
50 // On SnowLoepard and later we just call the thread registration function.
51 objc_registerThreadWithCollector();
52#endif
53 }
54 else
55 {
56 m_pool = [[NSAutoreleasePool alloc] init];
57 }
58
59
60 Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
61 }
62
63 ~MacOSXDarwinThread()
64 {
65 if (m_pool)
66 [m_pool release];
67 }
68
69 static void PThreadDestructor (void *v)
70 {
71 delete (MacOSXDarwinThread*)v;
72 }
73
74protected:
75 NSAutoreleasePool * m_pool;
76private:
77 DISALLOW_COPY_AND_ASSIGN (MacOSXDarwinThread);
78};
79
80static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
81static pthread_key_t g_thread_create_key = 0;
82
83static void
84InitThreadCreated()
85{
86 ::pthread_key_create (&g_thread_create_key, MacOSXDarwinThread::PThreadDestructor);
87}
88
Chris Lattner24943d22010-06-08 16:52:24 +000089void
90Host::ThreadCreated (const char *thread_name)
91{
92 ::pthread_once (&g_thread_create_once, InitThreadCreated);
93 if (g_thread_create_key)
94 {
95 ::pthread_setspecific (g_thread_create_key, new MacOSXDarwinThread(thread_name));
96 }
97}
98
Chris Lattner24943d22010-06-08 16:52:24 +000099
100bool
Greg Clayton24b48ff2010-10-17 22:03:32 +0000101Host::ResolveExecutableInBundle (FileSpec &file)
Chris Lattner24943d22010-06-08 16:52:24 +0000102{
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000103#if defined (__APPLE__)
Greg Clayton24b48ff2010-10-17 22:03:32 +0000104 if (file.GetFileType () == FileSpec::eFileTypeDirectory)
Chris Lattner24943d22010-06-08 16:52:24 +0000105 {
Greg Clayton24b48ff2010-10-17 22:03:32 +0000106 char path[PATH_MAX];
107 if (file.GetPath(path, sizeof(path)))
Chris Lattner24943d22010-06-08 16:52:24 +0000108 {
Greg Clayton24b48ff2010-10-17 22:03:32 +0000109 CFCBundle bundle (path);
110 CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
111 if (url.get())
112 {
113 if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
114 {
115 file.SetFile(path);
116 return true;
117 }
118 }
Chris Lattner24943d22010-06-08 16:52:24 +0000119 }
120 }
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000121#endif
122 return false;
Jim Ingham7508e732010-08-09 23:31:02 +0000123}
Jim Ingham74989e82010-08-30 19:44:40 +0000124
Greg Clayton4b407112010-09-30 21:49:03 +0000125lldb::pid_t
126Host::LaunchApplication (const FileSpec &app_file_spec)
127{
128 char app_path[PATH_MAX];
129 app_file_spec.GetPath(app_path, sizeof(app_path));
130
131 LSApplicationParameters app_params;
132 ::bzero (&app_params, sizeof (app_params));
133 app_params.flags = kLSLaunchDefaults |
134 kLSLaunchDontAddToRecents |
Greg Clayton24b48ff2010-10-17 22:03:32 +0000135 kLSLaunchNewInstance;
136
Greg Clayton4b407112010-09-30 21:49:03 +0000137
138 FSRef app_fsref;
139 CFCString app_cfstr (app_path, kCFStringEncodingUTF8);
140
141 OSStatus error = ::FSPathMakeRef ((const UInt8 *)app_path, &app_fsref, false);
142
143 // If we found the app, then store away the name so we don't have to re-look it up.
144 if (error != noErr)
145 return LLDB_INVALID_PROCESS_ID;
146
147 app_params.application = &app_fsref;
148
149 ProcessSerialNumber psn;
150
151 error = ::LSOpenApplication (&app_params, &psn);
152
153 if (error != noErr)
154 return LLDB_INVALID_PROCESS_ID;
155
156 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
157 error = ::GetProcessPID(&psn, &pid);
158 return pid;
159}
160
Greg Clayton24b48ff2010-10-17 22:03:32 +0000161lldb::pid_t
162Host::LaunchInNewTerminal
163(
164 const char **argv,
165 const char **envp,
166 const ArchSpec *arch_spec,
167 bool stop_at_entry,
168 bool disable_aslr
169)
170{
171 if (!argv || !argv[0])
172 return LLDB_INVALID_PROCESS_ID;
173
174 OSStatus error = 0;
175
176 FileSpec program (argv[0]);
177
178
179 char temp_file_path[PATH_MAX];
180 const char *tmpdir = ::getenv ("TMPDIR");
181 if (tmpdir == NULL)
182 tmpdir = "/tmp/";
183 ::snprintf (temp_file_path, sizeof(temp_file_path), "%s%s-XXXXXX", tmpdir, program.GetFilename().AsCString());
184
185 if (::mktemp (temp_file_path) == NULL)
186 return LLDB_INVALID_PROCESS_ID;
187
188 ::strncat (temp_file_path, ".command", sizeof (temp_file_path));
189
190 StreamFile command_file (temp_file_path, "w");
191
192 FileSpec darwin_debug_file_spec;
193 if (!Host::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec))
194 return LLDB_INVALID_PROCESS_ID;
195 darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
196
197 if (!darwin_debug_file_spec.Exists())
198 return LLDB_INVALID_PROCESS_ID;
199
200 char launcher_path[PATH_MAX];
201 darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
202 command_file.Printf("\"%s\" ", launcher_path);
203
204 if (arch_spec && arch_spec->IsValid())
205 {
206 command_file.Printf("--arch=%s ", arch_spec->AsCString());
207 }
208
209 if (disable_aslr)
210 {
211 command_file.PutCString("--disable-aslr ");
212 }
213
214 command_file.PutCString("-- ");
215
216 if (argv)
217 {
218 for (size_t i=0; argv[i] != NULL; ++i)
219 {
220 command_file.Printf("\"%s\" ", argv[i]);
221 }
222 }
Greg Claytonc1d37752010-10-18 01:45:30 +0000223 command_file.PutCString("\necho Process exited with status $?\n");
Greg Clayton24b48ff2010-10-17 22:03:32 +0000224 command_file.Close();
225 if (::chmod (temp_file_path, S_IRWXU | S_IRWXG) != 0)
226 return LLDB_INVALID_PROCESS_ID;
227
228 CFCMutableDictionary cf_env_dict;
229
230 const bool can_create = true;
231 if (envp)
232 {
233 for (size_t i=0; envp[i] != NULL; ++i)
234 {
235 const char *env_entry = envp[i];
236 const char *equal_pos = strchr(env_entry, '=');
237 if (equal_pos)
238 {
239 std::string env_key (env_entry, equal_pos);
240 std::string env_val (equal_pos + 1);
241 CFCString cf_env_key (env_key.c_str(), kCFStringEncodingUTF8);
242 CFCString cf_env_val (env_val.c_str(), kCFStringEncodingUTF8);
243 cf_env_dict.AddValue (cf_env_key.get(), cf_env_val.get(), can_create);
244 }
245 }
246 }
247
248 LSApplicationParameters app_params;
249 ::bzero (&app_params, sizeof (app_params));
250 app_params.flags = kLSLaunchDontAddToRecents | kLSLaunchAsync;
251 app_params.argv = NULL;
252 app_params.environment = (CFDictionaryRef)cf_env_dict.get();
253
254 CFCReleaser<CFURLRef> command_file_url (::CFURLCreateFromFileSystemRepresentation (NULL,
255 (const UInt8 *)temp_file_path,
256 strlen (temp_file_path),
257 false));
258
259 CFCMutableArray urls;
260
261 // Terminal.app will open the ".command" file we have created
262 // and run our process inside it which will wait at the entry point
263 // for us to attach.
264 urls.AppendValue(command_file_url.get());
265
266 ProcessSerialNumber psn;
267 error = LSOpenURLsWithRole(urls.get(), kLSRolesShell, NULL, &app_params, &psn, 1);
268
269 if (error != noErr)
270 return LLDB_INVALID_PROCESS_ID;
271
272 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
273 error = ::GetProcessPID(&psn, &pid);
274 return pid;
275}
276
Jim Ingham74989e82010-08-30 19:44:40 +0000277bool
Greg Clayton4b407112010-09-30 21:49:03 +0000278Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
Jim Ingham74989e82010-08-30 19:44:40 +0000279{
280 // We attach this to an 'odoc' event to specify a particular selection
281 typedef struct {
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000282 int16_t reserved0; // must be zero
283 int16_t fLineNumber;
284 int32_t fSelStart;
285 int32_t fSelEnd;
286 uint32_t reserved1; // must be zero
287 uint32_t reserved2; // must be zero
Jim Ingham74989e82010-08-30 19:44:40 +0000288 } BabelAESelInfo;
289
Jim Inghamb0fff352010-08-31 18:05:13 +0000290 Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST);
Jim Ingham74989e82010-08-30 19:44:40 +0000291 char file_path[PATH_MAX];
292 file_spec.GetPath(file_path, PATH_MAX);
293 CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000294 CFCReleaser<CFURLRef> file_URL (::CFURLCreateWithFileSystemPath (NULL,
295 file_cfstr.get(),
296 kCFURLPOSIXPathStyle,
297 false));
Jim Inghamb0fff352010-08-31 18:05:13 +0000298
299 if (log)
300 log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000301
Jim Ingham74989e82010-08-30 19:44:40 +0000302 OSStatus error;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000303 BabelAESelInfo file_and_line_info =
304 {
305 0, // reserved0
306 line_no - 1, // fLineNumber (zero based line number)
307 1, // fSelStart
308 1024, // fSelEnd
309 0, // reserved1
310 0 // reserved2
311 };
Jim Ingham74989e82010-08-30 19:44:40 +0000312
313 AEKeyDesc file_and_line_desc;
314
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000315 error = ::AECreateDesc (typeUTF8Text,
316 &file_and_line_info,
317 sizeof (file_and_line_info),
318 &(file_and_line_desc.descContent));
Jim Ingham74989e82010-08-30 19:44:40 +0000319
Jim Ingham74989e82010-08-30 19:44:40 +0000320 if (error != noErr)
321 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000322 if (log)
323 log->Printf("Error creating AEDesc: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000324 return false;
325 }
326
327 file_and_line_desc.descKey = keyAEPosition;
328
Greg Claytoncb0989a2010-08-31 18:56:24 +0000329 static std::string g_app_name;
Greg Clayton452bf612010-08-31 18:35:14 +0000330 static FSRef g_app_fsref;
331
Jim Ingham74989e82010-08-30 19:44:40 +0000332 LSApplicationParameters app_params;
Greg Clayton452bf612010-08-31 18:35:14 +0000333 ::bzero (&app_params, sizeof (app_params));
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000334 app_params.flags = kLSLaunchDefaults |
335 kLSLaunchDontAddToRecents |
336 kLSLaunchDontSwitch;
Greg Clayton452bf612010-08-31 18:35:14 +0000337
Jim Ingham363180d2010-08-30 23:48:25 +0000338 char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR");
339
Greg Clayton452bf612010-08-31 18:35:14 +0000340 if (external_editor)
Jim Ingham363180d2010-08-30 23:48:25 +0000341 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000342 if (log)
343 log->Printf("Looking for external editor \"%s\".\n", external_editor);
344
Greg Claytoncb0989a2010-08-31 18:56:24 +0000345 if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0)
Jim Ingham363180d2010-08-30 23:48:25 +0000346 {
Jim Ingham363180d2010-08-30 23:48:25 +0000347 CFCString editor_name (external_editor, kCFStringEncodingUTF8);
Greg Clayton452bf612010-08-31 18:35:14 +0000348 error = ::LSFindApplicationForInfo (kLSUnknownCreator,
349 NULL,
350 editor_name.get(),
351 &g_app_fsref,
352 NULL);
Jim Ingham363180d2010-08-30 23:48:25 +0000353
354 // 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 +0000355 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000356 {
357 if (log)
358 log->Printf("Could not find External Editor application, error: %d.\n", error);
Jim Ingham363180d2010-08-30 23:48:25 +0000359 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000360 }
Jim Ingham363180d2010-08-30 23:48:25 +0000361
362 }
Greg Clayton452bf612010-08-31 18:35:14 +0000363 app_params.application = &g_app_fsref;
Jim Ingham363180d2010-08-30 23:48:25 +0000364 }
365
Jim Ingham74989e82010-08-30 19:44:40 +0000366 ProcessSerialNumber psn;
367 CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000368 error = ::LSOpenURLsWithRole (file_array.get(),
Jim Ingham363180d2010-08-30 23:48:25 +0000369 kLSRolesAll,
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000370 &file_and_line_desc,
371 &app_params,
372 &psn,
373 1);
374
Jim Ingham74989e82010-08-30 19:44:40 +0000375 AEDisposeDesc (&(file_and_line_desc.descContent));
376
377 if (error != noErr)
378 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000379 if (log)
380 log->Printf("LSOpenURLsWithRole failed, error: %d.\n", error);
381
Jim Ingham74989e82010-08-30 19:44:40 +0000382 return false;
383 }
384
385 ProcessInfoRec which_process;
386 bzero(&which_process, sizeof(which_process));
387 unsigned char ap_name[PATH_MAX];
388 which_process.processName = ap_name;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000389 error = ::GetProcessInformation (&psn, &which_process);
Jim Ingham74989e82010-08-30 19:44:40 +0000390
Jim Inghamb0fff352010-08-31 18:05:13 +0000391 bool using_xcode;
392 if (error != noErr)
393 {
394 if (log)
395 log->Printf("GetProcessInformation failed, error: %d.\n", error);
396 using_xcode = false;
397 }
398 else
399 using_xcode = strncmp((char *) ap_name+1, "Xcode", (int) ap_name[0]) == 0;
Jim Ingham74989e82010-08-30 19:44:40 +0000400
401 // Xcode doesn't obey the line number in the Open Apple Event. So I have to send
402 // it an AppleScript to focus on the right line.
403
404 if (using_xcode)
405 {
406 static ComponentInstance osa_component = NULL;
407 static const char *as_template = "tell application \"Xcode\"\n"
408 "set doc to the first document whose path is \"%s\"\n"
409 "set the selection to paragraph %d of doc\n"
410 "--- set the selected paragraph range to {%d, %d} of doc\n"
411 "end tell\n";
412 const int chars_for_int = 32;
413 static int as_template_len = strlen (as_template);
414
415
416 char *as_str;
417 AEDesc as_desc;
418
419 if (osa_component == NULL)
420 {
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000421 osa_component = ::OpenDefaultComponent (kOSAComponentType,
422 kAppleScriptSubtype);
Jim Ingham74989e82010-08-30 19:44:40 +0000423 }
424
425 if (osa_component == NULL)
426 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000427 if (log)
428 log->Printf("Could not get default AppleScript component.\n");
Jim Ingham74989e82010-08-30 19:44:40 +0000429 return false;
430 }
431
432 uint32_t as_str_size = as_template_len + strlen (file_path) + 3 * chars_for_int + 1;
433 as_str = (char *) malloc (as_str_size);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000434 ::snprintf (as_str,
435 as_str_size - 1,
436 as_template,
437 file_path,
438 line_no,
439 line_no,
440 line_no);
Jim Ingham74989e82010-08-30 19:44:40 +0000441
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000442 error = ::AECreateDesc (typeChar,
443 as_str,
444 strlen (as_str),
445 &as_desc);
446
447 ::free (as_str);
Jim Ingham74989e82010-08-30 19:44:40 +0000448
449 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000450 {
451 if (log)
452 log->Printf("Failed to create AEDesc for Xcode AppleEvent: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000453 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000454 }
Jim Ingham74989e82010-08-30 19:44:40 +0000455
456 OSAID ret_OSAID;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000457 error = ::OSACompileExecute (osa_component,
458 &as_desc,
459 kOSANullScript,
460 kOSAModeNeverInteract,
461 &ret_OSAID);
462
463 ::OSADispose (osa_component, ret_OSAID);
Jim Ingham74989e82010-08-30 19:44:40 +0000464
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000465 ::AEDisposeDesc (&as_desc);
Jim Ingham74989e82010-08-30 19:44:40 +0000466
467 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000468 {
469 if (log)
470 log->Printf("Sending AppleEvent to Xcode failed, error: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000471 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000472 }
Jim Ingham74989e82010-08-30 19:44:40 +0000473 }
474
475 return true;
476}