aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp1324
1 files changed, 675 insertions, 649 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index b8a737586eb4..6ed3f4fc3f59 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -43,7 +43,6 @@
#include "lldb/Host/HostThread.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Host/PseudoTerminal.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Host/XML.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -106,7 +105,7 @@ namespace lldb {
// and get the packet history dumped to a file.
void DumpProcessGDBRemotePacketHistory(void *p, const char *path) {
auto file = FileSystem::Instance().Open(
- FileSpec(path), File::eOpenOptionWrite | File::eOpenOptionCanCreate);
+ FileSpec(path), File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate);
if (!file) {
llvm::consumeError(file.takeError());
return;
@@ -129,7 +128,7 @@ enum {
class PluginProperties : public Properties {
public:
static ConstString GetSettingName() {
- return ProcessGDBRemote::GetPluginNameStatic();
+ return ConstString(ProcessGDBRemote::GetPluginNameStatic());
}
PluginProperties() : Properties() {
@@ -168,13 +167,9 @@ public:
}
};
-typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP;
-
-static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() {
- static ProcessKDPPropertiesSP g_settings_sp;
- if (!g_settings_sp)
- g_settings_sp = std::make_shared<PluginProperties>();
- return g_settings_sp;
+static PluginProperties &GetGlobalPluginProperties() {
+ static PluginProperties g_settings;
+ return g_settings;
}
} // namespace
@@ -191,12 +186,7 @@ static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() {
#define HIGH_PORT (49151u)
#endif
-ConstString ProcessGDBRemote::GetPluginNameStatic() {
- static ConstString g_name("gdb-remote");
- return g_name;
-}
-
-const char *ProcessGDBRemote::GetPluginDescriptionStatic() {
+llvm::StringRef ProcessGDBRemote::GetPluginDescriptionStatic() {
return "GDB Remote protocol based debugging plug-in.";
}
@@ -216,7 +206,7 @@ ProcessGDBRemote::CreateInstance(lldb::TargetSP target_sp,
}
std::chrono::seconds ProcessGDBRemote::GetPacketTimeout() {
- return std::chrono::seconds(GetGlobalPluginProperties()->GetPacketTimeout());
+ return std::chrono::seconds(GetGlobalPluginProperties().GetPacketTimeout());
}
bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp,
@@ -254,8 +244,7 @@ bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp,
ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
ListenerSP listener_sp)
: Process(target_sp, listener_sp),
- m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_last_stop_packet_mutex(),
- m_register_info_sp(nullptr),
+ m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_register_info_sp(nullptr),
m_async_broadcaster(nullptr, "lldb.process.gdb-remote.async-broadcaster"),
m_async_listener_sp(
Listener::MakeListener("lldb.process.gdb-remote.async-listener")),
@@ -267,7 +256,8 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
m_waiting_for_attach(false), m_destroy_tried_resuming(false),
m_command_sp(), m_breakpoint_pc_offset(0),
m_initial_tid(LLDB_INVALID_THREAD_ID), m_replay_mode(false),
- m_allow_flash_writes(false), m_erased_flash_ranges() {
+ m_allow_flash_writes(false), m_erased_flash_ranges(),
+ m_vfork_in_progress(false) {
m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit,
"async thread should exit");
m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue,
@@ -305,12 +295,12 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
}
const uint64_t timeout_seconds =
- GetGlobalPluginProperties()->GetPacketTimeout();
+ GetGlobalPluginProperties().GetPacketTimeout();
if (timeout_seconds > 0)
m_gdb_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds));
m_use_g_packet_for_reading =
- GetGlobalPluginProperties()->GetUseGPacketForReading();
+ GetGlobalPluginProperties().GetUseGPacketForReading();
}
// Destructor
@@ -331,11 +321,6 @@ ProcessGDBRemote::~ProcessGDBRemote() {
KillDebugserverProcess();
}
-// PluginInterface
-ConstString ProcessGDBRemote::GetPluginName() { return GetPluginNameStatic(); }
-
-uint32_t ProcessGDBRemote::GetPluginVersion() { return 1; }
-
bool ProcessGDBRemote::ParsePythonTargetDefinition(
const FileSpec &target_definition_fspec) {
ScriptInterpreter *interpreter =
@@ -384,20 +369,14 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition(
}
static size_t SplitCommaSeparatedRegisterNumberString(
- const llvm::StringRef &comma_separated_regiter_numbers,
+ const llvm::StringRef &comma_separated_register_numbers,
std::vector<uint32_t> &regnums, int base) {
regnums.clear();
- std::pair<llvm::StringRef, llvm::StringRef> value_pair;
- value_pair.second = comma_separated_regiter_numbers;
- do {
- value_pair = value_pair.second.split(',');
- if (!value_pair.first.empty()) {
- uint32_t reg = StringConvert::ToUInt32(value_pair.first.str().c_str(),
- LLDB_INVALID_REGNUM, base);
- if (reg != LLDB_INVALID_REGNUM)
- regnums.push_back(reg);
- }
- } while (!value_pair.second.empty());
+ for (llvm::StringRef x : llvm::split(comma_separated_register_numbers, ',')) {
+ uint32_t reg;
+ if (llvm::to_integer(x, reg, base))
+ regnums.push_back(reg);
+ }
return regnums.size();
}
@@ -412,7 +391,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
// timeout is and can see it.
const auto host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout();
if (host_packet_timeout > std::chrono::seconds(0)) {
- GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout.count());
+ GetGlobalPluginProperties().SetPacketTimeout(host_packet_timeout.count());
}
// Register info search order:
@@ -422,7 +401,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
// 3 - Fall back on the qRegisterInfo packets.
FileSpec target_definition_fspec =
- GetGlobalPluginProperties()->GetTargetDefinitionFile();
+ GetGlobalPluginProperties().GetTargetDefinitionFile();
if (!FileSystem::Instance().Exists(target_definition_fspec)) {
// If the filename doesn't exist, it may be a ~ not having been expanded -
// try to resolve it.
@@ -457,7 +436,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
return;
char packet[128];
- uint32_t reg_offset = LLDB_INVALID_INDEX32;
+ std::vector<DynamicRegisterInfo::Register> registers;
uint32_t reg_num = 0;
for (StringExtractorGDBRemote::ResponseType response_type =
StringExtractorGDBRemote::eResponse;
@@ -473,53 +452,25 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
if (response_type == StringExtractorGDBRemote::eResponse) {
llvm::StringRef name;
llvm::StringRef value;
- ConstString reg_name;
- ConstString alt_name;
- ConstString set_name;
- std::vector<uint32_t> value_regs;
- std::vector<uint32_t> invalidate_regs;
- std::vector<uint8_t> dwarf_opcode_bytes;
- RegisterInfo reg_info = {
- nullptr, // Name
- nullptr, // Alt name
- 0, // byte size
- reg_offset, // offset
- eEncodingUint, // encoding
- eFormatHex, // format
- {
- LLDB_INVALID_REGNUM, // eh_frame reg num
- LLDB_INVALID_REGNUM, // DWARF reg num
- LLDB_INVALID_REGNUM, // generic reg num
- reg_num, // process plugin reg num
- reg_num // native register number
- },
- nullptr,
- nullptr,
- nullptr, // Dwarf expression opcode bytes pointer
- 0 // Dwarf expression opcode bytes length
- };
+ DynamicRegisterInfo::Register reg_info;
while (response.GetNameColonValue(name, value)) {
if (name.equals("name")) {
- reg_name.SetString(value);
+ reg_info.name.SetString(value);
} else if (name.equals("alt-name")) {
- alt_name.SetString(value);
+ reg_info.alt_name.SetString(value);
} else if (name.equals("bitsize")) {
- value.getAsInteger(0, reg_info.byte_size);
- reg_info.byte_size /= CHAR_BIT;
+ if (!value.getAsInteger(0, reg_info.byte_size))
+ reg_info.byte_size /= CHAR_BIT;
} else if (name.equals("offset")) {
- if (value.getAsInteger(0, reg_offset))
- reg_offset = UINT32_MAX;
+ value.getAsInteger(0, reg_info.byte_offset);
} else if (name.equals("encoding")) {
const Encoding encoding = Args::StringToEncoding(value);
if (encoding != eEncodingInvalid)
reg_info.encoding = encoding;
} else if (name.equals("format")) {
- Format format = eFormatInvalid;
- if (OptionArgParser::ToFormat(value.str().c_str(), format, nullptr)
+ if (!OptionArgParser::ToFormat(value.str().c_str(), reg_info.format, nullptr)
.Success())
- reg_info.format = format;
- else {
reg_info.format =
llvm::StringSwitch<Format>(value)
.Case("binary", eFormatBinary)
@@ -536,58 +487,23 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
.Case("vector-uint64", eFormatVectorOfUInt64)
.Case("vector-uint128", eFormatVectorOfUInt128)
.Default(eFormatInvalid);
- }
} else if (name.equals("set")) {
- set_name.SetString(value);
+ reg_info.set_name.SetString(value);
} else if (name.equals("gcc") || name.equals("ehframe")) {
- if (value.getAsInteger(0, reg_info.kinds[eRegisterKindEHFrame]))
- reg_info.kinds[eRegisterKindEHFrame] = LLDB_INVALID_REGNUM;
+ value.getAsInteger(0, reg_info.regnum_ehframe);
} else if (name.equals("dwarf")) {
- if (value.getAsInteger(0, reg_info.kinds[eRegisterKindDWARF]))
- reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM;
+ value.getAsInteger(0, reg_info.regnum_dwarf);
} else if (name.equals("generic")) {
- reg_info.kinds[eRegisterKindGeneric] =
- Args::StringToGenericRegister(value);
+ reg_info.regnum_generic = Args::StringToGenericRegister(value);
} else if (name.equals("container-regs")) {
- SplitCommaSeparatedRegisterNumberString(value, value_regs, 16);
+ SplitCommaSeparatedRegisterNumberString(value, reg_info.value_regs, 16);
} else if (name.equals("invalidate-regs")) {
- SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 16);
- } else if (name.equals("dynamic_size_dwarf_expr_bytes")) {
- size_t dwarf_opcode_len = value.size() / 2;
- assert(dwarf_opcode_len > 0);
-
- dwarf_opcode_bytes.resize(dwarf_opcode_len);
- reg_info.dynamic_size_dwarf_len = dwarf_opcode_len;
-
- StringExtractor opcode_extractor(value);
- uint32_t ret_val =
- opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes);
- assert(dwarf_opcode_len == ret_val);
- UNUSED_IF_ASSERT_DISABLED(ret_val);
- reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data();
+ SplitCommaSeparatedRegisterNumberString(value, reg_info.invalidate_regs, 16);
}
}
- reg_info.byte_offset = reg_offset;
assert(reg_info.byte_size != 0);
- reg_offset = LLDB_INVALID_INDEX32;
- if (!value_regs.empty()) {
- value_regs.push_back(LLDB_INVALID_REGNUM);
- reg_info.value_regs = value_regs.data();
- }
- if (!invalidate_regs.empty()) {
- invalidate_regs.push_back(LLDB_INVALID_REGNUM);
- reg_info.invalidate_regs = invalidate_regs.data();
- }
-
- reg_info.name = reg_name.AsCString();
- // We have to make a temporary ABI here, and not use the GetABI because
- // this code gets called in DidAttach, when the target architecture
- // (and consequently the ABI we'll get from the process) may be wrong.
- if (ABISP abi_sp = ABI::FindPlugin(shared_from_this(), arch_to_use))
- abi_sp->AugmentRegisterInfo(reg_info);
-
- m_register_info_sp->AddRegister(reg_info, reg_name, alt_name, set_name);
+ registers.push_back(reg_info);
} else {
break; // ensure exit before reg_num is incremented
}
@@ -596,31 +512,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
}
}
- if (m_register_info_sp->GetNumRegisters() > 0) {
- m_register_info_sp->Finalize(GetTarget().GetArchitecture());
- return;
- }
-
- // We didn't get anything if the accumulated reg_num is zero. See if we are
- // debugging ARM and fill with a hard coded register set until we can get an
- // updated debugserver down on the devices. On the other hand, if the
- // accumulated reg_num is positive, see if we can add composite registers to
- // the existing primordial ones.
- bool from_scratch = (m_register_info_sp->GetNumRegisters() == 0);
-
- if (!target_arch.IsValid()) {
- if (arch_to_use.IsValid() &&
- (arch_to_use.GetMachine() == llvm::Triple::arm ||
- arch_to_use.GetMachine() == llvm::Triple::thumb) &&
- arch_to_use.GetTriple().getVendor() == llvm::Triple::Apple)
- m_register_info_sp->HardcodeARMRegisters(from_scratch);
- } else if (target_arch.GetMachine() == llvm::Triple::arm ||
- target_arch.GetMachine() == llvm::Triple::thumb) {
- m_register_info_sp->HardcodeARMRegisters(from_scratch);
- }
-
- // At this point, we can finalize our register info.
- m_register_info_sp->Finalize(GetTarget().GetArchitecture());
+ AddRemoteRegisters(registers, arch_to_use);
}
Status ProcessGDBRemote::WillLaunch(lldb_private::Module *module) {
@@ -665,10 +557,6 @@ Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) {
if (m_gdb_comm.GetStopReply(response)) {
SetLastStopPacket(response);
- // '?' Packets must be handled differently in non-stop mode
- if (GetTarget().GetNonStopModeEnabled())
- HandleStopReplySequence();
-
Target &target = GetTarget();
if (!target.GetArchitecture().IsValid()) {
if (m_gdb_comm.GetProcessArchitecture().IsValid()) {
@@ -721,14 +609,6 @@ Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) {
__FUNCTION__, GetID(),
GetTarget().GetArchitecture().GetTriple().getTriple().c_str());
- if (error.Success()) {
- PlatformSP platform_sp = GetTarget().GetPlatform();
- if (platform_sp && platform_sp->IsConnected())
- SetUnixSignals(platform_sp->GetUnixSignals());
- else
- SetUnixSignals(UnixSignals::Create(GetTarget().GetArchitecture()));
- }
-
return error;
}
@@ -799,146 +679,133 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module,
// LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
// ::LogSetLogFile ("/dev/stdout");
- ObjectFile *object_file = exe_module->GetObjectFile();
- if (object_file) {
- error = EstablishConnectionIfNeeded(launch_info);
- if (error.Success()) {
- PseudoTerminal pty;
- const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
-
- PlatformSP platform_sp(GetTarget().GetPlatform());
- if (disable_stdio) {
- // set to /dev/null unless redirected to a file above
- if (!stdin_file_spec)
- stdin_file_spec.SetFile(FileSystem::DEV_NULL,
- FileSpec::Style::native);
- if (!stdout_file_spec)
- stdout_file_spec.SetFile(FileSystem::DEV_NULL,
- FileSpec::Style::native);
- if (!stderr_file_spec)
- stderr_file_spec.SetFile(FileSystem::DEV_NULL,
- FileSpec::Style::native);
- } else if (platform_sp && platform_sp->IsHost()) {
- // If the debugserver is local and we aren't disabling STDIO, lets use
- // a pseudo terminal to instead of relying on the 'O' packets for stdio
- // since 'O' packets can really slow down debugging if the inferior
- // does a lot of output.
- if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
- !errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) {
- FileSpec secondary_name(pty.GetSecondaryName());
-
- if (!stdin_file_spec)
- stdin_file_spec = secondary_name;
-
- if (!stdout_file_spec)
- stdout_file_spec = secondary_name;
-
- if (!stderr_file_spec)
- stderr_file_spec = secondary_name;
- }
- LLDB_LOGF(
- log,
- "ProcessGDBRemote::%s adjusted STDIO paths for local platform "
- "(IsHost() is true) using secondary: stdin=%s, stdout=%s, "
- "stderr=%s",
- __FUNCTION__,
- stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
- stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
- stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
- }
-
- LLDB_LOGF(log,
- "ProcessGDBRemote::%s final STDIO paths after all "
- "adjustments: stdin=%s, stdout=%s, stderr=%s",
- __FUNCTION__,
- stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
- stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
- stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
-
- if (stdin_file_spec)
- m_gdb_comm.SetSTDIN(stdin_file_spec);
- if (stdout_file_spec)
- m_gdb_comm.SetSTDOUT(stdout_file_spec);
- if (stderr_file_spec)
- m_gdb_comm.SetSTDERR(stderr_file_spec);
+ error = EstablishConnectionIfNeeded(launch_info);
+ if (error.Success()) {
+ PseudoTerminal pty;
+ const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
- m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR);
- m_gdb_comm.SetDetachOnError(launch_flags & eLaunchFlagDetachOnError);
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+ if (disable_stdio) {
+ // set to /dev/null unless redirected to a file above
+ if (!stdin_file_spec)
+ stdin_file_spec.SetFile(FileSystem::DEV_NULL,
+ FileSpec::Style::native);
+ if (!stdout_file_spec)
+ stdout_file_spec.SetFile(FileSystem::DEV_NULL,
+ FileSpec::Style::native);
+ if (!stderr_file_spec)
+ stderr_file_spec.SetFile(FileSystem::DEV_NULL,
+ FileSpec::Style::native);
+ } else if (platform_sp && platform_sp->IsHost()) {
+ // If the debugserver is local and we aren't disabling STDIO, lets use
+ // a pseudo terminal to instead of relying on the 'O' packets for stdio
+ // since 'O' packets can really slow down debugging if the inferior
+ // does a lot of output.
+ if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
+ !errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) {
+ FileSpec secondary_name(pty.GetSecondaryName());
- m_gdb_comm.SendLaunchArchPacket(
- GetTarget().GetArchitecture().GetArchitectureName());
+ if (!stdin_file_spec)
+ stdin_file_spec = secondary_name;
- const char *launch_event_data = launch_info.GetLaunchEventData();
- if (launch_event_data != nullptr && *launch_event_data != '\0')
- m_gdb_comm.SendLaunchEventDataPacket(launch_event_data);
+ if (!stdout_file_spec)
+ stdout_file_spec = secondary_name;
- if (working_dir) {
- m_gdb_comm.SetWorkingDir(working_dir);
+ if (!stderr_file_spec)
+ stderr_file_spec = secondary_name;
}
+ LLDB_LOGF(
+ log,
+ "ProcessGDBRemote::%s adjusted STDIO paths for local platform "
+ "(IsHost() is true) using secondary: stdin=%s, stdout=%s, "
+ "stderr=%s",
+ __FUNCTION__,
+ stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
+ }
- // Send the environment and the program + arguments after we connect
- m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s final STDIO paths after all "
+ "adjustments: stdin=%s, stdout=%s, stderr=%s",
+ __FUNCTION__,
+ stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
+
+ if (stdin_file_spec)
+ m_gdb_comm.SetSTDIN(stdin_file_spec);
+ if (stdout_file_spec)
+ m_gdb_comm.SetSTDOUT(stdout_file_spec);
+ if (stderr_file_spec)
+ m_gdb_comm.SetSTDERR(stderr_file_spec);
+
+ m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR);
+ m_gdb_comm.SetDetachOnError(launch_flags & eLaunchFlagDetachOnError);
+
+ m_gdb_comm.SendLaunchArchPacket(
+ GetTarget().GetArchitecture().GetArchitectureName());
+
+ const char *launch_event_data = launch_info.GetLaunchEventData();
+ if (launch_event_data != nullptr && *launch_event_data != '\0')
+ m_gdb_comm.SendLaunchEventDataPacket(launch_event_data);
+
+ if (working_dir) {
+ m_gdb_comm.SetWorkingDir(working_dir);
+ }
- {
- // Scope for the scoped timeout object
- GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm,
- std::chrono::seconds(10));
+ // Send the environment and the program + arguments after we connect
+ m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
- int arg_packet_err = m_gdb_comm.SendArgumentsPacket(launch_info);
- if (arg_packet_err == 0) {
- std::string error_str;
- if (m_gdb_comm.GetLaunchSuccess(error_str)) {
- SetID(m_gdb_comm.GetCurrentProcessID());
- } else {
- error.SetErrorString(error_str.c_str());
- }
+ {
+ // Scope for the scoped timeout object
+ GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm,
+ std::chrono::seconds(10));
+
+ int arg_packet_err = m_gdb_comm.SendArgumentsPacket(launch_info);
+ if (arg_packet_err == 0) {
+ std::string error_str;
+ if (m_gdb_comm.GetLaunchSuccess(error_str)) {
+ SetID(m_gdb_comm.GetCurrentProcessID());
} else {
- error.SetErrorStringWithFormat("'A' packet returned an error: %i",
- arg_packet_err);
+ error.SetErrorString(error_str.c_str());
}
+ } else {
+ error.SetErrorStringWithFormat("'A' packet returned an error: %i",
+ arg_packet_err);
}
+ }
- if (GetID() == LLDB_INVALID_PROCESS_ID) {
- LLDB_LOGF(log, "failed to connect to debugserver: %s",
- error.AsCString());
- KillDebugserverProcess();
- return error;
- }
+ if (GetID() == LLDB_INVALID_PROCESS_ID) {
+ LLDB_LOGF(log, "failed to connect to debugserver: %s",
+ error.AsCString());
+ KillDebugserverProcess();
+ return error;
+ }
- StringExtractorGDBRemote response;
- if (m_gdb_comm.GetStopReply(response)) {
- SetLastStopPacket(response);
- // '?' Packets must be handled differently in non-stop mode
- if (GetTarget().GetNonStopModeEnabled())
- HandleStopReplySequence();
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.GetStopReply(response)) {
+ SetLastStopPacket(response);
- const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
+ const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
- if (process_arch.IsValid()) {
- GetTarget().MergeArchitecture(process_arch);
- } else {
- const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture();
- if (host_arch.IsValid())
- GetTarget().MergeArchitecture(host_arch);
- }
+ if (process_arch.IsValid()) {
+ GetTarget().MergeArchitecture(process_arch);
+ } else {
+ const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture();
+ if (host_arch.IsValid())
+ GetTarget().MergeArchitecture(host_arch);
+ }
- SetPrivateState(SetThreadStopInfo(response));
+ SetPrivateState(SetThreadStopInfo(response));
- if (!disable_stdio) {
- if (pty.GetPrimaryFileDescriptor() != PseudoTerminal::invalid_fd)
- SetSTDIOFileDescriptor(pty.ReleasePrimaryFileDescriptor());
- }
+ if (!disable_stdio) {
+ if (pty.GetPrimaryFileDescriptor() != PseudoTerminal::invalid_fd)
+ SetSTDIOFileDescriptor(pty.ReleasePrimaryFileDescriptor());
}
- } else {
- LLDB_LOGF(log, "failed to connect to debugserver: %s", error.AsCString());
}
} else {
- // Set our user ID to an invalid process ID.
- SetID(LLDB_INVALID_PROCESS_ID);
- error.SetErrorStringWithFormat(
- "failed to get object file from '%s' for arch %s",
- exe_module->GetFileSpec().GetFilename().AsCString(),
- exe_module->GetArchitecture().GetArchitectureName());
+ LLDB_LOGF(log, "failed to connect to debugserver: %s", error.AsCString());
}
return error;
}
@@ -960,9 +827,6 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
if (conn_up->Connect(connect_url, &error) == eConnectionStatusSuccess) {
m_gdb_comm.SetConnection(std::move(conn_up));
break;
- } else if (error.WasInterrupted()) {
- // If we were interrupted, don't keep retrying.
- break;
}
retry_count++;
@@ -981,11 +845,6 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
return error;
}
- // Start the communications read thread so all incoming data can be parsed
- // into packets and queued as they arrive.
- if (GetTarget().GetNonStopModeEnabled())
- m_gdb_comm.StartReadThread();
-
// We always seem to be able to open a connection to a local port so we need
// to make sure we can then send data to it. If we can't then we aren't
// actually connected to anything, so try and do the handshake with the
@@ -997,10 +856,6 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
return error;
}
- // Send $QNonStop:1 packet on startup if required
- if (GetTarget().GetNonStopModeEnabled())
- GetTarget().SetNonStopModeEnabled(m_gdb_comm.SetNonStopMode(true));
-
m_gdb_comm.GetEchoSupported();
m_gdb_comm.GetThreadSuffixSupported();
m_gdb_comm.GetListThreadsInStopReplySupported();
@@ -1009,10 +864,6 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
m_gdb_comm.GetVAttachOrWaitSupported();
m_gdb_comm.EnableErrorStringInPacket();
- // Ask the remote server for the default thread id
- if (GetTarget().GetNonStopModeEnabled())
- m_gdb_comm.GetDefaultThreadId(m_initial_tid);
-
size_t num_cmds = GetExtraStartupCommands().GetArgumentCount();
for (size_t idx = 0; idx < num_cmds; idx++) {
StringExtractorGDBRemote response;
@@ -1113,6 +964,18 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {
if (StructuredData::Array *supported_packets =
m_gdb_comm.GetSupportedStructuredDataPlugins())
MapSupportedStructuredDataPlugins(*supported_packets);
+
+ // If connected to LLDB ("native-signals+"), use signal defs for
+ // the remote platform. If connected to GDB, just use the standard set.
+ if (!m_gdb_comm.UsesNativeSignals()) {
+ SetUnixSignals(std::make_shared<GDBRemoteSignals>());
+ } else {
+ PlatformSP platform_sp = GetTarget().GetPlatform();
+ if (platform_sp && platform_sp->IsConnected())
+ SetUnixSignals(platform_sp->GetUnixSignals());
+ else
+ SetUnixSignals(UnixSignals::Create(GetTarget().GetArchitecture()));
+ }
}
void ProcessGDBRemote::MaybeLoadExecutableModule() {
@@ -1272,10 +1135,9 @@ Status ProcessGDBRemote::DoResume() {
StreamString continue_packet;
bool continue_packet_error = false;
if (m_gdb_comm.HasAnyVContSupport()) {
- if (!GetTarget().GetNonStopModeEnabled() &&
- (m_continue_c_tids.size() == num_threads ||
- (m_continue_c_tids.empty() && m_continue_C_tids.empty() &&
- m_continue_s_tids.empty() && m_continue_S_tids.empty()))) {
+ if (m_continue_c_tids.size() == num_threads ||
+ (m_continue_c_tids.empty() && m_continue_C_tids.empty() &&
+ m_continue_s_tids.empty() && m_continue_S_tids.empty())) {
// All threads are continuing, just send a "c" packet
continue_packet.PutCString("c");
} else {
@@ -1393,14 +1255,7 @@ Status ProcessGDBRemote::DoResume() {
// All threads are resuming...
m_gdb_comm.SetCurrentThreadForRun(-1);
- // If in Non-Stop-Mode use vCont when stepping
- if (GetTarget().GetNonStopModeEnabled()) {
- if (m_gdb_comm.GetVContSupported('s'))
- continue_packet.PutCString("vCont;s");
- else
- continue_packet.PutChar('s');
- } else
- continue_packet.PutChar('s');
+ continue_packet.PutChar('s');
continue_packet_error = false;
} else if (num_continue_c_tids == 0 && num_continue_C_tids == 0 &&
@@ -1514,21 +1369,14 @@ size_t ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue(
return m_thread_ids.size();
}
-size_t
-ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue(std::string &value) {
+size_t ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue(
+ llvm::StringRef value) {
m_thread_pcs.clear();
- size_t comma_pos;
- lldb::addr_t pc;
- while ((comma_pos = value.find(',')) != std::string::npos) {
- value[comma_pos] = '\0';
- pc = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16);
- if (pc != LLDB_INVALID_ADDRESS)
+ for (llvm::StringRef x : llvm::split(value, ',')) {
+ lldb::addr_t pc;
+ if (llvm::to_integer(x, pc, 16))
m_thread_pcs.push_back(pc);
- value.erase(0, comma_pos + 1);
}
- pc = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16);
- if (pc != LLDB_INVALID_ADDRESS)
- m_thread_pcs.push_back(pc);
return m_thread_pcs.size();
}
@@ -1559,40 +1407,30 @@ bool ProcessGDBRemote::UpdateThreadIDList() {
// See if we can get the thread IDs from the current stop reply packets
// that might contain a "threads" key/value pair
- // Lock the thread stack while we access it
- // Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex);
- std::unique_lock<std::recursive_mutex> stop_stack_lock(
- m_last_stop_packet_mutex, std::defer_lock);
- if (stop_stack_lock.try_lock()) {
- // Get the number of stop packets on the stack
- int nItems = m_stop_packet_stack.size();
- // Iterate over them
- for (int i = 0; i < nItems; i++) {
- // Get the thread stop info
- StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i];
- const std::string &stop_info_str =
- std::string(stop_info.GetStringRef());
+ if (m_last_stop_packet) {
+ // Get the thread stop info
+ StringExtractorGDBRemote &stop_info = *m_last_stop_packet;
+ const std::string &stop_info_str = std::string(stop_info.GetStringRef());
- m_thread_pcs.clear();
- const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:");
- if (thread_pcs_pos != std::string::npos) {
- const size_t start = thread_pcs_pos + strlen(";thread-pcs:");
- const size_t end = stop_info_str.find(';', start);
- if (end != std::string::npos) {
- std::string value = stop_info_str.substr(start, end - start);
- UpdateThreadPCsFromStopReplyThreadsValue(value);
- }
+ m_thread_pcs.clear();
+ const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:");
+ if (thread_pcs_pos != std::string::npos) {
+ const size_t start = thread_pcs_pos + strlen(";thread-pcs:");
+ const size_t end = stop_info_str.find(';', start);
+ if (end != std::string::npos) {
+ std::string value = stop_info_str.substr(start, end - start);
+ UpdateThreadPCsFromStopReplyThreadsValue(value);
}
+ }
- const size_t threads_pos = stop_info_str.find(";threads:");
- if (threads_pos != std::string::npos) {
- const size_t start = threads_pos + strlen(";threads:");
- const size_t end = stop_info_str.find(';', start);
- if (end != std::string::npos) {
- std::string value = stop_info_str.substr(start, end - start);
- if (UpdateThreadIDsFromStopReplyThreadsValue(value))
- return true;
- }
+ const size_t threads_pos = stop_info_str.find(";threads:");
+ if (threads_pos != std::string::npos) {
+ const size_t start = threads_pos + strlen(";threads:");
+ const size_t end = stop_info_str.find(';', start);
+ if (end != std::string::npos) {
+ std::string value = stop_info_str.substr(start, end - start);
+ if (UpdateThreadIDsFromStopReplyThreadsValue(value))
+ return true;
}
}
}
@@ -1908,6 +1746,28 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
} else if (reason == "processor trace") {
thread_sp->SetStopInfo(StopInfo::CreateStopReasonProcessorTrace(
*thread_sp, description.c_str()));
+ } else if (reason == "fork") {
+ StringExtractor desc_extractor(description.c_str());
+ lldb::pid_t child_pid = desc_extractor.GetU64(
+ LLDB_INVALID_PROCESS_ID);
+ lldb::tid_t child_tid = desc_extractor.GetU64(
+ LLDB_INVALID_THREAD_ID);
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonFork(
+ *thread_sp, child_pid, child_tid));
+ handled = true;
+ } else if (reason == "vfork") {
+ StringExtractor desc_extractor(description.c_str());
+ lldb::pid_t child_pid = desc_extractor.GetU64(
+ LLDB_INVALID_PROCESS_ID);
+ lldb::tid_t child_tid = desc_extractor.GetU64(
+ LLDB_INVALID_THREAD_ID);
+ thread_sp->SetStopInfo(StopInfo::CreateStopReasonVFork(
+ *thread_sp, child_pid, child_tid));
+ handled = true;
+ } else if (reason == "vforkdone") {
+ thread_sp->SetStopInfo(
+ StopInfo::CreateStopReasonVForkDone(*thread_sp));
+ handled = true;
}
} else if (!signo) {
addr_t pc = thread_sp->GetRegisterContext()->GetPC();
@@ -2032,6 +1892,7 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
// Iterate through all of the thread dictionary key/value pairs from the
// structured data dictionary
+ // FIXME: we're silently ignoring invalid data here
thread_dict->ForEach([this, &tid, &expedited_register_map, &thread_name,
&signo, &reason, &description, &exc_type, &exc_data,
&thread_dispatch_qaddr, &queue_vars_valid,
@@ -2096,9 +1957,8 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
registers_dict->ForEach(
[&expedited_register_map](ConstString key,
StructuredData::Object *object) -> bool {
- const uint32_t reg =
- StringConvert::ToUInt32(key.GetCString(), UINT32_MAX, 10);
- if (reg != UINT32_MAX)
+ uint32_t reg;
+ if (llvm::to_integer(key.AsCString(), reg))
expedited_register_map[reg] =
std::string(object->GetStringValue());
return true; // Keep iterating through all array items
@@ -2314,6 +2174,21 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
LLDB_LOG_ERROR(log, std::move(error), "Failed to load modules: {0}");
}
+ } else if (key.compare("fork") == 0 || key.compare("vfork") == 0) {
+ // fork includes child pid/tid in thread-id format
+ StringExtractorGDBRemote thread_id{value};
+ auto pid_tid = thread_id.GetPidTid(LLDB_INVALID_PROCESS_ID);
+ if (!pid_tid) {
+ Log *log(
+ ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ LLDB_LOG(log, "Invalid PID/TID to fork: {0}", value);
+ pid_tid = {{LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID}};
+ }
+
+ reason = key.str();
+ StreamString ostr;
+ ostr.Printf("%" PRIu64 " %" PRIu64, pid_tid->first, pid_tid->second);
+ description = std::string(ostr.GetString());
} else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) {
uint32_t reg = UINT32_MAX;
if (!key.getAsInteger(16, reg))
@@ -2380,22 +2255,9 @@ void ProcessGDBRemote::RefreshStateAfterStop() {
// date before we do that or we might overwrite what was computed here.
UpdateThreadListIfNeeded();
- // Scope for the lock
- {
- // Lock the thread stack while we access it
- std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex);
- // Get the number of stop packets on the stack
- int nItems = m_stop_packet_stack.size();
- // Iterate over them
- for (int i = 0; i < nItems; i++) {
- // Get the thread stop info
- StringExtractorGDBRemote stop_info = m_stop_packet_stack[i];
- // Process thread stop info
- SetThreadStopInfo(stop_info);
- }
- // Clear the thread stop stack
- m_stop_packet_stack.clear();
- }
+ if (m_last_stop_packet)
+ SetThreadStopInfo(*m_last_stop_packet);
+ m_last_stop_packet.reset();
// If we have queried for a default thread id
if (m_initial_tid != LLDB_INVALID_THREAD_ID) {
@@ -2479,9 +2341,9 @@ Status ProcessGDBRemote::DoDestroy() {
m_public_state.GetValue() != eStateRunning) {
PlatformSP platform_sp = GetTarget().GetPlatform();
- // FIXME: These should be ConstStrings so we aren't doing strcmp'ing.
if (platform_sp && platform_sp->GetName() &&
- platform_sp->GetName() == PlatformRemoteiOS::GetPluginNameStatic()) {
+ platform_sp->GetName().GetStringRef() ==
+ PlatformRemoteiOS::GetPluginNameStatic()) {
if (m_destroy_tried_resuming) {
if (log)
log->PutCString("ProcessGDBRemote::DoDestroy() - Tried resuming to "
@@ -2644,20 +2506,7 @@ void ProcessGDBRemote::SetLastStopPacket(
m_gdb_comm.ResetDiscoverableSettings(did_exec);
}
- // Scope the lock
- {
- // Lock the thread stack while we access it
- std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex);
-
- // We are are not using non-stop mode, there can only be one last stop
- // reply packet, so clear the list.
- if (!GetTarget().GetNonStopModeEnabled())
- m_stop_packet_stack.clear();
-
- // Add this stop packet to the stop packet stack This stack will get popped
- // and examined when we switch to the Stopped state
- m_stop_packet_stack.push_back(response);
- }
+ m_last_stop_packet = response;
}
void ProcessGDBRemote::SetUnixSignals(const UnixSignalsSP &signals_sp) {
@@ -3052,8 +2901,8 @@ lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t size,
return allocated_addr;
}
-Status ProcessGDBRemote::GetMemoryRegionInfo(addr_t load_addr,
- MemoryRegionInfo &region_info) {
+Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr,
+ MemoryRegionInfo &region_info) {
Status error(m_gdb_comm.GetMemoryRegionInfo(load_addr, region_info));
return error;
@@ -3638,7 +3487,7 @@ void ProcessGDBRemote::DebuggerInitialize(Debugger &debugger) {
debugger, PluginProperties::GetSettingName())) {
const bool is_global_setting = true;
PluginManager::CreateSettingForProcessPlugin(
- debugger, GetGlobalPluginProperties()->GetValueProperties(),
+ debugger, GetGlobalPluginProperties().GetValueProperties(),
ConstString("Properties for the gdb-remote process plug-in."),
is_global_setting);
}
@@ -3774,88 +3623,72 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) {
process->SetPrivateState(eStateRunning);
StringExtractorGDBRemote response;
- // If in Non-Stop-Mode
- if (process->GetTarget().GetNonStopModeEnabled()) {
- // send the vCont packet
- if (!process->GetGDBRemote().SendvContPacket(
- llvm::StringRef(continue_cstr, continue_cstr_len),
- process->GetInterruptTimeout(), response)) {
- // Something went wrong
- done = true;
- break;
- }
- }
- // If in All-Stop-Mode
- else {
- StateType stop_state =
- process->GetGDBRemote().SendContinuePacketAndWaitForResponse(
- *process, *process->GetUnixSignals(),
- llvm::StringRef(continue_cstr, continue_cstr_len),
- process->GetInterruptTimeout(),
- response);
-
- // We need to immediately clear the thread ID list so we are sure
- // to get a valid list of threads. The thread ID list might be
- // contained within the "response", or the stop reply packet that
- // caused the stop. So clear it now before we give the stop reply
- // packet to the process using the
- // process->SetLastStopPacket()...
- process->ClearThreadIDList();
+ StateType stop_state =
+ process->GetGDBRemote().SendContinuePacketAndWaitForResponse(
+ *process, *process->GetUnixSignals(),
+ llvm::StringRef(continue_cstr, continue_cstr_len),
+ process->GetInterruptTimeout(), response);
+
+ // We need to immediately clear the thread ID list so we are sure
+ // to get a valid list of threads. The thread ID list might be
+ // contained within the "response", or the stop reply packet that
+ // caused the stop. So clear it now before we give the stop reply
+ // packet to the process using the
+ // process->SetLastStopPacket()...
+ process->ClearThreadIDList();
+
+ switch (stop_state) {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ process->SetLastStopPacket(response);
+ process->SetPrivateState(stop_state);
+ break;
- switch (stop_state) {
- case eStateStopped:
- case eStateCrashed:
- case eStateSuspended:
- process->SetLastStopPacket(response);
- process->SetPrivateState(stop_state);
- break;
-
- case eStateExited: {
- process->SetLastStopPacket(response);
- process->ClearThreadIDList();
- response.SetFilePos(1);
-
- int exit_status = response.GetHexU8();
- std::string desc_string;
- if (response.GetBytesLeft() > 0 &&
- response.GetChar('-') == ';') {
- llvm::StringRef desc_str;
- llvm::StringRef desc_token;
- while (response.GetNameColonValue(desc_token, desc_str)) {
- if (desc_token != "description")
- continue;
- StringExtractor extractor(desc_str);
- extractor.GetHexByteString(desc_string);
- }
+ case eStateExited: {
+ process->SetLastStopPacket(response);
+ process->ClearThreadIDList();
+ response.SetFilePos(1);
+
+ int exit_status = response.GetHexU8();
+ std::string desc_string;
+ if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') {
+ llvm::StringRef desc_str;
+ llvm::StringRef desc_token;
+ while (response.GetNameColonValue(desc_token, desc_str)) {
+ if (desc_token != "description")
+ continue;
+ StringExtractor extractor(desc_str);
+ extractor.GetHexByteString(desc_string);
}
- process->SetExitStatus(exit_status, desc_string.c_str());
- done = true;
- break;
}
- case eStateInvalid: {
- // Check to see if we were trying to attach and if we got back
- // the "E87" error code from debugserver -- this indicates that
- // the process is not debuggable. Return a slightly more
- // helpful error message about why the attach failed.
- if (::strstr(continue_cstr, "vAttach") != nullptr &&
- response.GetError() == 0x87) {
- process->SetExitStatus(-1, "cannot attach to process due to "
- "System Integrity Protection");
- } else if (::strstr(continue_cstr, "vAttach") != nullptr &&
- response.GetStatus().Fail()) {
- process->SetExitStatus(-1, response.GetStatus().AsCString());
- } else {
- process->SetExitStatus(-1, "lost connection");
- }
- done = true;
- break;
+ process->SetExitStatus(exit_status, desc_string.c_str());
+ done = true;
+ break;
+ }
+ case eStateInvalid: {
+ // Check to see if we were trying to attach and if we got back
+ // the "E87" error code from debugserver -- this indicates that
+ // the process is not debuggable. Return a slightly more
+ // helpful error message about why the attach failed.
+ if (::strstr(continue_cstr, "vAttach") != nullptr &&
+ response.GetError() == 0x87) {
+ process->SetExitStatus(-1, "cannot attach to process due to "
+ "System Integrity Protection");
+ } else if (::strstr(continue_cstr, "vAttach") != nullptr &&
+ response.GetStatus().Fail()) {
+ process->SetExitStatus(-1, response.GetStatus().AsCString());
+ } else {
+ process->SetExitStatus(-1, "lost connection");
}
+ done = true;
+ break;
+ }
- default:
- process->SetPrivateState(stop_state);
- break;
- } // switch(stop_state)
- } // else // if in All-stop-mode
+ default:
+ process->SetPrivateState(stop_state);
+ break;
+ } // switch(stop_state)
} // if (continue_packet)
} // case eBroadcastBitAsyncContinue
break;
@@ -4027,7 +3860,7 @@ bool ProcessGDBRemote::StopNoticingNewThreads() {
DynamicLoader *ProcessGDBRemote::GetDynamicLoader() {
if (m_dyld_up.get() == nullptr)
- m_dyld_up.reset(DynamicLoader::FindPlugin(this, nullptr));
+ m_dyld_up.reset(DynamicLoader::FindPlugin(this, ""));
return m_dyld_up.get();
}
@@ -4051,12 +3884,14 @@ Status ProcessGDBRemote::SendEventData(const char *data) {
DataExtractor ProcessGDBRemote::GetAuxvData() {
DataBufferSP buf;
if (m_gdb_comm.GetQXferAuxvReadSupported()) {
- std::string response_string;
- if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::",
- response_string) ==
- GDBRemoteCommunication::PacketResult::Success)
- buf = std::make_shared<DataBufferHeap>(response_string.c_str(),
- response_string.length());
+ llvm::Expected<std::string> response = m_gdb_comm.ReadExtFeature("auxv", "");
+ if (response)
+ buf = std::make_shared<DataBufferHeap>(response->c_str(),
+ response->length());
+ else
+ LLDB_LOG_ERROR(
+ ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS),
+ response.takeError(), "{0}");
}
return DataExtractor(buf, GetByteOrder(), GetAddressByteSize());
}
@@ -4351,132 +4186,84 @@ struct GdbServerTargetInfo {
};
bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
- GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp,
- uint32_t &reg_num_remote, uint32_t &reg_num_local) {
+ std::vector<DynamicRegisterInfo::Register> &registers) {
if (!feature_node)
return false;
- uint32_t reg_offset = LLDB_INVALID_INDEX32;
feature_node.ForEachChildElementWithName(
- "reg", [&target_info, &dyn_reg_info, &reg_num_remote, &reg_num_local,
- &reg_offset, &abi_sp](const XMLNode &reg_node) -> bool {
+ "reg", [&target_info, &registers](const XMLNode &reg_node) -> bool {
std::string gdb_group;
std::string gdb_type;
- ConstString reg_name;
- ConstString alt_name;
- ConstString set_name;
- std::vector<uint32_t> value_regs;
- std::vector<uint32_t> invalidate_regs;
- std::vector<uint8_t> dwarf_opcode_bytes;
+ DynamicRegisterInfo::Register reg_info;
bool encoding_set = false;
bool format_set = false;
- RegisterInfo reg_info = {
- nullptr, // Name
- nullptr, // Alt name
- 0, // byte size
- reg_offset, // offset
- eEncodingUint, // encoding
- eFormatHex, // format
- {
- LLDB_INVALID_REGNUM, // eh_frame reg num
- LLDB_INVALID_REGNUM, // DWARF reg num
- LLDB_INVALID_REGNUM, // generic reg num
- reg_num_remote, // process plugin reg num
- reg_num_local // native register number
- },
- nullptr,
- nullptr,
- nullptr, // Dwarf Expression opcode bytes pointer
- 0 // Dwarf Expression opcode bytes length
- };
+ // FIXME: we're silently ignoring invalid data here
reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type,
- &reg_name, &alt_name, &set_name, &value_regs,
- &invalidate_regs, &encoding_set, &format_set,
- &reg_info, &reg_offset, &dwarf_opcode_bytes](
+ &encoding_set, &format_set, &reg_info](
const llvm::StringRef &name,
const llvm::StringRef &value) -> bool {
if (name == "name") {
- reg_name.SetString(value);
+ reg_info.name.SetString(value);
} else if (name == "bitsize") {
- reg_info.byte_size =
- StringConvert::ToUInt32(value.data(), 0, 0) / CHAR_BIT;
+ if (llvm::to_integer(value, reg_info.byte_size))
+ reg_info.byte_size =
+ llvm::divideCeil(reg_info.byte_size, CHAR_BIT);
} else if (name == "type") {
gdb_type = value.str();
} else if (name == "group") {
gdb_group = value.str();
} else if (name == "regnum") {
- const uint32_t regnum =
- StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
- if (regnum != LLDB_INVALID_REGNUM) {
- reg_info.kinds[eRegisterKindProcessPlugin] = regnum;
- }
+ llvm::to_integer(value, reg_info.regnum_remote);
} else if (name == "offset") {
- reg_offset = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ llvm::to_integer(value, reg_info.byte_offset);
} else if (name == "altname") {
- alt_name.SetString(value);
+ reg_info.alt_name.SetString(value);
} else if (name == "encoding") {
encoding_set = true;
reg_info.encoding = Args::StringToEncoding(value, eEncodingUint);
} else if (name == "format") {
format_set = true;
- Format format = eFormatInvalid;
- if (OptionArgParser::ToFormat(value.data(), format, nullptr)
- .Success())
- reg_info.format = format;
- else if (value == "vector-sint8")
- reg_info.format = eFormatVectorOfSInt8;
- else if (value == "vector-uint8")
- reg_info.format = eFormatVectorOfUInt8;
- else if (value == "vector-sint16")
- reg_info.format = eFormatVectorOfSInt16;
- else if (value == "vector-uint16")
- reg_info.format = eFormatVectorOfUInt16;
- else if (value == "vector-sint32")
- reg_info.format = eFormatVectorOfSInt32;
- else if (value == "vector-uint32")
- reg_info.format = eFormatVectorOfUInt32;
- else if (value == "vector-float32")
- reg_info.format = eFormatVectorOfFloat32;
- else if (value == "vector-uint64")
- reg_info.format = eFormatVectorOfUInt64;
- else if (value == "vector-uint128")
- reg_info.format = eFormatVectorOfUInt128;
+ if (!OptionArgParser::ToFormat(value.data(), reg_info.format,
+ nullptr)
+ .Success())
+ reg_info.format =
+ llvm::StringSwitch<lldb::Format>(value)
+ .Case("vector-sint8", eFormatVectorOfSInt8)
+ .Case("vector-uint8", eFormatVectorOfUInt8)
+ .Case("vector-sint16", eFormatVectorOfSInt16)
+ .Case("vector-uint16", eFormatVectorOfUInt16)
+ .Case("vector-sint32", eFormatVectorOfSInt32)
+ .Case("vector-uint32", eFormatVectorOfUInt32)
+ .Case("vector-float32", eFormatVectorOfFloat32)
+ .Case("vector-uint64", eFormatVectorOfUInt64)
+ .Case("vector-uint128", eFormatVectorOfUInt128)
+ .Default(eFormatInvalid);
} else if (name == "group_id") {
- const uint32_t set_id =
- StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ uint32_t set_id = UINT32_MAX;
+ llvm::to_integer(value, set_id);
RegisterSetMap::const_iterator pos =
target_info.reg_set_map.find(set_id);
if (pos != target_info.reg_set_map.end())
- set_name = pos->second.name;
+ reg_info.set_name = pos->second.name;
} else if (name == "gcc_regnum" || name == "ehframe_regnum") {
- reg_info.kinds[eRegisterKindEHFrame] =
- StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ llvm::to_integer(value, reg_info.regnum_ehframe);
} else if (name == "dwarf_regnum") {
- reg_info.kinds[eRegisterKindDWARF] =
- StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ llvm::to_integer(value, reg_info.regnum_dwarf);
} else if (name == "generic") {
- reg_info.kinds[eRegisterKindGeneric] =
- Args::StringToGenericRegister(value);
+ reg_info.regnum_generic = Args::StringToGenericRegister(value);
} else if (name == "value_regnums") {
- SplitCommaSeparatedRegisterNumberString(value, value_regs, 0);
+ SplitCommaSeparatedRegisterNumberString(value, reg_info.value_regs,
+ 0);
} else if (name == "invalidate_regnums") {
- SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 0);
- } else if (name == "dynamic_size_dwarf_expr_bytes") {
- std::string opcode_string = value.str();
- size_t dwarf_opcode_len = opcode_string.length() / 2;
- assert(dwarf_opcode_len > 0);
-
- dwarf_opcode_bytes.resize(dwarf_opcode_len);
- reg_info.dynamic_size_dwarf_len = dwarf_opcode_len;
- StringExtractor opcode_extractor(opcode_string);
- uint32_t ret_val =
- opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes);
- assert(dwarf_opcode_len == ret_val);
- UNUSED_IF_ASSERT_DISABLED(ret_val);
- reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data();
+ SplitCommaSeparatedRegisterNumberString(
+ value, reg_info.invalidate_regs, 0);
} else {
- printf("unhandled attribute %s = %s\n", name.data(), value.data());
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(
+ GDBR_LOG_PROCESS));
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s unhandled reg attribute %s = %s",
+ __FUNCTION__, name.data(), value.data());
}
return true; // Keep iterating through all attributes
});
@@ -4488,43 +4275,40 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
} else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") {
reg_info.format = eFormatAddressInfo;
reg_info.encoding = eEncodingUint;
- } else if (gdb_type == "i387_ext" || gdb_type == "float") {
+ } else if (gdb_type == "float") {
reg_info.format = eFormatFloat;
reg_info.encoding = eEncodingIEEE754;
+ } else if (gdb_type == "aarch64v" ||
+ llvm::StringRef(gdb_type).startswith("vec") ||
+ gdb_type == "i387_ext" || gdb_type == "uint128") {
+ // lldb doesn't handle 128-bit uints correctly (for ymm*h), so treat
+ // them as vector (similarly to xmm/ymm)
+ reg_info.format = eFormatVectorOfUInt8;
+ reg_info.encoding = eEncodingVector;
}
}
// Only update the register set name if we didn't get a "reg_set"
// attribute. "set_name" will be empty if we didn't have a "reg_set"
// attribute.
- if (!set_name) {
+ if (!reg_info.set_name) {
if (!gdb_group.empty()) {
- set_name.SetCString(gdb_group.c_str());
+ reg_info.set_name.SetCString(gdb_group.c_str());
} else {
// If no register group name provided anywhere,
// we'll create a 'general' register set
- set_name.SetCString("general");
+ reg_info.set_name.SetCString("general");
}
}
- reg_info.byte_offset = reg_offset;
- assert(reg_info.byte_size != 0);
- reg_offset = LLDB_INVALID_INDEX32;
- if (!value_regs.empty()) {
- value_regs.push_back(LLDB_INVALID_REGNUM);
- reg_info.value_regs = value_regs.data();
- }
- if (!invalidate_regs.empty()) {
- invalidate_regs.push_back(LLDB_INVALID_REGNUM);
- reg_info.invalidate_regs = invalidate_regs.data();
- }
-
- reg_num_remote = reg_info.kinds[eRegisterKindProcessPlugin] + 1;
- ++reg_num_local;
- reg_info.name = reg_name.AsCString();
- if (abi_sp)
- abi_sp->AugmentRegisterInfo(reg_info);
- dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+ if (reg_info.byte_size == 0) {
+ Log *log(
+ ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::%s Skipping zero bitsize register %s",
+ __FUNCTION__, reg_info.name.AsCString());
+ } else
+ registers.push_back(reg_info);
return true; // Keep iterating through all "reg" elements
});
@@ -4539,20 +4323,17 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
// for nested register definition files. It returns true if it was able
// to fetch and parse an xml file.
bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
- ArchSpec &arch_to_use, std::string xml_filename, uint32_t &reg_num_remote,
- uint32_t &reg_num_local) {
+ ArchSpec &arch_to_use, std::string xml_filename,
+ std::vector<DynamicRegisterInfo::Register> &registers) {
// request the target xml file
- std::string raw;
- lldb_private::Status lldberr;
- if (!m_gdb_comm.ReadExtFeature(ConstString("features"),
- ConstString(xml_filename.c_str()), raw,
- lldberr)) {
+ llvm::Expected<std::string> raw = m_gdb_comm.ReadExtFeature("features", xml_filename);
+ if (errorToBool(raw.takeError()))
return false;
- }
XMLDocument xml_document;
- if (xml_document.ParseMemory(raw.c_str(), raw.size(), xml_filename.c_str())) {
+ if (xml_document.ParseMemory(raw->c_str(), raw->size(),
+ xml_filename.c_str())) {
GdbServerTargetInfo target_info;
std::vector<XMLNode> feature_nodes;
@@ -4581,9 +4362,9 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
node.ForEachAttribute(
[&set_id, &set_info](const llvm::StringRef &name,
const llvm::StringRef &value) -> bool {
+ // FIXME: we're silently ignoring invalid data here
if (name == "id")
- set_id = StringConvert::ToUInt32(value.data(),
- UINT32_MAX, 0);
+ llvm::to_integer(value, set_id);
if (name == "name")
set_info.name = ConstString(value);
return true; // Keep iterating through all attributes
@@ -4617,39 +4398,33 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
}
}
- // If the target.xml includes an architecture entry like
+ // gdbserver does not implement the LLDB packets used to determine host
+ // or process architecture. If that is the case, attempt to use
+ // the <architecture/> field from target.xml, e.g.:
+ //
// <architecture>i386:x86-64</architecture> (seen from VMWare ESXi)
- // <architecture>arm</architecture> (seen from Segger JLink on unspecified arm board)
- // use that if we don't have anything better.
+ // <architecture>arm</architecture> (seen from Segger JLink on unspecified
+ // arm board)
if (!arch_to_use.IsValid() && !target_info.arch.empty()) {
- if (target_info.arch == "i386:x86-64") {
- // We don't have any information about vendor or OS.
- arch_to_use.SetTriple("x86_64--");
- GetTarget().MergeArchitecture(arch_to_use);
- }
+ // We don't have any information about vendor or OS.
+ arch_to_use.SetTriple(llvm::StringSwitch<std::string>(target_info.arch)
+ .Case("i386:x86-64", "x86_64")
+ .Default(target_info.arch) +
+ "--");
- // SEGGER J-Link jtag boards send this very-generic arch name,
- // we'll need to use this if we have absolutely nothing better
- // to work with or the register definitions won't be accepted.
- if (target_info.arch == "arm") {
- arch_to_use.SetTriple("arm--");
+ if (arch_to_use.IsValid())
GetTarget().MergeArchitecture(arch_to_use);
- }
}
if (arch_to_use.IsValid()) {
- // Don't use Process::GetABI, this code gets called from DidAttach, and
- // in that context we haven't set the Target's architecture yet, so the
- // ABI is also potentially incorrect.
- ABISP abi_to_use_sp = ABI::FindPlugin(shared_from_this(), arch_to_use);
for (auto &feature_node : feature_nodes) {
- ParseRegisters(feature_node, target_info, *this->m_register_info_sp,
- abi_to_use_sp, reg_num_remote, reg_num_local);
+ ParseRegisters(feature_node, target_info,
+ registers);
}
for (const auto &include : target_info.includes) {
GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include,
- reg_num_remote, reg_num_local);
+ registers);
}
}
} else {
@@ -4658,6 +4433,46 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
return true;
}
+void ProcessGDBRemote::AddRemoteRegisters(
+ std::vector<DynamicRegisterInfo::Register> &registers,
+ const ArchSpec &arch_to_use) {
+ std::map<uint32_t, uint32_t> remote_to_local_map;
+ uint32_t remote_regnum = 0;
+ for (auto it : llvm::enumerate(registers)) {
+ DynamicRegisterInfo::Register &remote_reg_info = it.value();
+
+ // Assign successive remote regnums if missing.
+ if (remote_reg_info.regnum_remote == LLDB_INVALID_REGNUM)
+ remote_reg_info.regnum_remote = remote_regnum;
+
+ // Create a mapping from remote to local regnos.
+ remote_to_local_map[remote_reg_info.regnum_remote] = it.index();
+
+ remote_regnum = remote_reg_info.regnum_remote + 1;
+ }
+
+ for (DynamicRegisterInfo::Register &remote_reg_info : registers) {
+ auto proc_to_lldb = [&remote_to_local_map](uint32_t process_regnum) {
+ auto lldb_regit = remote_to_local_map.find(process_regnum);
+ return lldb_regit != remote_to_local_map.end() ? lldb_regit->second
+ : LLDB_INVALID_REGNUM;
+ };
+
+ llvm::transform(remote_reg_info.value_regs,
+ remote_reg_info.value_regs.begin(), proc_to_lldb);
+ llvm::transform(remote_reg_info.invalidate_regs,
+ remote_reg_info.invalidate_regs.begin(), proc_to_lldb);
+ }
+
+ // Don't use Process::GetABI, this code gets called from DidAttach, and
+ // in that context we haven't set the Target's architecture yet, so the
+ // ABI is also potentially incorrect.
+ if (ABISP abi_sp = ABI::FindPlugin(shared_from_this(), arch_to_use))
+ abi_sp->AugmentRegisterInfo(registers);
+
+ m_register_info_sp->SetRegisterInfo(std::move(registers), arch_to_use);
+}
+
// query the target of gdb-remote for extended target information returns
// true on success (got register definitions), false on failure (did not).
bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
@@ -4669,11 +4484,10 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
if (!m_gdb_comm.GetQXferFeaturesReadSupported())
return false;
- uint32_t reg_num_remote = 0;
- uint32_t reg_num_local = 0;
+ std::vector<DynamicRegisterInfo::Register> registers;
if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml",
- reg_num_remote, reg_num_local))
- this->m_register_info_sp->Finalize(arch_to_use);
+ registers))
+ AddRemoteRegisters(registers, arch_to_use);
return m_register_info_sp->GetNumRegisters() > 0;
}
@@ -4689,24 +4503,20 @@ llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {
LoadedModuleInfoList list;
GDBRemoteCommunicationClient &comm = m_gdb_comm;
- bool can_use_svr4 = GetGlobalPluginProperties()->GetUseSVR4();
+ bool can_use_svr4 = GetGlobalPluginProperties().GetUseSVR4();
// check that we have extended feature read support
if (can_use_svr4 && comm.GetQXferLibrariesSVR4ReadSupported()) {
// request the loaded library list
- std::string raw;
- lldb_private::Status lldberr;
-
- if (!comm.ReadExtFeature(ConstString("libraries-svr4"), ConstString(""),
- raw, lldberr))
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Error in libraries-svr4 packet");
+ llvm::Expected<std::string> raw = comm.ReadExtFeature("libraries-svr4", "");
+ if (!raw)
+ return raw.takeError();
// parse the xml file in memory
- LLDB_LOGF(log, "parsing: %s", raw.c_str());
+ LLDB_LOGF(log, "parsing: %s", raw->c_str());
XMLDocument doc;
- if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml"))
+ if (!doc.ParseMemory(raw->c_str(), raw->size(), "noname.xml"))
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Error reading noname.xml");
@@ -4718,38 +4528,37 @@ llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {
// main link map structure
llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm");
- if (!main_lm.empty()) {
- list.m_link_map =
- StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0);
- }
+ // FIXME: we're silently ignoring invalid data here
+ if (!main_lm.empty())
+ llvm::to_integer(main_lm, list.m_link_map);
root_element.ForEachChildElementWithName(
"library", [log, &list](const XMLNode &library) -> bool {
-
LoadedModuleInfoList::LoadedModuleInfo module;
+ // FIXME: we're silently ignoring invalid data here
library.ForEachAttribute(
[&module](const llvm::StringRef &name,
const llvm::StringRef &value) -> bool {
-
+ uint64_t uint_value = LLDB_INVALID_ADDRESS;
if (name == "name")
module.set_name(value.str());
else if (name == "lm") {
// the address of the link_map struct.
- module.set_link_map(StringConvert::ToUInt64(
- value.data(), LLDB_INVALID_ADDRESS, 0));
+ llvm::to_integer(value, uint_value);
+ module.set_link_map(uint_value);
} else if (name == "l_addr") {
// the displacement as read from the field 'l_addr' of the
// link_map struct.
- module.set_base(StringConvert::ToUInt64(
- value.data(), LLDB_INVALID_ADDRESS, 0));
+ llvm::to_integer(value, uint_value);
+ module.set_base(uint_value);
// base address is always a displacement, not an absolute
// value.
module.set_base_is_offset(true);
} else if (name == "l_ld") {
// the memory address of the libraries PT_DYNAMIC section.
- module.set_dynamic(StringConvert::ToUInt64(
- value.data(), LLDB_INVALID_ADDRESS, 0));
+ llvm::to_integer(value, uint_value);
+ module.set_dynamic(uint_value);
}
return true; // Keep iterating over all properties of "library"
@@ -4784,18 +4593,15 @@ llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {
return list;
} else if (comm.GetQXferLibrariesReadSupported()) {
// request the loaded library list
- std::string raw;
- lldb_private::Status lldberr;
+ llvm::Expected<std::string> raw = comm.ReadExtFeature("libraries", "");
- if (!comm.ReadExtFeature(ConstString("libraries"), ConstString(""), raw,
- lldberr))
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Error in libraries packet");
+ if (!raw)
+ return raw.takeError();
- LLDB_LOGF(log, "parsing: %s", raw.c_str());
+ LLDB_LOGF(log, "parsing: %s", raw->c_str());
XMLDocument doc;
- if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml"))
+ if (!doc.ParseMemory(raw->c_str(), raw->size(), "noname.xml"))
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Error reading noname.xml");
@@ -4804,6 +4610,7 @@ llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Error finding library-list xml element");
+ // FIXME: we're silently ignoring invalid data here
root_element.ForEachChildElementWithName(
"library", [log, &list](const XMLNode &library) -> bool {
LoadedModuleInfoList::LoadedModuleInfo module;
@@ -4817,8 +4624,9 @@ llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {
const XMLNode &section =
library.FindFirstChildElementWithName("section");
llvm::StringRef address = section.GetAttributeValue("address");
- module.set_base(
- StringConvert::ToUInt64(address.data(), LLDB_INVALID_ADDRESS, 0));
+ uint64_t address_value = LLDB_INVALID_ADDRESS;
+ llvm::to_integer(address, address_value);
+ module.set_base(address_value);
// These addresses are absolute values.
module.set_base_is_offset(false);
@@ -5113,6 +4921,56 @@ void ProcessGDBRemote::HandleStopReply() {
BuildDynamicRegisterInfo(true);
}
+llvm::Expected<bool> ProcessGDBRemote::SaveCore(llvm::StringRef outfile) {
+ if (!m_gdb_comm.GetSaveCoreSupported())
+ return false;
+
+ StreamString packet;
+ packet.PutCString("qSaveCore;path-hint:");
+ packet.PutStringAsRawHex8(outfile);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ // TODO: grab error message from the packet? StringExtractor seems to
+ // be missing a method for that
+ if (response.IsErrorResponse())
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ llvm::formatv("qSaveCore returned an error"));
+
+ std::string path;
+
+ // process the response
+ for (auto x : llvm::split(response.GetStringRef(), ';')) {
+ if (x.consume_front("core-path:"))
+ StringExtractor(x).GetHexByteString(path);
+ }
+
+ // verify that we've gotten what we need
+ if (path.empty())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "qSaveCore returned no core path");
+
+ // now transfer the core file
+ FileSpec remote_core{llvm::StringRef(path)};
+ Platform &platform = *GetTarget().GetPlatform();
+ Status error = platform.GetFile(remote_core, FileSpec(outfile));
+
+ if (platform.IsRemote()) {
+ // NB: we unlink the file on error too
+ platform.Unlink(remote_core);
+ if (error.Fail())
+ return error.ToError();
+ }
+
+ return true;
+ }
+
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Unable to send qSaveCore");
+}
+
static const char *const s_async_json_packet_prefix = "JSON-async:";
static StructuredData::ObjectSP
@@ -5451,3 +5309,171 @@ CommandObject *ProcessGDBRemote::GetPluginCommandObject() {
GetTarget().GetDebugger().GetCommandInterpreter());
return m_command_sp.get();
}
+
+void ProcessGDBRemote::DidForkSwitchSoftwareBreakpoints(bool enable) {
+ GetBreakpointSiteList().ForEach([this, enable](BreakpointSite *bp_site) {
+ if (bp_site->IsEnabled() &&
+ (bp_site->GetType() == BreakpointSite::eSoftware ||
+ bp_site->GetType() == BreakpointSite::eExternal)) {
+ m_gdb_comm.SendGDBStoppointTypePacket(
+ eBreakpointSoftware, enable, bp_site->GetLoadAddress(),
+ GetSoftwareBreakpointTrapOpcode(bp_site), GetInterruptTimeout());
+ }
+ });
+}
+
+void ProcessGDBRemote::DidForkSwitchHardwareTraps(bool enable) {
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) {
+ GetBreakpointSiteList().ForEach([this, enable](BreakpointSite *bp_site) {
+ if (bp_site->IsEnabled() &&
+ bp_site->GetType() == BreakpointSite::eHardware) {
+ m_gdb_comm.SendGDBStoppointTypePacket(
+ eBreakpointHardware, enable, bp_site->GetLoadAddress(),
+ GetSoftwareBreakpointTrapOpcode(bp_site), GetInterruptTimeout());
+ }
+ });
+ }
+
+ WatchpointList &wps = GetTarget().GetWatchpointList();
+ size_t wp_count = wps.GetSize();
+ for (size_t i = 0; i < wp_count; ++i) {
+ WatchpointSP wp = wps.GetByIndex(i);
+ if (wp->IsEnabled()) {
+ GDBStoppointType type = GetGDBStoppointType(wp.get());
+ m_gdb_comm.SendGDBStoppointTypePacket(type, enable, wp->GetLoadAddress(),
+ wp->GetByteSize(),
+ GetInterruptTimeout());
+ }
+ }
+}
+
+void ProcessGDBRemote::DidFork(lldb::pid_t child_pid, lldb::tid_t child_tid) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ lldb::pid_t parent_pid = m_gdb_comm.GetCurrentProcessID();
+ // Any valid TID will suffice, thread-relevant actions will set a proper TID
+ // anyway.
+ lldb::tid_t parent_tid = m_thread_ids.front();
+
+ lldb::pid_t follow_pid, detach_pid;
+ lldb::tid_t follow_tid, detach_tid;
+
+ switch (GetFollowForkMode()) {
+ case eFollowParent:
+ follow_pid = parent_pid;
+ follow_tid = parent_tid;
+ detach_pid = child_pid;
+ detach_tid = child_tid;
+ break;
+ case eFollowChild:
+ follow_pid = child_pid;
+ follow_tid = child_tid;
+ detach_pid = parent_pid;
+ detach_tid = parent_tid;
+ break;
+ }
+
+ // Switch to the process that is going to be detached.
+ if (!m_gdb_comm.SetCurrentThread(detach_tid, detach_pid)) {
+ LLDB_LOG(log, "ProcessGDBRemote::DidFork() unable to set pid/tid");
+ return;
+ }
+
+ // Disable all software breakpoints in the forked process.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware))
+ DidForkSwitchSoftwareBreakpoints(false);
+
+ // Remove hardware breakpoints / watchpoints from parent process if we're
+ // following child.
+ if (GetFollowForkMode() == eFollowChild)
+ DidForkSwitchHardwareTraps(false);
+
+ // Switch to the process that is going to be followed
+ if (!m_gdb_comm.SetCurrentThread(follow_tid, follow_pid) ||
+ !m_gdb_comm.SetCurrentThreadForRun(follow_tid, follow_pid)) {
+ LLDB_LOG(log, "ProcessGDBRemote::DidFork() unable to reset pid/tid");
+ return;
+ }
+
+ LLDB_LOG(log, "Detaching process {0}", detach_pid);
+ Status error = m_gdb_comm.Detach(false, detach_pid);
+ if (error.Fail()) {
+ LLDB_LOG(log, "ProcessGDBRemote::DidFork() detach packet send failed: {0}",
+ error.AsCString() ? error.AsCString() : "<unknown error>");
+ return;
+ }
+
+ // Hardware breakpoints/watchpoints are not inherited implicitly,
+ // so we need to readd them if we're following child.
+ if (GetFollowForkMode() == eFollowChild)
+ DidForkSwitchHardwareTraps(true);
+}
+
+void ProcessGDBRemote::DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ assert(!m_vfork_in_progress);
+ m_vfork_in_progress = true;
+
+ // Disable all software breakpoints for the duration of vfork.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware))
+ DidForkSwitchSoftwareBreakpoints(false);
+
+ lldb::pid_t detach_pid;
+ lldb::tid_t detach_tid;
+
+ switch (GetFollowForkMode()) {
+ case eFollowParent:
+ detach_pid = child_pid;
+ detach_tid = child_tid;
+ break;
+ case eFollowChild:
+ detach_pid = m_gdb_comm.GetCurrentProcessID();
+ // Any valid TID will suffice, thread-relevant actions will set a proper TID
+ // anyway.
+ detach_tid = m_thread_ids.front();
+
+ // Switch to the parent process before detaching it.
+ if (!m_gdb_comm.SetCurrentThread(detach_tid, detach_pid)) {
+ LLDB_LOG(log, "ProcessGDBRemote::DidFork() unable to set pid/tid");
+ return;
+ }
+
+ // Remove hardware breakpoints / watchpoints from the parent process.
+ DidForkSwitchHardwareTraps(false);
+
+ // Switch to the child process.
+ if (!m_gdb_comm.SetCurrentThread(child_tid, child_pid) ||
+ !m_gdb_comm.SetCurrentThreadForRun(child_tid, child_pid)) {
+ LLDB_LOG(log, "ProcessGDBRemote::DidFork() unable to reset pid/tid");
+ return;
+ }
+ break;
+ }
+
+ LLDB_LOG(log, "Detaching process {0}", detach_pid);
+ Status error = m_gdb_comm.Detach(false, detach_pid);
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::DidFork() detach packet send failed: {0}",
+ error.AsCString() ? error.AsCString() : "<unknown error>");
+ return;
+ }
+}
+
+void ProcessGDBRemote::DidVForkDone() {
+ assert(m_vfork_in_progress);
+ m_vfork_in_progress = false;
+
+ // Reenable all software breakpoints that were enabled before vfork.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware))
+ DidForkSwitchSoftwareBreakpoints(true);
+}
+
+void ProcessGDBRemote::DidExec() {
+ // If we are following children, vfork is finished by exec (rather than
+ // vforkdone that is submitted for parent).
+ if (GetFollowForkMode() == eFollowChild)
+ m_vfork_in_progress = false;
+ Process::DidExec();
+}