blob: 6ee246b7e89249d1ca1371a1fe6e8e67dde268da [file] [log] [blame]
Jason Molendae369aed2013-04-05 01:03:25 +00001//===-- PlatformDarwinKernel.cpp -----------------------------------*- 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
10#include "PlatformDarwinKernel.h"
11
12#if defined (__APPLE__) // This Plugin uses the Mac-specific source/Host/macosx/cfcpp utilities
13
14
15// C Includes
16// C++ Includes
17// Other libraries and framework includes
18// Project includes
19#include "lldb/Breakpoint/BreakpointLocation.h"
20#include "lldb/Core/ArchSpec.h"
21#include "lldb/Core/Error.h"
22#include "lldb/Core/Module.h"
23#include "lldb/Core/ModuleList.h"
24#include "lldb/Core/ModuleSpec.h"
25#include "lldb/Core/PluginManager.h"
26#include "lldb/Core/StreamString.h"
27#include "lldb/Host/FileSpec.h"
28#include "lldb/Host/Host.h"
29#include "lldb/Target/Process.h"
30#include "lldb/Target/Target.h"
31
32#include <CoreFoundation/CoreFoundation.h>
33
34#include "Host/macosx/cfcpp/CFCBundle.h"
35
36using namespace lldb;
37using namespace lldb_private;
38
39//------------------------------------------------------------------
40// Static Variables
41//------------------------------------------------------------------
42static uint32_t g_initialize_count = 0;
43
44//------------------------------------------------------------------
45// Static Functions
46//------------------------------------------------------------------
47void
48PlatformDarwinKernel::Initialize ()
49{
50 if (g_initialize_count++ == 0)
51 {
52 PluginManager::RegisterPlugin (PlatformDarwinKernel::GetShortPluginNameStatic(),
53 PlatformDarwinKernel::GetDescriptionStatic(),
54 PlatformDarwinKernel::CreateInstance);
55 }
56}
57
58void
59PlatformDarwinKernel::Terminate ()
60{
61 if (g_initialize_count > 0)
62 {
63 if (--g_initialize_count == 0)
64 {
65 PluginManager::UnregisterPlugin (PlatformDarwinKernel::CreateInstance);
66 }
67 }
68}
69
70Platform*
71PlatformDarwinKernel::CreateInstance (bool force, const ArchSpec *arch)
72{
73 // This is a special plugin that we don't want to activate just based on an ArchSpec for normal
74 // userlnad debugging. It is only useful in kernel debug sessions and the DynamicLoaderDarwinPlugin
75 // (or a user doing 'platform select') will force the creation of this Platform plugin.
76 if (force == false)
77 return NULL;
78
79 bool create = force;
80 LazyBool is_ios_debug_session = eLazyBoolCalculate;
81
82 if (create == false && arch && arch->IsValid())
83 {
84 const llvm::Triple &triple = arch->GetTriple();
85 switch (triple.getVendor())
86 {
87 case llvm::Triple::Apple:
88 create = true;
89 break;
90
91 // Only accept "unknown" for vendor if the host is Apple and
92 // it "unknown" wasn't specified (it was just returned becasue it
93 // was NOT specified)
94 case llvm::Triple::UnknownArch:
95 create = !arch->TripleVendorWasSpecified();
96 break;
97 default:
98 break;
99 }
100
101 if (create)
102 {
103 switch (triple.getOS())
104 {
105 case llvm::Triple::Darwin: // Deprecated, but still support Darwin for historical reasons
106 case llvm::Triple::MacOSX:
107 break;
108 // Only accept "vendor" for vendor if the host is Apple and
109 // it "unknown" wasn't specified (it was just returned becasue it
110 // was NOT specified)
111 case llvm::Triple::UnknownOS:
112 create = !arch->TripleOSWasSpecified();
113 break;
114 default:
115 create = false;
116 break;
117 }
118 }
119 }
120 if (arch && arch->IsValid())
121 {
122 switch (arch->GetMachine())
123 {
124 case llvm::Triple::x86:
125 case llvm::Triple::x86_64:
126 case llvm::Triple::ppc:
127 case llvm::Triple::ppc64:
128 is_ios_debug_session = eLazyBoolNo;
129 break;
130 case llvm::Triple::arm:
131 case llvm::Triple::thumb:
132 is_ios_debug_session = eLazyBoolYes;
133 break;
134 default:
135 is_ios_debug_session = eLazyBoolCalculate;
136 break;
137 }
138 }
139 if (create)
140 return new PlatformDarwinKernel (is_ios_debug_session);
141 return NULL;
142}
143
144
145const char *
146PlatformDarwinKernel::GetPluginNameStatic ()
147{
148 return "PlatformDarwinKernel";
149}
150
151const char *
152PlatformDarwinKernel::GetShortPluginNameStatic()
153{
154 return "darwin-kernel";
155}
156
157const char *
158PlatformDarwinKernel::GetDescriptionStatic()
159{
160 return "Darwin Kernel platform plug-in.";
161}
162
163
164//------------------------------------------------------------------
165/// Default Constructor
166//------------------------------------------------------------------
167PlatformDarwinKernel::PlatformDarwinKernel (lldb_private::LazyBool is_ios_debug_session) :
168 PlatformDarwin (false), // This is a remote platform
169 m_name_to_kext_path_map(),
170 m_directories_searched(),
171 m_ios_debug_session(is_ios_debug_session)
172
173{
174 SearchForKexts ();
175}
176
177//------------------------------------------------------------------
178/// Destructor.
179///
180/// The destructor is virtual since this class is designed to be
181/// inherited from by the plug-in instance.
182//------------------------------------------------------------------
183PlatformDarwinKernel::~PlatformDarwinKernel()
184{
185}
186
187
188void
189PlatformDarwinKernel::GetStatus (Stream &strm)
190{
191 Platform::GetStatus (strm);
192 strm.Printf (" Debug session type: ");
193 if (m_ios_debug_session == eLazyBoolYes)
194 strm.Printf ("iOS kernel debugging\n");
195 else if (m_ios_debug_session == eLazyBoolNo)
196 strm.Printf ("Mac OS X kernel debugging\n");
197 else
198 strm.Printf ("unknown kernel debugging\n");
199 const uint32_t num_kdk_dirs = m_directories_searched.size();
200 for (uint32_t i=0; i<num_kdk_dirs; ++i)
201 {
202 const FileSpec &kdk_dir = m_directories_searched[i];
203
204 strm.Printf (" KDK Roots: [%2u] \"%s/%s\"\n",
205 i,
206 kdk_dir.GetDirectory().GetCString(),
207 kdk_dir.GetFilename().GetCString());
208 }
209 strm.Printf (" Total number of kexts indexed: %d\n", (int) m_name_to_kext_path_map.size());
210}
211
212void
213PlatformDarwinKernel::SearchForKexts ()
214{
215 // Differentiate between "ios debug session" and "mac debug session" so we don't index
216 // kext bundles that won't be used in this debug session. If this is an ios kext debug
217 // session, looking in /System/Library/Extensions is a waste of stat()s, for example.
218
219 // Build up a list of all SDKs we'll be searching for directories of kexts
220 // e.g. /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk
221 std::vector<FileSpec> sdk_dirs;
222 if (m_ios_debug_session != eLazyBoolNo)
223 GetiOSSDKDirectoriesToSearch (sdk_dirs);
224 if (m_ios_debug_session != eLazyBoolYes)
225 GetMacSDKDirectoriesToSearch (sdk_dirs);
226
227 GetGenericSDKDirectoriesToSearch (sdk_dirs);
228
229 // Build up a list of directories that hold kext bundles on the system
230 // e.g. /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.Internal.sdk/System/Library/Extensions
231 std::vector<FileSpec> kext_dirs;
232 SearchSDKsForKextDirectories (sdk_dirs, kext_dirs);
233
234 if (m_ios_debug_session != eLazyBoolNo)
235 GetiOSDirectoriesToSearch (kext_dirs);
236 if (m_ios_debug_session != eLazyBoolYes)
237 GetMacDirectoriesToSearch (kext_dirs);
238
239 GetGenericDirectoriesToSearch (kext_dirs);
240
241 // We now have a complete list of directories that we will search for kext bundles
242 m_directories_searched = kext_dirs;
243
244 IndexKextsInDirectories (kext_dirs);
245}
246
247void
248PlatformDarwinKernel::GetiOSSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
249{
250 // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer"
251 const char *developer_dir = GetDeveloperDirectory();
252 if (developer_dir == NULL)
253 developer_dir = "/Applications/Xcode.app/Contents/Developer";
254
255 char pathbuf[PATH_MAX];
256 ::snprintf (pathbuf, sizeof (pathbuf), "%s/Platforms/iPhoneOS.platform/Developer/SDKs", developer_dir);
257 FileSpec ios_sdk(pathbuf, true);
258 if (ios_sdk.Exists() && ios_sdk.GetFileType() == FileSpec::eFileTypeDirectory)
259 {
260 directories.push_back (ios_sdk);
261 }
262}
263
264void
265PlatformDarwinKernel::GetMacSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
266{
267 // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer"
268 const char *developer_dir = GetDeveloperDirectory();
269 if (developer_dir == NULL)
270 developer_dir = "/Applications/Xcode.app/Contents/Developer";
271
272 char pathbuf[PATH_MAX];
273 ::snprintf (pathbuf, sizeof (pathbuf), "%s/Platforms/MacOSX.platform/Developer/SDKs", developer_dir);
274 FileSpec mac_sdk(pathbuf, true);
275 if (mac_sdk.Exists() && mac_sdk.GetFileType() == FileSpec::eFileTypeDirectory)
276 {
277 directories.push_back (mac_sdk);
278 }
279}
280
281void
282PlatformDarwinKernel::GetGenericSDKDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
283{
284 FileSpec generic_sdk("/AppleInternal/Developer/KDKs", true);
285 if (generic_sdk.Exists() && generic_sdk.GetFileType() == FileSpec::eFileTypeDirectory)
286 {
287 directories.push_back (generic_sdk);
288 }
289}
290
291void
292PlatformDarwinKernel::GetiOSDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
293{
294}
295
296void
297PlatformDarwinKernel::GetMacDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
298{
299 FileSpec sle("/System/Library/Extensions", true);
300 if (sle.Exists() && sle.GetFileType() == FileSpec::eFileTypeDirectory)
301 {
302 directories.push_back(sle);
303 }
304}
305
306void
307PlatformDarwinKernel::GetGenericDirectoriesToSearch (std::vector<lldb_private::FileSpec> &directories)
308{
309 // DeveloperDirectory is something like "/Applications/Xcode.app/Contents/Developer"
310 const char *developer_dir = GetDeveloperDirectory();
311 if (developer_dir == NULL)
312 developer_dir = "/Applications/Xcode.app/Contents/Developer";
313
314 char pathbuf[PATH_MAX];
315 ::snprintf (pathbuf, sizeof (pathbuf), "%s/../Symbols", developer_dir);
316 FileSpec symbols_dir (pathbuf, true);
317 if (symbols_dir.Exists() && symbols_dir.GetFileType() == FileSpec::eFileTypeDirectory)
318 {
319 directories.push_back (symbols_dir);
320 }
321}
322
323// Scan through the SDK directories, looking for directories where kexts are likely.
324// Add those directories to kext_dirs.
325void
326PlatformDarwinKernel::SearchSDKsForKextDirectories (std::vector<lldb_private::FileSpec> sdk_dirs, std::vector<lldb_private::FileSpec> &kext_dirs)
327{
328 const uint32_t num_sdks = sdk_dirs.size();
329 for (uint32_t i = 0; i < num_sdks; i++)
330 {
331 const FileSpec &sdk_dir = sdk_dirs[i];
332 char pathbuf[PATH_MAX];
333 if (sdk_dir.GetPath (pathbuf, sizeof (pathbuf)))
334 {
335 const bool find_directories = true;
336 const bool find_files = false;
337 const bool find_other = false;
338 FileSpec::EnumerateDirectory (pathbuf,
339 find_directories,
340 find_files,
341 find_other,
342 GetKextDirectoriesInSDK,
343 &kext_dirs);
344 }
345 }
346}
347
348// Callback for FileSpec::EnumerateDirectory().
349// Step through the entries in a directory like
350// /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs
351// looking for any subdirectories of the form MacOSX10.8.Internal.sdk/System/Library/Extensions
352// Adds these to the vector of FileSpec's.
353
354FileSpec::EnumerateDirectoryResult
355PlatformDarwinKernel::GetKextDirectoriesInSDK (void *baton,
356 FileSpec::FileType file_type,
357 const FileSpec &file_spec)
358{
359 if (file_type == FileSpec::eFileTypeDirectory
360 && (file_spec.GetFileNameExtension() == ConstString("sdk")
361 || file_spec.GetFileNameExtension() == ConstString("kdk")))
362 {
363 char pathbuf[PATH_MAX];
364 if (file_spec.GetPath (pathbuf, PATH_MAX))
365 {
366 char kext_directory_str[PATH_MAX];
367 ::snprintf (kext_directory_str, sizeof (kext_directory_str), "%s/%s", pathbuf, "System/Library/Extensions");
368 FileSpec kext_directory (kext_directory_str, true);
369 if (kext_directory.Exists() && kext_directory.GetFileType() == FileSpec::eFileTypeDirectory)
370 {
371 ((std::vector<lldb_private::FileSpec> *)baton)->push_back(kext_directory);
372 }
373 }
374 }
375 return FileSpec::eEnumerateDirectoryResultNext;
376}
377
378void
379PlatformDarwinKernel::IndexKextsInDirectories (std::vector<lldb_private::FileSpec> kext_dirs)
380{
381 std::vector<FileSpec> kext_bundles;
382 const uint32_t num_dirs = kext_dirs.size();
383 for (uint32_t i = 0; i < num_dirs; i++)
384 {
385 const FileSpec &dir = kext_dirs[i];
386 char pathbuf[PATH_MAX];
387 if (dir.GetPath (pathbuf, sizeof(pathbuf)))
388 {
389 const bool find_directories = true;
390 const bool find_files = false;
391 const bool find_other = false;
392 FileSpec::EnumerateDirectory (pathbuf,
393 find_directories,
394 find_files,
395 find_other,
396 GetKextsInDirectory,
397 &kext_bundles);
398 }
399 }
400
401 const uint32_t num_kexts = kext_bundles.size();
402 for (uint32_t i = 0; i < num_kexts; i++)
403 {
404 const FileSpec &kext = kext_bundles[i];
405 char pathbuf[PATH_MAX];
406 if (kext.GetPath (pathbuf, sizeof (pathbuf)))
407 {
408 CFCBundle bundle (pathbuf);
409 CFStringRef bundle_id (bundle.GetIdentifier());
410 if (bundle_id && CFGetTypeID (bundle_id) == CFStringGetTypeID ())
411 {
412 char bundle_id_buf[PATH_MAX];
413 if (CFStringGetCString (bundle_id, bundle_id_buf, sizeof (bundle_id_buf), kCFStringEncodingUTF8))
414 {
415 ConstString bundle_conststr(bundle_id_buf);
416 m_name_to_kext_path_map.insert(std::pair<ConstString, FileSpec>(bundle_conststr, kext));
417 }
418 }
419 }
420 }
421}
422
423// Callback for FileSpec::EnumerateDirectory().
424// Step through the entries in a directory like /System/Library/Extensions, find .kext bundles, add them
425// to the vector of FileSpecs.
426// If a .kext bundle has a Contents/PlugIns or PlugIns subdir, search for kexts in there too.
427
428FileSpec::EnumerateDirectoryResult
429PlatformDarwinKernel::GetKextsInDirectory (void *baton,
430 FileSpec::FileType file_type,
431 const FileSpec &file_spec)
432{
433 if (file_type == FileSpec::eFileTypeDirectory && file_spec.GetFileNameExtension() == ConstString("kext"))
434 {
435 ((std::vector<lldb_private::FileSpec> *)baton)->push_back(file_spec);
436 bool search_inside = false;
437 char pathbuf[PATH_MAX];
438 ::snprintf (pathbuf, sizeof (pathbuf), "%s/%s/Contents/PlugIns", file_spec.GetDirectory().GetCString(), file_spec.GetFilename().GetCString());
439 FileSpec contents_plugins (pathbuf, false);
440 if (contents_plugins.Exists() && contents_plugins.GetFileType() == FileSpec::eFileTypeDirectory)
441 {
442 search_inside = true;
443 }
444 else
445 {
446 ::snprintf (pathbuf, sizeof (pathbuf), "%s/%s/PlugIns", file_spec.GetDirectory().GetCString(), file_spec.GetFilename().GetCString());
447 FileSpec plugins (pathbuf, false);
448 if (plugins.Exists() && plugins.GetFileType() == FileSpec::eFileTypeDirectory)
449 {
450 search_inside = true;
451 }
452 }
453
454 if (search_inside)
455 {
456 const bool find_directories = true;
457 const bool find_files = false;
458 const bool find_other = false;
459 FileSpec::EnumerateDirectory (pathbuf,
460 find_directories,
461 find_files,
462 find_other,
463 GetKextsInDirectory,
464 baton);
465 }
466 }
467 return FileSpec::eEnumerateDirectoryResultNext;
468}
469
470Error
471PlatformDarwinKernel::GetSharedModule (const ModuleSpec &module_spec,
472 ModuleSP &module_sp,
473 const FileSpecList *module_search_paths_ptr,
474 ModuleSP *old_module_sp_ptr,
475 bool *did_create_ptr)
476{
477 Error error;
478 module_sp.reset();
479 const FileSpec &platform_file = module_spec.GetFileSpec();
480 char kext_bundle_id[PATH_MAX];
481 if (platform_file.GetPath (kext_bundle_id, sizeof (kext_bundle_id)))
482 {
483 ConstString kext_bundle_cs(kext_bundle_id);
484 if (m_name_to_kext_path_map.count(kext_bundle_cs) > 0)
485 {
486 for (BundleIDToKextIterator it = m_name_to_kext_path_map.begin (); it != m_name_to_kext_path_map.end (); ++it)
487 {
488 if (it->first == kext_bundle_cs)
489 {
490 error = ExamineKextForMatchingUUID (it->second, module_spec.GetUUID(), module_sp);
491 if (module_sp.get())
492 {
493 return error;
494 }
495 }
496 }
497 }
498 }
499
500 return error;
501}
502
503Error
504PlatformDarwinKernel::ExamineKextForMatchingUUID (const FileSpec &kext_bundle_path, const lldb_private::UUID &uuid, ModuleSP &exe_module_sp)
505{
506 Error error;
507 FileSpec exe_file = kext_bundle_path;
508 Host::ResolveExecutableInBundle (exe_file);
509 if (exe_file.Exists())
510 {
511 ModuleSpec exe_spec (exe_file);
512 exe_spec.GetUUID() = uuid;
513 error = ModuleList::GetSharedModule (exe_spec, exe_module_sp, NULL, NULL, NULL);
514 if (exe_module_sp && exe_module_sp->GetObjectFile())
515 {
516 return error;
517 }
518 exe_module_sp.reset();
519 }
520 return error;
521}
522
523bool
524PlatformDarwinKernel::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
525{
526#if defined (__arm__)
527 return ARMGetSupportedArchitectureAtIndex (idx, arch);
528#else
529 return x86GetSupportedArchitectureAtIndex (idx, arch);
530#endif
531}
532
533#endif // __APPLE__