Error TargetList::CreateTargetInternal (Debugger &debugger, const char *user_exe_path, const char *triple_cstr, bool get_dependent_files, const OptionGroupPlatform *platform_options, TargetSP &target_sp, bool is_dummy_target) { Error error; PlatformSP platform_sp; // This is purposely left empty unless it is specified by triple_cstr. // If not initialized via triple_cstr, then the currently selected platform // will set the architecture correctly. const ArchSpec arch(triple_cstr); if (triple_cstr && triple_cstr[0]) { if (!arch.IsValid()) { error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr); return error; } } ArchSpec platform_arch(arch); bool prefer_platform_arch = false; CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); // let's see if there is already an existing plaform before we go creating another... platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); if (platform_options && platform_options->PlatformWasSpecified ()) { // Create a new platform if it doesn't match the selected platform if (!platform_options->PlatformMatches(platform_sp)) { const bool select_platform = true; platform_sp = platform_options->CreatePlatformWithOptions (interpreter, arch, select_platform, error, platform_arch); if (!platform_sp) return error; } } if (user_exe_path && user_exe_path[0]) { ModuleSpecList module_specs; ModuleSpec module_spec; module_spec.GetFileSpec().SetFile(user_exe_path, true); // Resolve the executable in case we are given a path to a application bundle // like a .app bundle on MacOSX Host::ResolveExecutableInBundle (module_spec.GetFileSpec()); lldb::offset_t file_offset = 0; lldb::offset_t file_size = 0; const size_t num_specs = ObjectFile::GetModuleSpecifications (module_spec.GetFileSpec(), file_offset, file_size, module_specs); if (num_specs > 0) { ModuleSpec matching_module_spec; if (num_specs == 1) { if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) { if (platform_arch.IsValid()) { if (platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture())) { // If the OS or vendor weren't specified, then adopt the module's // architecture so that the platform matching can be more accurate if (!platform_arch.TripleOSWasSpecified() || !platform_arch.TripleVendorWasSpecified()) { prefer_platform_arch = true; platform_arch = matching_module_spec.GetArchitecture(); } } else { StreamString platform_arch_strm; StreamString module_arch_strm; platform_arch.DumpTriple(platform_arch_strm); matching_module_spec.GetArchitecture().DumpTriple(module_arch_strm); error.SetErrorStringWithFormat("the specified architecture '%s' is not compatible with '%s' in '%s'", platform_arch_strm.GetString().c_str(), module_arch_strm.GetString().c_str(), module_spec.GetFileSpec().GetPath().c_str()); return error; } } else { // Only one arch and none was specified prefer_platform_arch = true; platform_arch = matching_module_spec.GetArchitecture(); } } } else { if (arch.IsValid()) { module_spec.GetArchitecture() = arch; if (module_specs.FindMatchingModuleSpec(module_spec, matching_module_spec)) { prefer_platform_arch = true; platform_arch = matching_module_spec.GetArchitecture(); } } else { // No architecture specified, check if there is only one platform for // all of the architectures. typedef std::vector<PlatformSP> PlatformList; PlatformList platforms; PlatformSP host_platform_sp = Platform::GetHostPlatform(); for (size_t i=0; i<num_specs; ++i) { ModuleSpec module_spec; if (module_specs.GetModuleSpecAtIndex(i, module_spec)) { // See if there was a selected platform and check that first // since the user may have specified it. if (platform_sp) { if (platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, NULL)) { platforms.push_back(platform_sp); continue; } } // Next check the host platform it if wasn't already checked above if (host_platform_sp && (!platform_sp || host_platform_sp->GetName() != platform_sp->GetName())) { if (host_platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, NULL)) { platforms.push_back(host_platform_sp); continue; } } // Just find a platform that matches the architecture in the executable file PlatformSP fallback_platform_sp (Platform::GetPlatformForArchitecture(module_spec.GetArchitecture(), nullptr)); if (fallback_platform_sp) { platforms.push_back(fallback_platform_sp); } } } Platform *platform_ptr = NULL; bool more_than_one_platforms = false; for (const auto &the_platform_sp : platforms) { if (platform_ptr) { if (platform_ptr->GetName() != the_platform_sp->GetName()) { more_than_one_platforms = true; platform_ptr = NULL; break; } } else { platform_ptr = the_platform_sp.get(); } } if (platform_ptr) { // All platforms for all modules in the exectuable match, so we can select this platform platform_sp = platforms.front(); } else if (more_than_one_platforms == false) { // No platforms claim to support this file error.SetErrorString ("No matching platforms found for this file, specify one with the --platform option"); return error; } else { // More than one platform claims to support this file, so the --platform option must be specified StreamString error_strm; std::set<Platform *> platform_set; error_strm.Printf ("more than one platform supports this executable ("); for (const auto &the_platform_sp : platforms) { if (platform_set.find(the_platform_sp.get()) == platform_set.end()) { if (!platform_set.empty()) error_strm.PutCString(", "); error_strm.PutCString(the_platform_sp->GetName().GetCString()); platform_set.insert(the_platform_sp.get()); } } error_strm.Printf("), use the --platform option to specify a platform"); error.SetErrorString(error_strm.GetString().c_str()); return error; } } } } } // If we have a valid architecture, make sure the current platform is // compatible with that architecture if (!prefer_platform_arch && arch.IsValid()) { if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) { platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); if (!is_dummy_target && platform_sp) debugger.GetPlatformList().SetSelectedPlatform(platform_sp); } } else if (platform_arch.IsValid()) { // if "arch" isn't valid, yet "platform_arch" is, it means we have an executable file with // a single architecture which should be used ArchSpec fixed_platform_arch; if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, &fixed_platform_arch)) { platform_sp = Platform::GetPlatformForArchitecture(platform_arch, &fixed_platform_arch); if (!is_dummy_target && platform_sp) debugger.GetPlatformList().SetSelectedPlatform(platform_sp); } } if (!platform_arch.IsValid()) platform_arch = arch; error = TargetList::CreateTargetInternal (debugger, user_exe_path, platform_arch, get_dependent_files, platform_sp, target_sp, is_dummy_target); return error; }
Error TargetList::CreateTargetInternal (Debugger &debugger, const char *user_exe_path, const ArchSpec& specified_arch, bool get_dependent_files, lldb::PlatformSP &platform_sp, lldb::TargetSP &target_sp, bool is_dummy_target) { Timer scoped_timer (__PRETTY_FUNCTION__, "TargetList::CreateTarget (file = '%s', arch = '%s')", user_exe_path, specified_arch.GetArchitectureName()); Error error; ArchSpec arch(specified_arch); if (arch.IsValid()) { if (!platform_sp || !platform_sp->IsCompatibleArchitecture(arch, false, NULL)) platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); } if (!platform_sp) platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); if (!arch.IsValid()) arch = specified_arch; FileSpec file (user_exe_path, false); if (!file.Exists() && user_exe_path && user_exe_path[0] == '~') { // we want to expand the tilde but we don't want to resolve any symbolic links // so we can't use the FileSpec constructor's resolve flag llvm::SmallString<64> unglobbed_path(user_exe_path); FileSpec::ResolveUsername(unglobbed_path); if (unglobbed_path.empty()) file = FileSpec(user_exe_path, false); else file = FileSpec(unglobbed_path.c_str(), false); } bool user_exe_path_is_bundle = false; char resolved_bundle_exe_path[PATH_MAX]; resolved_bundle_exe_path[0] = '\0'; if (file) { if (file.GetFileType() == FileSpec::eFileTypeDirectory) user_exe_path_is_bundle = true; if (file.IsRelative() && user_exe_path) { // Ignore paths that start with "./" and "../" if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') || (user_exe_path[0] == '.' && user_exe_path[1] == '.' && user_exe_path[2] == '/'))) { char cwd[PATH_MAX]; if (getcwd (cwd, sizeof(cwd))) { std::string cwd_user_exe_path (cwd); cwd_user_exe_path += '/'; cwd_user_exe_path += user_exe_path; FileSpec cwd_file (cwd_user_exe_path.c_str(), false); if (cwd_file.Exists()) file = cwd_file; } } } ModuleSP exe_module_sp; if (platform_sp) { FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); ModuleSpec module_spec(file, arch); error = platform_sp->ResolveExecutable (module_spec, exe_module_sp, executable_search_paths.GetSize() ? &executable_search_paths : NULL); } if (error.Success() && exe_module_sp) { if (exe_module_sp->GetObjectFile() == NULL) { if (arch.IsValid()) { error.SetErrorStringWithFormat("\"%s\" doesn't contain architecture %s", file.GetPath().c_str(), arch.GetArchitectureName()); } else { error.SetErrorStringWithFormat("unsupported file type \"%s\"", file.GetPath().c_str()); } return error; } target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target)); target_sp->SetExecutableModule (exe_module_sp, get_dependent_files); if (user_exe_path_is_bundle) exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path, sizeof(resolved_bundle_exe_path)); } } else { // No file was specified, just create an empty target with any arch // if a valid arch was specified target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target)); } if (target_sp) { // Set argv0 with what the user typed, unless the user specified a // directory. If the user specified a directory, then it is probably a // bundle that was resolved and we need to use the resolved bundle path if (user_exe_path) { // Use exactly what the user typed as the first argument when we exec or posix_spawn if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) { target_sp->SetArg0 (resolved_bundle_exe_path); } else { // Use resolved path target_sp->SetArg0 (file.GetPath().c_str()); } } if (file.GetDirectory()) { FileSpec file_dir; file_dir.GetDirectory() = file.GetDirectory(); target_sp->GetExecutableSearchPaths ().Append (file_dir); } // Don't put the dummy target in the target list, it's held separately. if (!is_dummy_target) { Mutex::Locker locker(m_target_list_mutex); m_selected_target_idx = m_target_list.size(); m_target_list.push_back(target_sp); // Now prime this from the dummy target: target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget()); } else { m_dummy_target_sp = target_sp; } } return error; }
Error TargetList::CreateTarget ( Debugger &debugger, const FileSpec& file, const ArchSpec& specified_arch, bool get_dependent_files, PlatformSP &platform_sp, TargetSP &target_sp ) { Timer scoped_timer (__PRETTY_FUNCTION__, "TargetList::CreateTarget (file = '%s/%s', arch = '%s')", file.GetDirectory().AsCString(), file.GetFilename().AsCString(), specified_arch.GetArchitectureName()); Error error; ArchSpec arch(specified_arch); if (platform_sp) { if (arch.IsValid()) { if (!platform_sp->IsCompatibleArchitecture(arch)) platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); } } else if (arch.IsValid()) { platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); } if (!platform_sp) platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); if (!arch.IsValid()) arch = specified_arch; if (file) { ModuleSP exe_module_sp; FileSpec resolved_file(file); if (platform_sp) { FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); error = platform_sp->ResolveExecutable (file, arch, exe_module_sp, executable_search_paths.GetSize() ? &executable_search_paths : NULL); } if (error.Success() && exe_module_sp) { if (exe_module_sp->GetObjectFile() == NULL) { if (arch.IsValid()) { error.SetErrorStringWithFormat("\"%s%s%s\" doesn't contain architecture %s", file.GetDirectory().AsCString(), file.GetDirectory() ? "/" : "", file.GetFilename().AsCString(), arch.GetArchitectureName()); } else { error.SetErrorStringWithFormat("unsupported file type \"%s%s%s\"", file.GetDirectory().AsCString(), file.GetDirectory() ? "/" : "", file.GetFilename().AsCString()); } return error; } target_sp.reset(new Target(debugger, arch, platform_sp)); target_sp->SetExecutableModule (exe_module_sp, get_dependent_files); } } else { // No file was specified, just create an empty target with any arch // if a valid arch was specified target_sp.reset(new Target(debugger, arch, platform_sp)); } if (target_sp) { target_sp->UpdateInstanceName(); Mutex::Locker locker(m_target_list_mutex); m_selected_target_idx = m_target_list.size(); m_target_list.push_back(target_sp); } return error; }
Error TargetList::CreateTarget (Debugger &debugger, const FileSpec& file, const char *triple_cstr, bool get_dependent_files, const OptionGroupPlatform *platform_options, TargetSP &target_sp) { Error error; PlatformSP platform_sp; // This is purposely left empty unless it is specified by triple_cstr. // If not initialized via triple_cstr, then the currently selected platform // will set the architecture correctly. const ArchSpec arch(triple_cstr); if (triple_cstr && triple_cstr[0]) { if (!arch.IsValid()) { error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr); return error; } } ArchSpec platform_arch(arch); CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); if (platform_options) { if (platform_options->PlatformWasSpecified ()) { const bool select_platform = true; platform_sp = platform_options->CreatePlatformWithOptions (interpreter, arch, select_platform, error, platform_arch); if (!platform_sp) return error; } } if (!platform_sp) { // Get the current platform and make sure it is compatible with the // current architecture if we have a valid architecture. platform_sp = debugger.GetPlatformList().GetSelectedPlatform (); if (arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, &platform_arch)) { platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); } } if (!platform_arch.IsValid()) platform_arch = arch; error = TargetList::CreateTarget (debugger, file, platform_arch, get_dependent_files, platform_sp, target_sp); if (target_sp) { if (file.GetDirectory()) { FileSpec file_dir; file_dir.GetDirectory() = file.GetDirectory(); target_sp->GetExecutableSearchPaths ().Append (file_dir); } } return error; }
Error TargetList::CreateTarget (Debugger &debugger, const char *user_exe_path, const char *triple_cstr, bool get_dependent_files, const OptionGroupPlatform *platform_options, TargetSP &target_sp) { Error error; PlatformSP platform_sp; // This is purposely left empty unless it is specified by triple_cstr. // If not initialized via triple_cstr, then the currently selected platform // will set the architecture correctly. const ArchSpec arch(triple_cstr); if (triple_cstr && triple_cstr[0]) { if (!arch.IsValid()) { error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr); return error; } } ArchSpec platform_arch(arch); bool prefer_platform_arch = false; if (user_exe_path && user_exe_path[0]) { ModuleSpecList module_specs; ModuleSpec module_spec; module_spec.GetFileSpec().SetFile(user_exe_path, true); // Resolve the executable in case we are given a path to a application bundle // like a .app bundle on MacOSX Host::ResolveExecutableInBundle (module_spec.GetFileSpec()); lldb::offset_t file_offset = 0; lldb::offset_t file_size = 0; const size_t num_specs = ObjectFile::GetModuleSpecifications (module_spec.GetFileSpec(), file_offset, file_size, module_specs); if (num_specs > 0) { ModuleSpec matching_module_spec; if (num_specs == 1) { if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) { if (platform_arch.IsValid()) { if (platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture())) { // If the OS or vendor weren't specified, then adopt the module's // architecture so that the platform matching can be more accurate if (!platform_arch.TripleOSWasSpecified() || !platform_arch.TripleVendorWasSpecified()) { prefer_platform_arch = true; platform_arch = matching_module_spec.GetArchitecture(); } } else { error.SetErrorStringWithFormat("the specified architecture '%s' is not compatible with '%s' in '%s'", platform_arch.GetTriple().str().c_str(), matching_module_spec.GetArchitecture().GetTriple().str().c_str(), module_spec.GetFileSpec().GetPath().c_str()); return error; } } else { // Only one arch and none was specified prefer_platform_arch = true; platform_arch = matching_module_spec.GetArchitecture(); } } } else { if (arch.IsValid()) { module_spec.GetArchitecture() = arch; if (module_specs.FindMatchingModuleSpec(module_spec, matching_module_spec)) { prefer_platform_arch = true; platform_arch = matching_module_spec.GetArchitecture(); } } } } } CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); if (platform_options) { if (platform_options->PlatformWasSpecified ()) { const bool select_platform = true; platform_sp = platform_options->CreatePlatformWithOptions (interpreter, arch, select_platform, error, platform_arch); if (!platform_sp) return error; } } if (!platform_sp) { // Get the current platform and make sure it is compatible with the // current architecture if we have a valid architecture. platform_sp = debugger.GetPlatformList().GetSelectedPlatform (); if (!prefer_platform_arch && arch.IsValid()) { if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); } else if (platform_arch.IsValid()) { // if "arch" isn't valid, yet "platform_arch" is, it means we have an executable file with // a single architecture which should be used ArchSpec fixed_platform_arch; if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, &fixed_platform_arch)) platform_sp = Platform::GetPlatformForArchitecture(platform_arch, &fixed_platform_arch); } } if (!platform_arch.IsValid()) platform_arch = arch; error = TargetList::CreateTarget (debugger, user_exe_path, platform_arch, get_dependent_files, platform_sp, target_sp); return error; }