Coverage Report

Created: 2023-09-12 09:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- PlatformDarwinDevice.cpp ------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "PlatformDarwinDevice.h"
10
#include "lldb/Core/Module.h"
11
#include "lldb/Core/ModuleList.h"
12
#include "lldb/Core/ModuleSpec.h"
13
#include "lldb/Host/HostInfo.h"
14
#include "lldb/Utility/FileSpec.h"
15
#include "lldb/Utility/LLDBLog.h"
16
#include "lldb/Utility/Log.h"
17
#include <optional>
18
19
using namespace lldb;
20
using namespace lldb_private;
21
22
3.95k
PlatformDarwinDevice::~PlatformDarwinDevice() = default;
23
24
FileSystem::EnumerateDirectoryResult
25
PlatformDarwinDevice::GetContainedFilesIntoVectorOfStringsCallback(
26
81
    void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path) {
27
81
  ((PlatformDarwinDevice::SDKDirectoryInfoCollection *)baton)
28
81
      ->push_back(PlatformDarwinDevice::SDKDirectoryInfo(FileSpec(path)));
29
81
  return FileSystem::eEnumerateDirectoryResultNext;
30
81
}
31
32
1.89k
bool PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded() {
33
1.89k
  Log *log = GetLog(LLDBLog::Host);
34
1.89k
  std::lock_guard<std::mutex> guard(m_sdk_dir_mutex);
35
1.89k
  if (m_sdk_directory_infos.empty()) {
36
    // A --sysroot option was supplied - add it to our list of SDKs to check
37
1.89k
    if (!m_sdk_sysroot.empty()) {
38
0
      FileSpec sdk_sysroot_fspec(m_sdk_sysroot.c_str());
39
0
      FileSystem::Instance().Resolve(sdk_sysroot_fspec);
40
0
      const SDKDirectoryInfo sdk_sysroot_directory_info(sdk_sysroot_fspec);
41
0
      m_sdk_directory_infos.push_back(sdk_sysroot_directory_info);
42
0
      if (log) {
43
0
        LLDB_LOGF(log,
44
0
                  "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded added "
45
0
                  "--sysroot SDK directory %s",
46
0
                  m_sdk_sysroot.c_str());
47
0
      }
48
0
      return true;
49
0
    }
50
1.89k
    const char *device_support_dir = GetDeviceSupportDirectory();
51
1.89k
    if (log) {
52
2
      LLDB_LOGF(log,
53
2
                "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded Got "
54
2
                "DeviceSupport directory %s",
55
2
                device_support_dir);
56
2
    }
57
1.89k
    if (device_support_dir) {
58
1.89k
      const bool find_directories = true;
59
1.89k
      const bool find_files = false;
60
1.89k
      const bool find_other = false;
61
62
1.89k
      SDKDirectoryInfoCollection builtin_sdk_directory_infos;
63
1.89k
      FileSystem::Instance().EnumerateDirectory(
64
1.89k
          m_device_support_directory, find_directories, find_files, find_other,
65
1.89k
          GetContainedFilesIntoVectorOfStringsCallback,
66
1.89k
          &builtin_sdk_directory_infos);
67
68
      // Only add SDK directories that have symbols in them, some SDKs only
69
      // contain developer disk images and no symbols, so they aren't useful to
70
      // us.
71
1.89k
      FileSpec sdk_symbols_symlink_fspec;
72
1.89k
      for (const auto &sdk_directory_info : builtin_sdk_directory_infos) {
73
80
        sdk_symbols_symlink_fspec = sdk_directory_info.directory;
74
80
        sdk_symbols_symlink_fspec.AppendPathComponent("Symbols");
75
80
        if (FileSystem::Instance().Exists(sdk_symbols_symlink_fspec)) {
76
0
          m_sdk_directory_infos.push_back(sdk_directory_info);
77
0
          if (log) {
78
0
            LLDB_LOGF(log,
79
0
                      "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded "
80
0
                      "added builtin SDK directory %s",
81
0
                      sdk_symbols_symlink_fspec.GetPath().c_str());
82
0
          }
83
0
        }
84
80
      }
85
86
1.89k
      const uint32_t num_installed = m_sdk_directory_infos.size();
87
1.89k
      llvm::StringRef dirname = GetDeviceSupportDirectoryName();
88
1.89k
      std::string local_sdk_cache_str = "~/Library/Developer/Xcode/";
89
1.89k
      local_sdk_cache_str += std::string(dirname);
90
1.89k
      FileSpec local_sdk_cache(local_sdk_cache_str.c_str());
91
1.89k
      FileSystem::Instance().Resolve(local_sdk_cache);
92
1.89k
      if (FileSystem::Instance().Exists(local_sdk_cache)) {
93
1
        if (log) {
94
0
          LLDB_LOGF(log,
95
0
                    "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded "
96
0
                    "searching %s for additional SDKs",
97
0
                    local_sdk_cache.GetPath().c_str());
98
0
        }
99
1
        char path[PATH_MAX];
100
1
        if (local_sdk_cache.GetPath(path, sizeof(path))) {
101
1
          FileSystem::Instance().EnumerateDirectory(
102
1
              path, find_directories, find_files, find_other,
103
1
              GetContainedFilesIntoVectorOfStringsCallback,
104
1
              &m_sdk_directory_infos);
105
1
          const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
106
          // First try for an exact match of major, minor and update
107
2
          for (uint32_t i = num_installed; i < num_sdk_infos; 
++i1
) {
108
1
            m_sdk_directory_infos[i].user_cached = true;
109
1
            if (log) {
110
0
              LLDB_LOGF(log,
111
0
                        "PlatformDarwinDevice::"
112
0
                        "UpdateSDKDirectoryInfosIfNeeded "
113
0
                        "user SDK directory %s",
114
0
                        m_sdk_directory_infos[i].directory.GetPath().c_str());
115
0
            }
116
1
          }
117
1
        }
118
1
      }
119
120
1.89k
      const char *addtional_platform_dirs = getenv("PLATFORM_SDK_DIRECTORY");
121
1.89k
      if (addtional_platform_dirs) {
122
0
        SDKDirectoryInfoCollection env_var_sdk_directory_infos;
123
0
        FileSystem::Instance().EnumerateDirectory(
124
0
            addtional_platform_dirs, find_directories, find_files, find_other,
125
0
            GetContainedFilesIntoVectorOfStringsCallback,
126
0
            &env_var_sdk_directory_infos);
127
0
        FileSpec sdk_symbols_symlink_fspec;
128
0
        for (const auto &sdk_directory_info : env_var_sdk_directory_infos) {
129
0
          sdk_symbols_symlink_fspec = sdk_directory_info.directory;
130
0
          sdk_symbols_symlink_fspec.AppendPathComponent("Symbols");
131
0
          if (FileSystem::Instance().Exists(sdk_symbols_symlink_fspec)) {
132
0
            m_sdk_directory_infos.push_back(sdk_directory_info);
133
0
            if (log) {
134
0
              LLDB_LOGF(log,
135
0
                        "PlatformDarwinDevice::UpdateSDKDirectoryInfosIfNeeded "
136
0
                        "added env var SDK directory %s",
137
0
                        sdk_symbols_symlink_fspec.GetPath().c_str());
138
0
            }
139
0
          }
140
0
        }
141
0
      }
142
1.89k
    }
143
1.89k
  }
144
1.89k
  return !m_sdk_directory_infos.empty();
145
1.89k
}
146
147
const PlatformDarwinDevice::SDKDirectoryInfo *
148
947
PlatformDarwinDevice::GetSDKDirectoryForCurrentOSVersion() {
149
947
  uint32_t i;
150
947
  if (UpdateSDKDirectoryInfosIfNeeded()) {
151
2
    const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
152
2
    std::vector<bool> check_sdk_info(num_sdk_infos, true);
153
154
    // Prefer the user SDK build string.
155
2
    std::string build = GetSDKBuild();
156
157
    // Fall back to the platform's build string.
158
2
    if (build.empty()) {
159
2
      if (std::optional<std::string> os_build_str = GetOSBuildString())
160
0
        build.assign(*os_build_str);
161
2
    }
162
163
    // If we have a build string, only check platforms for which the build
164
    // string matches.
165
2
    if (!build.empty()) {
166
0
      for (i = 0; i < num_sdk_infos; ++i)
167
0
        check_sdk_info[i] = m_sdk_directory_infos[i].build.GetStringRef() ==
168
0
                            llvm::StringRef(build);
169
0
    }
170
171
    // If we are connected we can find the version of the OS the platform us
172
    // running on and select the right SDK
173
2
    llvm::VersionTuple version = GetOSVersion();
174
2
    if (!version.empty()) {
175
0
      if (UpdateSDKDirectoryInfosIfNeeded()) {
176
        // First try for an exact match of major, minor and update.
177
0
        for (i = 0; i < num_sdk_infos; ++i) {
178
0
          if (check_sdk_info[i]) {
179
0
            if (m_sdk_directory_infos[i].version == version)
180
0
              return &m_sdk_directory_infos[i];
181
0
          }
182
0
        }
183
        // Try for an exact match of major and minor.
184
0
        for (i = 0; i < num_sdk_infos; ++i) {
185
0
          if (check_sdk_info[i]) {
186
0
            if (m_sdk_directory_infos[i].version.getMajor() ==
187
0
                    version.getMajor() &&
188
0
                m_sdk_directory_infos[i].version.getMinor() ==
189
0
                    version.getMinor()) {
190
0
              return &m_sdk_directory_infos[i];
191
0
            }
192
0
          }
193
0
        }
194
        // Lastly try to match of major version only.
195
0
        for (i = 0; i < num_sdk_infos; ++i) {
196
0
          if (check_sdk_info[i]) {
197
0
            if (m_sdk_directory_infos[i].version.getMajor() ==
198
0
                version.getMajor()) {
199
0
              return &m_sdk_directory_infos[i];
200
0
            }
201
0
          }
202
0
        }
203
0
      }
204
2
    } else if (!build.empty()) {
205
      // No version, just a build number, return the first one that matches.
206
0
      for (i = 0; i < num_sdk_infos; ++i)
207
0
        if (check_sdk_info[i])
208
0
          return &m_sdk_directory_infos[i];
209
0
    }
210
2
  }
211
947
  return nullptr;
212
947
}
213
214
const PlatformDarwinDevice::SDKDirectoryInfo *
215
896
PlatformDarwinDevice::GetSDKDirectoryForLatestOSVersion() {
216
896
  const PlatformDarwinDevice::SDKDirectoryInfo *result = nullptr;
217
896
  if (UpdateSDKDirectoryInfosIfNeeded()) {
218
1
    auto max = std::max_element(
219
1
        m_sdk_directory_infos.begin(), m_sdk_directory_infos.end(),
220
1
        [](const SDKDirectoryInfo &a, const SDKDirectoryInfo &b) {
221
0
          return a.version < b.version;
222
0
        });
223
1
    if (max != m_sdk_directory_infos.end())
224
1
      result = &*max;
225
1
  }
226
896
  return result;
227
896
}
228
229
1.89k
const char *PlatformDarwinDevice::GetDeviceSupportDirectory() {
230
1.89k
  std::string platform_dir =
231
1.89k
      ("/Platforms/" + GetPlatformName() + "/DeviceSupport").str();
232
1.89k
  if (m_device_support_directory.empty()) {
233
892
    if (FileSpec fspec = HostInfo::GetXcodeDeveloperDirectory()) {
234
892
      m_device_support_directory = fspec.GetPath();
235
892
      m_device_support_directory.append(platform_dir.c_str());
236
892
    } else {
237
      // Assign a single NULL character so we know we tried to find the device
238
      // support directory and we don't keep trying to find it over and over.
239
0
      m_device_support_directory.assign(1, '\0');
240
0
    }
241
892
  }
242
  // We should have put a single NULL character into m_device_support_directory
243
  // or it should have a valid path if the code gets here
244
1.89k
  assert(m_device_support_directory.empty() == false);
245
1.89k
  if (m_device_support_directory[0])
246
1.89k
    return m_device_support_directory.c_str();
247
0
  return nullptr;
248
1.89k
}
249
250
7.06k
const char *PlatformDarwinDevice::GetDeviceSupportDirectoryForOSVersion() {
251
7.06k
  if (!m_sdk_sysroot.empty())
252
30
    return m_sdk_sysroot.c_str();
253
254
7.03k
  if (m_device_support_directory_for_os_version.empty()) {
255
895
    const PlatformDarwinDevice::SDKDirectoryInfo *sdk_dir_info =
256
895
        GetSDKDirectoryForCurrentOSVersion();
257
895
    if (sdk_dir_info == nullptr)
258
896
      sdk_dir_info = GetSDKDirectoryForLatestOSVersion();
259
895
    if (sdk_dir_info) {
260
1
      char path[PATH_MAX];
261
1
      if (sdk_dir_info->directory.GetPath(path, sizeof(path))) {
262
1
        m_device_support_directory_for_os_version = path;
263
1
        return m_device_support_directory_for_os_version.c_str();
264
1
      }
265
894
    } else {
266
      // Assign a single NULL character so we know we tried to find the device
267
      // support directory and we don't keep trying to find it over and over.
268
894
      m_device_support_directory_for_os_version.assign(1, '\0');
269
894
    }
270
895
  }
271
  // We should have put a single NULL character into
272
  // m_device_support_directory_for_os_version or it should have a valid path
273
  // if the code gets here
274
7.03k
  assert(m_device_support_directory_for_os_version.empty() == false);
275
7.03k
  if (m_device_support_directory_for_os_version[0])
276
0
    return m_device_support_directory_for_os_version.c_str();
277
7.03k
  return nullptr;
278
7.03k
}
279
280
static lldb_private::Status
281
0
MakeCacheFolderForFile(const FileSpec &module_cache_spec) {
282
0
  FileSpec module_cache_folder =
283
0
      module_cache_spec.CopyByRemovingLastPathComponent();
284
0
  return llvm::sys::fs::create_directory(module_cache_folder.GetPath());
285
0
}
286
287
static lldb_private::Status
288
BringInRemoteFile(Platform *platform,
289
                  const lldb_private::ModuleSpec &module_spec,
290
0
                  const FileSpec &module_cache_spec) {
291
0
  MakeCacheFolderForFile(module_cache_spec);
292
0
  Status err = platform->GetFile(module_spec.GetFileSpec(), module_cache_spec);
293
0
  return err;
294
0
}
295
296
lldb_private::Status PlatformDarwinDevice::GetSharedModuleWithLocalCache(
297
    const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
298
    const lldb_private::FileSpecList *module_search_paths_ptr,
299
114k
    llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {
300
301
114k
  Log *log = GetLog(LLDBLog::Platform);
302
114k
  LLDB_LOGF(log,
303
114k
            "[%s] Trying to find module %s/%s - platform path %s/%s symbol "
304
114k
            "path %s/%s",
305
114k
            (IsHost() ? "host" : "remote"),
306
114k
            module_spec.GetFileSpec().GetDirectory().AsCString(),
307
114k
            module_spec.GetFileSpec().GetFilename().AsCString(),
308
114k
            module_spec.GetPlatformFileSpec().GetDirectory().AsCString(),
309
114k
            module_spec.GetPlatformFileSpec().GetFilename().AsCString(),
310
114k
            module_spec.GetSymbolFileSpec().GetDirectory().AsCString(),
311
114k
            module_spec.GetSymbolFileSpec().GetFilename().AsCString());
312
313
114k
  Status err;
314
315
114k
  if (CheckLocalSharedCache()) {
316
    // When debugging on the host, we are most likely using the same shared
317
    // cache as our inferior. The dylibs from the shared cache might not
318
    // exist on the filesystem, so let's use the images in our own memory
319
    // to create the modules.
320
321
    // Check if the requested image is in our shared cache.
322
114k
    SharedCacheImageInfo image_info =
323
114k
        HostInfo::GetSharedCacheImageInfo(module_spec.GetFileSpec().GetPath());
324
325
    // If we found it and it has the correct UUID, let's proceed with
326
    // creating a module from the memory contents.
327
114k
    if (image_info.uuid &&
328
114k
        
(107k
!module_spec.GetUUID()107k
||
module_spec.GetUUID() == image_info.uuid0
)) {
329
107k
      ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid,
330
107k
                                   image_info.data_sp);
331
107k
      err = ModuleList::GetSharedModule(shared_cache_spec, module_sp,
332
107k
                                        module_search_paths_ptr, old_modules,
333
107k
                                        did_create_ptr);
334
107k
      if (module_sp) {
335
107k
        LLDB_LOGF(log, "[%s] module %s was found in the in-memory shared cache",
336
107k
                  (IsHost() ? "host" : "remote"),
337
107k
                  module_spec.GetFileSpec().GetPath().c_str());
338
107k
        return err;
339
107k
      }
340
107k
    }
341
342
    // We failed to find the module in our shared cache. Let's see if we have a
343
    // copy in our device support directory.
344
7.06k
    FileSpec device_support_spec(GetDeviceSupportDirectoryForOSVersion());
345
7.06k
    device_support_spec.AppendPathComponent("Symbols");
346
7.06k
    device_support_spec.AppendPathComponent(
347
7.06k
        module_spec.GetFileSpec().GetPath());
348
7.06k
    FileSystem::Instance().Resolve(device_support_spec);
349
7.06k
    if (FileSystem::Instance().Exists(device_support_spec)) {
350
0
      ModuleSpec local_spec(device_support_spec, module_spec.GetUUID());
351
0
      err = ModuleList::GetSharedModule(local_spec, module_sp,
352
0
                                        module_search_paths_ptr, old_modules,
353
0
                                        did_create_ptr);
354
0
      if (module_sp) {
355
0
        LLDB_LOGF(log,
356
0
                  "[%s] module %s was found in Device Support "
357
0
                  "directory: %s",
358
0
                  (IsHost() ? "host" : "remote"),
359
0
                  module_spec.GetFileSpec().GetPath().c_str(),
360
0
                  local_spec.GetFileSpec().GetPath().c_str());
361
0
        return err;
362
0
      }
363
0
    }
364
7.06k
  }
365
366
7.11k
  err = ModuleList::GetSharedModule(module_spec, module_sp,
367
7.11k
                                    module_search_paths_ptr, old_modules,
368
7.11k
                                    did_create_ptr);
369
7.11k
  if (module_sp)
370
6.75k
    return err;
371
372
363
  if (!IsHost()) {
373
10
    std::string cache_path(GetLocalCacheDirectory());
374
    // Only search for a locally cached file if we have a valid cache path
375
10
    if (!cache_path.empty()) {
376
0
      std::string module_path(module_spec.GetFileSpec().GetPath());
377
0
      cache_path.append(module_path);
378
0
      FileSpec module_cache_spec(cache_path);
379
380
      // if rsync is supported, always bring in the file - rsync will be very
381
      // efficient when files are the same on the local and remote end of the
382
      // connection
383
0
      if (this->GetSupportsRSync()) {
384
0
        err = BringInRemoteFile(this, module_spec, module_cache_spec);
385
0
        if (err.Fail())
386
0
          return err;
387
0
        if (FileSystem::Instance().Exists(module_cache_spec)) {
388
0
          Log *log = GetLog(LLDBLog::Platform);
389
0
          LLDB_LOGF(log, "[%s] module %s/%s was rsynced and is now there",
390
0
                    (IsHost() ? "host" : "remote"),
391
0
                    module_spec.GetFileSpec().GetDirectory().AsCString(),
392
0
                    module_spec.GetFileSpec().GetFilename().AsCString());
393
0
          ModuleSpec local_spec(module_cache_spec,
394
0
                                module_spec.GetArchitecture());
395
0
          module_sp = std::make_shared<Module>(local_spec);
396
0
          module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
397
0
          return Status();
398
0
        }
399
0
      }
400
401
      // try to find the module in the cache
402
0
      if (FileSystem::Instance().Exists(module_cache_spec)) {
403
        // get the local and remote MD5 and compare
404
0
        if (m_remote_platform_sp) {
405
          // when going over the *slow* GDB remote transfer mechanism we first
406
          // check the hashes of the files - and only do the actual transfer if
407
          // they differ
408
0
          uint64_t high_local, high_remote, low_local, low_remote;
409
0
          auto MD5 = llvm::sys::fs::md5_contents(module_cache_spec.GetPath());
410
0
          if (!MD5)
411
0
            return Status(MD5.getError());
412
0
          std::tie(high_local, low_local) = MD5->words();
413
414
0
          m_remote_platform_sp->CalculateMD5(module_spec.GetFileSpec(),
415
0
                                             low_remote, high_remote);
416
0
          if (low_local != low_remote || high_local != high_remote) {
417
            // bring in the remote file
418
0
            Log *log = GetLog(LLDBLog::Platform);
419
0
            LLDB_LOGF(log,
420
0
                      "[%s] module %s/%s needs to be replaced from remote copy",
421
0
                      (IsHost() ? "host" : "remote"),
422
0
                      module_spec.GetFileSpec().GetDirectory().AsCString(),
423
0
                      module_spec.GetFileSpec().GetFilename().AsCString());
424
0
            Status err =
425
0
                BringInRemoteFile(this, module_spec, module_cache_spec);
426
0
            if (err.Fail())
427
0
              return err;
428
0
          }
429
0
        }
430
431
0
        ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
432
0
        module_sp = std::make_shared<Module>(local_spec);
433
0
        module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
434
0
        Log *log = GetLog(LLDBLog::Platform);
435
0
        LLDB_LOGF(log, "[%s] module %s/%s was found in the cache",
436
0
                  (IsHost() ? "host" : "remote"),
437
0
                  module_spec.GetFileSpec().GetDirectory().AsCString(),
438
0
                  module_spec.GetFileSpec().GetFilename().AsCString());
439
0
        return Status();
440
0
      }
441
442
      // bring in the remote module file
443
0
      LLDB_LOGF(log, "[%s] module %s/%s needs to come in remotely",
444
0
                (IsHost() ? "host" : "remote"),
445
0
                module_spec.GetFileSpec().GetDirectory().AsCString(),
446
0
                module_spec.GetFileSpec().GetFilename().AsCString());
447
0
      Status err = BringInRemoteFile(this, module_spec, module_cache_spec);
448
0
      if (err.Fail())
449
0
        return err;
450
0
      if (FileSystem::Instance().Exists(module_cache_spec)) {
451
0
        Log *log = GetLog(LLDBLog::Platform);
452
0
        LLDB_LOGF(log, "[%s] module %s/%s is now cached and fine",
453
0
                  (IsHost() ? "host" : "remote"),
454
0
                  module_spec.GetFileSpec().GetDirectory().AsCString(),
455
0
                  module_spec.GetFileSpec().GetFilename().AsCString());
456
0
        ModuleSpec local_spec(module_cache_spec, module_spec.GetArchitecture());
457
0
        module_sp = std::make_shared<Module>(local_spec);
458
0
        module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
459
0
        return Status();
460
0
      } else
461
0
        return Status("unable to obtain valid module file");
462
0
    } else
463
10
      return Status("no cache path");
464
10
  } else
465
353
    return Status("unable to resolve module");
466
363
}