blob: 05e883383652c50112be704631d6bd1f7ca6d1c6 [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"
15#include "cfcpp/CFCReleaser.h"
16#include "cfcpp/CFCString.h"
Chris Lattner24943d22010-06-08 16:52:24 +000017
Greg Clayton8f3b21d2010-09-07 20:11:56 +000018#include <objc/objc-auto.h>
19
20#include <Carbon/Carbon.h>
21#include <Foundation/Foundation.h>
Chris Lattner24943d22010-06-08 16:52:24 +000022
23using namespace lldb;
24using namespace lldb_private;
25
Chris Lattner24943d22010-06-08 16:52:24 +000026class MacOSXDarwinThread
27{
28public:
29 MacOSXDarwinThread(const char *thread_name) :
30 m_pool (nil)
31 {
32 // Register our thread with the collector if garbage collection is enabled.
33 if (objc_collectingEnabled())
34 {
35#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
36 // On Leopard and earlier there is no way objc_registerThreadWithCollector
37 // function, so we do it manually.
38 auto_zone_register_thread(auto_zone());
39#else
40 // On SnowLoepard and later we just call the thread registration function.
41 objc_registerThreadWithCollector();
42#endif
43 }
44 else
45 {
46 m_pool = [[NSAutoreleasePool alloc] init];
47 }
48
49
50 Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
51 }
52
53 ~MacOSXDarwinThread()
54 {
55 if (m_pool)
56 [m_pool release];
57 }
58
59 static void PThreadDestructor (void *v)
60 {
61 delete (MacOSXDarwinThread*)v;
62 }
63
64protected:
65 NSAutoreleasePool * m_pool;
66private:
67 DISALLOW_COPY_AND_ASSIGN (MacOSXDarwinThread);
68};
69
70static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
71static pthread_key_t g_thread_create_key = 0;
72
73static void
74InitThreadCreated()
75{
76 ::pthread_key_create (&g_thread_create_key, MacOSXDarwinThread::PThreadDestructor);
77}
78
Chris Lattner24943d22010-06-08 16:52:24 +000079void
80Host::ThreadCreated (const char *thread_name)
81{
82 ::pthread_once (&g_thread_create_once, InitThreadCreated);
83 if (g_thread_create_key)
84 {
85 ::pthread_setspecific (g_thread_create_key, new MacOSXDarwinThread(thread_name));
86 }
87}
88
Chris Lattner24943d22010-06-08 16:52:24 +000089
90bool
91Host::ResolveExecutableInBundle (FileSpec *file)
92{
Greg Clayton8f3b21d2010-09-07 20:11:56 +000093#if defined (__APPLE__)
94 if (file->GetFileType () == FileSpec::eFileTypeDirectory)
95 {
96 char path[PATH_MAX];
97 if (file->GetPath(path, sizeof(path)))
Chris Lattner24943d22010-06-08 16:52:24 +000098 {
Greg Clayton8f3b21d2010-09-07 20:11:56 +000099 CFCBundle bundle (path);
100 CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
101 if (url.get())
102 {
103 if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
Chris Lattner24943d22010-06-08 16:52:24 +0000104 {
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000105 file->SetFile(path);
106 return true;
Chris Lattner24943d22010-06-08 16:52:24 +0000107 }
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000108 }
Chris Lattner24943d22010-06-08 16:52:24 +0000109 }
Greg Clayton8f3b21d2010-09-07 20:11:56 +0000110 }
111#endif
112 return false;
Jim Ingham7508e732010-08-09 23:31:02 +0000113}
Jim Ingham74989e82010-08-30 19:44:40 +0000114
115bool
116Host::OpenFileInExternalEditor (FileSpec &file_spec, uint32_t line_no)
117{
118 // We attach this to an 'odoc' event to specify a particular selection
119 typedef struct {
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000120 int16_t reserved0; // must be zero
121 int16_t fLineNumber;
122 int32_t fSelStart;
123 int32_t fSelEnd;
124 uint32_t reserved1; // must be zero
125 uint32_t reserved2; // must be zero
Jim Ingham74989e82010-08-30 19:44:40 +0000126 } BabelAESelInfo;
127
Jim Inghamb0fff352010-08-31 18:05:13 +0000128 Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST);
Jim Ingham74989e82010-08-30 19:44:40 +0000129 char file_path[PATH_MAX];
130 file_spec.GetPath(file_path, PATH_MAX);
131 CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000132 CFCReleaser<CFURLRef> file_URL (::CFURLCreateWithFileSystemPath (NULL,
133 file_cfstr.get(),
134 kCFURLPOSIXPathStyle,
135 false));
Jim Inghamb0fff352010-08-31 18:05:13 +0000136
137 if (log)
138 log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000139
Jim Ingham74989e82010-08-30 19:44:40 +0000140 OSStatus error;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000141 BabelAESelInfo file_and_line_info =
142 {
143 0, // reserved0
144 line_no - 1, // fLineNumber (zero based line number)
145 1, // fSelStart
146 1024, // fSelEnd
147 0, // reserved1
148 0 // reserved2
149 };
Jim Ingham74989e82010-08-30 19:44:40 +0000150
151 AEKeyDesc file_and_line_desc;
152
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000153 error = ::AECreateDesc (typeUTF8Text,
154 &file_and_line_info,
155 sizeof (file_and_line_info),
156 &(file_and_line_desc.descContent));
Jim Ingham74989e82010-08-30 19:44:40 +0000157
Jim Ingham74989e82010-08-30 19:44:40 +0000158 if (error != noErr)
159 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000160 if (log)
161 log->Printf("Error creating AEDesc: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000162 return false;
163 }
164
165 file_and_line_desc.descKey = keyAEPosition;
166
Greg Claytoncb0989a2010-08-31 18:56:24 +0000167 static std::string g_app_name;
Greg Clayton452bf612010-08-31 18:35:14 +0000168 static FSRef g_app_fsref;
169
Jim Ingham74989e82010-08-30 19:44:40 +0000170 LSApplicationParameters app_params;
Greg Clayton452bf612010-08-31 18:35:14 +0000171 ::bzero (&app_params, sizeof (app_params));
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000172 app_params.flags = kLSLaunchDefaults |
173 kLSLaunchDontAddToRecents |
174 kLSLaunchDontSwitch;
Greg Clayton452bf612010-08-31 18:35:14 +0000175
Jim Ingham363180d2010-08-30 23:48:25 +0000176 char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR");
177
Greg Clayton452bf612010-08-31 18:35:14 +0000178 if (external_editor)
Jim Ingham363180d2010-08-30 23:48:25 +0000179 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000180 if (log)
181 log->Printf("Looking for external editor \"%s\".\n", external_editor);
182
Greg Claytoncb0989a2010-08-31 18:56:24 +0000183 if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0)
Jim Ingham363180d2010-08-30 23:48:25 +0000184 {
Jim Ingham363180d2010-08-30 23:48:25 +0000185 CFCString editor_name (external_editor, kCFStringEncodingUTF8);
Greg Clayton452bf612010-08-31 18:35:14 +0000186 error = ::LSFindApplicationForInfo (kLSUnknownCreator,
187 NULL,
188 editor_name.get(),
189 &g_app_fsref,
190 NULL);
Jim Ingham363180d2010-08-30 23:48:25 +0000191
192 // 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 +0000193 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000194 {
195 if (log)
196 log->Printf("Could not find External Editor application, error: %d.\n", error);
Jim Ingham363180d2010-08-30 23:48:25 +0000197 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000198 }
Jim Ingham363180d2010-08-30 23:48:25 +0000199
200 }
Greg Clayton452bf612010-08-31 18:35:14 +0000201 app_params.application = &g_app_fsref;
Jim Ingham363180d2010-08-30 23:48:25 +0000202 }
203
Jim Ingham74989e82010-08-30 19:44:40 +0000204 ProcessSerialNumber psn;
205 CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000206 error = ::LSOpenURLsWithRole (file_array.get(),
Jim Ingham363180d2010-08-30 23:48:25 +0000207 kLSRolesAll,
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000208 &file_and_line_desc,
209 &app_params,
210 &psn,
211 1);
212
Jim Ingham74989e82010-08-30 19:44:40 +0000213 AEDisposeDesc (&(file_and_line_desc.descContent));
214
215 if (error != noErr)
216 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000217 if (log)
218 log->Printf("LSOpenURLsWithRole failed, error: %d.\n", error);
219
Jim Ingham74989e82010-08-30 19:44:40 +0000220 return false;
221 }
222
223 ProcessInfoRec which_process;
224 bzero(&which_process, sizeof(which_process));
225 unsigned char ap_name[PATH_MAX];
226 which_process.processName = ap_name;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000227 error = ::GetProcessInformation (&psn, &which_process);
Jim Ingham74989e82010-08-30 19:44:40 +0000228
Jim Inghamb0fff352010-08-31 18:05:13 +0000229 bool using_xcode;
230 if (error != noErr)
231 {
232 if (log)
233 log->Printf("GetProcessInformation failed, error: %d.\n", error);
234 using_xcode = false;
235 }
236 else
237 using_xcode = strncmp((char *) ap_name+1, "Xcode", (int) ap_name[0]) == 0;
Jim Ingham74989e82010-08-30 19:44:40 +0000238
239 // Xcode doesn't obey the line number in the Open Apple Event. So I have to send
240 // it an AppleScript to focus on the right line.
241
242 if (using_xcode)
243 {
244 static ComponentInstance osa_component = NULL;
245 static const char *as_template = "tell application \"Xcode\"\n"
246 "set doc to the first document whose path is \"%s\"\n"
247 "set the selection to paragraph %d of doc\n"
248 "--- set the selected paragraph range to {%d, %d} of doc\n"
249 "end tell\n";
250 const int chars_for_int = 32;
251 static int as_template_len = strlen (as_template);
252
253
254 char *as_str;
255 AEDesc as_desc;
256
257 if (osa_component == NULL)
258 {
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000259 osa_component = ::OpenDefaultComponent (kOSAComponentType,
260 kAppleScriptSubtype);
Jim Ingham74989e82010-08-30 19:44:40 +0000261 }
262
263 if (osa_component == NULL)
264 {
Jim Inghamb0fff352010-08-31 18:05:13 +0000265 if (log)
266 log->Printf("Could not get default AppleScript component.\n");
Jim Ingham74989e82010-08-30 19:44:40 +0000267 return false;
268 }
269
270 uint32_t as_str_size = as_template_len + strlen (file_path) + 3 * chars_for_int + 1;
271 as_str = (char *) malloc (as_str_size);
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000272 ::snprintf (as_str,
273 as_str_size - 1,
274 as_template,
275 file_path,
276 line_no,
277 line_no,
278 line_no);
Jim Ingham74989e82010-08-30 19:44:40 +0000279
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000280 error = ::AECreateDesc (typeChar,
281 as_str,
282 strlen (as_str),
283 &as_desc);
284
285 ::free (as_str);
Jim Ingham74989e82010-08-30 19:44:40 +0000286
287 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000288 {
289 if (log)
290 log->Printf("Failed to create AEDesc for Xcode AppleEvent: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000291 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000292 }
Jim Ingham74989e82010-08-30 19:44:40 +0000293
294 OSAID ret_OSAID;
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000295 error = ::OSACompileExecute (osa_component,
296 &as_desc,
297 kOSANullScript,
298 kOSAModeNeverInteract,
299 &ret_OSAID);
300
301 ::OSADispose (osa_component, ret_OSAID);
Jim Ingham74989e82010-08-30 19:44:40 +0000302
Greg Claytonf4fa8a92010-08-30 22:00:34 +0000303 ::AEDisposeDesc (&as_desc);
Jim Ingham74989e82010-08-30 19:44:40 +0000304
305 if (error != noErr)
Jim Inghamb0fff352010-08-31 18:05:13 +0000306 {
307 if (log)
308 log->Printf("Sending AppleEvent to Xcode failed, error: %d.\n", error);
Jim Ingham74989e82010-08-30 19:44:40 +0000309 return false;
Jim Inghamb0fff352010-08-31 18:05:13 +0000310 }
Jim Ingham74989e82010-08-30 19:44:40 +0000311 }
312
313 return true;
314}