summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp784
1 files changed, 446 insertions, 338 deletions
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 35d02c15ab85b..b3d33b19bd666 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -24,6 +24,7 @@
// C++ Includes
#include <algorithm>
+#include <csignal>
#include <map>
#include <mutex>
#include <sstream>
@@ -46,11 +47,11 @@
#include "lldb/Host/Symbols.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Host/XML.h"
-#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandObjectMultiword.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Interpreter/OptionGroupBoolean.h"
#include "lldb/Interpreter/OptionGroupUInt64.h"
#include "lldb/Interpreter/OptionValueProperties.h"
@@ -59,10 +60,12 @@
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Utility/Args.h"
#include "lldb/Utility/CleanUp.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/StreamString.h"
@@ -77,8 +80,8 @@
#include "ProcessGDBRemote.h"
#include "ProcessGDBRemoteLog.h"
#include "ThreadGDBRemote.h"
-#include "Utility/StringExtractorGDBRemote.h"
#include "lldb/Host/Host.h"
+#include "lldb/Utility/StringExtractorGDBRemote.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Threading.h"
@@ -91,11 +94,11 @@ using namespace lldb_private::process_gdb_remote;
namespace lldb {
// Provide a function that can easily dump the packet history if we know a
-// ProcessGDBRemote * value (which we can get from logs or from debugging).
-// We need the function in the lldb namespace so it makes it into the final
+// ProcessGDBRemote * value (which we can get from logs or from debugging). We
+// need the function in the lldb namespace so it makes it into the final
// executable since the LLDB shared library only exports stuff in the lldb
-// namespace. This allows you to attach with a debugger and call this
-// function and get the packet history dumped to a file.
+// namespace. This allows you to attach with a debugger and call this function
+// and get the packet history dumped to a file.
void DumpProcessGDBRemotePacketHistory(void *p, const char *path) {
StreamFile strm;
Status error(strm.GetFile().Open(path, File::eOpenOptionWrite |
@@ -158,8 +161,8 @@ static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() {
} // anonymous namespace end
// TODO Randomly assigning a port is unsafe. We should get an unused
-// ephemeral port from the kernel and make sure we reserve it before passing
-// it to debugserver.
+// ephemeral port from the kernel and make sure we reserve it before passing it
+// to debugserver.
#if defined(__APPLE__)
#define LOW_PORT (IPPORT_RESERVED)
@@ -233,8 +236,8 @@ bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp,
}
return exe_module->GetFileSpec().Exists();
}
- // However, if there is no executable module, we return true since we might be
- // preparing to attach.
+ // However, if there is no executable module, we return true since we might
+ // be preparing to attach.
return true;
}
@@ -256,7 +259,8 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
m_addr_to_mmap_size(), m_thread_create_bp_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_initial_tid(LLDB_INVALID_THREAD_ID), m_allow_flash_writes(false),
+ m_erased_flash_ranges() {
m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit,
"async thread should exit");
m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue,
@@ -299,17 +303,16 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
ProcessGDBRemote::~ProcessGDBRemote() {
// m_mach_process.UnregisterNotificationCallbacks (this);
Clear();
- // We need to call finalize on the process before destroying ourselves
- // to make sure all of the broadcaster cleanup goes as planned. If we
- // destruct this class, then Process::~Process() might have problems
- // trying to fully destroy the broadcaster.
+ // We need to call finalize on the process before destroying ourselves to
+ // make sure all of the broadcaster cleanup goes as planned. If we destruct
+ // this class, then Process::~Process() might have problems trying to fully
+ // destroy the broadcaster.
Finalize();
- // The general Finalize is going to try to destroy the process and that SHOULD
- // shut down the async thread. However, if we don't kill it it will get
- // stranded and
- // its connection will go away so when it wakes up it will crash. So kill it
- // for sure here.
+ // The general Finalize is going to try to destroy the process and that
+ // SHOULD shut down the async thread. However, if we don't kill it it will
+ // get stranded and its connection will go away so when it wakes up it will
+ // crash. So kill it for sure here.
StopAsyncThread();
KillDebugserverProcess();
}
@@ -368,8 +371,7 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition(
}
// If the remote stub didn't give us eh_frame or DWARF register numbers for a
-// register,
-// see if the ABI can provide them.
+// register, see if the ABI can provide them.
// DWARF and eh_frame register numbers are defined as a part of the ABI.
static void AugmentRegisterInfoViaABI(RegisterInfo &reg_info,
ConstString reg_name, ABISP abi_sp) {
@@ -422,9 +424,9 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
m_register_info.Clear();
- // Check if qHostInfo specified a specific packet timeout for this connection.
- // If so then lets update our setting so the user knows what the timeout is
- // and can see it.
+ // Check if qHostInfo specified a specific packet timeout for this
+ // connection. If so then lets update our setting so the user knows what the
+ // 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());
@@ -531,7 +533,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
reg_info.encoding = encoding;
} else if (name.equals("format")) {
Format format = eFormatInvalid;
- if (Args::StringToFormat(value.str().c_str(), format, NULL)
+ if (OptionArgParser::ToFormat(value.str().c_str(), format, NULL)
.Success())
reg_info.format = format;
else {
@@ -596,10 +598,8 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
}
// 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.
+ // this code gets called in DidAttach, when the target architecture
+ // (and consequently the ABI we'll get from the process) may be wrong.
ABISP abi_to_use = ABI::FindPlugin(shared_from_this(), arch_to_use);
AugmentRegisterInfoViaABI(reg_info, reg_name, abi_to_use);
@@ -620,9 +620,9 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
// 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.
+ // 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.GetNumRegisters() == 0);
if (!target_arch.IsValid()) {
@@ -669,9 +669,8 @@ Status ProcessGDBRemote::DoConnectRemote(Stream *strm,
lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID();
if (pid == LLDB_INVALID_PROCESS_ID) {
- // We don't have a valid process ID, so note that we are connected
- // and could now request to launch or attach, or get remote process
- // listings...
+ // We don't have a valid process ID, so note that we are connected and
+ // could now request to launch or attach, or get remote process listings...
SetPrivateState(eStateConnected);
} else {
// We have a valid process
@@ -721,7 +720,8 @@ Status ProcessGDBRemote::DoConnectRemote(Stream *strm,
if (error.Success() && !GetTarget().GetArchitecture().IsValid() &&
m_gdb_comm.GetHostArchitecture().IsValid()) {
- // Prefer the *process'* architecture over that of the *host*, if available.
+ // Prefer the *process'* architecture over that of the *host*, if
+ // available.
if (m_gdb_comm.GetProcessArchitecture().IsValid())
GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture());
else
@@ -800,8 +800,8 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module,
const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
if (stdin_file_spec || disable_stdio) {
- // the inferior will be reading stdin from the specified file
- // or stdio is completely disabled
+ // the inferior will be reading stdin from the specified file or stdio is
+ // completely disabled
m_stdin_forward = false;
} else {
m_stdin_forward = true;
@@ -824,11 +824,14 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module,
if (disable_stdio) {
// set to /dev/null unless redirected to a file above
if (!stdin_file_spec)
- stdin_file_spec.SetFile(FileSystem::DEV_NULL, false);
+ stdin_file_spec.SetFile(FileSystem::DEV_NULL, false,
+ FileSpec::Style::native);
if (!stdout_file_spec)
- stdout_file_spec.SetFile(FileSystem::DEV_NULL, false);
+ stdout_file_spec.SetFile(FileSystem::DEV_NULL, false,
+ FileSpec::Style::native);
if (!stderr_file_spec)
- stderr_file_spec.SetFile(FileSystem::DEV_NULL, false);
+ stderr_file_spec.SetFile(FileSystem::DEV_NULL, false,
+ 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
@@ -888,16 +891,7 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module,
}
// Send the environment and the program + arguments after we connect
- const Args &environment = launch_info.GetEnvironmentEntries();
- if (environment.GetArgumentCount()) {
- size_t num_environment_entries = environment.GetArgumentCount();
- for (size_t i = 0; i < num_environment_entries; ++i) {
- const char *env_entry = environment.GetArgumentAtIndex(i);
- if (env_entry == NULL ||
- m_gdb_comm.SendEnvironmentPacket(env_entry) != 0)
- break;
- }
- }
+ m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
{
// Scope for the scoped timeout object
@@ -1004,16 +998,15 @@ 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.
+ // 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 remote GDB server and make sure that goes
- // alright.
+ // 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
+ // remote GDB server and make sure that goes alright.
if (!m_gdb_comm.HandshakeWithServer(&error)) {
m_gdb_comm.Disconnect();
if (error.Success())
@@ -1055,9 +1048,9 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {
// See if the GDB server supports the qHostInfo information
- // See if the GDB server supports the qProcessInfo packet, if so
- // prefer that over the Host information as it will be more specific
- // to our process.
+ // See if the GDB server supports the qProcessInfo packet, if so prefer
+ // that over the Host information as it will be more specific to our
+ // process.
const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture();
if (remote_process_arch.IsValid()) {
@@ -1102,9 +1095,8 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {
// architectures.
// You can have an armv6 executable, and if the host is armv7, then the
// system will load the best possible architecture for all shared
- // libraries
- // it has, so we really need to take the remote host architecture as our
- // defacto architecture in this case.
+ // libraries it has, so we really need to take the remote host
+ // architecture as our defacto architecture in this case.
if ((process_arch.GetMachine() == llvm::Triple::arm ||
process_arch.GetMachine() == llvm::Triple::thumb) &&
@@ -1150,14 +1142,14 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {
? target_arch.GetTriple().getTriple().c_str()
: "<null>");
} else {
- // The target doesn't have a valid architecture yet, set it from
- // the architecture we got from the remote GDB server
+ // The target doesn't have a valid architecture yet, set it from the
+ // architecture we got from the remote GDB server
GetTarget().SetArchitecture(process_arch);
}
}
- // Find out which StructuredDataPlugins are supported by the
- // debug monitor. These plugins transmit data over async $J packets.
+ // Find out which StructuredDataPlugins are supported by the debug monitor.
+ // These plugins transmit data over async $J packets.
auto supported_packets_array =
m_gdb_comm.GetSupportedStructuredDataPlugins();
if (supported_packets_array)
@@ -1365,9 +1357,9 @@ Status ProcessGDBRemote::DoResume() {
continue_packet_error = true;
if (continue_packet_error) {
- // Either no vCont support, or we tried to use part of the vCont
- // packet that wasn't supported by the remote GDB server.
- // We need to try and make a simple packet that can do our continue
+ // Either no vCont support, or we tried to use part of the vCont packet
+ // that wasn't supported by the remote GDB server. We need to try and
+ // make a simple packet that can do our continue
const size_t num_continue_c_tids = m_continue_c_tids.size();
const size_t num_continue_C_tids = m_continue_C_tids.size();
const size_t num_continue_s_tids = m_continue_s_tids.size();
@@ -1394,11 +1386,10 @@ Status ProcessGDBRemote::DoResume() {
const int continue_signo = m_continue_C_tids.front().second;
// Only one thread is continuing
if (num_continue_C_tids > 1) {
- // More that one thread with a signal, yet we don't have
- // vCont support and we are being asked to resume each
- // thread with a signal, we need to make sure they are
- // all the same signal, or we can't issue the continue
- // accurately with the current support...
+ // More that one thread with a signal, yet we don't have vCont
+ // support and we are being asked to resume each thread with a
+ // signal, we need to make sure they are all the same signal, or we
+ // can't issue the continue accurately with the current support...
if (num_continue_C_tids > 1) {
continue_packet_error = false;
for (size_t i = 1; i < m_continue_C_tids.size(); ++i) {
@@ -1532,7 +1523,6 @@ void ProcessGDBRemote::ClearThreadIDList() {
size_t
ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue(std::string &value) {
m_thread_ids.clear();
- m_thread_pcs.clear();
size_t comma_pos;
lldb::tid_t tid;
while ((comma_pos = value.find(',')) != std::string::npos) {
@@ -1675,9 +1665,8 @@ bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list,
}
}
- // Whatever that is left in old_thread_list_copy are not
- // present in new_thread_list. Remove non-existent threads from internal id
- // table.
+ // Whatever that is left in old_thread_list_copy are not present in
+ // new_thread_list. Remove non-existent threads from internal id table.
size_t old_num_thread_ids = old_thread_list_copy.GetSize(false);
for (size_t i = 0; i < old_num_thread_ids; i++) {
ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false));
@@ -1738,12 +1727,11 @@ bool ProcessGDBRemote::CalculateThreadStopInfo(ThreadGDBRemote *thread) {
return true;
// See if we got thread stop info for any threads valid stop info reasons
- // threads
- // via the "jstopinfo" packet stop reply packet key/value pair?
+ // threads via the "jstopinfo" packet stop reply packet key/value pair?
if (m_jstopinfo_sp) {
// If we have "jstopinfo" then we have stop descriptions for all threads
- // that have stop reasons, and if there is no entry for a thread, then
- // it has no stop reason.
+ // that have stop reasons, and if there is no entry for a thread, then it
+ // has no stop reason.
thread->GetRegisterContext()->InvalidateIfNeeded(true);
if (!GetThreadStopInfoFromJSON(thread, m_jstopinfo_sp)) {
thread->SetStopInfo(StopInfoSP());
@@ -1771,9 +1759,8 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
if (tid != LLDB_INVALID_THREAD_ID) {
// Scope for "locker" below
{
- // m_thread_list_real does have its own mutex, but we need to
- // hold onto the mutex between the call to
- // m_thread_list_real.FindThreadByID(...)
+ // m_thread_list_real does have its own mutex, but we need to hold onto
+ // the mutex between the call to m_thread_list_real.FindThreadByID(...)
// and the m_thread_list_real.AddThread(...) so it doesn't change on us
std::lock_guard<std::recursive_mutex> guard(
m_thread_list_real.GetMutex());
@@ -1827,10 +1814,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
if (!thread_sp->StopInfoIsUpToDate()) {
thread_sp->SetStopInfo(StopInfoSP());
// If there's a memory thread backed by this thread, we need to use it
- // to calcualte StopInfo.
- ThreadSP memory_thread_sp =
- m_thread_list.FindThreadByProtocolID(thread_sp->GetProtocolID());
- if (memory_thread_sp)
+ // to calculate StopInfo.
+ if (ThreadSP memory_thread_sp =
+ m_thread_list.GetBackingThread(thread_sp))
thread_sp = memory_thread_sp;
if (exc_type != 0) {
@@ -1852,9 +1838,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
->GetBreakpointSiteList()
.FindByAddress(pc);
- // If the current pc is a breakpoint site then the StopInfo should
- // be set to Breakpoint
- // Otherwise, it will be set to Trace.
+ // If the current pc is a breakpoint site then the StopInfo
+ // should be set to Breakpoint Otherwise, it will be set to
+ // Trace.
if (bp_site_sp &&
bp_site_sp->ValidForThisThread(thread_sp.get())) {
thread_sp->SetStopInfo(
@@ -1871,11 +1857,10 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
.FindByAddress(pc);
if (bp_site_sp) {
// If the breakpoint is for this thread, then we'll report the
- // hit, but if it is for another thread,
- // we can just report no reason. We don't need to worry about
- // stepping over the breakpoint here, that
- // will be taken care of when the thread resumes and notices
- // that there's a breakpoint under the pc.
+ // hit, but if it is for another thread, we can just report no
+ // reason. We don't need to worry about stepping over the
+ // breakpoint here, that will be taken care of when the thread
+ // resumes and notices that there's a breakpoint under the pc.
handled = true;
if (bp_site_sp->ValidForThisThread(thread_sp.get())) {
thread_sp->SetStopInfo(
@@ -1937,13 +1922,10 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
pc);
// If the current pc is a breakpoint site then the StopInfo should
- // be set to Breakpoint
- // even though the remote stub did not set it as such. This can
- // happen when
- // the thread is involuntarily interrupted (e.g. due to stops on
- // other
- // threads) just as it is about to execute the breakpoint
- // instruction.
+ // be set to Breakpoint even though the remote stub did not set it
+ // as such. This can happen when the thread is involuntarily
+ // interrupted (e.g. due to stops on other threads) just as it is
+ // about to execute the breakpoint instruction.
if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) {
thread_sp->SetStopInfo(
StopInfo::CreateStopReasonWithBreakpointSiteID(
@@ -1965,11 +1947,10 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
if (bp_site_sp) {
// If the breakpoint is for this thread, then we'll report the
- // hit, but if it is for another thread,
- // we can just report no reason. We don't need to worry about
- // stepping over the breakpoint here, that
- // will be taken care of when the thread resumes and notices
- // that there's a breakpoint under the pc.
+ // hit, but if it is for another thread, we can just report no
+ // reason. We don't need to worry about stepping over the
+ // breakpoint here, that will be taken care of when the thread
+ // resumes and notices that there's a breakpoint under the pc.
if (bp_site_sp->ValidForThisThread(thread_sp.get())) {
if (m_breakpoint_pc_offset != 0)
thread_sp->GetRegisterContext()->SetPC(pc);
@@ -1982,8 +1963,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
}
} else {
// If we were stepping then assume the stop was the result of
- // the trace. If we were
- // not stepping then report the SIGTRAP.
+ // the trace. If we were not stepping then report the SIGTRAP.
// FIXME: We are still missing the case where we single step
// over a trap instruction.
if (thread_sp->GetTemporaryResumeState() == eStateStepping)
@@ -2178,15 +2158,15 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
switch (stop_type) {
case 'T':
case 'S': {
- // This is a bit of a hack, but is is required. If we did exec, we
- // need to clear our thread lists and also know to rebuild our dynamic
- // register info before we lookup and threads and populate the expedited
- // register values so we need to know this right away so we can cleanup
- // and update our registers.
+ // This is a bit of a hack, but is is required. If we did exec, we need to
+ // clear our thread lists and also know to rebuild our dynamic register
+ // info before we lookup and threads and populate the expedited register
+ // values so we need to know this right away so we can cleanup and update
+ // our registers.
const uint32_t stop_id = GetStopID();
if (stop_id == 0) {
- // Our first stop, make sure we have a process ID, and also make
- // sure we know about our registers
+ // Our first stop, make sure we have a process ID, and also make sure we
+ // know about our registers
if (GetID() == LLDB_INVALID_PROCESS_ID) {
lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID();
if (pid != LLDB_INVALID_PROCESS_ID)
@@ -2232,8 +2212,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
m_thread_ids.clear();
// A comma separated list of all threads in the current
- // process that includes the thread for this stop reply
- // packet
+ // process that includes the thread for this stop reply packet
lldb::tid_t tid;
while (!value.empty()) {
llvm::StringRef tid_str;
@@ -2245,8 +2224,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
} else if (key.compare("thread-pcs") == 0) {
m_thread_pcs.clear();
// A comma separated list of all threads in the current
- // process that includes the thread for this stop reply
- // packet
+ // process that includes the thread for this stop reply packet
lldb::addr_t pc;
while (!value.empty()) {
llvm::StringRef pc_str;
@@ -2298,13 +2276,10 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
desc_extractor.GetHexByteString(description);
} else if (key.compare("memory") == 0) {
// Expedited memory. GDB servers can choose to send back expedited
- // memory
- // that can populate the L1 memory cache in the process so that things
- // like
- // the frame pointer backchain can be expedited. This will help stack
- // backtracing be more efficient by not having to send as many memory
- // read
- // requests down the remote GDB server.
+ // memory that can populate the L1 memory cache in the process so that
+ // things like the frame pointer backchain can be expedited. This will
+ // help stack backtracing be more efficient by not having to send as
+ // many memory read requests down the remote GDB server.
// Key/value pair format: memory:<addr>=<bytes>;
// <addr> is a number whose base will be interpreted by the prefix:
@@ -2356,7 +2331,8 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
if (tid == LLDB_INVALID_THREAD_ID) {
// A thread id may be invalid if the response is old style 'S' packet
// which does not provide the
- // thread information. So update the thread list and choose the first one.
+ // thread information. So update the thread list and choose the first
+ // one.
UpdateThreadIDList();
if (!m_thread_ids.empty()) {
@@ -2389,9 +2365,9 @@ void ProcessGDBRemote::RefreshStateAfterStop() {
m_thread_ids.clear();
m_thread_pcs.clear();
- // Set the thread stop info. It might have a "threads" key whose value is
- // a list of all thread IDs in the current process, so m_thread_ids might
- // get set.
+ // Set the thread stop info. It might have a "threads" key whose value is a
+ // list of all thread IDs in the current process, so m_thread_ids might get
+ // set.
// Scope for the lock
{
@@ -2422,8 +2398,8 @@ void ProcessGDBRemote::RefreshStateAfterStop() {
m_initial_tid = LLDB_INVALID_THREAD_ID;
}
- // Let all threads recover from stopping and do any clean up based
- // on the previous thread state (if any).
+ // Let all threads recover from stopping and do any clean up based on the
+ // previous thread state (if any).
m_thread_list_real.RefreshStateAfterStop();
}
@@ -2431,8 +2407,8 @@ Status ProcessGDBRemote::DoHalt(bool &caused_stop) {
Status error;
if (m_public_state.GetValue() == eStateAttaching) {
- // We are being asked to halt during an attach. We need to just close
- // our file handle and debugserver will go away, and we can be done...
+ // We are being asked to halt during an attach. We need to just close our
+ // file handle and debugserver will go away, and we can be done...
m_gdb_comm.Disconnect();
} else
caused_stop = m_gdb_comm.Interrupt();
@@ -2475,31 +2451,24 @@ Status ProcessGDBRemote::DoDestroy() {
log->Printf("ProcessGDBRemote::DoDestroy()");
// There is a bug in older iOS debugservers where they don't shut down the
- // process
- // they are debugging properly. If the process is sitting at a breakpoint or
- // an exception,
- // this can cause problems with restarting. So we check to see if any of our
- // threads are stopped
- // at a breakpoint, and if so we remove all the breakpoints, resume the
- // process, and THEN
- // destroy it again.
+ // process they are debugging properly. If the process is sitting at a
+ // breakpoint or an exception, this can cause problems with restarting. So
+ // we check to see if any of our threads are stopped at a breakpoint, and if
+ // so we remove all the breakpoints, resume the process, and THEN destroy it
+ // again.
//
// Note, we don't have a good way to test the version of debugserver, but I
- // happen to know that
- // the set of all the iOS debugservers which don't support
- // GetThreadSuffixSupported() and that of
- // the debugservers with this bug are equal. There really should be a better
- // way to test this!
+ // happen to know that the set of all the iOS debugservers which don't
+ // support GetThreadSuffixSupported() and that of the debugservers with this
+ // bug are equal. There really should be a better way to test this!
//
// We also use m_destroy_tried_resuming to make sure we only do this once, if
- // we resume and then halt and
- // get called here to destroy again and we're still at a breakpoint or
- // exception, then we should
- // just do the straight-forward kill.
+ // we resume and then halt and get called here to destroy again and we're
+ // still at a breakpoint or exception, then we should just do the straight-
+ // forward kill.
//
// And of course, if we weren't able to stop the process by the time we get
- // here, it isn't
- // necessary (or helpful) to do any of this.
+ // here, it isn't necessary (or helpful) to do any of this.
if (!m_gdb_comm.GetThreadSuffixSupported() &&
m_public_state.GetValue() != eStateRunning) {
@@ -2514,9 +2483,8 @@ Status ProcessGDBRemote::DoDestroy() {
"destroy once already, not doing it again.");
} else {
// At present, the plans are discarded and the breakpoints disabled
- // Process::Destroy,
- // but we really need it to happen here and it doesn't matter if we do
- // it twice.
+ // Process::Destroy, but we really need it to happen here and it
+ // doesn't matter if we do it twice.
m_thread_list.DiscardThreadPlans();
DisableAllBreakpointSites();
@@ -2553,12 +2521,11 @@ Status ProcessGDBRemote::DoDestroy() {
m_destroy_tried_resuming = true;
// If we are going to run again before killing, it would be good to
- // suspend all the threads
- // before resuming so they won't get into more trouble. Sadly, for
- // the threads stopped with
- // the breakpoint or exception, the exception doesn't get cleared if
- // it is suspended, so we do
- // have to run the risk of letting those threads proceed a bit.
+ // suspend all the threads before resuming so they won't get into
+ // more trouble. Sadly, for the threads stopped with the breakpoint
+ // or exception, the exception doesn't get cleared if it is
+ // suspended, so we do have to run the risk of letting those threads
+ // proceed a bit.
{
std::lock_guard<std::recursive_mutex> guard(threads.GetMutex());
@@ -2605,17 +2572,14 @@ Status ProcessGDBRemote::DoDestroy() {
if (packet_cmd == 'W' || packet_cmd == 'X') {
#if defined(__APPLE__)
// For Native processes on Mac OS X, we launch through the Host
- // Platform, then hand the process off
- // to debugserver, which becomes the parent process through
- // "PT_ATTACH". Then when we go to kill
- // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then we
- // call waitpid which returns
- // with no error and the correct status. But amusingly enough that
- // doesn't seem to actually reap
+ // Platform, then hand the process off to debugserver, which becomes
+ // the parent process through "PT_ATTACH". Then when we go to kill
+ // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then
+ // we call waitpid which returns with no error and the correct
+ // status. But amusingly enough that doesn't seem to actually reap
// the process, but instead it is left around as a Zombie. Probably
- // the kernel is in the process of
- // switching ownership back to lldb which was the original parent, and
- // gets confused in the handoff.
+ // the kernel is in the process of switching ownership back to lldb
+ // which was the original parent, and gets confused in the handoff.
// Anyway, so call waitpid here to finally reap it.
PlatformSP platform_sp(GetTarget().GetPlatform());
if (platform_sp && platform_sp->IsHost()) {
@@ -2687,9 +2651,8 @@ void ProcessGDBRemote::SetLastStopPacket(
if (GetTarget().GetNonStopModeEnabled() == false)
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
+ // 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);
}
}
@@ -2721,12 +2684,11 @@ addr_t ProcessGDBRemote::GetImageInfoAddress() {
}
void ProcessGDBRemote::WillPublicStop() {
- // See if the GDB remote client supports the JSON threads info.
- // If so, we gather stop info for all threads, expedited registers,
- // expedited memory, runtime queue information (iOS and MacOSX only),
- // and more. Expediting memory will help stack backtracing be much
- // faster. Expediting registers will make sure we don't have to read
- // the thread registers for GPRs.
+ // See if the GDB remote client supports the JSON threads info. If so, we
+ // gather stop info for all threads, expedited registers, expedited memory,
+ // runtime queue information (iOS and MacOSX only), and more. Expediting
+ // memory will help stack backtracing be much faster. Expediting registers
+ // will make sure we don't have to read the thread registers for GPRs.
m_jthreadsinfo_sp = m_gdb_comm.GetThreadsInfo();
if (m_jthreadsinfo_sp) {
@@ -2776,14 +2738,13 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
error.Clear();
if (binary_memory_read) {
// The lower level GDBRemoteCommunication packet receive layer has
- // already de-quoted any
- // 0x7d character escaping that was present in the packet
+ // already de-quoted any 0x7d character escaping that was present in
+ // the packet
size_t data_received_size = response.GetBytesLeft();
if (data_received_size > size) {
// Don't write past the end of BUF if the remote debug server gave us
- // too
- // much data for some reason.
+ // too much data for some reason.
data_received_size = size;
}
memcpy(buf, response.GetStringRef().data(), data_received_size);
@@ -2807,6 +2768,145 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
return 0;
}
+Status ProcessGDBRemote::WriteObjectFile(
+ std::vector<ObjectFile::LoadableData> entries) {
+ Status error;
+ // Sort the entries by address because some writes, like those to flash
+ // memory, must happen in order of increasing address.
+ std::stable_sort(
+ std::begin(entries), std::end(entries),
+ [](const ObjectFile::LoadableData a, const ObjectFile::LoadableData b) {
+ return a.Dest < b.Dest;
+ });
+ m_allow_flash_writes = true;
+ error = Process::WriteObjectFile(entries);
+ if (error.Success())
+ error = FlashDone();
+ else
+ // Even though some of the writing failed, try to send a flash done if some
+ // of the writing succeeded so the flash state is reset to normal, but
+ // don't stomp on the error status that was set in the write failure since
+ // that's the one we want to report back.
+ FlashDone();
+ m_allow_flash_writes = false;
+ return error;
+}
+
+bool ProcessGDBRemote::HasErased(FlashRange range) {
+ auto size = m_erased_flash_ranges.GetSize();
+ for (size_t i = 0; i < size; ++i)
+ if (m_erased_flash_ranges.GetEntryAtIndex(i)->Contains(range))
+ return true;
+ return false;
+}
+
+Status ProcessGDBRemote::FlashErase(lldb::addr_t addr, size_t size) {
+ Status status;
+
+ MemoryRegionInfo region;
+ status = GetMemoryRegionInfo(addr, region);
+ if (!status.Success())
+ return status;
+
+ // The gdb spec doesn't say if erasures are allowed across multiple regions,
+ // but we'll disallow it to be safe and to keep the logic simple by worring
+ // about only one region's block size. DoMemoryWrite is this function's
+ // primary user, and it can easily keep writes within a single memory region
+ if (addr + size > region.GetRange().GetRangeEnd()) {
+ status.SetErrorString("Unable to erase flash in multiple regions");
+ return status;
+ }
+
+ uint64_t blocksize = region.GetBlocksize();
+ if (blocksize == 0) {
+ status.SetErrorString("Unable to erase flash because blocksize is 0");
+ return status;
+ }
+
+ // Erasures can only be done on block boundary adresses, so round down addr
+ // and round up size
+ lldb::addr_t block_start_addr = addr - (addr % blocksize);
+ size += (addr - block_start_addr);
+ if ((size % blocksize) != 0)
+ size += (blocksize - size % blocksize);
+
+ FlashRange range(block_start_addr, size);
+
+ if (HasErased(range))
+ return status;
+
+ // We haven't erased the entire range, but we may have erased part of it.
+ // (e.g., block A is already erased and range starts in A and ends in B). So,
+ // adjust range if necessary to exclude already erased blocks.
+ if (!m_erased_flash_ranges.IsEmpty()) {
+ // Assuming that writes and erasures are done in increasing addr order,
+ // because that is a requirement of the vFlashWrite command. Therefore, we
+ // only need to look at the last range in the list for overlap.
+ const auto &last_range = *m_erased_flash_ranges.Back();
+ if (range.GetRangeBase() < last_range.GetRangeEnd()) {
+ auto overlap = last_range.GetRangeEnd() - range.GetRangeBase();
+ // overlap will be less than range.GetByteSize() or else HasErased()
+ // would have been true
+ range.SetByteSize(range.GetByteSize() - overlap);
+ range.SetRangeBase(range.GetRangeBase() + overlap);
+ }
+ }
+
+ StreamString packet;
+ packet.Printf("vFlashErase:%" PRIx64 ",%" PRIx64, range.GetRangeBase(),
+ (uint64_t)range.GetByteSize());
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ m_erased_flash_ranges.Insert(range, true);
+ } else {
+ if (response.IsErrorResponse())
+ status.SetErrorStringWithFormat("flash erase failed for 0x%" PRIx64,
+ addr);
+ else if (response.IsUnsupportedResponse())
+ status.SetErrorStringWithFormat("GDB server does not support flashing");
+ else
+ status.SetErrorStringWithFormat(
+ "unexpected response to GDB server flash erase packet '%s': '%s'",
+ packet.GetData(), response.GetStringRef().c_str());
+ }
+ } else {
+ status.SetErrorStringWithFormat("failed to send packet: '%s'",
+ packet.GetData());
+ }
+ return status;
+}
+
+Status ProcessGDBRemote::FlashDone() {
+ Status status;
+ // If we haven't erased any blocks, then we must not have written anything
+ // either, so there is no need to actually send a vFlashDone command
+ if (m_erased_flash_ranges.IsEmpty())
+ return status;
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse("vFlashDone", response, true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ m_erased_flash_ranges.Clear();
+ } else {
+ if (response.IsErrorResponse())
+ status.SetErrorStringWithFormat("flash done failed");
+ else if (response.IsUnsupportedResponse())
+ status.SetErrorStringWithFormat("GDB server does not support flashing");
+ else
+ status.SetErrorStringWithFormat(
+ "unexpected response to GDB server flash done packet: '%s'",
+ response.GetStringRef().c_str());
+ }
+ } else {
+ status.SetErrorStringWithFormat("failed to send flash done packet");
+ }
+ return status;
+}
+
size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf,
size_t size, Status &error) {
GetMaxMemorySize();
@@ -2819,10 +2919,33 @@ size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf,
size = max_memory_size;
}
- StreamString packet;
- packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size);
- packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(),
- endian::InlHostByteOrder());
+ StreamGDBRemote packet;
+
+ MemoryRegionInfo region;
+ Status region_status = GetMemoryRegionInfo(addr, region);
+
+ bool is_flash =
+ region_status.Success() && region.GetFlash() == MemoryRegionInfo::eYes;
+
+ if (is_flash) {
+ if (!m_allow_flash_writes) {
+ error.SetErrorString("Writing to flash memory is not allowed");
+ return 0;
+ }
+ // Keep the write within a flash memory region
+ if (addr + size > region.GetRange().GetRangeEnd())
+ size = region.GetRange().GetRangeEnd() - addr;
+ // Flash memory must be erased before it can be written
+ error = FlashErase(addr, size);
+ if (!error.Success())
+ return 0;
+ packet.Printf("vFlashWrite:%" PRIx64 ":", addr);
+ packet.PutEscapedBytes(buf, size);
+ } else {
+ packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size);
+ packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(),
+ endian::InlHostByteOrder());
+ }
StringExtractorGDBRemote response;
if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response,
true) ==
@@ -2918,8 +3041,8 @@ Status ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) {
switch (supported) {
case eLazyBoolCalculate:
- // We should never be deallocating memory without allocating memory
- // first so we should never get eLazyBoolCalculate
+ // We should never be deallocating memory without allocating memory first
+ // so we should never get eLazyBoolCalculate
error.SetErrorString(
"tried to deallocate memory without ever allocating memory");
break;
@@ -2991,18 +3114,14 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) {
const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site);
// SupportsGDBStoppointPacket() simply checks a boolean, indicating if this
- // breakpoint type
- // is supported by the remote stub. These are set to true by default, and
- // later set to false
- // only after we receive an unimplemented response when sending a breakpoint
- // packet. This means
- // initially that unless we were specifically instructed to use a hardware
- // breakpoint, LLDB will
- // attempt to set a software breakpoint. HardwareRequired() also queries a
- // boolean variable which
- // indicates if the user specifically asked for hardware breakpoints. If true
- // then we will
- // skip over software breakpoints.
+ // breakpoint type is supported by the remote stub. These are set to true by
+ // default, and later set to false only after we receive an unimplemented
+ // response when sending a breakpoint packet. This means initially that
+ // unless we were specifically instructed to use a hardware breakpoint, LLDB
+ // will attempt to set a software breakpoint. HardwareRequired() also queries
+ // a boolean variable which indicates if the user specifically asked for
+ // hardware breakpoints. If true then we will skip over software
+ // breakpoints.
if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) &&
(!bp_site->HardwareRequired())) {
// Try to send off a software breakpoint packet ($Z0)
@@ -3015,19 +3134,14 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) {
return error;
}
- // SendGDBStoppointTypePacket() will return an error if it was unable to set
- // this
- // breakpoint. We need to differentiate between a error specific to placing
- // this breakpoint
- // or if we have learned that this breakpoint type is unsupported. To do
- // this, we
- // must test the support boolean for this breakpoint type to see if it now
- // indicates that
- // this breakpoint type is unsupported. If they are still supported then we
- // should return
+ // SendGDBStoppointTypePacket() will return an error if it was unable to
+ // set this breakpoint. We need to differentiate between a error specific
+ // to placing this breakpoint or if we have learned that this breakpoint
+ // type is unsupported. To do this, we must test the support boolean for
+ // this breakpoint type to see if it now indicates that this breakpoint
+ // type is unsupported. If they are still supported then we should return
// with the error code. If they are now unsupported, then we would like to
- // fall through
- // and try another form of breakpoint.
+ // fall through and try another form of breakpoint.
if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) {
if (error_no != UINT8_MAX)
error.SetErrorStringWithFormat(
@@ -3038,21 +3152,18 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) {
}
// We reach here when software breakpoints have been found to be
- // unsupported. For future
- // calls to set a breakpoint, we will not attempt to set a breakpoint with a
- // type that is
- // known not to be supported.
+ // unsupported. For future calls to set a breakpoint, we will not attempt
+ // to set a breakpoint with a type that is known not to be supported.
if (log)
log->Printf("Software breakpoints are unsupported");
// So we will fall through and try a hardware breakpoint
}
- // The process of setting a hardware breakpoint is much the same as above. We
- // check the
- // supported boolean for this breakpoint type, and if it is thought to be
- // supported then we
- // will try to set this breakpoint with a hardware breakpoint.
+ // The process of setting a hardware breakpoint is much the same as above.
+ // We check the supported boolean for this breakpoint type, and if it is
+ // thought to be supported then we will try to set this breakpoint with a
+ // hardware breakpoint.
if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) {
// Try to send off a hardware breakpoint packet ($Z1)
uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket(
@@ -3094,8 +3205,8 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) {
return error;
}
- // As a last resort we want to place a manual breakpoint. An instruction
- // is placed into the process memory using memory write packets.
+ // As a last resort we want to place a manual breakpoint. An instruction is
+ // placed into the process memory using memory write packets.
return EnableSoftwareBreakpoint(bp_site);
}
@@ -3225,10 +3336,9 @@ Status ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) {
log->Printf("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)",
watchID, (uint64_t)addr);
- // See also 'class WatchpointSentry' within StopInfo.cpp.
- // This disabling attempt might come from the user-supplied actions, we'll
- // route it in order for
- // the watchpoint object to intelligently process this action.
+ // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling
+ // attempt might come from the user-supplied actions, we'll route it in
+ // order for the watchpoint object to intelligently process this action.
wp->SetEnabled(false, notify);
return error;
}
@@ -3313,8 +3423,8 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver(
static FileSpec g_debugserver_file_spec;
ProcessLaunchInfo debugserver_launch_info;
- // Make debugserver run in its own session so signals generated by
- // special terminal key sequences (^C) don't affect debugserver.
+ // Make debugserver run in its own session so signals generated by special
+ // terminal key sequences (^C) don't affect debugserver.
debugserver_launch_info.SetLaunchInSeparateProcessGroup(true);
const std::weak_ptr<ProcessGDBRemote> this_wp =
@@ -3325,27 +3435,22 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver(
int communication_fd = -1;
#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION
- // Auto close the sockets we might open up unless everything goes OK. This
- // helps us not leak file descriptors when things go wrong.
- lldb_utility::CleanUp<int, int> our_socket(-1, -1, close);
- lldb_utility::CleanUp<int, int> gdb_socket(-1, -1, close);
-
// Use a socketpair on non-Windows systems for security and performance
// reasons.
- {
- int sockets[2]; /* the pair of socket descriptors */
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
- error.SetErrorToErrno();
- return error;
- }
-
- our_socket.set(sockets[0]);
- gdb_socket.set(sockets[1]);
+ int sockets[2]; /* the pair of socket descriptors */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
+ error.SetErrorToErrno();
+ return error;
}
+ int our_socket = sockets[0];
+ int gdb_socket = sockets[1];
+ CleanUp cleanup_our(close, our_socket);
+ CleanUp cleanup_gdb(close, gdb_socket);
+
// Don't let any child processes inherit our communication socket
- SetCloexecFlag(our_socket.get());
- communication_fd = gdb_socket.get();
+ SetCloexecFlag(our_socket);
+ communication_fd = gdb_socket;
#endif
error = m_gdb_comm.StartDebugserverProcess(
@@ -3359,10 +3464,10 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver(
if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) {
#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION
- // Our process spawned correctly, we can now set our connection to use our
- // end of the socket pair
- m_gdb_comm.SetConnection(
- new ConnectionFileDescriptor(our_socket.release(), true));
+ // Our process spawned correctly, we can now set our connection to use
+ // our end of the socket pair
+ cleanup_our.disable();
+ m_gdb_comm.SetConnection(new ConnectionFileDescriptor(our_socket, true));
#endif
StartAsyncThread();
}
@@ -3377,9 +3482,9 @@ Status ProcessGDBRemote::LaunchAndConnectToDebugserver(
}
if (m_gdb_comm.IsConnected()) {
- // Finish the connection process by doing the handshake without connecting
- // (send NULL URL)
- ConnectToDebugserver("");
+ // Finish the connection process by doing the handshake without
+ // connecting (send NULL URL)
+ error = ConnectToDebugserver("");
} else {
error.SetErrorString("connection failed");
}
@@ -3393,8 +3498,8 @@ bool ProcessGDBRemote::MonitorDebugserverProcess(
int signo, // Zero for no signal
int exit_status // Exit value of process if signal is zero
) {
- // "debugserver_pid" argument passed in is the process ID for
- // debugserver that we are tracking...
+ // "debugserver_pid" argument passed in is the process ID for debugserver
+ // that we are tracking...
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
const bool handled = true;
@@ -3410,12 +3515,12 @@ bool ProcessGDBRemote::MonitorDebugserverProcess(
if (!process_sp || process_sp->m_debugserver_pid != debugserver_pid)
return handled;
- // Sleep for a half a second to make sure our inferior process has
- // time to set its exit status before we set it incorrectly when
- // both the debugserver and the inferior process shut down.
+ // Sleep for a half a second to make sure our inferior process has time to
+ // set its exit status before we set it incorrectly when both the debugserver
+ // and the inferior process shut down.
usleep(500000);
- // If our process hasn't yet exited, debugserver might have died.
- // If the process did exit, then we are reaping it.
+ // If our process hasn't yet exited, debugserver might have died. If the
+ // process did exit, then we are reaping it.
const StateType state = process_sp->GetState();
if (state != eStateInvalid && state != eStateUnloaded &&
@@ -3438,8 +3543,8 @@ bool ProcessGDBRemote::MonitorDebugserverProcess(
process_sp->SetExitStatus(-1, error_str);
}
- // Debugserver has exited we need to let our ProcessGDBRemote
- // know that it no longer has a debugserver instance
+ // Debugserver has exited we need to let our ProcessGDBRemote know that it no
+ // longer has a debugserver instance
process_sp->m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
return handled;
}
@@ -3529,10 +3634,9 @@ bool ProcessGDBRemote::HandleNotifyPacket(StringExtractorGDBRemote &packet) {
// check for more stop reasons
HandleStopReplySequence();
- // if the process is stopped then we need to fake a resume
- // so that we can stop properly with the new break. This
- // is possible due to SetPrivateState() broadcasting the
- // state change as a side effect.
+ // if the process is stopped then we need to fake a resume so that we can
+ // stop properly with the new break. This is possible due to
+ // SetPrivateState() broadcasting the state change as a side effect.
if (GetPrivateState() == lldb::StateType::eStateStopped) {
SetPrivateState(lldb::StateType::eStateRunning);
}
@@ -3605,12 +3709,11 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) {
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
+ // 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()...
+ // packet to the process using the
+ // process->SetLastStopPacket()...
process->ClearThreadIDList();
switch (stop_state) {
@@ -3647,17 +3750,14 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) {
// 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.
+ // helpful error message about why the attach failed.
if (::strstr(continue_cstr, "vAttach") != NULL &&
response.GetError() == 0x87) {
process->SetExitStatus(-1, "cannot attach to process due to "
"System Integrity Protection");
- }
- // E01 code from vAttach means that the attach failed
- if (::strstr(continue_cstr, "vAttach") != NULL &&
- response.GetError() == 0x1) {
- process->SetExitStatus(-1, "unable to attach");
+ } else if (::strstr(continue_cstr, "vAttach") != NULL &&
+ response.GetStatus().Fail()) {
+ process->SetExitStatus(-1, response.GetStatus().AsCString());
} else {
process->SetExitStatus(-1, "lost connection");
}
@@ -3769,8 +3869,8 @@ Status ProcessGDBRemote::UpdateAutomaticSignalFiltering() {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
LLDB_LOG(log, "Check if need to update ignored signals");
- // QPassSignals package is not supported by the server,
- // there is no way we can ignore any signals on server side.
+ // QPassSignals package is not supported by the server, there is no way we
+ // can ignore any signals on server side.
if (!m_gdb_comm.GetQPassSignalsSupported())
return Status();
@@ -3894,9 +3994,9 @@ ProcessGDBRemote::GetExtendedInfoForThread(lldb::tid_t tid) {
// FIXME the final character of a JSON dictionary, '}', is the escape
// character in gdb-remote binary mode. lldb currently doesn't escape
- // these characters in its packet output -- so we add the quoted version
- // of the } character here manually in case we talk to a debugserver which
- // un-escapes the characters at packet read time.
+ // these characters in its packet output -- so we add the quoted version of
+ // the } character here manually in case we talk to a debugserver which un-
+ // escapes the characters at packet read time.
packet << (char)(0x7d ^ 0x20);
StringExtractorGDBRemote response;
@@ -3966,9 +4066,9 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender(
// FIXME the final character of a JSON dictionary, '}', is the escape
// character in gdb-remote binary mode. lldb currently doesn't escape
- // these characters in its packet output -- so we add the quoted version
- // of the } character here manually in case we talk to a debugserver which
- // un-escapes the characters at packet read time.
+ // these characters in its packet output -- so we add the quoted version of
+ // the } character here manually in case we talk to a debugserver which un-
+ // escapes the characters at packet read time.
packet << (char)(0x7d ^ 0x20);
StringExtractorGDBRemote response;
@@ -3999,9 +4099,9 @@ StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() {
// FIXME the final character of a JSON dictionary, '}', is the escape
// character in gdb-remote binary mode. lldb currently doesn't escape
- // these characters in its packet output -- so we add the quoted version
- // of the } character here manually in case we talk to a debugserver which
- // un-escapes the characters at packet read time.
+ // these characters in its packet output -- so we add the quoted version of
+ // the } character here manually in case we talk to a debugserver which un-
+ // escapes the characters at packet read time.
packet << (char)(0x7d ^ 0x20);
StringExtractorGDBRemote response;
@@ -4026,14 +4126,14 @@ Status ProcessGDBRemote::ConfigureStructuredData(
return m_gdb_comm.ConfigureRemoteStructuredData(type_name, config_sp);
}
-// Establish the largest memory read/write payloads we should use.
-// If the remote stub has a max packet size, stay under that size.
+// Establish the largest memory read/write payloads we should use. If the
+// remote stub has a max packet size, stay under that size.
//
-// If the remote stub's max packet size is crazy large, use a
-// reasonable largeish default.
+// If the remote stub's max packet size is crazy large, use a reasonable
+// largeish default.
//
-// If the remote stub doesn't advertise a max packet size, use a
-// conservative default.
+// If the remote stub doesn't advertise a max packet size, use a conservative
+// default.
void ProcessGDBRemote::GetMaxMemorySize() {
const uint64_t reasonable_largeish_default = 128 * 1024;
@@ -4045,15 +4145,15 @@ void ProcessGDBRemote::GetMaxMemorySize() {
// Save the stub's claimed maximum packet size
m_remote_stub_max_memory_size = stub_max_size;
- // Even if the stub says it can support ginormous packets,
- // don't exceed our reasonable largeish default packet size.
+ // Even if the stub says it can support ginormous packets, don't exceed
+ // our reasonable largeish default packet size.
if (stub_max_size > reasonable_largeish_default) {
stub_max_size = reasonable_largeish_default;
}
- // Memory packet have other overheads too like Maddr,size:#NN
- // Instead of calculating the bytes taken by size and addr every
- // time, we take a maximum guess here.
+ // Memory packet have other overheads too like Maddr,size:#NN Instead of
+ // calculating the bytes taken by size and addr every time, we take a
+ // maximum guess here.
if (stub_max_size > 70)
stub_max_size -= 32 + 32 + 6;
else {
@@ -4140,13 +4240,8 @@ void ProcessGDBRemote::PrefetchModuleSpecs(
}
}
-bool ProcessGDBRemote::GetHostOSVersion(uint32_t &major, uint32_t &minor,
- uint32_t &update) {
- if (m_gdb_comm.GetOSVersion(major, minor, update))
- return true;
- // We failed to get the host OS version, defer to the base
- // implementation to correctly invalidate the arguments.
- return Process::GetHostOSVersion(major, minor, update);
+llvm::VersionTuple ProcessGDBRemote::GetHostOSVersion() {
+ return m_gdb_comm.GetOSVersion();
}
namespace {
@@ -4237,7 +4332,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
} else if (name == "format") {
format_set = true;
Format format = eFormatInvalid;
- if (Args::StringToFormat(value.data(), format, NULL).Success())
+ if (OptionArgParser::ToFormat(value.data(), format, NULL).Success())
reg_info.format = format;
else if (value == "vector-sint8")
reg_info.format = eFormatVectorOfSInt8;
@@ -4311,8 +4406,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
}
// 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.
- // "set_name" will be empty if we didn't have a "reg_set" attribute.
if (!set_name && !gdb_group.empty())
set_name.SetCString(gdb_group.c_str());
@@ -4339,8 +4434,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
} // namespace {}
-// query the target of gdb-remote for extended target information
-// return: 'true' on success
+// query the target of gdb-remote for extended target information return:
+// 'true' on success
// 'false' on failure
bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
// Make sure LLDB has an XML parser it can use first
@@ -4409,15 +4504,27 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
return true; // Keep iterating through all children of the target_node
});
+ // If the target.xml includes an architecture entry like
+ // <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.
+ 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);
+ }
+ }
+
// Initialize these outside of ParseRegisters, since they should not be
// reset inside each include feature
uint32_t cur_reg_num = 0;
uint32_t reg_offset = 0;
- // 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.
+ // 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,
@@ -4758,8 +4865,8 @@ void ProcessGDBRemote::ModulesDidLoad(ModuleList &module_list) {
// do anything
Process::ModulesDidLoad(module_list);
- // After loading shared libraries, we can ask our remote GDB server if
- // it needs any symbols.
+ // After loading shared libraries, we can ask our remote GDB server if it
+ // needs any symbols.
m_gdb_comm.ServeSymbolLookups(this);
}
@@ -4817,8 +4924,8 @@ std::string ProcessGDBRemote::HarmonizeThreadIdsForProfileData(
has_used_usec = true;
usec_value.getAsInteger(0, curr_used_usec);
} else {
- // We didn't find what we want, it is probably
- // an older version. Bail out.
+ // We didn't find what we want, it is probably an older version. Bail
+ // out.
profileDataExtractor.SetFilePos(input_file_pos);
}
}
@@ -4840,8 +4947,8 @@ std::string ProcessGDBRemote::HarmonizeThreadIdsForProfileData(
((real_used_usec > 0) || (HasAssignedIndexIDToThread(thread_id)));
if (good_first_time || good_subsequent_time) {
- // We try to avoid doing too many index id reservation,
- // resulting in fast increase of index ids.
+ // We try to avoid doing too many index id reservation, resulting in
+ // fast increase of index ids.
output_stream << name << ":";
int32_t index_id = AssignIndexIDToThread(thread_id);
@@ -4892,7 +4999,7 @@ ParseStructuredDataPacket(llvm::StringRef packet) {
if (!packet.consume_front(s_async_json_packet_prefix)) {
if (log) {
log->Printf(
- "GDBRemoteCommmunicationClientBase::%s() received $J packet "
+ "GDBRemoteCommunicationClientBase::%s() received $J packet "
"but was not a StructuredData packet: packet starts with "
"%s",
__FUNCTION__,
@@ -4901,8 +5008,7 @@ ParseStructuredDataPacket(llvm::StringRef packet) {
return StructuredData::ObjectSP();
}
- // This is an asynchronous JSON packet, destined for a
- // StructuredDataPlugin.
+ // This is an asynchronous JSON packet, destined for a StructuredDataPlugin.
StructuredData::ObjectSP json_sp = StructuredData::ParseJSON(packet);
if (log) {
if (json_sp) {
@@ -5137,8 +5243,9 @@ public:
~CommandObjectProcessGDBRemotePacketMonitor() {}
- bool DoExecute(const char *command, CommandReturnObject &result) override {
- if (command == NULL || command[0] == '\0') {
+ bool DoExecute(llvm::StringRef command,
+ CommandReturnObject &result) override {
+ if (command.empty()) {
result.AppendErrorWithFormat("'%s' takes a command string argument",
m_cmd_name.c_str());
result.SetStatus(eReturnStatusFailed);
@@ -5150,14 +5257,15 @@ public:
if (process) {
StreamString packet;
packet.PutCString("qRcmd,");
- packet.PutBytesAsRawHex8(command, strlen(command));
+ packet.PutBytesAsRawHex8(command.data(), command.size());
bool send_async = true;
StringExtractorGDBRemote response;
- process->GetGDBRemote().SendPacketAndWaitForResponse(
- packet.GetString(), response, send_async);
- result.SetStatus(eReturnStatusSuccessFinishResult);
Stream &output_strm = result.GetOutputStream();
+ process->GetGDBRemote().SendPacketAndReceiveResponseWithOutputSupport(
+ packet.GetString(), response, send_async,
+ [&output_strm](llvm::StringRef output) { output_strm << output; });
+ result.SetStatus(eReturnStatusSuccessFinishResult);
output_strm.Printf(" packet: %s\n", packet.GetData());
const std::string &response_str = response.GetStringRef();