mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-17 05:40:48 +00:00

With this change, both local-process llgs and remote-target llgs stdout/stderr handling from inferior work correctly. Several log lines have been added around PTY and stdout/stderr redirection logic on the lldb client side. Regarding remote llgs execution, see the following: With these changes, remote llgs with $O now works properly: $ lldb (lldb) platform select remote-linux (lldb) target create ~/some/inferior/exe (lldb) gdb-remote {some-target}:{port} (lldb) run The sequence above will correctly redirect stdout/stderr over gdb-remote $O, as is needed for remote debugging. That sequence assumes there is a lldb-gdbserver exe running on the target with {some-host}:{port}. You can replace the gdb-remote command with a '(lldb) platform connect connect://{target-ip}:{target-port}'. If you do this and have a lldb-platform running on the remote end, it will go ahead and launch llgs for lldb for each target instance that is run/attached. For local debugging with llgs, the following sequence also works, and uses local PTYs instead to avoid $O and extra gdb-remote messages: $ lldb (lldb) settings set platform.plugin.linux.use-llgs true (lldb) target create ~/some/inferior/exe (lldb) run The above will run the inferior using llgs on the local host, and will use PTYs rather than $O redirection. This change also removes the logging that happened after the fork but before the exec when llgs is launching a new inferior process. Some aspect of the file handling during that portion of code would not do the right thing with log handling. We might want to go back later and have that communicate over a pipe from the child to parent to pass along any messages that previously were logged in that section of code. llvm-svn: 219578
552 lines
16 KiB
C++
552 lines
16 KiB
C++
//===-- GDBRemoteCommunicationServer.h --------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef liblldb_GDBRemoteCommunicationServer_h_
|
|
#define liblldb_GDBRemoteCommunicationServer_h_
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
#include <vector>
|
|
#include <set>
|
|
#include <unordered_map>
|
|
// Other libraries and framework includes
|
|
// Project includes
|
|
#include "lldb/lldb-private-forward.h"
|
|
#include "lldb/Core/Communication.h"
|
|
#include "lldb/Host/Mutex.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "GDBRemoteCommunication.h"
|
|
|
|
#include "../../../Host/common/NativeProcessProtocol.h"
|
|
|
|
class ProcessGDBRemote;
|
|
class StringExtractorGDBRemote;
|
|
|
|
class GDBRemoteCommunicationServer :
|
|
public GDBRemoteCommunication,
|
|
public lldb_private::NativeProcessProtocol::NativeDelegate
|
|
{
|
|
public:
|
|
typedef std::map<uint16_t, lldb::pid_t> PortMap;
|
|
|
|
enum
|
|
{
|
|
eBroadcastBitRunPacketSent = kLoUserBroadcastBit
|
|
};
|
|
//------------------------------------------------------------------
|
|
// Constructors and Destructors
|
|
//------------------------------------------------------------------
|
|
GDBRemoteCommunicationServer(bool is_platform);
|
|
|
|
GDBRemoteCommunicationServer(bool is_platform,
|
|
const lldb::PlatformSP& platform_sp,
|
|
lldb::DebuggerSP& debugger_sp);
|
|
|
|
virtual
|
|
~GDBRemoteCommunicationServer();
|
|
|
|
PacketResult
|
|
GetPacketAndSendResponse (uint32_t timeout_usec,
|
|
lldb_private::Error &error,
|
|
bool &interrupt,
|
|
bool &quit);
|
|
|
|
virtual bool
|
|
GetThreadSuffixSupported ()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// After connecting, do a little handshake with the client to make sure
|
|
// we are at least communicating
|
|
bool
|
|
HandshakeWithClient (lldb_private::Error *error_ptr);
|
|
|
|
// Set both ports to zero to let the platform automatically bind to
|
|
// a port chosen by the OS.
|
|
void
|
|
SetPortMap (PortMap &&port_map)
|
|
{
|
|
m_port_map = port_map;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// If we are using a port map where we can only use certain ports,
|
|
// get the next available port.
|
|
//
|
|
// If we are using a port map and we are out of ports, return UINT16_MAX
|
|
//
|
|
// If we aren't using a port map, return 0 to indicate we should bind to
|
|
// port 0 and then figure out which port we used.
|
|
//----------------------------------------------------------------------
|
|
uint16_t
|
|
GetNextAvailablePort ()
|
|
{
|
|
if (m_port_map.empty())
|
|
return 0; // Bind to port zero and get a port, we didn't have any limitations
|
|
|
|
for (auto &pair : m_port_map)
|
|
{
|
|
if (pair.second == LLDB_INVALID_PROCESS_ID)
|
|
{
|
|
pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
|
|
return pair.first;
|
|
}
|
|
}
|
|
return UINT16_MAX;
|
|
}
|
|
|
|
bool
|
|
AssociatePortWithProcess (uint16_t port, lldb::pid_t pid)
|
|
{
|
|
PortMap::iterator pos = m_port_map.find(port);
|
|
if (pos != m_port_map.end())
|
|
{
|
|
pos->second = pid;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
FreePort (uint16_t port)
|
|
{
|
|
PortMap::iterator pos = m_port_map.find(port);
|
|
if (pos != m_port_map.end())
|
|
{
|
|
pos->second = LLDB_INVALID_PROCESS_ID;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
FreePortForProcess (lldb::pid_t pid)
|
|
{
|
|
if (!m_port_map.empty())
|
|
{
|
|
for (auto &pair : m_port_map)
|
|
{
|
|
if (pair.second == pid)
|
|
{
|
|
pair.second = LLDB_INVALID_PROCESS_ID;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void
|
|
SetPortOffset (uint16_t port_offset)
|
|
{
|
|
m_port_offset = port_offset;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
/// Specify the program to launch and its arguments.
|
|
///
|
|
/// @param[in] args
|
|
/// The command line to launch.
|
|
///
|
|
/// @param[in] argc
|
|
/// The number of elements in the args array of cstring pointers.
|
|
///
|
|
/// @return
|
|
/// An Error object indicating the success or failure of making
|
|
/// the setting.
|
|
//------------------------------------------------------------------
|
|
lldb_private::Error
|
|
SetLaunchArguments (const char *const args[], int argc);
|
|
|
|
//------------------------------------------------------------------
|
|
/// Specify the launch flags for the process.
|
|
///
|
|
/// @param[in] launch_flags
|
|
/// The launch flags to use when launching this process.
|
|
///
|
|
/// @return
|
|
/// An Error object indicating the success or failure of making
|
|
/// the setting.
|
|
//------------------------------------------------------------------
|
|
lldb_private::Error
|
|
SetLaunchFlags (unsigned int launch_flags);
|
|
|
|
//------------------------------------------------------------------
|
|
/// Launch a process with the current launch settings.
|
|
///
|
|
/// This method supports running an lldb-gdbserver or similar
|
|
/// server in a situation where the startup code has been provided
|
|
/// with all the information for a child process to be launched.
|
|
///
|
|
/// @return
|
|
/// An Error object indicating the success or failure of the
|
|
/// launch.
|
|
//------------------------------------------------------------------
|
|
lldb_private::Error
|
|
LaunchProcess ();
|
|
|
|
//------------------------------------------------------------------
|
|
/// Attach to a process.
|
|
///
|
|
/// This method supports attaching llgs to a process accessible via the
|
|
/// configured Platform.
|
|
///
|
|
/// @return
|
|
/// An Error object indicating the success or failure of the
|
|
/// attach operation.
|
|
//------------------------------------------------------------------
|
|
lldb_private::Error
|
|
AttachToProcess (lldb::pid_t pid);
|
|
|
|
//------------------------------------------------------------------
|
|
// NativeProcessProtocol::NativeDelegate overrides
|
|
//------------------------------------------------------------------
|
|
void
|
|
InitializeDelegate (lldb_private::NativeProcessProtocol *process) override;
|
|
|
|
void
|
|
ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state) override;
|
|
|
|
void
|
|
DidExec (lldb_private::NativeProcessProtocol *process) override;
|
|
|
|
protected:
|
|
lldb::PlatformSP m_platform_sp;
|
|
lldb::thread_t m_async_thread;
|
|
lldb_private::ProcessLaunchInfo m_process_launch_info;
|
|
lldb_private::Error m_process_launch_error;
|
|
std::set<lldb::pid_t> m_spawned_pids;
|
|
lldb_private::Mutex m_spawned_pids_mutex;
|
|
lldb_private::ProcessInstanceInfoList m_proc_infos;
|
|
uint32_t m_proc_infos_index;
|
|
PortMap m_port_map;
|
|
uint16_t m_port_offset;
|
|
lldb::tid_t m_current_tid;
|
|
lldb::tid_t m_continue_tid;
|
|
lldb_private::Mutex m_debugged_process_mutex;
|
|
lldb_private::NativeProcessProtocolSP m_debugged_process_sp;
|
|
lldb::DebuggerSP m_debugger_sp;
|
|
Communication m_stdio_communication;
|
|
bool m_exit_now; // use in asynchronous handling to indicate process should exit.
|
|
lldb::StateType m_inferior_prev_state;
|
|
bool m_thread_suffix_supported;
|
|
bool m_list_threads_in_stop_reply;
|
|
lldb::DataBufferSP m_active_auxv_buffer_sp;
|
|
lldb_private::Mutex m_saved_registers_mutex;
|
|
std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map;
|
|
uint32_t m_next_saved_registers_id;
|
|
|
|
PacketResult
|
|
SendUnimplementedResponse (const char *packet);
|
|
|
|
PacketResult
|
|
SendErrorResponse (uint8_t error);
|
|
|
|
PacketResult
|
|
SendIllFormedResponse (const StringExtractorGDBRemote &packet, const char *error_message);
|
|
|
|
PacketResult
|
|
SendOKResponse ();
|
|
|
|
PacketResult
|
|
SendONotification (const char *buffer, uint32_t len);
|
|
|
|
PacketResult
|
|
SendWResponse (lldb_private::NativeProcessProtocol *process);
|
|
|
|
PacketResult
|
|
SendStopReplyPacketForThread (lldb::tid_t tid);
|
|
|
|
PacketResult
|
|
SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit);
|
|
|
|
PacketResult
|
|
Handle_A (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qLaunchSuccess (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qHostInfo (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_k (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qPlatform_chmod (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qProcessInfo (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qfProcessInfo (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qsProcessInfo (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qC (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qUserName (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qGroupName (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qSpeedTest (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QEnvironment (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QLaunchArch (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QSetDetachOnError (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qGetWorkingDir (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QStartNoAckMode (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QSetSTDIN (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QSetSTDOUT (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_C (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment = false);
|
|
|
|
PacketResult
|
|
Handle_vCont (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vCont_actions (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_stop_reason (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_Open (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_Close (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_pRead (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_pWrite (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_Size (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_Mode (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_Exists (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_symlink (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_unlink (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_Stat (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vFile_MD5 (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qPlatform_shell (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qRegisterInfo (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qfThreadInfo (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qsThreadInfo (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_p (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_P (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_H (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_interrupt (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_m (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_M (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_Z (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_z (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_s (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qSupported (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QSaveRegisterState (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_vAttach (StringExtractorGDBRemote &packet);
|
|
|
|
PacketResult
|
|
Handle_qThreadStopInfo (StringExtractorGDBRemote &packet);
|
|
|
|
void
|
|
SetCurrentThreadID (lldb::tid_t tid);
|
|
|
|
lldb::tid_t
|
|
GetCurrentThreadID () const;
|
|
|
|
void
|
|
SetContinueThreadID (lldb::tid_t tid);
|
|
|
|
lldb::tid_t
|
|
GetContinueThreadID () const { return m_continue_tid; }
|
|
|
|
lldb_private::Error
|
|
SetSTDIOFileDescriptor (int fd);
|
|
|
|
static void
|
|
STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
|
|
|
|
private:
|
|
bool
|
|
DebugserverProcessReaped (lldb::pid_t pid);
|
|
|
|
static bool
|
|
ReapDebugserverProcess (void *callback_baton,
|
|
lldb::pid_t pid,
|
|
bool exited,
|
|
int signal,
|
|
int status);
|
|
|
|
bool
|
|
DebuggedProcessReaped (lldb::pid_t pid);
|
|
|
|
static bool
|
|
ReapDebuggedProcess (void *callback_baton,
|
|
lldb::pid_t pid,
|
|
bool exited,
|
|
int signal,
|
|
int status);
|
|
|
|
bool
|
|
KillSpawnedProcess (lldb::pid_t pid);
|
|
|
|
bool
|
|
IsGdbServer ()
|
|
{
|
|
return !m_is_platform;
|
|
}
|
|
|
|
/// Launch an inferior process from lldb-gdbserver
|
|
lldb_private::Error
|
|
LaunchProcessForDebugging ();
|
|
|
|
/// Launch a process from lldb-platform
|
|
lldb_private::Error
|
|
LaunchPlatformProcess ();
|
|
|
|
void
|
|
HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process);
|
|
|
|
void
|
|
HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process);
|
|
|
|
void
|
|
FlushInferiorOutput ();
|
|
|
|
lldb_private::NativeThreadProtocolSP
|
|
GetThreadFromSuffix (StringExtractorGDBRemote &packet);
|
|
|
|
uint32_t
|
|
GetNextSavedRegistersID ();
|
|
|
|
void
|
|
MaybeCloseInferiorTerminalConnection ();
|
|
|
|
void
|
|
ClearProcessSpecificData ();
|
|
|
|
bool
|
|
ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const;
|
|
|
|
//------------------------------------------------------------------
|
|
// For GDBRemoteCommunicationServer only
|
|
//------------------------------------------------------------------
|
|
DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServer);
|
|
};
|
|
|
|
#endif // liblldb_GDBRemoteCommunicationServer_h_
|