llvm/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp

//===-- ProcessGDBRemote.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "lldb/Host/Config.h"

#include <cerrno>
#include <cstdlib>
#if LLDB_ENABLE_POSIX
#include <netinet/in.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#include <sys/stat.h>
#if defined(__APPLE__)
#include <sys/sysctl.h>
#endif
#include <ctime>
#include <sys/types.h>

#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Breakpoint/WatchpointAlgorithms.h"
#include "lldb/Breakpoint/WatchpointResource.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Value.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Host/StreamFile.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Host/XML.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"
#include "lldb/Interpreter/Options.h"
#include "lldb/Interpreter/Property.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/RegisterFlags.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/FileSpec.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h"
#include <algorithm>
#include <csignal>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <sstream>
#include <thread>

#include "GDBRemoteRegisterContext.h"
#include "GDBRemoteRegisterFallback.h"
#include "Plugins/Process/Utility/GDBRemoteSignals.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
#include "Plugins/Process/Utility/StopInfoMachException.h"
#include "ProcessGDBRemote.h"
#include "ProcessGDBRemoteLog.h"
#include "ThreadGDBRemote.h"
#include "lldb/Host/Host.h"
#include "lldb/Utility/StringExtractorGDBRemote.h"

#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"

#define DEBUGSERVER_BASENAME
usingnamespacelldb;
usingnamespacelldb_private;
usingnamespacelldb_private::process_gdb_remote;

LLDB_PLUGIN_DEFINE()

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
// 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.
void DumpProcessGDBRemotePacketHistory(void *p, const char *path) {}
} // namespace lldb

namespace {

#define LLDB_PROPERTIES_processgdbremote
#include "ProcessGDBRemoteProperties.inc"

enum {};

class PluginProperties : public Properties {};

} // namespace

static PluginProperties &GetGlobalPluginProperties() {}

// 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.

#if defined(__APPLE__)
#define LOW_PORT
#define HIGH_PORT
#else
#define LOW_PORT
#define HIGH_PORT
#endif

llvm::StringRef ProcessGDBRemote::GetPluginDescriptionStatic() {}

void ProcessGDBRemote::Terminate() {}

lldb::ProcessSP ProcessGDBRemote::CreateInstance(
    lldb::TargetSP target_sp, ListenerSP listener_sp,
    const FileSpec *crash_file_path, bool can_connect) {}

void ProcessGDBRemote::DumpPluginHistory(Stream &s) {}

std::chrono::seconds ProcessGDBRemote::GetPacketTimeout() {}

ArchSpec ProcessGDBRemote::GetSystemArchitecture() {}

bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp,
                                bool plugin_specified_by_name) {}

// ProcessGDBRemote constructor
ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
                                   ListenerSP listener_sp)
    :{}

// Destructor
ProcessGDBRemote::~ProcessGDBRemote() {}

bool ProcessGDBRemote::ParsePythonTargetDefinition(
    const FileSpec &target_definition_fspec) {}

static size_t SplitCommaSeparatedRegisterNumberString(
    const llvm::StringRef &comma_separated_register_numbers,
    std::vector<uint32_t> &regnums, int base) {}

void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {}

Status ProcessGDBRemote::DoWillLaunch(lldb_private::Module *module) {}

Status ProcessGDBRemote::DoWillAttachToProcessWithID(lldb::pid_t pid) {}

Status ProcessGDBRemote::DoWillAttachToProcessWithName(const char *process_name,
                                                       bool wait_for_launch) {}

Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) {}

Status ProcessGDBRemote::WillLaunchOrAttach() {}

// Process Control
Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module,
                                  ProcessLaunchInfo &launch_info) {}

Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {}

void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) {}

void ProcessGDBRemote::LoadStubBinaries() {}

void ProcessGDBRemote::MaybeLoadExecutableModule() {}

void ProcessGDBRemote::DidLaunch() {}

Status ProcessGDBRemote::DoAttachToProcessWithID(
    lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) {}

Status ProcessGDBRemote::DoAttachToProcessWithName(
    const char *process_name, const ProcessAttachInfo &attach_info) {}

llvm::Expected<TraceSupportedResponse> ProcessGDBRemote::TraceSupported() {}

llvm::Error ProcessGDBRemote::TraceStop(const TraceStopRequest &request) {}

llvm::Error ProcessGDBRemote::TraceStart(const llvm::json::Value &request) {}

llvm::Expected<std::string>
ProcessGDBRemote::TraceGetState(llvm::StringRef type) {}

llvm::Expected<std::vector<uint8_t>>
ProcessGDBRemote::TraceGetBinaryData(const TraceGetBinaryDataRequest &request) {}

void ProcessGDBRemote::DidExit() {}

void ProcessGDBRemote::DidAttach(ArchSpec &process_arch) {}

Status ProcessGDBRemote::WillResume() {}

Status ProcessGDBRemote::DoResume() {}

void ProcessGDBRemote::ClearThreadIDList() {}

size_t ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue(
    llvm::StringRef value) {}

size_t ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue(
    llvm::StringRef value) {}

bool ProcessGDBRemote::UpdateThreadIDList() {}

bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list,
                                          ThreadList &new_thread_list) {}

void ProcessGDBRemote::SetThreadPc(const ThreadSP &thread_sp, uint64_t index) {}

bool ProcessGDBRemote::GetThreadStopInfoFromJSON(
    ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp) {}

bool ProcessGDBRemote::CalculateThreadStopInfo(ThreadGDBRemote *thread) {}

void ProcessGDBRemote::ParseExpeditedRegisters(
    ExpeditedRegisterMap &expedited_register_map, ThreadSP thread_sp) {}

ThreadSP ProcessGDBRemote::SetThreadStopInfo(
    lldb::tid_t tid, ExpeditedRegisterMap &expedited_register_map,
    uint8_t signo, const std::string &thread_name, const std::string &reason,
    const std::string &description, uint32_t exc_type,
    const std::vector<addr_t> &exc_data, addr_t thread_dispatch_qaddr,
    bool queue_vars_valid, // Set to true if queue_name, queue_kind and
                           // queue_serial are valid
    LazyBool associated_with_dispatch_queue, addr_t dispatch_queue_t,
    std::string &queue_name, QueueKind queue_kind, uint64_t queue_serial) {}

ThreadSP
ProcessGDBRemote::HandleThreadAsyncInterrupt(uint8_t signo,
                                             const std::string &description) {}

lldb::ThreadSP
ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {}

StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {}

void ProcessGDBRemote::RefreshStateAfterStop() {}

Status ProcessGDBRemote::DoHalt(bool &caused_stop) {}

Status ProcessGDBRemote::DoDetach(bool keep_stopped) {}

Status ProcessGDBRemote::DoDestroy() {}

void ProcessGDBRemote::SetLastStopPacket(
    const StringExtractorGDBRemote &response) {}

void ProcessGDBRemote::SetUnixSignals(const UnixSignalsSP &signals_sp) {}

// Process Queries

bool ProcessGDBRemote::IsAlive() {}

addr_t ProcessGDBRemote::GetImageInfoAddress() {}

void ProcessGDBRemote::WillPublicStop() {}

// Process Memory
size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
                                      Status &error) {}

bool ProcessGDBRemote::SupportsMemoryTagging() {}

llvm::Expected<std::vector<uint8_t>>
ProcessGDBRemote::DoReadMemoryTags(lldb::addr_t addr, size_t len,
                                   int32_t type) {}

Status ProcessGDBRemote::DoWriteMemoryTags(lldb::addr_t addr, size_t len,
                                           int32_t type,
                                           const std::vector<uint8_t> &tags) {}

Status ProcessGDBRemote::WriteObjectFile(
    std::vector<ObjectFile::LoadableData> entries) {}

bool ProcessGDBRemote::HasErased(FlashRange range) {}

Status ProcessGDBRemote::FlashErase(lldb::addr_t addr, size_t size) {}

Status ProcessGDBRemote::FlashDone() {}

size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf,
                                       size_t size, Status &error) {}

lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t size,
                                                uint32_t permissions,
                                                Status &error) {}

Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr,
                                               MemoryRegionInfo &region_info) {}

std::optional<uint32_t> ProcessGDBRemote::GetWatchpointSlotCount() {}

std::optional<bool> ProcessGDBRemote::DoGetWatchpointReportedAfter() {}

Status ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) {}

// Process STDIO
size_t ProcessGDBRemote::PutSTDIN(const char *src, size_t src_len,
                                  Status &error) {}

Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) {}

Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) {}

// Pre-requisite: wp != NULL.
static GDBStoppointType
GetGDBStoppointType(const WatchpointResourceSP &wp_res_sp) {}

Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {}

Status ProcessGDBRemote::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {}

void ProcessGDBRemote::Clear() {}

Status ProcessGDBRemote::DoSignal(int signo) {}

Status
ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) {}
#if !defined(_WIN32)
#define USE_SOCKETPAIR_FOR_LOCAL_CONNECTION
#endif

#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION
static bool SetCloexecFlag(int fd) {}
#endif

Status ProcessGDBRemote::LaunchAndConnectToDebugserver(
    const ProcessInfo &process_info) {}

void ProcessGDBRemote::MonitorDebugserverProcess(
    std::weak_ptr<ProcessGDBRemote> process_wp, lldb::pid_t debugserver_pid,
    int signo,      // Zero for no signal
    int exit_status // Exit value of process if signal is zero
) {}

void ProcessGDBRemote::KillDebugserverProcess() {}

void ProcessGDBRemote::Initialize() {}

void ProcessGDBRemote::DebuggerInitialize(Debugger &debugger) {}

bool ProcessGDBRemote::StartAsyncThread() {}

void ProcessGDBRemote::StopAsyncThread() {}

thread_result_t ProcessGDBRemote::AsyncThread() {}

// uint32_t
// ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList
// &matches, std::vector<lldb::pid_t> &pids)
//{
//    // If we are planning to launch the debugserver remotely, then we need to
//    fire up a debugserver
//    // process and ask it for the list of processes. But if we are local, we
//    can let the Host do it.
//    if (m_local_debugserver)
//    {
//        return Host::ListProcessesMatchingName (name, matches, pids);
//    }
//    else
//    {
//        // FIXME: Implement talking to the remote debugserver.
//        return 0;
//    }
//
//}
//
bool ProcessGDBRemote::NewThreadNotifyBreakpointHit(
    void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
    lldb::user_id_t break_loc_id) {}

Status ProcessGDBRemote::UpdateAutomaticSignalFiltering() {}

bool ProcessGDBRemote::StartNoticingNewThreads() {}

bool ProcessGDBRemote::StopNoticingNewThreads() {}

DynamicLoader *ProcessGDBRemote::GetDynamicLoader() {}

Status ProcessGDBRemote::SendEventData(const char *data) {}

DataExtractor ProcessGDBRemote::GetAuxvData() {}

StructuredData::ObjectSP
ProcessGDBRemote::GetExtendedInfoForThread(lldb::tid_t tid) {}

StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos(
    lldb::addr_t image_list_address, lldb::addr_t image_count) {}

StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos() {}

StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos(
    const std::vector<lldb::addr_t> &load_addresses) {}

StructuredData::ObjectSP
ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender(
    StructuredData::ObjectSP args_dict) {}

StructuredData::ObjectSP ProcessGDBRemote::GetDynamicLoaderProcessState() {}

StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() {}

Status ProcessGDBRemote::ConfigureStructuredData(
    llvm::StringRef type_name, const StructuredData::ObjectSP &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.
//
// 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.

void ProcessGDBRemote::GetMaxMemorySize() {}

void ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize(
    uint64_t user_specified_max) {}

bool ProcessGDBRemote::GetModuleSpec(const FileSpec &module_file_spec,
                                     const ArchSpec &arch,
                                     ModuleSpec &module_spec) {}

void ProcessGDBRemote::PrefetchModuleSpecs(
    llvm::ArrayRef<FileSpec> module_file_specs, const llvm::Triple &triple) {}

llvm::VersionTuple ProcessGDBRemote::GetHostOSVersion() {}

llvm::VersionTuple ProcessGDBRemote::GetHostMacCatalystVersion() {}

namespace {

stringVec;

GDBServerRegisterVec;
struct RegisterSetInfo {};

RegisterSetMap;

struct GdbServerTargetInfo {};

static FieldEnum::Enumerators ParseEnumEvalues(const XMLNode &enum_node) {}

static void
ParseEnums(XMLNode feature_node,
           llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {}

static std::vector<RegisterFlags::Field> ParseFlagsFields(
    XMLNode flags_node, unsigned size,
    const llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {}

void ParseFlags(
    XMLNode feature_node,
    llvm::StringMap<std::unique_ptr<RegisterFlags>> &registers_flags_types,
    const llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {}

bool ParseRegisters(
    XMLNode feature_node, GdbServerTargetInfo &target_info,
    std::vector<DynamicRegisterInfo::Register> &registers,
    llvm::StringMap<std::unique_ptr<RegisterFlags>> &registers_flags_types,
    llvm::StringMap<std::unique_ptr<FieldEnum>> &registers_enum_types) {}

} // namespace

// This method fetches a register description feature xml file from
// the remote stub and adds registers/register groupsets/architecture
// information to the current process.  It will call itself recursively
// 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,
    std::vector<DynamicRegisterInfo::Register> &registers) {}

void ProcessGDBRemote::AddRemoteRegisters(
    std::vector<DynamicRegisterInfo::Register> &registers,
    const ArchSpec &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) {}

llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {}

lldb::ModuleSP ProcessGDBRemote::LoadModuleAtAddress(const FileSpec &file,
                                                     lldb::addr_t link_map,
                                                     lldb::addr_t base_addr,
                                                     bool value_is_offset) {}

llvm::Error ProcessGDBRemote::LoadModules() {}

Status ProcessGDBRemote::GetFileLoadAddress(const FileSpec &file,
                                            bool &is_loaded,
                                            lldb::addr_t &load_addr) {}

void ProcessGDBRemote::ModulesDidLoad(ModuleList &module_list) {}

void ProcessGDBRemote::HandleAsyncStdout(llvm::StringRef out) {}

static const char *end_delimiter =;
static const int end_delimiter_len =;

void ProcessGDBRemote::HandleAsyncMisc(llvm::StringRef data) {}

std::string ProcessGDBRemote::HarmonizeThreadIdsForProfileData(
    StringExtractorGDBRemote &profileDataExtractor) {}

void ProcessGDBRemote::HandleStopReply() {}

llvm::Expected<bool> ProcessGDBRemote::SaveCore(llvm::StringRef outfile) {}

static const char *const s_async_json_packet_prefix =;

static StructuredData::ObjectSP
ParseStructuredDataPacket(llvm::StringRef packet) {}

void ProcessGDBRemote::HandleAsyncStructuredDataPacket(llvm::StringRef data) {}

class CommandObjectProcessGDBRemoteSpeedTest : public CommandObjectParsed {};

class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed {};

class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed {};

class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed {};

class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw {};

class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword {};

class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword {};

CommandObject *ProcessGDBRemote::GetPluginCommandObject() {}

void ProcessGDBRemote::DidForkSwitchSoftwareBreakpoints(bool enable) {}

void ProcessGDBRemote::DidForkSwitchHardwareTraps(bool enable) {}

void ProcessGDBRemote::DidFork(lldb::pid_t child_pid, lldb::tid_t child_tid) {}

void ProcessGDBRemote::DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) {}

void ProcessGDBRemote::DidVForkDone() {}

void ProcessGDBRemote::DidExec() {}