LLDB mainline
PlatformQemuUser.cpp
Go to the documentation of this file.
1//===-- PlatformQemuUser.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
15#include "lldb/Target/Process.h"
16#include "lldb/Target/Target.h"
19#include "lldb/Utility/Log.h"
20
21using namespace lldb;
22using namespace lldb_private;
23
25
26namespace {
27#define LLDB_PROPERTIES_platformqemuuser
28#include "PlatformQemuUserProperties.inc"
29
30enum {
31#define LLDB_PROPERTIES_platformqemuuser
32#include "PlatformQemuUserPropertiesEnum.inc"
33};
34
35class PluginProperties : public Properties {
36public:
37 PluginProperties() {
38 m_collection_sp = std::make_shared<OptionValueProperties>(
40 m_collection_sp->Initialize(g_platformqemuuser_properties);
41 }
42
43 llvm::StringRef GetArchitecture() {
44 return GetPropertyAtIndexAs<llvm::StringRef>(ePropertyArchitecture, "");
45 }
46
47 FileSpec GetEmulatorPath() {
48 return GetPropertyAtIndexAs<FileSpec>(ePropertyEmulatorPath, {});
49 }
50
51 Args GetEmulatorArgs() {
52 Args result;
53 m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyEmulatorArgs, result);
54 return result;
55 }
56
57 Environment GetEmulatorEnvVars() {
58 Args args;
59 m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyEmulatorEnvVars, args);
60 return Environment(args);
61 }
62
63 Environment GetTargetEnvVars() {
64 Args args;
65 m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyTargetEnvVars, args);
66 return Environment(args);
67 }
68};
69
70} // namespace
71
72static PluginProperties &GetGlobalProperties() {
73 static PluginProperties g_settings;
74 return g_settings;
75}
76
78 return "Platform for debugging binaries under user mode qemu";
79}
80
85}
86
89}
90
93 debugger, ConstString(GetPluginNameStatic()))) {
95 debugger, GetGlobalProperties().GetValueProperties(),
96 "Properties for the qemu-user platform plugin.",
97 /*is_global_property=*/true);
98 }
99}
100
101PlatformSP PlatformQemuUser::CreateInstance(bool force, const ArchSpec *arch) {
102 if (force)
103 return PlatformSP(new PlatformQemuUser());
104 return nullptr;
105}
106
107std::vector<ArchSpec>
109 llvm::Triple triple = HostInfo::GetArchitecture().GetTriple();
110 triple.setEnvironment(llvm::Triple::UnknownEnvironment);
111 triple.setArchName(GetGlobalProperties().GetArchitecture());
112 if (triple.getArch() != llvm::Triple::UnknownArch)
113 return {ArchSpec(triple)};
114 return {};
115}
116
117static auto get_arg_range(const Args &args) {
118 return llvm::make_range(args.GetArgumentArrayRef().begin(),
119 args.GetArgumentArrayRef().end());
120}
121
122// Returns the emulator environment which result in the desired environment
123// being presented to the emulated process. We want to be careful about
124// preserving the host environment, as it may contain entries (LD_LIBRARY_PATH,
125// for example) needed for the operation of the emulator itself.
127 Environment host) {
128 std::vector<std::string> set_env;
129 for (const auto &KV : target) {
130 // If the host value differs from the target (or is unset), then set it
131 // through QEMU_SET_ENV. Identical entries will be forwarded automatically.
132 auto host_it = host.find(KV.first());
133 if (host_it == host.end() || host_it->second != KV.second)
134 set_env.push_back(Environment::compose(KV));
135 }
136 llvm::sort(set_env);
137
138 std::vector<llvm::StringRef> unset_env;
139 for (const auto &KV : host) {
140 // If the target is missing some host entries, then unset them through
141 // QEMU_UNSET_ENV.
142 if (target.count(KV.first()) == 0)
143 unset_env.push_back(KV.first());
144 }
145 llvm::sort(unset_env);
146
147 // The actual QEMU_(UN)SET_ENV variables should not be forwarded to the
148 // target.
149 if (!set_env.empty()) {
150 host["QEMU_SET_ENV"] = llvm::join(set_env, ",");
151 unset_env.push_back("QEMU_SET_ENV");
152 }
153 if (!unset_env.empty()) {
154 unset_env.push_back("QEMU_UNSET_ENV");
155 host["QEMU_UNSET_ENV"] = llvm::join(unset_env, ",");
156 }
157 return host;
158}
159
161 Debugger &debugger,
162 Target &target, Status &error) {
164
165 FileSpec qemu = GetGlobalProperties().GetEmulatorPath();
166 if (!qemu)
167 qemu.SetPath(("qemu-" + GetGlobalProperties().GetArchitecture()).str());
169
170 llvm::SmallString<0> socket_model, socket_path;
171 HostInfo::GetProcessTempDir().GetPath(socket_model);
172 llvm::sys::path::append(socket_model, "qemu-%%%%%%%%.socket");
173 do {
174 llvm::sys::fs::createUniquePath(socket_model, socket_path, false);
175 } while (FileSystem::Instance().Exists(socket_path));
176
177 Args args({qemu.GetPath(), "-g", socket_path});
178 if (!launch_info.GetArg0().empty()) {
179 args.AppendArgument("-0");
180 args.AppendArgument(launch_info.GetArg0());
181 }
182 args.AppendArguments(GetGlobalProperties().GetEmulatorArgs());
183 args.AppendArgument("--");
184 args.AppendArgument(launch_info.GetExecutableFile().GetPath());
185 for (size_t i = 1; i < launch_info.GetArguments().size(); ++i)
186 args.AppendArgument(launch_info.GetArguments()[i].ref());
187
188 LLDB_LOG(log, "{0} -> {1}", get_arg_range(launch_info.GetArguments()),
189 get_arg_range(args));
190
191 launch_info.SetArguments(args, true);
192
193 Environment emulator_env = Host::GetEnvironment();
194 if (ConstString sysroot = GetSDKRootDirectory())
195 emulator_env["QEMU_LD_PREFIX"] = sysroot.GetStringRef().str();
196 for (const auto &KV : GetGlobalProperties().GetEmulatorEnvVars())
197 emulator_env[KV.first()] = KV.second;
199 std::move(launch_info.GetEnvironment()), std::move(emulator_env));
200
201 launch_info.SetLaunchInSeparateProcessGroup(true);
202 launch_info.GetFlags().Clear(eLaunchFlagDebug);
204
205 // This is automatically done for host platform in
206 // Target::FinalizeFileActions, but we're not a host platform.
207 llvm::Error Err = launch_info.SetUpPtyRedirection();
208 LLDB_LOG_ERROR(log, std::move(Err), "SetUpPtyRedirection failed: {0}");
209
210 error = Host::LaunchProcess(launch_info);
211 if (error.Fail())
212 return nullptr;
213
214 ProcessSP process_sp = target.CreateProcess(
215 launch_info.GetListener(),
217 true);
218 if (!process_sp) {
219 error.SetErrorString("Failed to create GDB process");
220 return nullptr;
221 }
222
223 process_sp->HijackProcessEvents(launch_info.GetHijackListener());
224
225 error = process_sp->ConnectRemote(("unix-connect://" + socket_path).str());
226 if (error.Fail())
227 return nullptr;
228
229 if (launch_info.GetPTY().GetPrimaryFileDescriptor() !=
231 process_sp->SetSTDIOFileDescriptor(
232 launch_info.GetPTY().ReleasePrimaryFileDescriptor());
233
234 return process_sp;
235}
236
239 for (const auto &KV : GetGlobalProperties().GetTargetEnvVars())
240 env[KV.first()] = KV.second;
241 return env;
242}
static llvm::raw_ostream & error(Stream &strm)
static DynamicLoaderDarwinKernelProperties & GetGlobalProperties()
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:342
#define LLDB_LOG_ERROR(log, error,...)
Definition: Log.h:365
static PluginProperties & GetGlobalProperties()
static Environment ComputeLaunchEnvironment(Environment target, Environment host)
static auto get_arg_range(const Args &args)
#define LLDB_PLUGIN_DEFINE(PluginName)
Definition: PluginManager.h:31
An architecture specification class.
Definition: ArchSpec.h:31
A command line argument class.
Definition: Args.h:33
llvm::ArrayRef< const char * > GetArgumentArrayRef() const
Gets the argument as an ArrayRef.
Definition: Args.h:169
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
Definition: Args.cpp:322
A uniqued constant string class.
Definition: ConstString.h:40
A class to manage flag bits.
Definition: Debugger.h:78
static std::string compose(const value_type &KeyValue)
Definition: Environment.h:80
A file utility class.
Definition: FileSpec.h:56
void SetPath(llvm::StringRef p)
Temporary helper for FileSystem change.
Definition: FileSpec.h:279
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:366
bool ResolveExecutableLocation(FileSpec &file_spec)
Call into the Host to see if it can help find the file.
static FileSystem & Instance()
ValueType Clear(ValueType mask=~static_cast< ValueType >(0))
Clear one or more flags.
Definition: Flags.h:61
static Status LaunchProcess(ProcessLaunchInfo &launch_info)
Launch the process specified in launch_info.
static Environment GetEnvironment()
lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target &target, Status &error) override
Subclasses do not need to implement this function as it uses the Platform::LaunchProcess() followed b...
static llvm::StringRef GetPluginDescriptionStatic()
static llvm::StringRef GetPluginNameStatic()
Environment GetEnvironment() override
static void DebuggerInitialize(Debugger &debugger)
static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch)
std::vector< ArchSpec > GetSupportedArchitectures(const ArchSpec &process_host_arch) override
Get the platform's supported architectures in the order in which they should be searched.
ConstString GetSDKRootDirectory() const
Definition: Platform.h:451
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static lldb::OptionValuePropertiesSP GetSettingForPlatformPlugin(Debugger &debugger, ConstString setting_name)
static bool CreateSettingForPlatformPlugin(Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, llvm::StringRef description, bool is_global_property)
static bool UnregisterPlugin(ABICreateInstance create_callback)
lldb::ListenerSP GetHijackListener() const
Definition: ProcessInfo.h:107
llvm::StringRef GetArg0() const
Definition: ProcessInfo.cpp:80
void SetArguments(const Args &args, bool first_arg_is_executable)
FileSpec & GetExecutableFile()
Definition: ProcessInfo.h:42
lldb::ListenerSP GetListener() const
Definition: ProcessInfo.h:101
Environment & GetEnvironment()
Definition: ProcessInfo.h:87
static void NoOpMonitorCallback(lldb::pid_t pid, int signal, int status)
A Monitor callback which does not take any action on process events.
void SetMonitorProcessCallback(Host::MonitorChildProcessCallback callback)
void SetLaunchInSeparateProcessGroup(bool separate)
int GetPrimaryFileDescriptor() const
The primary file descriptor accessor.
int ReleasePrimaryFileDescriptor()
Release the primary file descriptor.
@ invalid_fd
Invalid file descriptor value.
An error handling class.
Definition: Status.h:44
const lldb::ProcessSP & CreateProcess(lldb::ListenerSP listener_sp, llvm::StringRef plugin_name, const FileSpec *crash_file, bool can_connect)
Definition: Target.cpp:208
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:314
Definition: SBAddress.h:15