diff options
author | Ed Maste <emaste@FreeBSD.org> | 2015-07-03 16:57:06 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2015-07-03 16:57:06 +0000 |
commit | 5e95aa85bb660d45e9905ef1d7180b2678280660 (patch) | |
tree | 3c2e41c3be19b7fc7666ed45a5f91ec3b6e35f2a /source/Plugins/Process | |
parent | 12bd4897ff0678fa663e09d78ebc22dd255ceb86 (diff) | |
download | src-5e95aa85bb660d45e9905ef1d7180b2678280660.tar.gz src-5e95aa85bb660d45e9905ef1d7180b2678280660.zip |
Import LLDB as of upstream SVN 241361 (git 612c075f)vendor/lldb/lldb-r241361
Notes
Notes:
svn path=/vendor/lldb/dist/; revision=285101
svn path=/vendor/lldb/lldb-r241361/; revision=285102; tag=vendor/lldb/lldb-r241361
Diffstat (limited to 'source/Plugins/Process')
93 files changed, 13358 insertions, 7012 deletions
diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp index 493f36ca8b48..cce7a1ef28c1 100644 --- a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp @@ -11,6 +11,7 @@ // C++ Includes // Other libraries and framework includes #include "lldb/Core/State.h" +#include "lldb/Target/UnixSignals.h" // Project includes #include "FreeBSDThread.h" diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.cpp b/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp index 3b8cea737bcb..3b8cea737bcb 100644 --- a/source/Plugins/Process/POSIX/POSIXStopInfo.cpp +++ b/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.h b/source/Plugins/Process/FreeBSD/POSIXStopInfo.h index a1ee2ea68524..a1ee2ea68524 100644 --- a/source/Plugins/Process/POSIX/POSIXStopInfo.h +++ b/source/Plugins/Process/FreeBSD/POSIXStopInfo.h diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/FreeBSD/POSIXThread.cpp index 1057585e1b2a..854796fb7448 100644 --- a/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/source/Plugins/Process/FreeBSD/POSIXThread.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - // C Includes #include <errno.h> @@ -31,14 +29,13 @@ #include "POSIXThread.h" #include "ProcessPOSIX.h" #include "ProcessPOSIXLog.h" -#include "Plugins/Process/Linux/ProcessMonitor.h" +#include "ProcessMonitor.h" +#include "RegisterContextPOSIXProcessMonitor_arm.h" #include "RegisterContextPOSIXProcessMonitor_arm64.h" #include "RegisterContextPOSIXProcessMonitor_mips64.h" #include "RegisterContextPOSIXProcessMonitor_powerpc.h" #include "RegisterContextPOSIXProcessMonitor_x86.h" -#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" -#include "Plugins/Process/Utility/RegisterContextLinux_i386.h" -#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" @@ -98,7 +95,6 @@ POSIXThread::GetMonitor() return process.GetMonitor(); } -// Overridden by FreeBSDThread; this is used only on Linux. void POSIXThread::RefreshStateAfterStop() { @@ -115,11 +111,6 @@ POSIXThread::RefreshStateAfterStop() const bool force = false; GetRegisterContext()->InvalidateIfNeeded (force); } - // FIXME: This should probably happen somewhere else. - SetResumeState(eStateRunning, true); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID()); } const char * @@ -169,6 +160,9 @@ POSIXThread::GetRegisterContext() case llvm::Triple::FreeBSD: switch (target_arch.GetMachine()) { + case llvm::Triple::arm: + reg_interface = new RegisterContextFreeBSD_arm(target_arch); + break; case llvm::Triple::ppc: #ifndef __powerpc64__ reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch); @@ -191,32 +185,6 @@ POSIXThread::GetRegisterContext() } break; - case llvm::Triple::Linux: - switch (target_arch.GetMachine()) - { - case llvm::Triple::aarch64: - assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); - reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm64(target_arch)); - break; - case llvm::Triple::x86: - case llvm::Triple::x86_64: - if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) - { - // 32-bit hosts run with a RegisterContextLinux_i386 context. - reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_i386(target_arch)); - } - else - { - assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && - "Register setting path assumes this is a 64-bit host"); - // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context. - reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_x86_64(target_arch)); - } - break; - default: - break; - } - default: break; } @@ -232,6 +200,13 @@ POSIXThread::GetRegisterContext() m_reg_context_sp.reset(reg_ctx); break; } + case llvm::Triple::arm: + { + RegisterContextPOSIXProcessMonitor_arm *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } case llvm::Triple::mips64: { RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface); @@ -313,18 +288,6 @@ POSIXThread::GetUnwinder() return m_unwinder_ap.get(); } -// Overridden by FreeBSDThread; this is used only on Linux. -void -POSIXThread::WillResume(lldb::StateType resume_state) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to %s", __FUNCTION__, GetID(), StateAsCString(resume_state)); - // TODO: the line below shouldn't really be done, but - // the POSIXThread might rely on this so I will leave this in for now - SetResumeState(resume_state); -} - void POSIXThread::DidStop() { @@ -512,7 +475,10 @@ POSIXThread::BreakNotify(const ProcessMessage &message) if (bp_site) { lldb::break_id_t bp_id = bp_site->GetID(); - if (bp_site->ValidForThisThread(this)) + // If we have an operating system plug-in, we might have set a thread specific breakpoint using the + // operating system thread ID, so we can't make any assumptions about the thread ID so we must always + // report the breakpoint regardless of the thread. + if (bp_site->ValidForThisThread(this) || GetProcess()->GetOperatingSystem () != NULL) SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id)); else { @@ -641,6 +607,7 @@ POSIXThread::GetRegisterIndexFromOffset(unsigned offset) break; case llvm::Triple::aarch64: + case llvm::Triple::arm: case llvm::Triple::mips64: case llvm::Triple::ppc: case llvm::Triple::ppc64: @@ -674,6 +641,7 @@ POSIXThread::GetRegisterName(unsigned reg) break; case llvm::Triple::aarch64: + case llvm::Triple::arm: case llvm::Triple::mips64: case llvm::Triple::ppc: case llvm::Triple::ppc64: diff --git a/source/Plugins/Process/POSIX/POSIXThread.h b/source/Plugins/Process/FreeBSD/POSIXThread.h index 56dcccbfb0f9..c38d194dbd19 100644 --- a/source/Plugins/Process/POSIX/POSIXThread.h +++ b/source/Plugins/Process/FreeBSD/POSIXThread.h @@ -35,32 +35,29 @@ public: virtual ~POSIXThread(); void - RefreshStateAfterStop(); - - virtual void - WillResume(lldb::StateType resume_state); + RefreshStateAfterStop() override; // This notifies the thread when a private stop occurs. - virtual void - DidStop (); + void + DidStop () override; const char * - GetInfo(); + GetInfo() override; void - SetName (const char *name); + SetName (const char *name) override; const char * - GetName (); + GetName () override; - virtual lldb::RegisterContextSP - GetRegisterContext(); + lldb::RegisterContextSP + GetRegisterContext() override; - virtual lldb::RegisterContextSP - CreateRegisterContextForFrame (lldb_private::StackFrame *frame); + lldb::RegisterContextSP + CreateRegisterContextForFrame (lldb_private::StackFrame *frame) override; - virtual lldb::addr_t - GetThreadPointer (); + lldb::addr_t + GetThreadPointer () override; //-------------------------------------------------------------------------- // These functions provide a mapping from the register offset @@ -114,8 +111,8 @@ protected: ProcessMonitor & GetMonitor(); - virtual bool - CalculateStopInfo(); + bool + CalculateStopInfo() override; void BreakNotify(const ProcessMessage &message); void WatchNotify(const ProcessMessage &message); @@ -129,7 +126,7 @@ protected: void ExecNotify(const ProcessMessage &message); lldb_private::Unwind * - GetUnwinder(); + GetUnwinder() override; }; #endif // #ifndef liblldb_POSIXThread_H_ diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index 5a0b5ed14194..a0458f16e558 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -11,6 +11,8 @@ #include <errno.h> // C++ Includes +#include <mutex> + // Other libraries and framework includes #include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" @@ -56,23 +58,14 @@ ProcessFreeBSD::CreateInstance(Target& target, void ProcessFreeBSD::Initialize() { - static bool g_initialized = false; + static std::once_flag g_once_flag; - if (!g_initialized) - { + std::call_once(g_once_flag, []() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); - Log::Callbacks log_callbacks = { - ProcessPOSIXLog::DisableLog, - ProcessPOSIXLog::EnableLog, - ProcessPOSIXLog::ListLogCategories - }; - - Log::RegisterLogChannel (ProcessFreeBSD::GetPluginNameStatic(), log_callbacks); - ProcessPOSIXLog::RegisterPluginName(GetPluginNameStatic()); - g_initialized = true; - } + ProcessPOSIXLog::Initialize(GetPluginNameStatic()); + }); } lldb_private::ConstString diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index b33f83303971..28bca0916148 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -28,6 +28,7 @@ #include "lldb/Host/ThreadLauncher.h" #include "lldb/Target/Thread.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/UnixSignals.h" #include "lldb/Utility/PseudoTerminal.h" #include "Plugins/Process/POSIX/CrashReason.h" @@ -107,13 +108,9 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, if (req == PT_GETREGS) { struct reg *r = (struct reg *) addr; - log->Printf("PT_GETREGS: ip=0x%lx", r->r_rip); - log->Printf("PT_GETREGS: sp=0x%lx", r->r_rsp); - log->Printf("PT_GETREGS: bp=0x%lx", r->r_rbp); - log->Printf("PT_GETREGS: ax=0x%lx", r->r_rax); + log->Printf("PT_GETREGS: rip=0x%lx rsp=0x%lx rbp=0x%lx rax=0x%lx", + r->r_rip, r->r_rsp, r->r_rbp, r->r_rax); } -#endif -#ifndef __powerpc__ if (req == PT_GETDBREGS || req == PT_SETDBREGS) { struct dbreg *r = (struct dbreg *) addr; char setget = (req == PT_GETDBREGS) ? 'G' : 'S'; @@ -772,17 +769,17 @@ ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor, lldb_private::Module *module, char const **argv, char const **envp, - const char *stdin_path, - const char *stdout_path, - const char *stderr_path, - const char *working_dir) + const FileSpec &stdin_file_spec, + const FileSpec &stdout_file_spec, + const FileSpec &stderr_file_spec, + const FileSpec &working_dir) : OperationArgs(monitor), m_module(module), m_argv(argv), m_envp(envp), - m_stdin_path(stdin_path), - m_stdout_path(stdout_path), - m_stderr_path(stderr_path), + m_stdin_file_spec(stdin_file_spec), + m_stdout_file_spec(stdout_file_spec), + m_stderr_file_spec(stderr_file_spec), m_working_dir(working_dir) { } ProcessMonitor::LaunchArgs::~LaunchArgs() @@ -811,10 +808,10 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process, Module *module, const char *argv[], const char *envp[], - const char *stdin_path, - const char *stdout_path, - const char *stderr_path, - const char *working_dir, + const FileSpec &stdin_file_spec, + const FileSpec &stdout_file_spec, + const FileSpec &stderr_file_spec, + const FileSpec &working_dir, const lldb_private::ProcessLaunchInfo & /* launch_info */, lldb_private::Error &error) : m_process(static_cast<ProcessFreeBSD *>(process)), @@ -823,8 +820,10 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process, m_operation(0) { std::unique_ptr<LaunchArgs> args(new LaunchArgs(this, module, argv, envp, - stdin_path, stdout_path, stderr_path, - working_dir)); + stdin_file_spec, + stdout_file_spec, + stderr_file_spec, + working_dir)); sem_init(&m_operation_pending, 0, 0); @@ -955,15 +954,15 @@ ProcessMonitor::Launch(LaunchArgs *args) ProcessFreeBSD &process = monitor->GetProcess(); const char **argv = args->m_argv; const char **envp = args->m_envp; - const char *stdin_path = args->m_stdin_path; - const char *stdout_path = args->m_stdout_path; - const char *stderr_path = args->m_stderr_path; - const char *working_dir = args->m_working_dir; + const FileSpec &stdin_file_spec = args->m_stdin_file_spec; + const FileSpec &stdout_file_spec = args->m_stdout_file_spec; + const FileSpec &stderr_file_spec = args->m_stderr_file_spec; + const FileSpec &working_dir = args->m_working_dir; lldb_utility::PseudoTerminal terminal; const size_t err_len = 1024; char err_str[err_len]; - lldb::pid_t pid; + ::pid_t pid; // Propagate the environment if one is not supplied. if (envp == NULL || envp[0] == NULL) @@ -1010,22 +1009,21 @@ ProcessMonitor::Launch(LaunchArgs *args) // // FIXME: If two or more of the paths are the same we needlessly open // the same file multiple times. - if (stdin_path != NULL && stdin_path[0]) - if (!DupDescriptor(stdin_path, STDIN_FILENO, O_RDONLY)) + if (stdin_file_spec) + if (!DupDescriptor(stdin_file_spec, STDIN_FILENO, O_RDONLY)) exit(eDupStdinFailed); - if (stdout_path != NULL && stdout_path[0]) - if (!DupDescriptor(stdout_path, STDOUT_FILENO, O_WRONLY | O_CREAT)) + if (stdout_file_spec) + if (!DupDescriptor(stdout_file_spec, STDOUT_FILENO, O_WRONLY | O_CREAT)) exit(eDupStdoutFailed); - if (stderr_path != NULL && stderr_path[0]) - if (!DupDescriptor(stderr_path, STDERR_FILENO, O_WRONLY | O_CREAT)) + if (stderr_file_spec) + if (!DupDescriptor(stderr_file_spec, STDERR_FILENO, O_WRONLY | O_CREAT)) exit(eDupStderrFailed); // Change working directory - if (working_dir != NULL && working_dir[0]) - if (0 != ::chdir(working_dir)) - exit(eChdirFailed); + if (working_dir && 0 != ::chdir(working_dir.GetCString())) + exit(eChdirFailed); // Execute. We should never return. execve(argv[0], @@ -1556,9 +1554,9 @@ ProcessMonitor::Detach(lldb::tid_t tid) } bool -ProcessMonitor::DupDescriptor(const char *path, int fd, int flags) +ProcessMonitor::DupDescriptor(const FileSpec &file_spec, int fd, int flags) { - int target_fd = open(path, flags, 0666); + int target_fd = open(file_spec.GetCString(), flags, 0666); if (target_fd == -1) return false; diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 4ae963c89a2f..20ce582d973e 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -17,6 +17,7 @@ // C++ Includes // Other libraries and framework includes #include "lldb/lldb-types.h" +#include "lldb/Host/FileSpec.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/Mutex.h" @@ -52,10 +53,10 @@ public: lldb_private::Module *module, char const *argv[], char const *envp[], - const char *stdin_path, - const char *stdout_path, - const char *stderr_path, - const char *working_dir, + const lldb_private::FileSpec &stdin_file_spec, + const lldb_private::FileSpec &stdout_file_spec, + const lldb_private::FileSpec &stderr_file_spec, + const lldb_private::FileSpec &working_dir, const lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Error &error); @@ -228,7 +229,7 @@ private: // the operation is complete. sem_t m_operation_pending; sem_t m_operation_done; - + struct OperationArgs { OperationArgs(ProcessMonitor *monitor); @@ -250,20 +251,20 @@ private: lldb_private::Module *module, char const **argv, char const **envp, - const char *stdin_path, - const char *stdout_path, - const char *stderr_path, - const char *working_dir); + const lldb_private::FileSpec &stdin_file_spec, + const lldb_private::FileSpec &stdout_file_spec, + const lldb_private::FileSpec &stderr_file_spec, + const lldb_private::FileSpec &working_dir); ~LaunchArgs(); - lldb_private::Module *m_module; // The executable image to launch. - char const **m_argv; // Process arguments. - char const **m_envp; // Process environment. - const char *m_stdin_path; // Redirect stdin or NULL. - const char *m_stdout_path; // Redirect stdout or NULL. - const char *m_stderr_path; // Redirect stderr or NULL. - const char *m_working_dir; // Working directory or NULL. + lldb_private::Module *m_module; // The executable image to launch. + char const **m_argv; // Process arguments. + char const **m_envp; // Process environment. + const lldb_private::FileSpec m_stdin_file_spec; // Redirect stdin or empty. + const lldb_private::FileSpec m_stdout_file_spec; // Redirect stdout or empty. + const lldb_private::FileSpec m_stderr_file_spec; // Redirect stderr or empty. + const lldb_private::FileSpec m_working_dir; // Working directory or empty. }; void @@ -298,7 +299,7 @@ private: ServeOperation(OperationArgs *args); static bool - DupDescriptor(const char *path, int fd, int flags); + DupDescriptor(const lldb_private::FileSpec &file_spec, int fd, int flags); static bool MonitorCallback(void *callback_baton, diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp index 882fac75c9a0..360382e2e63a 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp @@ -7,13 +7,12 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - // C Includes #include <errno.h> // C++ Includes // Other libraries and framework includes +#include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" @@ -29,46 +28,15 @@ #include "ProcessPOSIX.h" #include "ProcessPOSIXLog.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" -#include "Plugins/Process/Linux/ProcessMonitor.h" #include "POSIXThread.h" +#include "ProcessMonitor.h" + +#include "lldb/Host/posix/Fcntl.h" using namespace lldb; using namespace lldb_private; //------------------------------------------------------------------------------ -// Static functions. -#if 0 -Process* -ProcessPOSIX::CreateInstance(Target& target, Listener &listener) -{ - return new ProcessPOSIX(target, listener); -} - - -void -ProcessPOSIX::Initialize() -{ - static bool g_initialized = false; - - if (!g_initialized) - { - g_initialized = true; - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance); - - Log::Callbacks log_callbacks = { - ProcessPOSIXLog::DisableLog, - ProcessPOSIXLog::EnableLog, - ProcessPOSIXLog::ListLogCategories - }; - - Log::RegisterLogChannel (ProcessPOSIX::GetPluginNameStatic(), log_callbacks); - } -} -#endif - -//------------------------------------------------------------------------------ // Constructors and destructors. ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &unix_signals_sp) @@ -82,9 +50,9 @@ ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &un { // FIXME: Putting this code in the ctor and saving the byte order in a // member variable is a hack to avoid const qual issues in GetByteOrder. - lldb::ModuleSP module = GetTarget().GetExecutableModule(); - if (module && module->GetObjectFile()) - m_byte_order = module->GetObjectFile()->GetByteOrder(); + lldb::ModuleSP module = GetTarget().GetExecutableModule(); + if (module && module->GetObjectFile()) + m_byte_order = module->GetObjectFile()->GetByteOrder(); } ProcessPOSIX::~ProcessPOSIX() @@ -115,7 +83,7 @@ ProcessPOSIX::CanDebug(Target &target, bool plugin_specified_by_name) } Error -ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid) +ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) { Error error; assert(m_monitor == NULL); @@ -164,39 +132,30 @@ ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid) } Error -ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) -{ - return DoAttachToProcessWithID(pid); -} - -Error ProcessPOSIX::WillLaunch(Module* module) { Error error; return error; } -const char * -ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const char *default_path, - const char *dbg_pts_path) +FileSpec +ProcessPOSIX::GetFileSpec(const lldb_private::FileAction *file_action, + const FileSpec &default_file_spec, + const FileSpec &dbg_pts_file_spec) { - const char *path = NULL; + FileSpec file_spec{}; - if (file_action) + if (file_action && file_action->GetAction() == FileAction::eFileActionOpen) { - if (file_action->GetAction() == FileAction::eFileActionOpen) - { - path = file_action->GetPath(); - // By default the stdio paths passed in will be pseudo-terminal - // (/dev/pts). If so, convert to using a different default path - // instead to redirect I/O to the debugger console. This should - // also handle user overrides to /dev/null or a different file. - if (!path || (dbg_pts_path && - ::strncmp(path, dbg_pts_path, ::strlen(dbg_pts_path)) == 0)) - path = default_path; - } + file_spec = file_action->GetFileSpec(); + // By default the stdio paths passed in will be pseudo-terminal + // (/dev/pts). If so, convert to using a different default path + // instead to redirect I/O to the debugger console. This should + // also handle user overrides to /dev/null or a different file. + if (!file_spec || file_spec == dbg_pts_file_spec) + file_spec = default_file_spec; } - return path; + return file_spec; } Error @@ -206,46 +165,46 @@ ProcessPOSIX::DoLaunch (Module *module, Error error; assert(m_monitor == NULL); - const char* working_dir = launch_info.GetWorkingDirectory(); - if (working_dir) { - FileSpec WorkingDir(working_dir, true); - if (!WorkingDir || WorkingDir.GetFileType() != FileSpec::eFileTypeDirectory) - { - error.SetErrorStringWithFormat("No such file or directory: %s", working_dir); - return error; - } + FileSpec working_dir = launch_info.GetWorkingDirectory(); + if (working_dir && + (!working_dir.ResolvePath() || + working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) + { + error.SetErrorStringWithFormat("No such file or directory: %s", + working_dir.GetCString()); + return error; } SetPrivateState(eStateLaunching); const lldb_private::FileAction *file_action; - // Default of NULL will mean to use existing open file descriptors - const char *stdin_path = NULL; - const char *stdout_path = NULL; - const char *stderr_path = NULL; + // Default of empty will mean to use existing open file descriptors + FileSpec stdin_file_spec{}; + FileSpec stdout_file_spec{}; + FileSpec stderr_file_spec{}; - const char * dbg_pts_path = launch_info.GetPTY().GetSlaveName(NULL,0); + const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL,0), false}; file_action = launch_info.GetFileActionForFD (STDIN_FILENO); - stdin_path = GetFilePath(file_action, stdin_path, dbg_pts_path); + stdin_file_spec = GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec); file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); - stdout_path = GetFilePath(file_action, stdout_path, dbg_pts_path); + stdout_file_spec = GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec); file_action = launch_info.GetFileActionForFD (STDERR_FILENO); - stderr_path = GetFilePath(file_action, stderr_path, dbg_pts_path); - - m_monitor = new ProcessMonitor (this, - module, - launch_info.GetArguments().GetConstArgumentVector(), - launch_info.GetEnvironmentEntries().GetConstArgumentVector(), - stdin_path, - stdout_path, - stderr_path, - working_dir, - launch_info, - error); + stderr_file_spec = GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec); + + m_monitor = new ProcessMonitor(this, + module, + launch_info.GetArguments().GetConstArgumentVector(), + launch_info.GetEnvironmentEntries().GetConstArgumentVector(), + stdin_file_spec, + stdout_file_spec, + stderr_file_spec, + working_dir, + launch_info, + error); m_module = module; @@ -426,13 +385,11 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) } else { - StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); } } else { - StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); } break; @@ -468,7 +425,6 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) case ProcessMessage::eCrashMessage: assert(thread); thread->SetState(eStateStopped); - StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); break; @@ -481,7 +437,6 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) } assert(thread); thread->SetState(eStateStopped); - StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); break; } @@ -490,7 +445,6 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) { assert(thread); thread->SetState(eStateStopped); - StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); break; } @@ -500,12 +454,6 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) m_message_queue.push(message); } -void -ProcessPOSIX::StopAllThreads(lldb::tid_t stop_tid) -{ - // FIXME: Will this work the same way on FreeBSD and Linux? -} - bool ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid) { @@ -671,6 +619,33 @@ ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) assert(false && "CPU type not supported!"); break; + case llvm::Triple::arm: + { + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe + // but the linux kernel does otherwise. + static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 }; + static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde }; + + lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0)); + AddressClass addr_class = eAddressClassUnknown; + + if (bp_loc_sp) + addr_class = bp_loc_sp->GetAddress ().GetAddressClass (); + + if (addr_class == eAddressClassCodeAlternateISA + || (addr_class == eAddressClassUnknown + && bp_loc_sp->GetAddress().GetOffset() & 1)) + { + opcode = g_thumb_breakpoint_opcode; + opcode_size = sizeof(g_thumb_breakpoint_opcode); + } + else + { + opcode = g_arm_breakpoint_opcode; + opcode_size = sizeof(g_arm_breakpoint_opcode); + } + } + break; case llvm::Triple::aarch64: opcode = g_aarch64_opcode; opcode_size = sizeof(g_aarch64_opcode); diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/FreeBSD/ProcessPOSIX.h index f152356b3093..70694cb9b193 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/source/Plugins/Process/FreeBSD/ProcessPOSIX.h @@ -41,104 +41,101 @@ public: //------------------------------------------------------------------ // Process protocol. //------------------------------------------------------------------ - virtual void + void Finalize() override; - virtual bool + bool CanDebug(lldb_private::Target &target, bool plugin_specified_by_name) override; - virtual lldb_private::Error + lldb_private::Error WillLaunch(lldb_private::Module *module) override; - virtual lldb_private::Error - DoAttachToProcessWithID(lldb::pid_t pid) override; - - virtual lldb_private::Error + lldb_private::Error DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override; - virtual lldb_private::Error + lldb_private::Error DoLaunch (lldb_private::Module *exe_module, lldb_private::ProcessLaunchInfo &launch_info) override; - virtual void + void DidLaunch() override; - virtual lldb_private::Error + lldb_private::Error DoResume() override; - virtual lldb_private::Error + lldb_private::Error DoHalt(bool &caused_stop) override; - virtual lldb_private::Error + lldb_private::Error DoDetach(bool keep_stopped) override = 0; - virtual lldb_private::Error + lldb_private::Error DoSignal(int signal) override; - virtual lldb_private::Error + lldb_private::Error DoDestroy() override; - virtual void + void DoDidExec() override; - virtual void + void RefreshStateAfterStop() override; - virtual bool + bool IsAlive() override; - virtual size_t + size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, lldb_private::Error &error) override; - virtual size_t + size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, lldb_private::Error &error) override; - virtual lldb::addr_t + lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, lldb_private::Error &error) override; - virtual lldb_private::Error + lldb_private::Error DoDeallocateMemory(lldb::addr_t ptr) override; virtual size_t GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site); - virtual lldb_private::Error + lldb_private::Error EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - virtual lldb_private::Error + lldb_private::Error DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - virtual lldb_private::Error + lldb_private::Error EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override; - virtual lldb_private::Error + lldb_private::Error DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override; - virtual lldb_private::Error + lldb_private::Error GetWatchpointSupportInfo(uint32_t &num) override; - virtual lldb_private::Error + lldb_private::Error GetWatchpointSupportInfo(uint32_t &num, bool &after) override; virtual uint32_t UpdateThreadListIfNeeded(); - virtual bool + bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list) override = 0; virtual lldb::ByteOrder GetByteOrder() const; - virtual lldb::addr_t + lldb::addr_t GetImageInfoAddress() override; - virtual size_t + size_t PutSTDIN(const char *buf, size_t len, lldb_private::Error &error) override; const lldb::DataBufferSP @@ -154,13 +151,10 @@ public: ProcessMonitor & GetMonitor() { assert(m_monitor); return *m_monitor; } - const char *GetFilePath(const lldb_private::FileAction *file_action, const char *default_path, - const char *dbg_pts_path); - - /// Stops all threads in the process. - /// The \p stop_tid parameter indicates the thread which initiated the stop. - virtual void - StopAllThreads(lldb::tid_t stop_tid); + lldb_private::FileSpec + GetFileSpec(const lldb_private::FileAction *file_action, + const lldb_private::FileSpec &default_file_spec, + const lldb_private::FileSpec &dbg_pts_file_spec); /// Adds the thread to the list of threads for which we have received the initial stopping signal. /// The \p stop_tid parameter indicates the thread which the stop happened for. diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp new file mode 100644 index 000000000000..ac2f81d53929 --- /dev/null +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp @@ -0,0 +1,322 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm.cpp -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" + +#include "RegisterContextPOSIX_arm.h" +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_arm.h" +#include "ProcessMonitor.h" + +using namespace lldb_private; +using namespace lldb; + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm(Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_arm(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_arm::GetMonitor() +{ + ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + return false; + } + else + { + return ReadRegister(reg, value); + } + + // Get pointer to m_fpr variable and set the data from it. + assert (reg_info->byte_offset < sizeof m_fpr); + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 2: + value.SetUInt16(*(uint16_t *)src); + return true; + case 4: + value.SetUInt32(*(uint32_t *)src); + return true; + case 8: + value.SetUInt64(*(uint64_t *)src); + return true; + default: + assert(false && "Unhandled data size."); + return false; + } +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + { + return WriteRegister(reg, value); + } + else if (IsFPR(reg)) + { + return WriteFPR(); + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_arm, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy (dst, &m_fpr, sizeof(m_fpr)); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues(const DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_arm, src, GetGPRSize()); + + if (WriteGPR()) + { + src += GetGPRSize(); + ::memcpy (&m_fpr, src, sizeof(m_fpr)); + + success = WriteFPR(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint(addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint() +{ + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_arm; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_arm && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits() +{ + return false; +} + +addr_t +RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints() +{ + return 0; +} + diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h new file mode 100644 index 000000000000..12a43c77837c --- /dev/null +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm.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_RegisterContextPOSIXProcessMonitor_arm_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_arm_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" + +class RegisterContextPOSIXProcessMonitor_arm: + public RegisterContextPOSIX_arm, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_arm(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp index ec34d9e28161..d79def52499f 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp @@ -7,16 +7,20 @@ // //===---------------------------------------------------------------------===// -#include "lldb/Target/Thread.h" +#include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" #include "ProcessPOSIX.h" +#include "ProcessMonitor.h" #include "RegisterContextPOSIXProcessMonitor_arm64.h" -#include "Plugins/Process/Linux/ProcessMonitor.h" #define REG_CONTEXT_SIZE (GetGPRSize()) +using namespace lldb; +using namespace lldb_private; + RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread, uint32_t concrete_frame_idx, lldb_private::RegisterInfoInterface *register_info) diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h index eb24d4852ab8..eb24d4852ab8 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp index 6717d20da056..893a0f22b6f8 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -7,13 +7,14 @@ // //===---------------------------------------------------------------------===// -#include "lldb/Target/Thread.h" +#include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" #include "ProcessPOSIX.h" +#include "ProcessMonitor.h" #include "RegisterContextPOSIXProcessMonitor_mips64.h" -#include "Plugins/Process/Linux/ProcessMonitor.h" using namespace lldb_private; using namespace lldb; diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h index 79e4468b1adf..79e4468b1adf 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp index 80e1c1984225..8c12b62a202f 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp @@ -7,8 +7,9 @@ // //===---------------------------------------------------------------------===// -#include "lldb/Target/Thread.h" +#include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" #include "RegisterContextPOSIX_powerpc.h" #include "ProcessPOSIX.h" diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h index 5c686df4836f..5c686df4836f 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_powerpc.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp index 1956e4584fa9..9245441f659f 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -7,16 +7,13 @@ // //===---------------------------------------------------------------------===// -#include "lldb/Target/Thread.h" +#include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" -#include "Plugins/Process/POSIX/ProcessPOSIX.h" +#include "Plugins/Process/FreeBSD/ProcessPOSIX.h" #include "RegisterContextPOSIXProcessMonitor_x86.h" -#if defined(__FreeBSD__) #include "Plugins/Process/FreeBSD/ProcessMonitor.h" -#else -#include "Plugins/Process/Linux/ProcessMonitor.h" -#endif using namespace lldb_private; using namespace lldb; diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h index 2afb195c4c36..2afb195c4c36 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h diff --git a/source/Plugins/Process/POSIX/CrashReason.cpp b/source/Plugins/Process/POSIX/CrashReason.cpp index 4dd91a6f1de8..6de13f470c5e 100644 --- a/source/Plugins/Process/POSIX/CrashReason.cpp +++ b/source/Plugins/Process/POSIX/CrashReason.cpp @@ -134,69 +134,69 @@ GetCrashReasonString (CrashReason reason, lldb::addr_t fault_addr) break; case CrashReason::eInvalidAddress: - str = "invalid address"; + str = "signal SIGSEGV: invalid address"; AppendFaultAddr (str, fault_addr); break; case CrashReason::ePrivilegedAddress: - str = "address access protected"; + str = "signal SIGSEGV: address access protected"; AppendFaultAddr (str, fault_addr); break; case CrashReason::eIllegalOpcode: - str = "illegal instruction"; + str = "signal SIGILL: illegal instruction"; break; case CrashReason::eIllegalOperand: - str = "illegal instruction operand"; + str = "signal SIGILL: illegal instruction operand"; break; case CrashReason::eIllegalAddressingMode: - str = "illegal addressing mode"; + str = "signal SIGILL: illegal addressing mode"; break; case CrashReason::eIllegalTrap: - str = "illegal trap"; + str = "signal SIGILL: illegal trap"; break; case CrashReason::ePrivilegedOpcode: - str = "privileged instruction"; + str = "signal SIGILL: privileged instruction"; break; case CrashReason::ePrivilegedRegister: - str = "privileged register"; + str = "signal SIGILL: privileged register"; break; case CrashReason::eCoprocessorError: - str = "coprocessor error"; + str = "signal SIGILL: coprocessor error"; break; case CrashReason::eInternalStackError: - str = "internal stack error"; + str = "signal SIGILL: internal stack error"; break; case CrashReason::eIllegalAlignment: - str = "illegal alignment"; + str = "signal SIGBUS: illegal alignment"; break; case CrashReason::eIllegalAddress: - str = "illegal address"; + str = "signal SIGBUS: illegal address"; break; case CrashReason::eHardwareError: - str = "hardware error"; + str = "signal SIGBUS: hardware error"; break; case CrashReason::eIntegerDivideByZero: - str = "integer divide by zero"; + str = "signal SIGFPE: integer divide by zero"; break; case CrashReason::eIntegerOverflow: - str = "integer overflow"; + str = "signal SIGFPE: integer overflow"; break; case CrashReason::eFloatDivideByZero: - str = "floating point divide by zero"; + str = "signal SIGFPE: floating point divide by zero"; break; case CrashReason::eFloatOverflow: - str = "floating point overflow"; + str = "signal SIGFPE: floating point overflow"; break; case CrashReason::eFloatUnderflow: - str = "floating point underflow"; + str = "signal SIGFPE: floating point underflow"; break; case CrashReason::eFloatInexactResult: - str = "inexact floating point result"; + str = "signal SIGFPE: inexact floating point result"; break; case CrashReason::eFloatInvalidOperation: - str = "invalid floating point operation"; + str = "signal SIGFPE: invalid floating point operation"; break; case CrashReason::eFloatSubscriptRange: - str = "invalid floating point subscript range"; + str = "signal SIGFPE: invalid floating point subscript range"; break; } diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp b/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp index 624ca87b883a..b259804a3a27 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp +++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp @@ -9,10 +9,11 @@ #include "ProcessPOSIXLog.h" +#include <mutex> + #include "lldb/Interpreter/Args.h" #include "lldb/Core/StreamFile.h" -#include "ProcessPOSIX.h" #include "ProcessPOSIXLog.h" using namespace lldb; @@ -33,6 +34,22 @@ GetLog () return g_log; } +void +ProcessPOSIXLog::Initialize(ConstString name) +{ + static std::once_flag g_once_flag; + + std::call_once(g_once_flag, [name](){ + Log::Callbacks log_callbacks = { + DisableLog, + EnableLog, + ListLogCategories + }; + + Log::RegisterLogChannel (name, log_callbacks); + RegisterPluginName(name); + }); +} Log * ProcessPOSIXLog::GetLogIfAllCategoriesSet (uint32_t mask) diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.h b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h index a1e2e3747d21..7edd839152e6 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIXLog.h +++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h @@ -43,6 +43,12 @@ class ProcessPOSIXLog static const char *m_pluginname; public: + // --------------------------------------------------------------------- + // Public Static Methods + // --------------------------------------------------------------------- + static void + Initialize(lldb_private::ConstString name); + static void RegisterPluginName(const char *pluginName) { diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index 25a195e11a03..4eff442c1a0d 100644 --- a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -7,22 +7,18 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "DynamicRegisterInfo.h" // C Includes // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/Host/StringConvert.h" +#include "lldb/Core/ArchSpec.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/StreamFile.h" +#include "lldb/Core/StructuredData.h" #include "lldb/DataFormatters/FormatManager.h" - -#ifndef LLDB_DISABLE_PYTHON -#include "lldb/Interpreter/PythonDataObjects.h" -#endif +#include "lldb/Host/StringConvert.h" using namespace lldb; using namespace lldb_private; @@ -39,7 +35,8 @@ DynamicRegisterInfo::DynamicRegisterInfo () : { } -DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &dict, ByteOrder byte_order) : +DynamicRegisterInfo::DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict, + const lldb_private::ArchSpec &arch) : m_regs (), m_sets (), m_set_reg_nums (), @@ -49,30 +46,27 @@ DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary & m_reg_data_byte_size (0), m_finalized (false) { - SetRegisterInfo (dict, byte_order); + SetRegisterInfo (dict, arch); } DynamicRegisterInfo::~DynamicRegisterInfo () { } - size_t -DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict, - ByteOrder byte_order) +DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, const ArchSpec &arch) { assert(!m_finalized); -#ifndef LLDB_DISABLE_PYTHON - PythonList sets (dict.GetItemForKey("sets")); - if (sets) + StructuredData::Array *sets = nullptr; + if (dict.GetValueForKeyAsArray("sets", sets)) { - const uint32_t num_sets = sets.GetSize(); + const uint32_t num_sets = sets->GetSize(); for (uint32_t i=0; i<num_sets; ++i) { - PythonString py_set_name(sets.GetItemAtIndex(i)); + std::string set_name_str; ConstString set_name; - if (py_set_name) - set_name.SetCString(py_set_name.GetString()); + if (sets->GetItemAtIndexAsString(i, set_name_str)) + set_name.SetCString(set_name_str.c_str()); if (set_name) { RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL }; @@ -87,346 +81,312 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict } m_set_reg_nums.resize(m_sets.size()); } - PythonList regs (dict.GetItemForKey("registers")); - if (regs) - { - const uint32_t num_regs = regs.GetSize(); - PythonString name_pystr("name"); - PythonString altname_pystr("alt-name"); - PythonString bitsize_pystr("bitsize"); - PythonString offset_pystr("offset"); - PythonString encoding_pystr("encoding"); - PythonString format_pystr("format"); - PythonString set_pystr("set"); - PythonString gcc_pystr("gcc"); - PythonString dwarf_pystr("dwarf"); - PythonString generic_pystr("generic"); - PythonString slice_pystr("slice"); - PythonString composite_pystr("composite"); - PythonString invalidate_regs_pystr("invalidate-regs"); - + StructuredData::Array *regs = nullptr; + if (!dict.GetValueForKeyAsArray("registers", regs)) + return 0; + + const uint32_t num_regs = regs->GetSize(); // typedef std::map<std::string, std::vector<std::string> > InvalidateNameMap; // InvalidateNameMap invalidate_map; - for (uint32_t i=0; i<num_regs; ++i) + for (uint32_t i = 0; i < num_regs; ++i) + { + StructuredData::Dictionary *reg_info_dict = nullptr; + if (!regs->GetItemAtIndexAsDictionary(i, reg_info_dict)) { - PythonDictionary reg_info_dict(regs.GetItemAtIndex(i)); - if (reg_info_dict) - { - // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', }, - RegisterInfo reg_info; - std::vector<uint32_t> value_regs; - std::vector<uint32_t> invalidate_regs; - memset(®_info, 0, sizeof(reg_info)); - - reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString(); - if (reg_info.name == NULL) - { - Clear(); - printf("error: registers must have valid names\n"); - reg_info_dict.Dump(); - return 0; - } - - reg_info.alt_name = ConstString (reg_info_dict.GetItemForKeyAsString(altname_pystr)).GetCString(); - - reg_info.byte_offset = reg_info_dict.GetItemForKeyAsInteger(offset_pystr, UINT32_MAX); + Clear(); + printf("error: items in the 'registers' array must be dictionaries\n"); + regs->DumpToStdout(); + return 0; + } - if (reg_info.byte_offset == UINT32_MAX) + // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, + // 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', }, + RegisterInfo reg_info; + std::vector<uint32_t> value_regs; + std::vector<uint32_t> invalidate_regs; + memset(®_info, 0, sizeof(reg_info)); + + ConstString name_val; + ConstString alt_name_val; + if (!reg_info_dict->GetValueForKeyAsString("name", name_val, nullptr)) + { + Clear(); + printf("error: registers must have valid names and offsets\n"); + reg_info_dict->DumpToStdout(); + return 0; + } + reg_info.name = name_val.GetCString(); + reg_info_dict->GetValueForKeyAsString("alt-name", alt_name_val, nullptr); + reg_info.alt_name = alt_name_val.GetCString(); + + reg_info_dict->GetValueForKeyAsInteger("offset", reg_info.byte_offset, UINT32_MAX); + + const ByteOrder byte_order = arch.GetByteOrder(); + + if (reg_info.byte_offset == UINT32_MAX) + { + // No offset for this register, see if the register has a value expression + // which indicates this register is part of another register. Value expressions + // are things like "rax[31:0]" which state that the current register's value + // is in a concrete register "rax" in bits 31:0. If there is a value expression + // we can calculate the offset + bool success = false; + std::string slice_str; + if (reg_info_dict->GetValueForKeyAsString("slice", slice_str, nullptr)) + { + // Slices use the following format: + // REGNAME[MSBIT:LSBIT] + // REGNAME - name of the register to grab a slice of + // MSBIT - the most significant bit at which the current register value starts at + // LSBIT - the least significant bit at which the current register value ends at + static RegularExpression g_bitfield_regex("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]"); + RegularExpression::Match regex_match(3); + if (g_bitfield_regex.Execute(slice_str.c_str(), ®ex_match)) { - // No offset for this register, see if the register has a value expression - // which indicates this register is part of another register. Value expressions - // are things like "rax[31:0]" which state that the current register's value - // is in a concrete register "rax" in bits 31:0. If there is a value expression - // we can calculate the offset - bool success = false; - const char *slice_cstr = reg_info_dict.GetItemForKeyAsString(slice_pystr); - if (slice_cstr) + llvm::StringRef reg_name_str; + std::string msbit_str; + std::string lsbit_str; + if (regex_match.GetMatchAtIndex(slice_str.c_str(), 1, reg_name_str) && + regex_match.GetMatchAtIndex(slice_str.c_str(), 2, msbit_str) && + regex_match.GetMatchAtIndex(slice_str.c_str(), 3, lsbit_str)) { - // Slices use the following format: - // REGNAME[MSBIT:LSBIT] - // REGNAME - name of the register to grab a slice of - // MSBIT - the most significant bit at which the current register value starts at - // LSBIT - the least significant bit at which the current register value ends at - static RegularExpression g_bitfield_regex("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]"); - RegularExpression::Match regex_match(3); - if (g_bitfield_regex.Execute(slice_cstr, ®ex_match)) + const uint32_t msbit = StringConvert::ToUInt32(msbit_str.c_str(), UINT32_MAX); + const uint32_t lsbit = StringConvert::ToUInt32(lsbit_str.c_str(), UINT32_MAX); + if (msbit != UINT32_MAX && lsbit != UINT32_MAX) { - llvm::StringRef reg_name_str; - std::string msbit_str; - std::string lsbit_str; - if (regex_match.GetMatchAtIndex(slice_cstr, 1, reg_name_str) && - regex_match.GetMatchAtIndex(slice_cstr, 2, msbit_str) && - regex_match.GetMatchAtIndex(slice_cstr, 3, lsbit_str)) + if (msbit > lsbit) { - const uint32_t msbit = StringConvert::ToUInt32(msbit_str.c_str(), UINT32_MAX); - const uint32_t lsbit = StringConvert::ToUInt32(lsbit_str.c_str(), UINT32_MAX); - if (msbit != UINT32_MAX && lsbit != UINT32_MAX) + const uint32_t msbyte = msbit / 8; + const uint32_t lsbyte = lsbit / 8; + + ConstString containing_reg_name(reg_name_str); + + RegisterInfo *containing_reg_info = GetRegisterInfo(containing_reg_name); + if (containing_reg_info) { - if (msbit > lsbit) + const uint32_t max_bit = containing_reg_info->byte_size * 8; + if (msbit < max_bit && lsbit < max_bit) { - const uint32_t msbyte = msbit / 8; - const uint32_t lsbyte = lsbit / 8; + m_invalidate_regs_map[containing_reg_info->kinds[eRegisterKindLLDB]].push_back(i); + m_value_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]); + m_invalidate_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]); - ConstString containing_reg_name(reg_name_str); - - RegisterInfo *containing_reg_info = GetRegisterInfo (containing_reg_name); - if (containing_reg_info) + if (byte_order == eByteOrderLittle) + { + success = true; + reg_info.byte_offset = containing_reg_info->byte_offset + lsbyte; + } + else if (byte_order == eByteOrderBig) { - const uint32_t max_bit = containing_reg_info->byte_size * 8; - if (msbit < max_bit && lsbit < max_bit) - { - m_invalidate_regs_map[containing_reg_info->kinds[eRegisterKindLLDB]].push_back(i); - m_value_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]); - m_invalidate_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]); - - if (byte_order == eByteOrderLittle) - { - success = true; - reg_info.byte_offset = containing_reg_info->byte_offset + lsbyte; - } - else if (byte_order == eByteOrderBig) - { - success = true; - reg_info.byte_offset = containing_reg_info->byte_offset + msbyte; - } - else - { - assert(!"Invalid byte order"); - } - } - else - { - if (msbit > max_bit) - printf("error: msbit (%u) must be less than the bitsize of the register (%u)\n", msbit, max_bit); - else - printf("error: lsbit (%u) must be less than the bitsize of the register (%u)\n", lsbit, max_bit); - } + success = true; + reg_info.byte_offset = containing_reg_info->byte_offset + msbyte; } else { - printf("error: invalid concrete register \"%s\"\n", containing_reg_name.GetCString()); + assert(!"Invalid byte order"); } } else { - printf("error: msbit (%u) must be greater than lsbit (%u)\n", msbit, lsbit); + if (msbit > max_bit) + printf("error: msbit (%u) must be less than the bitsize of the register (%u)\n", msbit, + max_bit); + else + printf("error: lsbit (%u) must be less than the bitsize of the register (%u)\n", lsbit, + max_bit); } } else { - printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit, lsbit); + printf("error: invalid concrete register \"%s\"\n", containing_reg_name.GetCString()); } } else { - // TODO: print error invalid slice string that doesn't follow the format - printf("error: failed to extract regex matches for parsing the register bitfield regex\n"); - + printf("error: msbit (%u) must be greater than lsbit (%u)\n", msbit, lsbit); } } else { - // TODO: print error invalid slice string that doesn't follow the format - printf("error: failed to match against register bitfield regex\n"); + printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit, lsbit); } } else { - PythonList composite_reg_list (reg_info_dict.GetItemForKey(composite_pystr)); - if (composite_reg_list) + // TODO: print error invalid slice string that doesn't follow the format + printf("error: failed to extract regex matches for parsing the register bitfield regex\n"); + } + } + else + { + // TODO: print error invalid slice string that doesn't follow the format + printf("error: failed to match against register bitfield regex\n"); + } + } + else + { + StructuredData::Array *composite_reg_list = nullptr; + if (reg_info_dict->GetValueForKeyAsArray("composite", composite_reg_list)) + { + const size_t num_composite_regs = composite_reg_list->GetSize(); + if (num_composite_regs > 0) + { + uint32_t composite_offset = UINT32_MAX; + for (uint32_t composite_idx = 0; composite_idx < num_composite_regs; ++composite_idx) { - const size_t num_composite_regs = composite_reg_list.GetSize(); - if (num_composite_regs > 0) + ConstString composite_reg_name; + if (composite_reg_list->GetItemAtIndexAsString(composite_idx, composite_reg_name, nullptr)) { - uint32_t composite_offset = UINT32_MAX; - for (uint32_t composite_idx=0; composite_idx<num_composite_regs; ++composite_idx) + RegisterInfo *composite_reg_info = GetRegisterInfo(composite_reg_name); + if (composite_reg_info) { - PythonString composite_reg_name_pystr(composite_reg_list.GetItemAtIndex(composite_idx)); - if (composite_reg_name_pystr) - { - ConstString composite_reg_name(composite_reg_name_pystr.GetString()); - if (composite_reg_name) - { - RegisterInfo *composite_reg_info = GetRegisterInfo (composite_reg_name); - if (composite_reg_info) - { - if (composite_offset > composite_reg_info->byte_offset) - composite_offset = composite_reg_info->byte_offset; - m_value_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]); - m_invalidate_regs_map[composite_reg_info->kinds[eRegisterKindLLDB]].push_back(i); - m_invalidate_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]); - } - else - { - // TODO: print error invalid slice string that doesn't follow the format - printf("error: failed to find composite register by name: \"%s\"\n", composite_reg_name.GetCString()); - } - } - else - { - printf("error: 'composite' key contained an empty string\n"); - } - } - else - { - printf("error: 'composite' list value wasn't a python string\n"); - } - } - if (composite_offset != UINT32_MAX) - { - reg_info.byte_offset = composite_offset; - success = m_value_regs_map.find(i) != m_value_regs_map.end(); + composite_offset = std::min(composite_offset, composite_reg_info->byte_offset); + m_value_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]); + m_invalidate_regs_map[composite_reg_info->kinds[eRegisterKindLLDB]].push_back(i); + m_invalidate_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]); } else { - printf("error: 'composite' registers must specify at least one real register\n"); + // TODO: print error invalid slice string that doesn't follow the format + printf("error: failed to find composite register by name: \"%s\"\n", composite_reg_name.GetCString()); } } else { - printf("error: 'composite' list was empty\n"); + printf("error: 'composite' list value wasn't a python string\n"); } } + if (composite_offset != UINT32_MAX) + { + reg_info.byte_offset = composite_offset; + success = m_value_regs_map.find(i) != m_value_regs_map.end(); + } + else + { + printf("error: 'composite' registers must specify at least one real register\n"); + } } - - - if (!success) + else { - Clear(); - reg_info_dict.Dump(); - return 0; + printf("error: 'composite' list was empty\n"); } } - const int64_t bitsize = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0); - if (bitsize == 0) - { - Clear(); - printf("error: invalid or missing 'bitsize' key/value pair in register dictionary\n"); - reg_info_dict.Dump(); - return 0; - } + } - reg_info.byte_size = bitsize / 8; - - const char *format_cstr = reg_info_dict.GetItemForKeyAsString(format_pystr); - if (format_cstr) - { - if (Args::StringToFormat(format_cstr, reg_info.format, NULL).Fail()) - { - Clear(); - printf("error: invalid 'format' value in register dictionary\n"); - reg_info_dict.Dump(); - return 0; - } - } - else - { - reg_info.format = (Format)reg_info_dict.GetItemForKeyAsInteger (format_pystr, eFormatHex); - } - - const char *encoding_cstr = reg_info_dict.GetItemForKeyAsString(encoding_pystr); - if (encoding_cstr) - reg_info.encoding = Args::StringToEncoding (encoding_cstr, eEncodingUint); - else - reg_info.encoding = (Encoding)reg_info_dict.GetItemForKeyAsInteger (encoding_pystr, eEncodingUint); + if (!success) + { + Clear(); + reg_info_dict->DumpToStdout(); + return 0; + } + } - const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1); - if (static_cast<size_t>(set) >= m_sets.size()) - { - Clear(); - printf("error: invalid 'set' value in register dictionary, valid values are 0 - %i\n", (int)set); - reg_info_dict.Dump(); - return 0; - } + int64_t bitsize = 0; + if (!reg_info_dict->GetValueForKeyAsInteger("bitsize", bitsize)) + { + Clear(); + printf("error: invalid or missing 'bitsize' key/value pair in register dictionary\n"); + reg_info_dict->DumpToStdout(); + return 0; + } - // Fill in the register numbers - reg_info.kinds[lldb::eRegisterKindLLDB] = i; - reg_info.kinds[lldb::eRegisterKindGDB] = i; - reg_info.kinds[lldb::eRegisterKindGCC] = reg_info_dict.GetItemForKeyAsInteger(gcc_pystr, LLDB_INVALID_REGNUM); - reg_info.kinds[lldb::eRegisterKindDWARF] = reg_info_dict.GetItemForKeyAsInteger(dwarf_pystr, LLDB_INVALID_REGNUM); - const char *generic_cstr = reg_info_dict.GetItemForKeyAsString(generic_pystr); - if (generic_cstr) - reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (generic_cstr); - else - reg_info.kinds[lldb::eRegisterKindGeneric] = reg_info_dict.GetItemForKeyAsInteger(generic_pystr, LLDB_INVALID_REGNUM); + reg_info.byte_size = bitsize / 8; - // Check if this register invalidates any other register values when it is modified - PythonList invalidate_reg_list (reg_info_dict.GetItemForKey(invalidate_regs_pystr)); - if (invalidate_reg_list) + std::string format_str; + if (reg_info_dict->GetValueForKeyAsString("format", format_str, nullptr)) + { + if (Args::StringToFormat(format_str.c_str(), reg_info.format, NULL).Fail()) + { + Clear(); + printf("error: invalid 'format' value in register dictionary\n"); + reg_info_dict->DumpToStdout(); + return 0; + } + } + else + { + reg_info_dict->GetValueForKeyAsInteger("format", reg_info.format, eFormatHex); + } + + std::string encoding_str; + if (reg_info_dict->GetValueForKeyAsString("encoding", encoding_str)) + reg_info.encoding = Args::StringToEncoding(encoding_str.c_str(), eEncodingUint); + else + reg_info_dict->GetValueForKeyAsInteger("encoding", reg_info.encoding, eEncodingUint); + + size_t set = 0; + if (!reg_info_dict->GetValueForKeyAsInteger<size_t>("set", set, -1) || set >= m_sets.size()) + { + Clear(); + printf("error: invalid 'set' value in register dictionary, valid values are 0 - %i\n", (int)set); + reg_info_dict->DumpToStdout(); + return 0; + } + + // Fill in the register numbers + reg_info.kinds[lldb::eRegisterKindLLDB] = i; + reg_info.kinds[lldb::eRegisterKindGDB] = i; + reg_info_dict->GetValueForKeyAsInteger("gcc", reg_info.kinds[lldb::eRegisterKindGCC], LLDB_INVALID_REGNUM); + reg_info_dict->GetValueForKeyAsInteger("dwarf", reg_info.kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM); + std::string generic_str; + if (reg_info_dict->GetValueForKeyAsString("generic", generic_str)) + reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister(generic_str.c_str()); + else + reg_info_dict->GetValueForKeyAsInteger("generic", reg_info.kinds[lldb::eRegisterKindGeneric], LLDB_INVALID_REGNUM); + + // Check if this register invalidates any other register values when it is modified + StructuredData::Array *invalidate_reg_list = nullptr; + if (reg_info_dict->GetValueForKeyAsArray("invalidate-regs", invalidate_reg_list)) + { + const size_t num_regs = invalidate_reg_list->GetSize(); + if (num_regs > 0) + { + for (uint32_t idx = 0; idx < num_regs; ++idx) { - const size_t num_regs = invalidate_reg_list.GetSize(); - if (num_regs > 0) + ConstString invalidate_reg_name; + uint64_t invalidate_reg_num; + if (invalidate_reg_list->GetItemAtIndexAsString(idx, invalidate_reg_name)) { - for (uint32_t idx=0; idx<num_regs; ++idx) + RegisterInfo *invalidate_reg_info = GetRegisterInfo(invalidate_reg_name); + if (invalidate_reg_info) { - PythonObject invalidate_reg_object (invalidate_reg_list.GetItemAtIndex(idx)); - PythonString invalidate_reg_name_pystr(invalidate_reg_object); - if (invalidate_reg_name_pystr) - { - ConstString invalidate_reg_name(invalidate_reg_name_pystr.GetString()); - if (invalidate_reg_name) - { - RegisterInfo *invalidate_reg_info = GetRegisterInfo (invalidate_reg_name); - if (invalidate_reg_info) - { - m_invalidate_regs_map[i].push_back(invalidate_reg_info->kinds[eRegisterKindLLDB]); - } - else - { - // TODO: print error invalid slice string that doesn't follow the format - printf("error: failed to find a 'invalidate-regs' register for \"%s\" while parsing register \"%s\"\n", invalidate_reg_name.GetCString(), reg_info.name); - } - } - else - { - printf("error: 'invalidate-regs' list value was an empty string\n"); - } - } - else - { - PythonInteger invalidate_reg_num(invalidate_reg_object); - - if (invalidate_reg_num) - { - const int64_t r = invalidate_reg_num.GetInteger(); - if (r != static_cast<int64_t>(UINT64_MAX)) - m_invalidate_regs_map[i].push_back(r); - else - printf("error: 'invalidate-regs' list value wasn't a valid integer\n"); - } - else - { - printf("error: 'invalidate-regs' list value wasn't a python string or integer\n"); - } - } + m_invalidate_regs_map[i].push_back(invalidate_reg_info->kinds[eRegisterKindLLDB]); + } + else + { + // TODO: print error invalid slice string that doesn't follow the format + printf("error: failed to find a 'invalidate-regs' register for \"%s\" while parsing register \"%s\"\n", + invalidate_reg_name.GetCString(), reg_info.name); } } + else if (invalidate_reg_list->GetItemAtIndexAsInteger(idx, invalidate_reg_num)) + { + if (invalidate_reg_num != UINT64_MAX) + m_invalidate_regs_map[i].push_back(invalidate_reg_num); + else + printf("error: 'invalidate-regs' list value wasn't a valid integer\n"); + } else { - printf("error: 'invalidate-regs' contained an empty list\n"); + printf("error: 'invalidate-regs' list value wasn't a python string or integer\n"); } } - - // Calculate the register offset - const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size; - if (m_reg_data_byte_size < end_reg_offset) - m_reg_data_byte_size = end_reg_offset; - - m_regs.push_back (reg_info); - m_set_reg_nums[set].push_back(i); - } else { - Clear(); - printf("error: items in the 'registers' array must be dictionaries\n"); - regs.Dump(); - return 0; + printf("error: 'invalidate-regs' contained an empty list\n"); } } - Finalize (); + + // Calculate the register offset + const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size; + if (m_reg_data_byte_size < end_reg_offset) + m_reg_data_byte_size = end_reg_offset; + + m_regs.push_back(reg_info); + m_set_reg_nums[set].push_back(i); } -#endif + Finalize(arch); return m_regs.size(); } @@ -465,7 +425,7 @@ DynamicRegisterInfo::AddRegister (RegisterInfo ®_info, } void -DynamicRegisterInfo::Finalize () +DynamicRegisterInfo::Finalize (const ArchSpec &arch) { if (m_finalized) return; @@ -560,6 +520,95 @@ DynamicRegisterInfo::Finalize () else m_regs[i].invalidate_regs = NULL; } + + // Check if we need to automatically set the generic registers in case + // they weren't set + bool generic_regs_specified = false; + for (const auto ®: m_regs) + { + if (reg.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) + { + generic_regs_specified = true; + break; + } + } + + if (!generic_regs_specified) + { + switch (arch.GetMachine()) + { + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + for (auto ®: m_regs) + { + if (strcmp(reg.name, "pc") == 0) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; + else if ((strcmp(reg.name, "fp") == 0) || (strcmp(reg.name, "x29") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if ((strcmp(reg.name, "lr") == 0) || (strcmp(reg.name, "x30") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; + else if ((strcmp(reg.name, "sp") == 0) || (strcmp(reg.name, "x31") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; + else if (strcmp(reg.name, "cpsr") == 0) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; + } + break; + + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + for (auto ®: m_regs) + { + if ((strcmp(reg.name, "pc") == 0) || (strcmp(reg.name, "r15") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; + else if ((strcmp(reg.name, "sp") == 0) || (strcmp(reg.name, "r13") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; + else if ((strcmp(reg.name, "lr") == 0) || (strcmp(reg.name, "r14") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; + else if ((strcmp(reg.name, "r7") == 0) && arch.GetTriple().getVendor() == llvm::Triple::Apple) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if ((strcmp(reg.name, "r11") == 0) && arch.GetTriple().getVendor() != llvm::Triple::Apple) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if (strcmp(reg.name, "fp") == 0) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if (strcmp(reg.name, "cpsr") == 0) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; + } + break; + + case llvm::Triple::x86: + for (auto ®: m_regs) + { + if ((strcmp(reg.name, "eip") == 0) || (strcmp(reg.name, "pc") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; + else if ((strcmp(reg.name, "esp") == 0) || (strcmp(reg.name, "sp") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; + else if ((strcmp(reg.name, "ebp") == 0) || (strcmp(reg.name, "fp") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if ((strcmp(reg.name, "eflags") == 0) || (strcmp(reg.name, "flags") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; + } + break; + + case llvm::Triple::x86_64: + for (auto ®: m_regs) + { + if ((strcmp(reg.name, "rip") == 0) || (strcmp(reg.name, "pc") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; + else if ((strcmp(reg.name, "rsp") == 0) || (strcmp(reg.name, "sp") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; + else if ((strcmp(reg.name, "rbp") == 0) || (strcmp(reg.name, "fp") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; + else if ((strcmp(reg.name, "rflags") == 0) || (strcmp(reg.name, "flags") == 0)) + reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; + } + break; + + default: + break; + } + } } size_t diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/source/Plugins/Process/Utility/DynamicRegisterInfo.h index a41c77e49f9d..1b99e2f1e701 100644 --- a/source/Plugins/Process/Utility/DynamicRegisterInfo.h +++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.h @@ -19,21 +19,21 @@ // Project includes #include "lldb/lldb-private.h" #include "lldb/Core/ConstString.h" +#include "lldb/Core/StructuredData.h" class DynamicRegisterInfo { public: DynamicRegisterInfo (); - DynamicRegisterInfo (const lldb_private::PythonDictionary &dict, - lldb::ByteOrder byte_order); - + DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict, + const lldb_private::ArchSpec &arch); + virtual ~DynamicRegisterInfo (); - size_t - SetRegisterInfo (const lldb_private::PythonDictionary &dict, - lldb::ByteOrder byte_order); + size_t SetRegisterInfo(const lldb_private::StructuredData::Dictionary &dict, + const lldb_private::ArchSpec &arch); void AddRegister (lldb_private::RegisterInfo ®_info, @@ -42,7 +42,7 @@ public: lldb_private::ConstString &set_name); void - Finalize (); + Finalize (const lldb_private::ArchSpec &arch); size_t GetNumRegisters() const; diff --git a/source/Plugins/Process/Utility/FreeBSDSignals.cpp b/source/Plugins/Process/Utility/FreeBSDSignals.cpp index b7c52aeb6d13..f082e143059c 100644 --- a/source/Plugins/Process/Utility/FreeBSDSignals.cpp +++ b/source/Plugins/Process/Utility/FreeBSDSignals.cpp @@ -24,8 +24,70 @@ FreeBSDSignals::Reset() { UnixSignals::Reset(); - // SIGNO NAME SHORT NAME SUPPRESS STOP NOTIFY DESCRIPTION - // ====== ============ ========== ======== ====== ====== =================================================== - AddSignal (32, "SIGTHR", "THR", false, true , true , "thread interrupt"); - AddSignal (33, "SIGLIBRT", "LIBRT", false, true , true , "reserved by real-time library"); + // SIGNO NAME SHORT NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============ ========== ======== ====== ====== =================================================== + AddSignal (32, "SIGTHR", "THR", false, true , true , "thread interrupt"); + AddSignal (33, "SIGLIBRT", "LIBRT", false, true , true , "reserved by real-time library"); + AddSignal (65, "SIGRTMIN", "RTMIN", false, true , true , "real time signal 0"); + AddSignal (66, "SIGRTMIN+1", "RTMIN+1", false, true , true , "real time signal 1"); + AddSignal (67, "SIGRTMIN+2", "RTMIN+2", false, true , true , "real time signal 2"); + AddSignal (68, "SIGRTMIN+3", "RTMIN+3", false, true , true , "real time signal 3"); + AddSignal (69, "SIGRTMIN+4", "RTMIN+4", false, true , true , "real time signal 4"); + AddSignal (70, "SIGRTMIN+5", "RTMIN+5", false, true , true , "real time signal 5"); + AddSignal (71, "SIGRTMIN+6", "RTMIN+6", false, true , true , "real time signal 6"); + AddSignal (72, "SIGRTMIN+7", "RTMIN+7", false, true , true , "real time signal 7"); + AddSignal (73, "SIGRTMIN+8", "RTMIN+8", false, true , true , "real time signal 8"); + AddSignal (74, "SIGRTMIN+9", "RTMIN+9", false, true , true , "real time signal 9"); + AddSignal (75, "SIGRTMIN+10", "RTMIN+10", false, true , true , "real time signal 10"); + AddSignal (76, "SIGRTMIN+11", "RTMIN+11", false, true , true , "real time signal 11"); + AddSignal (77, "SIGRTMIN+12", "RTMIN+12", false, true , true , "real time signal 12"); + AddSignal (78, "SIGRTMIN+13", "RTMIN+13", false, true , true , "real time signal 13"); + AddSignal (79, "SIGRTMIN+14", "RTMIN+14", false, true , true , "real time signal 14"); + AddSignal (80, "SIGRTMIN+15", "RTMIN+15", false, true , true , "real time signal 15"); + AddSignal (81, "SIGRTMIN+16", "RTMIN+16", false, true , true , "real time signal 16"); + AddSignal (82, "SIGRTMIN+17", "RTMIN+17", false, true , true , "real time signal 17"); + AddSignal (83, "SIGRTMIN+18", "RTMIN+18", false, true , true , "real time signal 18"); + AddSignal (84, "SIGRTMIN+19", "RTMIN+19", false, true , true , "real time signal 19"); + AddSignal (85, "SIGRTMIN+20", "RTMIN+20", false, true , true , "real time signal 20"); + AddSignal (86, "SIGRTMIN+21", "RTMIN+21", false, true , true , "real time signal 21"); + AddSignal (87, "SIGRTMIN+22", "RTMIN+22", false, true , true , "real time signal 22"); + AddSignal (88, "SIGRTMIN+23", "RTMIN+23", false, true , true , "real time signal 23"); + AddSignal (89, "SIGRTMIN+24", "RTMIN+24", false, true , true , "real time signal 24"); + AddSignal (90, "SIGRTMIN+25", "RTMIN+25", false, true , true , "real time signal 25"); + AddSignal (91, "SIGRTMIN+26", "RTMIN+26", false, true , true , "real time signal 26"); + AddSignal (92, "SIGRTMIN+27", "RTMIN+27", false, true , true , "real time signal 27"); + AddSignal (93, "SIGRTMIN+28", "RTMIN+28", false, true , true , "real time signal 28"); + AddSignal (94, "SIGRTMIN+29", "RTMIN+29", false, true , true , "real time signal 29"); + AddSignal (95, "SIGRTMIN+30", "RTMIN+30", false, true , true , "real time signal 30"); + AddSignal (96, "SIGRTMAX-30", "RTMAX-30", false, true , true , "real time signal 31"); + AddSignal (97, "SIGRTMAX-29", "RTMAX-29", false, true , true , "real time signal 32"); + AddSignal (98, "SIGRTMAX-28", "RTMAX-28", false, true , true , "real time signal 33"); + AddSignal (99, "SIGRTMAX-27", "RTMAX-27", false, true , true , "real time signal 34"); + AddSignal (100, "SIGRTMAX-26", "RTMAX-26", false, true , true , "real time signal 35"); + AddSignal (101, "SIGRTMAX-25", "RTMAX-25", false, true , true , "real time signal 36"); + AddSignal (102, "SIGRTMAX-24", "RTMAX-24", false, true , true , "real time signal 37"); + AddSignal (103, "SIGRTMAX-23", "RTMAX-23", false, true , true , "real time signal 38"); + AddSignal (104, "SIGRTMAX-22", "RTMAX-22", false, true , true , "real time signal 39"); + AddSignal (105, "SIGRTMAX-21", "RTMAX-21", false, true , true , "real time signal 40"); + AddSignal (106, "SIGRTMAX-20", "RTMAX-20", false, true , true , "real time signal 41"); + AddSignal (107, "SIGRTMAX-19", "RTMAX-19", false, true , true , "real time signal 42"); + AddSignal (108, "SIGRTMAX-18", "RTMAX-18", false, true , true , "real time signal 43"); + AddSignal (109, "SIGRTMAX-17", "RTMAX-17", false, true , true , "real time signal 44"); + AddSignal (110, "SIGRTMAX-16", "RTMAX-16", false, true , true , "real time signal 45"); + AddSignal (111, "SIGRTMAX-15", "RTMAX-15", false, true , true , "real time signal 46"); + AddSignal (112, "SIGRTMAX-14", "RTMAX-14", false, true , true , "real time signal 47"); + AddSignal (113, "SIGRTMAX-13", "RTMAX-13", false, true , true , "real time signal 48"); + AddSignal (114, "SIGRTMAX-12", "RTMAX-12", false, true , true , "real time signal 49"); + AddSignal (115, "SIGRTMAX-11", "RTMAX-11", false, true , true , "real time signal 50"); + AddSignal (116, "SIGRTMAX-10", "RTMAX-10", false, true , true , "real time signal 51"); + AddSignal (117, "SIGRTMAX-9", "RTMAX-9", false, true , true , "real time signal 52"); + AddSignal (118, "SIGRTMAX-8", "RTMAX-8", false, true , true , "real time signal 53"); + AddSignal (119, "SIGRTMAX-7", "RTMAX-7", false, true , true , "real time signal 54"); + AddSignal (120, "SIGRTMAX-6", "RTMAX-6", false, true , true , "real time signal 55"); + AddSignal (121, "SIGRTMAX-5", "RTMAX-5", false, true , true , "real time signal 56"); + AddSignal (122, "SIGRTMAX-4", "RTMAX-4", false, true , true , "real time signal 57"); + AddSignal (123, "SIGRTMAX-3", "RTMAX-3", false, true , true , "real time signal 58"); + AddSignal (124, "SIGRTMAX-2", "RTMAX-2", false, true , true , "real time signal 59"); + AddSignal (125, "SIGRTMAX-1", "RTMAX-1", false, true , true , "real time signal 60"); + AddSignal (126, "SIGRTMAX", "RTMAX", false, true , true , "real time signal 61"); } diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 7db83ae5467f..3923c5433406 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -14,6 +14,7 @@ #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadPlanCallFunction.h" @@ -27,8 +28,6 @@ #define PROT_READ 1 #define PROT_WRITE 2 #define PROT_EXEC 4 -#define MAP_PRIVATE 2 -#define MAP_ANON 0x1000 #endif using namespace lldb; @@ -87,10 +86,8 @@ lldb_private::InferiorCallMmap (Process *process, prot_arg |= PROT_WRITE; } - if (flags & eMmapFlagsPrivate) - flags_arg |= MAP_PRIVATE; - if (flags & eMmapFlagsAnon) - flags_arg |= MAP_ANON; + const ArchSpec arch = process->GetTarget().GetArchitecture(); + flags_arg = process->GetTarget().GetPlatform()->ConvertMmapFlagsToPlatform(arch,flags); AddressRange mmap_range; if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, mmap_range)) diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/source/Plugins/Process/Utility/InferiorCallPOSIX.h index d8b6d0ed57fd..e56e95c43773 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.h +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.h @@ -25,11 +25,6 @@ enum MmapProt { eMmapProtWrite = 4 }; -enum MmapFlags { - eMmapFlagsPrivate = 1, - eMmapFlagsAnon = 2 -}; - bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr, lldb::addr_t addr, lldb::addr_t length, unsigned prot, unsigned flags, lldb::addr_t fd, lldb::addr_t offset); diff --git a/source/Plugins/Process/Utility/LinuxSignals.cpp b/source/Plugins/Process/Utility/LinuxSignals.cpp index 11a3eef23529..0680d268233c 100644 --- a/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -12,7 +12,7 @@ // Project includes #include "LinuxSignals.h" -using namespace process_linux; +using namespace lldb_private::process_linux; LinuxSignals::LinuxSignals() : UnixSignals() @@ -25,38 +25,71 @@ LinuxSignals::Reset() { m_signals.clear(); - AddSignal (1, "SIGHUP", "HUP", false, true , true , "hangup"); - AddSignal (2, "SIGINT", "INT", true , true , true , "interrupt"); - AddSignal (3, "SIGQUIT", "QUIT", false, true , true , "quit"); - AddSignal (4, "SIGILL", "ILL", false, true , true , "illegal instruction"); - AddSignal (5, "SIGTRAP", "TRAP", true , true , true , "trace trap (not reset when caught)"); - AddSignal (6, "SIGABRT", "ABRT", false, true , true , "abort()"); - AddSignal (6, "SIGIOT", "IOT", false, true , true , "IOT trap"); - AddSignal (7, "SIGBUS", "BUS", false, true , true , "bus error"); - AddSignal (8, "SIGFPE", "FPE", false, true , true , "floating point exception"); - AddSignal (9, "SIGKILL", "KILL", false, true , true , "kill"); - AddSignal (10, "SIGUSR1", "USR1", false, true , true , "user defined signal 1"); - AddSignal (11, "SIGSEGV", "SEGV", false, true , true , "segmentation violation"); - AddSignal (12, "SIGUSR2", "USR2", false, true , true , "user defined signal 2"); - AddSignal (13, "SIGPIPE", "PIPE", false, true , true , "write to pipe with reading end closed"); - AddSignal (14, "SIGALRM", "ALRM", false, false, false, "alarm"); - AddSignal (15, "SIGTERM", "TERM", false, true , true , "termination requested"); - AddSignal (16, "SIGSTKFLT", "STKFLT", false, true , true , "stack fault"); - AddSignal (16, "SIGCLD", "CLD", false, false, true , "same as SIGCHLD"); - AddSignal (17, "SIGCHLD", "CHLD", false, false, true , "child status has changed"); - AddSignal (18, "SIGCONT", "CONT", false, true , true , "process continue"); - AddSignal (19, "SIGSTOP", "STOP", true , true , true , "process stop"); - AddSignal (20, "SIGTSTP", "TSTP", false, true , true , "tty stop"); - AddSignal (21, "SIGTTIN", "TTIN", false, true , true , "background tty read"); - AddSignal (22, "SIGTTOU", "TTOU", false, true , true , "background tty write"); - AddSignal (23, "SIGURG", "URG", false, true , true , "urgent data on socket"); - AddSignal (24, "SIGXCPU", "XCPU", false, true , true , "CPU resource exceeded"); - AddSignal (25, "SIGXFSZ", "XFSZ", false, true , true , "file size limit exceeded"); - AddSignal (26, "SIGVTALRM", "VTALRM", false, true , true , "virtual time alarm"); - AddSignal (27, "SIGPROF", "PROF", false, false, false, "profiling time alarm"); - AddSignal (28, "SIGWINCH", "WINCH", false, true , true , "window size changes"); - AddSignal (29, "SIGPOLL", "POLL", false, true , true , "pollable event"); - AddSignal (29, "SIGIO", "IO", false, true , true , "input/output ready"); - AddSignal (30, "SIGPWR", "PWR", false, true , true , "power failure"); - AddSignal (31, "SIGSYS", "SYS", false, true , true , "invalid system call"); + AddSignal (1, "SIGHUP", "HUP", false, true , true , "hangup"); + AddSignal (2, "SIGINT", "INT", true , true , true , "interrupt"); + AddSignal (3, "SIGQUIT", "QUIT", false, true , true , "quit"); + AddSignal (4, "SIGILL", "ILL", false, true , true , "illegal instruction"); + AddSignal (5, "SIGTRAP", "TRAP", true , true , true , "trace trap (not reset when caught)"); + AddSignal (6, "SIGABRT", "ABRT", false, true , true , "abort()"); + AddSignal (6, "SIGIOT", "IOT", false, true , true , "IOT trap"); + AddSignal (7, "SIGBUS", "BUS", false, true , true , "bus error"); + AddSignal (8, "SIGFPE", "FPE", false, true , true , "floating point exception"); + AddSignal (9, "SIGKILL", "KILL", false, true , true , "kill"); + AddSignal (10, "SIGUSR1", "USR1", false, true , true , "user defined signal 1"); + AddSignal (11, "SIGSEGV", "SEGV", false, true , true , "segmentation violation"); + AddSignal (12, "SIGUSR2", "USR2", false, true , true , "user defined signal 2"); + AddSignal (13, "SIGPIPE", "PIPE", false, true , true , "write to pipe with reading end closed"); + AddSignal (14, "SIGALRM", "ALRM", false, false, false, "alarm"); + AddSignal (15, "SIGTERM", "TERM", false, true , true , "termination requested"); + AddSignal (16, "SIGSTKFLT", "STKFLT", false, true , true , "stack fault"); + AddSignal (16, "SIGCLD", "CLD", false, false, true , "same as SIGCHLD"); + AddSignal (17, "SIGCHLD", "CHLD", false, false, true , "child status has changed"); + AddSignal (18, "SIGCONT", "CONT", false, true , true , "process continue"); + AddSignal (19, "SIGSTOP", "STOP", true , true , true , "process stop"); + AddSignal (20, "SIGTSTP", "TSTP", false, true , true , "tty stop"); + AddSignal (21, "SIGTTIN", "TTIN", false, true , true , "background tty read"); + AddSignal (22, "SIGTTOU", "TTOU", false, true , true , "background tty write"); + AddSignal (23, "SIGURG", "URG", false, true , true , "urgent data on socket"); + AddSignal (24, "SIGXCPU", "XCPU", false, true , true , "CPU resource exceeded"); + AddSignal (25, "SIGXFSZ", "XFSZ", false, true , true , "file size limit exceeded"); + AddSignal (26, "SIGVTALRM", "VTALRM", false, true , true , "virtual time alarm"); + AddSignal (27, "SIGPROF", "PROF", false, false, false, "profiling time alarm"); + AddSignal (28, "SIGWINCH", "WINCH", false, true , true , "window size changes"); + AddSignal (29, "SIGPOLL", "POLL", false, true , true , "pollable event"); + AddSignal (29, "SIGIO", "IO", false, true , true , "input/output ready"); + AddSignal (30, "SIGPWR", "PWR", false, true , true , "power failure"); + AddSignal (31, "SIGSYS", "SYS", false, true , true , "invalid system call"); + AddSignal (32, "SIG32", "SIG32", false, true , true , "threading library internal signal 1"); + AddSignal (33, "SIG33", "SIG33", false, true , true , "threading library internal signal 2"); + AddSignal (34, "SIGRTMIN", "RTMIN", false, true , true , "real time signal 0"); + AddSignal (35, "SIGRTMIN+1", "RTMIN+1", false, true , true , "real time signal 1"); + AddSignal (36, "SIGRTMIN+2", "RTMIN+2", false, true , true , "real time signal 2"); + AddSignal (37, "SIGRTMIN+3", "RTMIN+3", false, true , true , "real time signal 3"); + AddSignal (38, "SIGRTMIN+4", "RTMIN+4", false, true , true , "real time signal 4"); + AddSignal (39, "SIGRTMIN+5", "RTMIN+5", false, true , true , "real time signal 5"); + AddSignal (40, "SIGRTMIN+6", "RTMIN+6", false, true , true , "real time signal 6"); + AddSignal (41, "SIGRTMIN+7", "RTMIN+7", false, true , true , "real time signal 7"); + AddSignal (42, "SIGRTMIN+8", "RTMIN+8", false, true , true , "real time signal 8"); + AddSignal (43, "SIGRTMIN+9", "RTMIN+9", false, true , true , "real time signal 9"); + AddSignal (44, "SIGRTMIN+10", "RTMIN+10", false, true , true , "real time signal 10"); + AddSignal (45, "SIGRTMIN+11", "RTMIN+11", false, true , true , "real time signal 11"); + AddSignal (46, "SIGRTMIN+12", "RTMIN+12", false, true , true , "real time signal 12"); + AddSignal (47, "SIGRTMIN+13", "RTMIN+13", false, true , true , "real time signal 13"); + AddSignal (48, "SIGRTMIN+14", "RTMIN+14", false, true , true , "real time signal 14"); + AddSignal (49, "SIGRTMIN+15", "RTMIN+15", false, true , true , "real time signal 15"); + AddSignal (50, "SIGRTMAX-14", "RTMAX-14", false, true , true , "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + AddSignal (51, "SIGRTMAX-13", "RTMAX-13", false, true , true , "real time signal 17"); + AddSignal (52, "SIGRTMAX-12", "RTMAX-12", false, true , true , "real time signal 18"); + AddSignal (53, "SIGRTMAX-11", "RTMAX-11", false, true , true , "real time signal 19"); + AddSignal (54, "SIGRTMAX-10", "RTMAX-10", false, true , true , "real time signal 20"); + AddSignal (55, "SIGRTMAX-9", "RTMAX-9", false, true , true , "real time signal 21"); + AddSignal (56, "SIGRTMAX-8", "RTMAX-8", false, true , true , "real time signal 22"); + AddSignal (57, "SIGRTMAX-7", "RTMAX-7", false, true , true , "real time signal 23"); + AddSignal (58, "SIGRTMAX-6", "RTMAX-6", false, true , true , "real time signal 24"); + AddSignal (59, "SIGRTMAX-5", "RTMAX-5", false, true , true , "real time signal 25"); + AddSignal (60, "SIGRTMAX-4", "RTMAX-4", false, true , true , "real time signal 26"); + AddSignal (61, "SIGRTMAX-3", "RTMAX-3", false, true , true , "real time signal 27"); + AddSignal (62, "SIGRTMAX-2", "RTMAX-2", false, true , true , "real time signal 28"); + AddSignal (63, "SIGRTMAX-1", "RTMAX-1", false, true , true , "real time signal 29"); + AddSignal (64, "SIGRTMAX", "RTMAX", false, true , true , "real time signal 30"); } diff --git a/source/Plugins/Process/Utility/LinuxSignals.h b/source/Plugins/Process/Utility/LinuxSignals.h index 9645b3d8725a..5102bcb95e74 100644 --- a/source/Plugins/Process/Utility/LinuxSignals.h +++ b/source/Plugins/Process/Utility/LinuxSignals.h @@ -16,8 +16,8 @@ // Project includes #include "lldb/Target/UnixSignals.h" -namespace process_linux -{ +namespace lldb_private { +namespace process_linux { /// Linux specific set of Unix signals. class LinuxSignals @@ -30,6 +30,8 @@ namespace process_linux void Reset(); }; -} + +} // namespace lldb_private +} // namespace process_linux #endif diff --git a/source/Plugins/Process/Utility/MipsLinuxSignals.cpp b/source/Plugins/Process/Utility/MipsLinuxSignals.cpp new file mode 100644 index 000000000000..e4e654626eaa --- /dev/null +++ b/source/Plugins/Process/Utility/MipsLinuxSignals.cpp @@ -0,0 +1,95 @@ +//===-- MipsLinuxSignals.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "MipsLinuxSignals.h" + +using namespace lldb_private::process_linux; + +MipsLinuxSignals::MipsLinuxSignals() + : UnixSignals() +{ + Reset(); +} + +void +MipsLinuxSignals::Reset() +{ + m_signals.clear(); + + AddSignal (1, "SIGHUP", "HUP", false, true , true , "hangup"); + AddSignal (2, "SIGINT", "INT", true , true , true , "interrupt"); + AddSignal (3, "SIGQUIT", "QUIT", false, true , true , "quit"); + AddSignal (4, "SIGILL", "ILL", false, true , true , "illegal instruction"); + AddSignal (5, "SIGTRAP", "TRAP", true , true , true , "trace trap (not reset when caught)"); + AddSignal (6, "SIGABRT", "ABRT", false, true , true , "abort()"); + AddSignal (6, "SIGIOT", "IOT", false, true , true , "IOT trap"); + AddSignal (7, "SIGEMT", "EMT", false, true , true , "terminate process with core dump"); + AddSignal (8, "SIGFPE", "FPE", false, true , true , "floating point exception"); + AddSignal (9, "SIGKILL", "KILL", false, true , true , "kill"); + AddSignal (10, "SIGBUS", "BUS", false, true , true , "bus error"); + AddSignal (11, "SIGSEGV", "SEGV", false, true , true , "segmentation violation"); + AddSignal (12, "SIGSYS", "SYS", false, true , true , "invalid system call"); + AddSignal (13, "SIGPIPE", "PIPE", false, true , true , "write to pipe with reading end closed"); + AddSignal (14, "SIGALRM", "ALRM", false, false, false, "alarm"); + AddSignal (15, "SIGTERM", "TERM", false, true , true , "termination requested"); + AddSignal (16, "SIGUSR1", "USR1", false, true , true , "user defined signal 1"); + AddSignal (17, "SIGUSR2", "USR2", false, true , true , "user defined signal 2"); + AddSignal (18, "SIGCLD", "CLD", false, false, true , "same as SIGCHLD"); + AddSignal (18, "SIGCHLD", "CHLD", false, false, true , "child status has changed"); + AddSignal (19, "SIGPWR", "PWR", false, true , true , "power failure"); + AddSignal (20, "SIGWINCH", "WINCH", false, true , true , "window size changes"); + AddSignal (21, "SIGURG", "URG", false, true , true , "urgent data on socket"); + AddSignal (22, "SIGIO", "IO", false, true , true , "input/output ready"); + AddSignal (22, "SIGPOLL", "POLL", false, true , true , "pollable event"); + AddSignal (23, "SIGSTOP", "STOP", true , true , true , "process stop"); + AddSignal (24, "SIGTSTP", "TSTP", false, true , true , "tty stop"); + AddSignal (25, "SIGCONT", "CONT", false, true , true , "process continue"); + AddSignal (26, "SIGTTIN", "TTIN", false, true , true , "background tty read"); + AddSignal (27, "SIGTTOU", "TTOU", false, true , true , "background tty write"); + AddSignal (28, "SIGVTALRM", "VTALRM", false, true , true , "virtual time alarm"); + AddSignal (29, "SIGPROF", "PROF", false, false, false, "profiling time alarm"); + AddSignal (30, "SIGXCPU", "XCPU", false, true , true , "CPU resource exceeded"); + AddSignal (31, "SIGXFSZ", "XFSZ", false, true , true , "file size limit exceeded"); + AddSignal (32, "SIG32", "SIG32", false, true , true , "threading library internal signal 1"); + AddSignal (33, "SIG33", "SIG33", false, true , true , "threading library internal signal 2"); + AddSignal (34, "SIGRTMIN", "RTMIN", false, true , true , "real time signal 0"); + AddSignal (35, "SIGRTMIN+1", "RTMIN+1", false, true , true , "real time signal 1"); + AddSignal (36, "SIGRTMIN+2", "RTMIN+2", false, true , true , "real time signal 2"); + AddSignal (37, "SIGRTMIN+3", "RTMIN+3", false, true , true , "real time signal 3"); + AddSignal (38, "SIGRTMIN+4", "RTMIN+4", false, true , true , "real time signal 4"); + AddSignal (39, "SIGRTMIN+5", "RTMIN+5", false, true , true , "real time signal 5"); + AddSignal (40, "SIGRTMIN+6", "RTMIN+6", false, true , true , "real time signal 6"); + AddSignal (41, "SIGRTMIN+7", "RTMIN+7", false, true , true , "real time signal 7"); + AddSignal (42, "SIGRTMIN+8", "RTMIN+8", false, true , true , "real time signal 8"); + AddSignal (43, "SIGRTMIN+9", "RTMIN+9", false, true , true , "real time signal 9"); + AddSignal (44, "SIGRTMIN+10", "RTMIN+10", false, true , true , "real time signal 10"); + AddSignal (45, "SIGRTMIN+11", "RTMIN+11", false, true , true , "real time signal 11"); + AddSignal (46, "SIGRTMIN+12", "RTMIN+12", false, true , true , "real time signal 12"); + AddSignal (47, "SIGRTMIN+13", "RTMIN+13", false, true , true , "real time signal 13"); + AddSignal (48, "SIGRTMIN+14", "RTMIN+14", false, true , true , "real time signal 14"); + AddSignal (49, "SIGRTMIN+15", "RTMIN+15", false, true , true , "real time signal 15"); + AddSignal (50, "SIGRTMAX-14", "RTMAX-14", false, true , true , "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + AddSignal (51, "SIGRTMAX-13", "RTMAX-13", false, true , true , "real time signal 17"); + AddSignal (52, "SIGRTMAX-12", "RTMAX-12", false, true , true , "real time signal 18"); + AddSignal (53, "SIGRTMAX-11", "RTMAX-11", false, true , true , "real time signal 19"); + AddSignal (54, "SIGRTMAX-10", "RTMAX-10", false, true , true , "real time signal 20"); + AddSignal (55, "SIGRTMAX-9", "RTMAX-9", false, true , true , "real time signal 21"); + AddSignal (56, "SIGRTMAX-8", "RTMAX-8", false, true , true , "real time signal 22"); + AddSignal (57, "SIGRTMAX-7", "RTMAX-7", false, true , true , "real time signal 23"); + AddSignal (58, "SIGRTMAX-6", "RTMAX-6", false, true , true , "real time signal 24"); + AddSignal (59, "SIGRTMAX-5", "RTMAX-5", false, true , true , "real time signal 25"); + AddSignal (60, "SIGRTMAX-4", "RTMAX-4", false, true , true , "real time signal 26"); + AddSignal (61, "SIGRTMAX-3", "RTMAX-3", false, true , true , "real time signal 27"); + AddSignal (62, "SIGRTMAX-2", "RTMAX-2", false, true , true , "real time signal 28"); + AddSignal (63, "SIGRTMAX-1", "RTMAX-1", false, true , true , "real time signal 29"); + AddSignal (64, "SIGRTMAX", "RTMAX", false, true , true , "real time signal 30"); +} diff --git a/source/Plugins/Process/Utility/MipsLinuxSignals.h b/source/Plugins/Process/Utility/MipsLinuxSignals.h new file mode 100644 index 000000000000..2e603fbbdf3c --- /dev/null +++ b/source/Plugins/Process/Utility/MipsLinuxSignals.h @@ -0,0 +1,37 @@ +//===-- MipsLinuxSignals.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_MipsLinuxSignals_H_ +#define liblldb_MipsLinuxSignals_H_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Target/UnixSignals.h" + +namespace lldb_private { +namespace process_linux { + + /// Linux specific set of Unix signals. + class MipsLinuxSignals + : public lldb_private::UnixSignals + { + public: + MipsLinuxSignals(); + + private: + void + Reset(); + }; + +} // namespace lldb_private +} // namespace process_linux + +#endif diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp new file mode 100644 index 000000000000..8005a6339f6d --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp @@ -0,0 +1,88 @@ +//===-- RegisterContextFreeBSD_arm.cpp -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include <stddef.h> +#include <vector> +#include <cassert> + +#include "llvm/Support/Compiler.h" +#include "lldb/lldb-defines.h" + +#include "RegisterContextFreeBSD_arm.h" + +using namespace lldb; +using namespace lldb_private; + +// Based on RegisterContextLinux_arm.cpp and +// http://svnweb.freebsd.org/base/head/sys/arm/include/reg.h +#define GPR_OFFSET(idx) ((idx) * 4) +#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextFreeBSD_arm::GPR)) +#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU)) +#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm::DBG, reg) + sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU) + sizeof (RegisterContextFreeBSD_arm::EXC))) + +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextFreeBSD_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define REG_CONTEXT_SIZE (sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU) + sizeof (RegisterContextFreeBSD_arm::EXC)) + +//----------------------------------------------------------------------------- +// Include RegisterInfos_arm to declare our g_register_infos_arm structure. +//----------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_ARM_STRUCT +#include "RegisterInfos_arm.h" +#undef DECLARE_REGISTER_INFOS_ARM_STRUCT + +static const lldb_private::RegisterInfo * +GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::arm: + return g_register_infos_arm; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } +} + +static uint32_t +GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::arm: + return static_cast<uint32_t>(sizeof(g_register_infos_arm) / sizeof(g_register_infos_arm[0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextFreeBSD_arm::RegisterContextFreeBSD_arm(const lldb_private::ArchSpec &target_arch) : + lldb_private::RegisterInfoInterface(target_arch), + m_register_info_p(GetRegisterInfoPtr(target_arch)), + m_register_info_count(GetRegisterInfoCount(target_arch)) +{ +} + +size_t +RegisterContextFreeBSD_arm::GetGPRSize() const +{ + return sizeof(struct RegisterContextFreeBSD_arm::GPR); +} + +const lldb_private::RegisterInfo * +RegisterContextFreeBSD_arm::GetRegisterInfo() const +{ + return m_register_info_p; +} + +uint32_t +RegisterContextFreeBSD_arm::GetRegisterCount() const +{ + return m_register_info_count; +} diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h new file mode 100644 index 000000000000..c4287e9f0a47 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h @@ -0,0 +1,75 @@ +//===-- RegisterContextFreeBSD_arm.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_RegisterContextFreeBSD_arm_h_ +#define liblldb_RegisterContextFreeBSD_arm_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" +#include "RegisterContextPOSIX.h" +#include "RegisterInfoInterface.h" + +class RegisterContextFreeBSD_arm + : public lldb_private::RegisterInfoInterface +{ +public: + + struct GPR + { + uint32_t r[16]; // R0-R15 + uint32_t cpsr; // CPSR + }; + + + struct QReg + { + uint8_t bytes[16]; + }; + + struct FPU + { + union { + uint32_t s[32]; + uint64_t d[32]; + QReg q[16]; // the 128-bit NEON registers + } floats; + uint32_t fpscr; + }; + struct EXC + { + uint32_t exception; + uint32_t fsr; /* Fault status */ + uint32_t far; /* Virtual Fault Address */ + }; + + struct DBG + { + uint32_t bvr[16]; + uint32_t bcr[16]; + uint32_t wvr[16]; + uint32_t wcr[16]; + }; + + RegisterContextFreeBSD_arm(const lldb_private::ArchSpec &target_arch); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + uint32_t m_register_info_count; +}; + +#endif // liblldb_RegisterContextFreeBSD_arm_h_ diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp new file mode 100644 index 000000000000..d39a9da5714b --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp @@ -0,0 +1,86 @@ +//===-- RegisterContextFreeBSD_arm64.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include <vector> +#include "RegisterContextPOSIX_arm64.h" +#include "RegisterContextFreeBSD_arm64.h" + +using namespace lldb; + +// Based on RegisterContextDarwin_arm64.cpp +#define GPR_OFFSET(idx) ((idx) * 8) +#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::GPR, reg)) + +#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextFreeBSD_arm64::GPR)) +#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::FPU, reg)) + +#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::EXC, reg) + sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU)) +#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::DBG, reg) + sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU) + sizeof (RegisterContextFreeBSD_arm64::EXC)) + +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextFreeBSD_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define REG_CONTEXT_SIZE (sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU) + sizeof (RegisterContextFreeBSD_arm64::EXC)) + +//----------------------------------------------------------------------------- +// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. +//----------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_ARM64_STRUCT +#include "RegisterInfos_arm64.h" +#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT + +static const lldb_private::RegisterInfo * +GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + return g_register_infos_arm64; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } +} + +static uint32_t +GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + return static_cast<uint32_t>(sizeof(g_register_infos_arm64) / sizeof(g_register_infos_arm64[0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextFreeBSD_arm64::RegisterContextFreeBSD_arm64(const lldb_private::ArchSpec &target_arch) : + RegisterInfoInterface(target_arch), + m_register_info_p(GetRegisterInfoPtr(target_arch)), + m_register_info_count(GetRegisterInfoCount(target_arch)) +{ +} + +size_t +RegisterContextFreeBSD_arm64::GetGPRSize() const +{ + return sizeof(struct RegisterContextFreeBSD_arm64::GPR); +} + +const lldb_private::RegisterInfo * +RegisterContextFreeBSD_arm64::GetRegisterInfo() const +{ + return m_register_info_p; +} + +uint32_t +RegisterContextFreeBSD_arm64::GetRegisterCount() const +{ + return m_register_info_count; +} + diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h new file mode 100644 index 000000000000..249027aaa76c --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h @@ -0,0 +1,78 @@ +//===-- RegisterContextFreeBSD_arm64.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_RegisterContextFreeBSD_arm64_H_ +#define liblldb_RegisterContextFreeBSD_arm64_H_ + +#include "RegisterContextPOSIX.h" + +class RegisterContextFreeBSD_arm64: + public lldb_private::RegisterInfoInterface +{ +public: + // based on RegisterContextDarwin_arm64.h + struct GPR + { + uint64_t x[29]; // x0-x28 + uint64_t fp; // x29 + uint64_t lr; // x30 + uint64_t sp; // x31 + uint64_t pc; // pc + uint32_t cpsr; // cpsr + }; + + // based on RegisterContextDarwin_arm64.h + struct VReg + { + uint8_t bytes[16]; + }; + + // based on RegisterContextDarwin_arm64.h + struct FPU + { + VReg v[32]; + uint32_t fpsr; + uint32_t fpcr; + }; + + // based on RegisterContextDarwin_arm64.h + struct EXC + { + uint64_t far; // Virtual Fault Address + uint32_t esr; // Exception syndrome + uint32_t exception; // number of arm exception token + }; + + // based on RegisterContextDarwin_arm64.h + struct DBG + { + uint64_t bvr[16]; + uint64_t bcr[16]; + uint64_t wvr[16]; + uint64_t wcr[16]; + uint64_t mdscr_el1; + }; + + RegisterContextFreeBSD_arm64(const lldb_private::ArchSpec &target_arch); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + uint32_t m_register_info_count; +}; + +#endif diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp index 185ba26944fe..0171da66a199 100644 --- a/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp @@ -45,6 +45,13 @@ struct dbreg { /* Index 7: debug control */ }; +using FPR_i386 = FXSAVE; + +struct UserArea +{ + GPR gpr; + FPR_i386 i387; +}; #define DR_SIZE sizeof(uint32_t) #define DR_OFFSET(reg_index) \ diff --git a/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp index 257de7198590..34f2d185da8a 100644 --- a/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp @@ -46,19 +46,24 @@ typedef struct _GPR uint64_t ss; } GPR; -struct dbreg { - uint64_t dr[16]; /* debug registers */ - /* Index 0-3: debug address registers */ - /* Index 4-5: reserved */ - /* Index 6: debug status */ - /* Index 7: debug control */ - /* Index 8-15: reserved */ +struct DBG { + uint64_t dr[16]; /* debug registers */ + /* Index 0-3: debug address registers */ + /* Index 4-5: reserved */ + /* Index 6: debug status */ + /* Index 7: debug control */ + /* Index 8-15: reserved */ }; -#define DR_SIZE sizeof(uint64_t) -#define DR_OFFSET(reg_index) \ - (LLVM_EXTENSION offsetof(dbreg, dr[reg_index])) +struct UserArea +{ + GPR gpr; + FPR fpr; + DBG dbg; +}; +#define DR_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(DBG, dr[reg_index])) //--------------------------------------------------------------------------- // Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64 structure. diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 1b3a9491d1c8..37b007cfffcf 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -38,6 +38,15 @@ using namespace lldb; using namespace lldb_private; +static ConstString GetSymbolOrFunctionName(const SymbolContext &sym_ctx) +{ + if (sym_ctx.symbol) + return sym_ctx.symbol->GetName(); + else if (sym_ctx.function) + return sym_ctx.function->GetName(); + return ConstString(); +} + RegisterContextLLDB::RegisterContextLLDB ( Thread& thread, @@ -175,12 +184,12 @@ RegisterContextLLDB::InitializeZerothFrame() if (m_sym_ctx.symbol) { UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'", - current_pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); + current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); } else if (m_sym_ctx.function) { UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'", - current_pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.function->GetName().AsCString()); + current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); } else { @@ -457,12 +466,12 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (m_sym_ctx.symbol) { UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'", - pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); + pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); } else if (m_sym_ctx.function) { UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'", - pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.function->GetName().AsCString()); + pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); } else { @@ -500,7 +509,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (decr_pc_and_recompute_addr_range) { UnwindLogMsg ("Backing up the pc value of 0x%" PRIx64 " by 1 and re-doing symbol lookup; old symbol was %s", - pc, m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); + pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); Address temporary_pc; temporary_pc.SetLoadAddress (pc - 1, &process->GetTarget()); m_sym_ctx.Clear (false); @@ -514,7 +523,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range)) m_sym_ctx_valid = true; } - UnwindLogMsg ("Symbol is now %s", m_sym_ctx.symbol == NULL ? "" : m_sym_ctx.symbol->GetName().AsCString()); + UnwindLogMsg ("Symbol is now %s", GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); } // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function. @@ -599,7 +608,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa)) { - UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister()); + UnwindLogMsg ("failed to get cfa"); m_frame_type = eNotAValidFrame; return; } @@ -683,7 +692,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame () if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame) return unwind_plan_sp; - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread); + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (*m_thread.CalculateTarget(), m_thread); if (unwind_plan_sp) { if (unwind_plan_sp->PlanValidAtAddress (m_current_pc)) @@ -846,12 +855,26 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () { if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) { - // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably - // don't have any eh_frame instructions available. - // The assembly profilers work really well with compiler-generated functions but hand-written - // assembly can be problematic. We'll set the architecture default UnwindPlan as our fallback - // UnwindPlan in case this doesn't work out when we try to unwind. - m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp; + // We probably have an UnwindPlan created by inspecting assembly instructions. The + // assembly profilers work really well with compiler-generated functions but hand- + // written assembly can be problematic. We set the eh_frame based unwind plan as our + // fallback unwind plan if instruction emulation doesn't work out even for non call + // sites if it is available and use the architecture default unwind plan if it is + // not available. The eh_frame unwind plan is more reliable even on non call sites + // then the architecture default plan and for hand written assembly code it is often + // written in a way that it valid at all location what helps in the most common + // cases when the instruction emulation fails. + UnwindPlanSP eh_frame_unwind_plan = func_unwinders_sp->GetEHFrameUnwindPlan (process->GetTarget(), m_current_offset_backed_up_one); + if (eh_frame_unwind_plan && + eh_frame_unwind_plan.get() != unwind_plan_sp.get() && + eh_frame_unwind_plan->GetSourceName() != unwind_plan_sp->GetSourceName()) + { + m_fallback_unwind_plan_sp = eh_frame_unwind_plan; + } + else + { + m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp; + } } UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); return unwind_plan_sp; @@ -878,12 +901,25 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () } if (unwind_plan_sp && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) { - // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably - // don't have any eh_frame instructions available. - // The assembly profilers work really well with compiler-generated functions but hand-written - // assembly can be problematic. We'll set the architecture default UnwindPlan as our fallback - // UnwindPlan in case this doesn't work out when we try to unwind. - m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp; + // We probably have an UnwindPlan created by inspecting assembly instructions. The assembly + // profilers work really well with compiler-generated functions but hand- written assembly + // can be problematic. We set the eh_frame based unwind plan as our fallback unwind plan if + // instruction emulation doesn't work out even for non call sites if it is available and use + // the architecture default unwind plan if it is not available. The eh_frame unwind plan is + // more reliable even on non call sites then the architecture default plan and for hand + // written assembly code it is often written in a way that it valid at all location what + // helps in the most common cases when the instruction emulation fails. + UnwindPlanSP eh_frame_unwind_plan = func_unwinders_sp->GetEHFrameUnwindPlan (process->GetTarget(), m_current_offset_backed_up_one); + if (eh_frame_unwind_plan && + eh_frame_unwind_plan.get() != unwind_plan_sp.get() && + eh_frame_unwind_plan->GetSourceName() != unwind_plan_sp->GetSourceName()) + { + m_fallback_unwind_plan_sp = eh_frame_unwind_plan; + } + else + { + m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp; + } } if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) @@ -1394,16 +1430,13 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat if (unwindplan_regloc.IsSame()) { - if (IsFrameZero ()) - { - UnwindLogMsg ("could not supply caller's %s (%d) location, IsSame", - regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } - else - { - return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; - } + regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister; + regloc.location.register_number = regnum.GetAsKind (eRegisterKindLLDB); + m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc; + UnwindLogMsg ("supplying caller's register %s (%d), saved in register %s (%d)", + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), + regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB)); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; } if (unwindplan_regloc.IsCFAPlusOffset()) @@ -1577,7 +1610,7 @@ RegisterContextLLDB::TryFallbackUnwindPlan () UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); - if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) + if (active_row && active_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::unspecified) { addr_t new_cfa; if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa) @@ -1654,7 +1687,7 @@ RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan () UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); - if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) + if (active_row && active_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::unspecified) { addr_t new_cfa; if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa) @@ -1683,57 +1716,90 @@ RegisterContextLLDB::ReadCFAValueForRow (lldb::RegisterKind row_register_kind, const UnwindPlan::RowSP &row, addr_t &cfa_value) { - RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFARegister()); RegisterValue reg_value; cfa_value = LLDB_INVALID_ADDRESS; addr_t cfa_reg_contents; - if (ReadGPRValue (cfa_reg, cfa_reg_contents)) + switch (row->GetCFAValue().GetValueType()) { - if (row->GetCFAType() == UnwindPlan::Row::CFAIsRegisterDereferenced) + case UnwindPlan::Row::CFAValue::isRegisterDereferenced: { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex (cfa_reg.GetAsKind (eRegisterKindLLDB)); - RegisterValue reg_value; - if (reg_info) + RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFAValue().GetRegisterNumber()); + if (ReadGPRValue (cfa_reg, cfa_reg_contents)) { - Error error = ReadRegisterValueFromMemory(reg_info, - cfa_reg_contents, - reg_info->byte_size, - reg_value); - if (error.Success ()) + const RegisterInfo *reg_info = GetRegisterInfoAtIndex (cfa_reg.GetAsKind (eRegisterKindLLDB)); + RegisterValue reg_value; + if (reg_info) { - cfa_value = reg_value.GetAsUInt64(); - UnwindLogMsg ("CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 ", CFA value is 0x%" PRIx64, - cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), - cfa_reg_contents, cfa_value); - return true; + Error error = ReadRegisterValueFromMemory(reg_info, + cfa_reg_contents, + reg_info->byte_size, + reg_value); + if (error.Success ()) + { + cfa_value = reg_value.GetAsUInt64(); + UnwindLogMsg ("CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 ", CFA value is 0x%" PRIx64, + cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), + cfa_reg_contents, cfa_value); + return true; + } + else + { + UnwindLogMsg ("Tried to deref reg %s (%d) [0x%" PRIx64 "] but memory read failed.", + cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), + cfa_reg_contents); + } } - else + } + break; + } + case UnwindPlan::Row::CFAValue::isRegisterPlusOffset: + { + RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFAValue().GetRegisterNumber()); + if (ReadGPRValue (cfa_reg, cfa_reg_contents)) + { + if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1) { - UnwindLogMsg ("Tried to deref reg %s (%d) [0x%" PRIx64 "] but memory read failed.", + UnwindLogMsg ("Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64, cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), cfa_reg_contents); + cfa_reg_contents = LLDB_INVALID_ADDRESS; + return false; } + cfa_value = cfa_reg_contents + row->GetCFAValue().GetOffset(); + UnwindLogMsg ("CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64 ", offset is %d", + cfa_value, + cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), + cfa_reg_contents, row->GetCFAValue().GetOffset()); + return true; } + break; } - else + case UnwindPlan::Row::CFAValue::isDWARFExpression: { - if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1) + ExecutionContext exe_ctx(m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + DataExtractor dwarfdata (row->GetCFAValue().GetDWARFExpressionBytes(), + row->GetCFAValue().GetDWARFExpressionLength(), + process->GetByteOrder(), process->GetAddressByteSize()); + ModuleSP opcode_ctx; + DWARFExpression dwarfexpr (opcode_ctx, dwarfdata, 0, row->GetCFAValue().GetDWARFExpressionLength()); + dwarfexpr.SetRegisterKind (row_register_kind); + Value result; + Error error; + if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, this, 0, NULL, result, &error)) { - UnwindLogMsg ("Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64, - cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), - cfa_reg_contents); - cfa_reg_contents = LLDB_INVALID_ADDRESS; - return false; + cfa_value = result.GetScalar().ULongLong(); + + UnwindLogMsg ("CFA value set by DWARF expression is 0x%" PRIx64, cfa_value); + return true; } - cfa_value = cfa_reg_contents + row->GetCFAOffset (); - UnwindLogMsg ("CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64 ", offset is %d", - cfa_value, - cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB), - cfa_reg_contents, row->GetCFAOffset ()); - return true; + UnwindLogMsg ("Failed to set CFA value via DWARF expression: %s", error.AsCString()); + break; } + default: + return false; } return false; } diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp new file mode 100644 index 000000000000..e7784b1712c3 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp @@ -0,0 +1,87 @@ +//===-- RegisterContextLinux_arm.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include <stddef.h> +#include <vector> +#include <cassert> + +#include "llvm/Support/Compiler.h" +#include "lldb/lldb-defines.h" + +#include "RegisterContextLinux_arm.h" + +using namespace lldb; +using namespace lldb_private; + +// Based on RegisterContextDarwin_arm.cpp +#define GPR_OFFSET(idx) ((idx) * 4) +#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR)) +#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU)) +#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextLinux_arm::DBG, reg) + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC))) + +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define REG_CONTEXT_SIZE (sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC)) + +//----------------------------------------------------------------------------- +// Include RegisterInfos_arm to declare our g_register_infos_arm structure. +//----------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_ARM_STRUCT +#include "RegisterInfos_arm.h" +#undef DECLARE_REGISTER_INFOS_ARM_STRUCT + +static const lldb_private::RegisterInfo * +GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::arm: + return g_register_infos_arm; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } +} + +static uint32_t +GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::arm: + return static_cast<uint32_t>(sizeof(g_register_infos_arm) / sizeof(g_register_infos_arm[0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextLinux_arm::RegisterContextLinux_arm(const lldb_private::ArchSpec &target_arch) : + lldb_private::RegisterInfoInterface(target_arch), + m_register_info_p(GetRegisterInfoPtr(target_arch)), + m_register_info_count(GetRegisterInfoCount(target_arch)) +{ +} + +size_t +RegisterContextLinux_arm::GetGPRSize() const +{ + return sizeof(struct RegisterContextLinux_arm::GPR); +} + +const lldb_private::RegisterInfo * +RegisterContextLinux_arm::GetRegisterInfo() const +{ + return m_register_info_p; +} + +uint32_t +RegisterContextLinux_arm::GetRegisterCount() const +{ + return m_register_info_count; +} diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_arm.h b/source/Plugins/Process/Utility/RegisterContextLinux_arm.h new file mode 100644 index 000000000000..7087eb4c3dcc --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextLinux_arm.h @@ -0,0 +1,76 @@ +//===-- RegisterContextLinux_arm.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_RegisterContextLinux_arm_h_ +#define liblldb_RegisterContextLinux_arm_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" +#include "RegisterContextPOSIX.h" +#include "RegisterInfoInterface.h" + +class RegisterContextLinux_arm + : public lldb_private::RegisterInfoInterface +{ +public: + + struct GPR + { + uint32_t r[16]; // R0-R15 + uint32_t cpsr; // CPSR + }; + + + struct QReg + { + uint8_t bytes[16]; + }; + + struct FPU + { + union { + uint32_t s[32]; + uint64_t d[32]; + QReg q[16]; // the 128-bit NEON registers + } floats; + uint32_t fpscr; + }; + struct EXC + { + uint32_t exception; + uint32_t fsr; /* Fault status */ + uint32_t far; /* Virtual Fault Address */ + }; + + struct DBG + { + uint32_t bvr[16]; + uint32_t bcr[16]; + uint32_t wvr[16]; + uint32_t wcr[16]; + }; + + RegisterContextLinux_arm(const lldb_private::ArchSpec &target_arch); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + uint32_t m_register_info_count; +}; + +#endif // liblldb_RegisterContextLinux_arm_h_ + diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp index b38d6cc60cac..4f6bbc8f8ab8 100644 --- a/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp @@ -66,7 +66,7 @@ struct UserArea { GPR regs; // General purpose registers. int32_t fpvalid; // True if FPU is being used. - FPR_i386 i387; // FPU registers. + FPR_i386 i387; // FPU registers. uint32_t tsize; // Text segment size. uint32_t dsize; // Data segment size. uint32_t ssize; // Stack segment size. @@ -112,6 +112,7 @@ RegisterContextLinux_i386::GetRegisterInfo() const switch (m_target_arch.GetMachine()) { case llvm::Triple::x86: + case llvm::Triple::x86_64: return g_register_infos_i386; default: assert(false && "Unhandled target architecture."); diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp new file mode 100644 index 000000000000..948437f51280 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp @@ -0,0 +1,102 @@ +//===-- RegisterContextLinux_mips.cpp ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include <vector> +#include <stddef.h> + +// For GDB, GCC and DWARF Register numbers +#include "RegisterContextLinux_mips.h" + +// Internal codes for mips registers +#include "lldb-mips64-register-enums.h" +#include "RegisterContext_mips64.h" + +using namespace lldb_private; +using namespace lldb; + +// GP registers +typedef struct _GPR +{ + uint32_t zero; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t r12; + uint32_t r13; + uint32_t r14; + uint32_t r15; + uint32_t r16; + uint32_t r17; + uint32_t r18; + uint32_t r19; + uint32_t r20; + uint32_t r21; + uint32_t r22; + uint32_t r23; + uint32_t r24; + uint32_t r25; + uint32_t r26; + uint32_t r27; + uint32_t gp; + uint32_t sp; + uint32_t r30; + uint32_t ra; + uint32_t mullo; + uint32_t mulhi; + uint32_t pc; + uint32_t badvaddr; + uint32_t sr; + uint32_t cause; +} GPR; + +//--------------------------------------------------------------------------- +// Include RegisterInfos_mips to declare our g_register_infos_mips structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_MIPS_STRUCT +#include "RegisterInfos_mips.h" +#undef DECLARE_REGISTER_INFOS_MIPS_STRUCT + +RegisterContextLinux_mips::RegisterContextLinux_mips(const ArchSpec &target_arch) : + RegisterInfoInterface(target_arch) +{ +} + +size_t +RegisterContextLinux_mips::GetGPRSize() const +{ + return sizeof(GPR); +} + +const RegisterInfo * +RegisterContextLinux_mips::GetRegisterInfo() const +{ + switch (m_target_arch.GetMachine()) + { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + return g_register_infos_mips; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } +} + +uint32_t +RegisterContextLinux_mips::GetRegisterCount () const +{ + return static_cast<uint32_t> (sizeof (g_register_infos_mips) / sizeof (g_register_infos_mips [0])); +} diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_mips.h b/source/Plugins/Process/Utility/RegisterContextLinux_mips.h new file mode 100644 index 000000000000..815473e76ddb --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextLinux_mips.h @@ -0,0 +1,32 @@ +//===-- RegisterContextLinux_mips.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_RegisterContextLinux_mips_H_ +#define liblldb_RegisterContextLinux_mips_H_ + +#include "lldb/lldb-private.h" +#include "RegisterInfoInterface.h" + +class RegisterContextLinux_mips + : public lldb_private::RegisterInfoInterface +{ +public: + RegisterContextLinux_mips(const lldb_private::ArchSpec &target_arch); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; +}; + +#endif diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp new file mode 100644 index 000000000000..a762930e8eb4 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp @@ -0,0 +1,143 @@ +//===-- RegisterContextLinux_mips64.cpp ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#if defined (__mips__) + +#include <vector> +#include <stddef.h> + +// For GDB, GCC and DWARF Register numbers +#include "RegisterContextLinux_mips64.h" + +// Internal codes for all mips64 registers +#include "lldb-mips64-register-enums.h" +#include "RegisterContext_mips64.h" + +using namespace lldb; +using namespace lldb_private; + +// GP registers +typedef struct _GPR +{ + uint64_t zero; + uint64_t r1; + uint64_t r2; + uint64_t r3; + uint64_t r4; + uint64_t r5; + uint64_t r6; + uint64_t r7; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t r16; + uint64_t r17; + uint64_t r18; + uint64_t r19; + uint64_t r20; + uint64_t r21; + uint64_t r22; + uint64_t r23; + uint64_t r24; + uint64_t r25; + uint64_t r26; + uint64_t r27; + uint64_t gp; + uint64_t sp; + uint64_t r30; + uint64_t ra; + uint64_t mullo; + uint64_t mulhi; + uint64_t pc; + uint64_t badvaddr; + uint64_t sr; + uint64_t cause; + uint64_t ic; + uint64_t dummy; +} GPR; + +//--------------------------------------------------------------------------- +// Include RegisterInfos_mips64 to declare our g_register_infos_mips64 structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_MIPS64_STRUCT +#include "RegisterInfos_mips64.h" +#undef DECLARE_REGISTER_INFOS_MIPS64_STRUCT + +//--------------------------------------------------------------------------- +// Include RegisterInfos_mips to declare our g_register_infos_mips structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_MIPS_STRUCT +#include "RegisterInfos_mips.h" +#undef DECLARE_REGISTER_INFOS_MIPS_STRUCT + +static const RegisterInfo * +GetRegisterInfoPtr (const ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return g_register_infos_mips64; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + return g_register_infos_mips; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } +} + +static uint32_t +GetRegisterInfoCount (const ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return static_cast<uint32_t> (sizeof (g_register_infos_mips64) / sizeof (g_register_infos_mips64 [0])); + case llvm::Triple::mips: + case llvm::Triple::mipsel: + return static_cast<uint32_t> (sizeof (g_register_infos_mips) / sizeof (g_register_infos_mips [0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextLinux_mips64::RegisterContextLinux_mips64(const ArchSpec &target_arch) : + lldb_private::RegisterInfoInterface(target_arch), + m_register_info_p (GetRegisterInfoPtr (target_arch)), + m_register_info_count (GetRegisterInfoCount (target_arch)) +{ +} + +size_t +RegisterContextLinux_mips64::GetGPRSize() const +{ + return sizeof(GPR); +} + +const RegisterInfo * +RegisterContextLinux_mips64::GetRegisterInfo() const +{ + return m_register_info_p; +} + +uint32_t +RegisterContextLinux_mips64::GetRegisterCount () const +{ + return m_register_info_count; +} + +#endif diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h b/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h new file mode 100644 index 000000000000..546d148eb693 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h @@ -0,0 +1,40 @@ +//===-- RegisterContextLinux_mips64.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#if defined (__mips__) + +#ifndef liblldb_RegisterContextLinux_mips64_H_ +#define liblldb_RegisterContextLinux_mips64_H_ + +#include "lldb/lldb-private.h" +#include "RegisterInfoInterface.h" + +class RegisterContextLinux_mips64 + : public lldb_private::RegisterInfoInterface +{ +public: + RegisterContextLinux_mips64(const lldb_private::ArchSpec &target_arch); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + uint32_t m_register_info_count; +}; + +#endif + +#endif diff --git a/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp index 5c93ebf88faa..c0993b47a126 100644 --- a/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp @@ -46,12 +46,16 @@ typedef struct _GPR uint64_t gs; } GPR; +struct DBG { + uint64_t dr[8]; +}; + struct UserArea { GPR gpr; // General purpose registers. int32_t fpvalid; // True if FPU is being used. int32_t pad0; - FXSAVE i387; // General purpose floating point registers (see FPR for extended register sets). + FXSAVE fpr; // General purpose floating point registers (see FPR for extended register sets). uint64_t tsize; // Text segment size. uint64_t dsize; // Data segment size. uint64_t ssize; // Stack segment size. @@ -64,14 +68,15 @@ struct UserArea FXSAVE* fpstate; // Location of FPR's. uint64_t magic; // Identifier for core dumps. char u_comm[32]; // Command causing core dump. - uint64_t u_debugreg[8]; // Debug registers (DR0 - DR7). + DBG dbg; // Debug registers. uint64_t error_code; // CPU error code. uint64_t fault_address; // Control register CR3. }; -#define DR_SIZE sizeof(((UserArea*)NULL)->u_debugreg[0]) + #define DR_OFFSET(reg_index) \ - (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index])) + (LLVM_EXTENSION offsetof(UserArea, dbg) + \ + LLVM_EXTENSION offsetof(DBG, dr[reg_index])) //--------------------------------------------------------------------------- // Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64 structure. diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp new file mode 100644 index 000000000000..d306f86256bc --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp @@ -0,0 +1,287 @@ +//===-- RegisterContextPOSIX_arm.cpp --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <cstring> +#include <errno.h> +#include <stdint.h> + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Host/Endian.h" +#include "llvm/Support/Compiler.h" + +#include "RegisterContextPOSIX_arm.h" +#include "Plugins/Process/elf-core/ProcessElfCore.h" + +using namespace lldb; +using namespace lldb_private; + +// arm general purpose registers. +const uint32_t g_gpr_regnums_arm[] = +{ + gpr_r0_arm, + gpr_r1_arm, + gpr_r2_arm, + gpr_r3_arm, + gpr_r4_arm, + gpr_r5_arm, + gpr_r6_arm, + gpr_r7_arm, + gpr_r8_arm, + gpr_r9_arm, + gpr_r10_arm, + gpr_r11_arm, + gpr_r12_arm, + gpr_sp_arm, + gpr_lr_arm, + gpr_pc_arm, + gpr_cpsr_arm, + LLDB_INVALID_REGNUM // register sets need to end with this flag + +}; +static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \ + "g_gpr_regnums_arm has wrong number of register infos"); + +// arm floating point registers. +static const uint32_t g_fpu_regnums_arm[] = +{ + fpu_s0_arm, + fpu_s1_arm, + fpu_s2_arm, + fpu_s3_arm, + fpu_s4_arm, + fpu_s5_arm, + fpu_s6_arm, + fpu_s7_arm, + fpu_s8_arm, + fpu_s9_arm, + fpu_s10_arm, + fpu_s11_arm, + fpu_s12_arm, + fpu_s13_arm, + fpu_s14_arm, + fpu_s15_arm, + fpu_s16_arm, + fpu_s17_arm, + fpu_s18_arm, + fpu_s19_arm, + fpu_s20_arm, + fpu_s21_arm, + fpu_s22_arm, + fpu_s23_arm, + fpu_s24_arm, + fpu_s25_arm, + fpu_s26_arm, + fpu_s27_arm, + fpu_s28_arm, + fpu_s29_arm, + fpu_s30_arm, + fpu_s31_arm, + fpu_fpscr_arm, + LLDB_INVALID_REGNUM // register sets need to end with this flag + +}; +static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \ + "g_fpu_regnums_arm has wrong number of register infos"); + +// Number of register sets provided by this context. +enum +{ + k_num_register_sets = 2 +}; + +// Register sets for arm. +static const lldb_private::RegisterSet +g_reg_sets_arm[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm } +}; + +bool RegisterContextPOSIX_arm::IsGPR(unsigned reg) +{ + return reg <= m_reg_info.last_gpr; // GPR's come first. +} + +bool RegisterContextPOSIX_arm::IsFPR(unsigned reg) +{ + return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); +} + +RegisterContextPOSIX_arm::RegisterContextPOSIX_arm(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : lldb_private::RegisterContext(thread, concrete_frame_idx) +{ + m_register_info_ap.reset(register_info); + + switch (register_info->m_target_arch.GetMachine()) + { + case llvm::Triple::arm: + m_reg_info.num_registers = k_num_registers_arm; + m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; + m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; + m_reg_info.last_gpr = k_last_gpr_arm; + m_reg_info.first_fpr = k_first_fpr_arm; + m_reg_info.last_fpr = k_last_fpr_arm; + m_reg_info.first_fpr_v = fpu_s0_arm; + m_reg_info.last_fpr_v = fpu_s31_arm; + m_reg_info.gpr_flags = gpr_cpsr_arm; + break; + default: + assert(false && "Unhandled target architecture."); + break; + } + + ::memset(&m_fpr, 0, sizeof m_fpr); + + // elf-core yet to support ReadFPR() + lldb::ProcessSP base = CalculateProcess(); + if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) + return; +} + +RegisterContextPOSIX_arm::~RegisterContextPOSIX_arm() +{ +} + +void +RegisterContextPOSIX_arm::Invalidate() +{ +} + +void +RegisterContextPOSIX_arm::InvalidateAllRegisters() +{ +} + +unsigned +RegisterContextPOSIX_arm::GetRegisterOffset(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_offset; +} + +unsigned +RegisterContextPOSIX_arm::GetRegisterSize(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_size; +} + +size_t +RegisterContextPOSIX_arm::GetRegisterCount() +{ + size_t num_registers = m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers; + return num_registers; +} + +size_t +RegisterContextPOSIX_arm::GetGPRSize() +{ + return m_register_info_ap->GetGPRSize (); +} + +const lldb_private::RegisterInfo * +RegisterContextPOSIX_arm::GetRegisterInfo() +{ + // Commonly, this method is overridden and g_register_infos is copied and specialized. + // So, use GetRegisterInfo() rather than g_register_infos in this scope. + return m_register_info_ap->GetRegisterInfo (); +} + +const lldb_private::RegisterInfo * +RegisterContextPOSIX_arm::GetRegisterInfoAtIndex(size_t reg) +{ + if (reg < m_reg_info.num_registers) + return &GetRegisterInfo()[reg]; + else + return NULL; +} + +size_t +RegisterContextPOSIX_arm::GetRegisterSetCount() +{ + size_t sets = 0; + for (size_t set = 0; set < k_num_register_sets; ++set) + { + if (IsRegisterSetAvailable(set)) + ++sets; + } + + return sets; +} + +const lldb_private::RegisterSet * +RegisterContextPOSIX_arm::GetRegisterSet(size_t set) +{ + if (IsRegisterSetAvailable(set)) + { + switch (m_register_info_ap->m_target_arch.GetMachine()) + { + case llvm::Triple::arm: + return &g_reg_sets_arm[set]; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } + } + return NULL; +} + +const char * +RegisterContextPOSIX_arm::GetRegisterName(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register offset."); + return GetRegisterInfo()[reg].name; +} + +lldb::ByteOrder +RegisterContextPOSIX_arm::GetByteOrder() +{ + // Get the target process whose privileged thread was used for the register read. + lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; + lldb_private::Process *process = CalculateProcess().get(); + + if (process) + byte_order = process->GetByteOrder(); + return byte_order; +} + +bool +RegisterContextPOSIX_arm::IsRegisterSetAvailable(size_t set_index) +{ + return set_index < k_num_register_sets; +} + + +// Used when parsing DWARF and EH frame information and any other +// object file sections that contain register numbers in them. +uint32_t +RegisterContextPOSIX_arm::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) +{ + const uint32_t num_regs = GetRegisterCount(); + + assert (kind < lldb::kNumRegisterKinds); + for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) + { + const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx); + + if (reg_info->kinds[kind] == num) + return reg_idx; + } + + return LLDB_INVALID_REGNUM; +} + diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h new file mode 100644 index 000000000000..a3a2926262f7 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h @@ -0,0 +1,121 @@ +//===-- RegisterContextPOSIX_arm.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_RegisterContextPOSIX_arm_H_ +#define liblldb_RegisterContextPOSIX_arm_H_ + +#include "lldb/Core/Log.h" +#include "lldb-arm-register-enums.h" +#include "RegisterContextPOSIX.h" + +class ProcessMonitor; + +class RegisterContextPOSIX_arm + : public lldb_private::RegisterContext +{ +public: + RegisterContextPOSIX_arm (lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + + ~RegisterContextPOSIX_arm(); + + void + Invalidate(); + + void + InvalidateAllRegisters(); + + size_t + GetRegisterCount(); + + virtual size_t + GetGPRSize(); + + virtual unsigned + GetRegisterSize(unsigned reg); + + virtual unsigned + GetRegisterOffset(unsigned reg); + + const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex(size_t reg); + + size_t + GetRegisterSetCount(); + + const lldb_private::RegisterSet * + GetRegisterSet(size_t set); + + const char * + GetRegisterName(unsigned reg); + + uint32_t + ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num); + +protected: + struct RegInfo + { + uint32_t num_registers; + uint32_t num_gpr_registers; + uint32_t num_fpr_registers; + + uint32_t last_gpr; + uint32_t first_fpr; + uint32_t last_fpr; + + uint32_t first_fpr_v; + uint32_t last_fpr_v; + + uint32_t gpr_flags; + }; + + struct QReg + { + uint8_t bytes[16]; + }; + + struct FPU + { + union { + uint32_t s[32]; + uint64_t d[32]; + QReg q[16]; // the 128-bit NEON registers + } floats; + uint32_t fpscr; + }; + + uint32_t m_gpr_arm[lldb_private::k_num_gpr_registers_arm]; // 32-bit general purpose registers. + RegInfo m_reg_info; + struct RegisterContextPOSIX_arm::FPU m_fpr; // floating-point registers including extended register sets. + std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) + + // Determines if an extended register set is supported on the processor running the inferior process. + virtual bool + IsRegisterSetAvailable(size_t set_index); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfo(); + + bool + IsGPR(unsigned reg); + + bool + IsFPR(unsigned reg); + + lldb::ByteOrder GetByteOrder(); + + virtual bool ReadGPR() = 0; + virtual bool ReadFPR() = 0; + virtual bool WriteGPR() = 0; + virtual bool WriteFPR() = 0; +}; + +#endif // #ifndef liblldb_RegisterContextPOSIX_arm_H_ + diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp index ea54a9ad9cf4..96508eafcce2 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -23,6 +23,9 @@ #include "RegisterContextPOSIX_arm64.h" #include "Plugins/Process/elf-core/ProcessElfCore.h" +using namespace lldb; +using namespace lldb_private; + // ARM64 general purpose registers. const uint32_t g_gpr_regnums_arm64[] = { diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h index 3639960ef3de..29e7a7d21e02 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h @@ -11,164 +11,11 @@ #define liblldb_RegisterContextPOSIX_arm64_H_ #include "lldb/Core/Log.h" +#include "lldb-arm64-register-enums.h" #include "RegisterContextPOSIX.h" class ProcessMonitor; -//--------------------------------------------------------------------------- -// Internal codes for all ARM64 registers. -//--------------------------------------------------------------------------- -enum -{ - k_first_gpr_arm64, - gpr_x0_arm64 = k_first_gpr_arm64, - gpr_x1_arm64, - gpr_x2_arm64, - gpr_x3_arm64, - gpr_x4_arm64, - gpr_x5_arm64, - gpr_x6_arm64, - gpr_x7_arm64, - gpr_x8_arm64, - gpr_x9_arm64, - gpr_x10_arm64, - gpr_x11_arm64, - gpr_x12_arm64, - gpr_x13_arm64, - gpr_x14_arm64, - gpr_x15_arm64, - gpr_x16_arm64, - gpr_x17_arm64, - gpr_x18_arm64, - gpr_x19_arm64, - gpr_x20_arm64, - gpr_x21_arm64, - gpr_x22_arm64, - gpr_x23_arm64, - gpr_x24_arm64, - gpr_x25_arm64, - gpr_x26_arm64, - gpr_x27_arm64, - gpr_x28_arm64, - gpr_fp_arm64, - gpr_lr_arm64, - gpr_sp_arm64, - gpr_pc_arm64, - gpr_cpsr_arm64, - - k_last_gpr_arm64 = gpr_cpsr_arm64, - - k_first_fpr_arm64, - fpu_v0_arm64 = k_first_fpr_arm64, - fpu_v1_arm64, - fpu_v2_arm64, - fpu_v3_arm64, - fpu_v4_arm64, - fpu_v5_arm64, - fpu_v6_arm64, - fpu_v7_arm64, - fpu_v8_arm64, - fpu_v9_arm64, - fpu_v10_arm64, - fpu_v11_arm64, - fpu_v12_arm64, - fpu_v13_arm64, - fpu_v14_arm64, - fpu_v15_arm64, - fpu_v16_arm64, - fpu_v17_arm64, - fpu_v18_arm64, - fpu_v19_arm64, - fpu_v20_arm64, - fpu_v21_arm64, - fpu_v22_arm64, - fpu_v23_arm64, - fpu_v24_arm64, - fpu_v25_arm64, - fpu_v26_arm64, - fpu_v27_arm64, - fpu_v28_arm64, - fpu_v29_arm64, - fpu_v30_arm64, - fpu_v31_arm64, - fpu_fpsr_arm64, - fpu_fpcr_arm64, - k_last_fpr_arm64 = fpu_fpcr_arm64, - - exc_far_arm64, - exc_esr_arm64, - exc_exception_arm64, - - dbg_bvr0_arm64, - dbg_bvr1_arm64, - dbg_bvr2_arm64, - dbg_bvr3_arm64, - dbg_bvr4_arm64, - dbg_bvr5_arm64, - dbg_bvr6_arm64, - dbg_bvr7_arm64, - dbg_bvr8_arm64, - dbg_bvr9_arm64, - dbg_bvr10_arm64, - dbg_bvr11_arm64, - dbg_bvr12_arm64, - dbg_bvr13_arm64, - dbg_bvr14_arm64, - dbg_bvr15_arm64, - dbg_bcr0_arm64, - dbg_bcr1_arm64, - dbg_bcr2_arm64, - dbg_bcr3_arm64, - dbg_bcr4_arm64, - dbg_bcr5_arm64, - dbg_bcr6_arm64, - dbg_bcr7_arm64, - dbg_bcr8_arm64, - dbg_bcr9_arm64, - dbg_bcr10_arm64, - dbg_bcr11_arm64, - dbg_bcr12_arm64, - dbg_bcr13_arm64, - dbg_bcr14_arm64, - dbg_bcr15_arm64, - dbg_wvr0_arm64, - dbg_wvr1_arm64, - dbg_wvr2_arm64, - dbg_wvr3_arm64, - dbg_wvr4_arm64, - dbg_wvr5_arm64, - dbg_wvr6_arm64, - dbg_wvr7_arm64, - dbg_wvr8_arm64, - dbg_wvr9_arm64, - dbg_wvr10_arm64, - dbg_wvr11_arm64, - dbg_wvr12_arm64, - dbg_wvr13_arm64, - dbg_wvr14_arm64, - dbg_wvr15_arm64, - dbg_wcr0_arm64, - dbg_wcr1_arm64, - dbg_wcr2_arm64, - dbg_wcr3_arm64, - dbg_wcr4_arm64, - dbg_wcr5_arm64, - dbg_wcr6_arm64, - dbg_wcr7_arm64, - dbg_wcr8_arm64, - dbg_wcr9_arm64, - dbg_wcr10_arm64, - dbg_wcr11_arm64, - dbg_wcr12_arm64, - dbg_wcr13_arm64, - dbg_wcr14_arm64, - dbg_wcr15_arm64, - - k_num_registers_arm64, - k_num_gpr_registers_arm64 = k_last_gpr_arm64 - k_first_gpr_arm64 + 1, - k_num_fpr_registers_arm64 = k_last_fpr_arm64 - k_first_fpr_arm64 + 1 -}; - class RegisterContextPOSIX_arm64 : public lldb_private::RegisterContext { @@ -243,9 +90,9 @@ protected: uint32_t fpcr; }; - uint64_t m_gpr_arm64[k_num_gpr_registers_arm64]; // 64-bit general purpose registers. + uint64_t m_gpr_arm64[lldb_private::k_num_gpr_registers_arm64]; // 64-bit general purpose registers. RegInfo m_reg_info; - struct RegisterContextPOSIX_arm64::FPU m_fpr; // floating-point registers including extended register sets. + struct RegisterContextPOSIX_arm64::FPU m_fpr; // floating-point registers including extended register sets. std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) // Determines if an extended register set is supported on the processor running the inferior process. diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h index 991179bdec66..2a61685f12ac 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h @@ -13,59 +13,11 @@ #include "lldb/Core/Log.h" #include "RegisterContextPOSIX.h" #include "RegisterContext_mips64.h" +#include "lldb-mips64-register-enums.h" -class ProcessMonitor; +using namespace lldb_private; -// --------------------------------------------------------------------------- -// Internal codes for all mips64 registers. -// --------------------------------------------------------------------------- -enum -{ - k_first_gpr_mips64, - gpr_zero_mips64 = k_first_gpr_mips64, - gpr_r1_mips64, - gpr_r2_mips64, - gpr_r3_mips64, - gpr_r4_mips64, - gpr_r5_mips64, - gpr_r6_mips64, - gpr_r7_mips64, - gpr_r8_mips64, - gpr_r9_mips64, - gpr_r10_mips64, - gpr_r11_mips64, - gpr_r12_mips64, - gpr_r13_mips64, - gpr_r14_mips64, - gpr_r15_mips64, - gpr_r16_mips64, - gpr_r17_mips64, - gpr_r18_mips64, - gpr_r19_mips64, - gpr_r20_mips64, - gpr_r21_mips64, - gpr_r22_mips64, - gpr_r23_mips64, - gpr_r24_mips64, - gpr_r25_mips64, - gpr_r26_mips64, - gpr_r27_mips64, - gpr_gp_mips64, - gpr_sp_mips64, - gpr_r30_mips64, - gpr_ra_mips64, - gpr_sr_mips64, - gpr_mullo_mips64, - gpr_mulhi_mips64, - gpr_badvaddr_mips64, - gpr_cause_mips64, - gpr_pc_mips64, - gpr_ic_mips64, - gpr_dummy_mips64, - - k_num_registers_mips64, - k_num_gpr_registers_mips64 = k_num_registers_mips64 -}; +class ProcessMonitor; class RegisterContextPOSIX_mips64 : public lldb_private::RegisterContext diff --git a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp index 828fb2571f79..e353e8114765 100644 --- a/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp +++ b/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp @@ -159,9 +159,10 @@ g_reg_sets_powerpc[k_num_register_sets] = { "Altivec/VMX Registers", "vmx", k_num_vmx_registers_powerpc, g_vmx_regnums }, }; +static_assert(k_first_gpr_powerpc == 0, "GPRs must index starting at 0, or fix IsGPR()"); bool RegisterContextPOSIX_powerpc::IsGPR(unsigned reg) { - return (reg >= k_first_gpr_powerpc) && (reg <= k_last_gpr_powerpc); // GPR's come first. + return (reg <= k_last_gpr_powerpc); // GPR's come first. } bool diff --git a/source/Plugins/Process/Utility/RegisterContext_mips64.h b/source/Plugins/Process/Utility/RegisterContext_mips64.h index dfd473d7cbec..96ce2a0acc5b 100644 --- a/source/Plugins/Process/Utility/RegisterContext_mips64.h +++ b/source/Plugins/Process/Utility/RegisterContext_mips64.h @@ -14,6 +14,84 @@ enum { // GP Registers + gcc_dwarf_zero_mips = 0, + gcc_dwarf_r1_mips, + gcc_dwarf_r2_mips, + gcc_dwarf_r3_mips, + gcc_dwarf_r4_mips, + gcc_dwarf_r5_mips, + gcc_dwarf_r6_mips, + gcc_dwarf_r7_mips, + gcc_dwarf_r8_mips, + gcc_dwarf_r9_mips, + gcc_dwarf_r10_mips, + gcc_dwarf_r11_mips, + gcc_dwarf_r12_mips, + gcc_dwarf_r13_mips, + gcc_dwarf_r14_mips, + gcc_dwarf_r15_mips, + gcc_dwarf_r16_mips, + gcc_dwarf_r17_mips, + gcc_dwarf_r18_mips, + gcc_dwarf_r19_mips, + gcc_dwarf_r20_mips, + gcc_dwarf_r21_mips, + gcc_dwarf_r22_mips, + gcc_dwarf_r23_mips, + gcc_dwarf_r24_mips, + gcc_dwarf_r25_mips, + gcc_dwarf_r26_mips, + gcc_dwarf_r27_mips, + gcc_dwarf_gp_mips, + gcc_dwarf_sp_mips, + gcc_dwarf_r30_mips, + gcc_dwarf_ra_mips, + gcc_dwarf_lo_mips, + gcc_dwarf_hi_mips, + gcc_dwarf_pc_mips, + gcc_dwarf_bad_mips, + gcc_dwarf_sr_mips, + gcc_dwarf_cause_mips, + gcc_dwarf_f0_mips, + gcc_dwarf_f1_mips, + gcc_dwarf_f2_mips, + gcc_dwarf_f3_mips, + gcc_dwarf_f4_mips, + gcc_dwarf_f5_mips, + gcc_dwarf_f6_mips, + gcc_dwarf_f7_mips, + gcc_dwarf_f8_mips, + gcc_dwarf_f9_mips, + gcc_dwarf_f10_mips, + gcc_dwarf_f11_mips, + gcc_dwarf_f12_mips, + gcc_dwarf_f13_mips, + gcc_dwarf_f14_mips, + gcc_dwarf_f15_mips, + gcc_dwarf_f16_mips, + gcc_dwarf_f17_mips, + gcc_dwarf_f18_mips, + gcc_dwarf_f19_mips, + gcc_dwarf_f20_mips, + gcc_dwarf_f21_mips, + gcc_dwarf_f22_mips, + gcc_dwarf_f23_mips, + gcc_dwarf_f24_mips, + gcc_dwarf_f25_mips, + gcc_dwarf_f26_mips, + gcc_dwarf_f27_mips, + gcc_dwarf_f28_mips, + gcc_dwarf_f29_mips, + gcc_dwarf_f30_mips, + gcc_dwarf_f31_mips, + gcc_dwarf_fcsr_mips, + gcc_dwarf_fir_mips, + gcc_dwarf_ic_mips, + gcc_dwarf_dummy_mips +}; + +enum +{ gcc_dwarf_zero_mips64 = 0, gcc_dwarf_r1_mips64, gcc_dwarf_r2_mips64, @@ -52,6 +130,40 @@ enum gcc_dwarf_bad_mips64, gcc_dwarf_cause_mips64, gcc_dwarf_pc_mips64, + gcc_dwarf_f0_mips64, + gcc_dwarf_f1_mips64, + gcc_dwarf_f2_mips64, + gcc_dwarf_f3_mips64, + gcc_dwarf_f4_mips64, + gcc_dwarf_f5_mips64, + gcc_dwarf_f6_mips64, + gcc_dwarf_f7_mips64, + gcc_dwarf_f8_mips64, + gcc_dwarf_f9_mips64, + gcc_dwarf_f10_mips64, + gcc_dwarf_f11_mips64, + gcc_dwarf_f12_mips64, + gcc_dwarf_f13_mips64, + gcc_dwarf_f14_mips64, + gcc_dwarf_f15_mips64, + gcc_dwarf_f16_mips64, + gcc_dwarf_f17_mips64, + gcc_dwarf_f18_mips64, + gcc_dwarf_f19_mips64, + gcc_dwarf_f20_mips64, + gcc_dwarf_f21_mips64, + gcc_dwarf_f22_mips64, + gcc_dwarf_f23_mips64, + gcc_dwarf_f24_mips64, + gcc_dwarf_f25_mips64, + gcc_dwarf_f26_mips64, + gcc_dwarf_f27_mips64, + gcc_dwarf_f28_mips64, + gcc_dwarf_f29_mips64, + gcc_dwarf_f30_mips64, + gcc_dwarf_f31_mips64, + gcc_dwarf_fcsr_mips64, + gcc_dwarf_fir_mips64, gcc_dwarf_ic_mips64, gcc_dwarf_dummy_mips64 }; @@ -59,6 +171,84 @@ enum // GDB Register numbers (eRegisterKindGDB) enum { + gdb_zero_mips = 0, + gdb_r1_mips, + gdb_r2_mips, + gdb_r3_mips, + gdb_r4_mips, + gdb_r5_mips, + gdb_r6_mips, + gdb_r7_mips, + gdb_r8_mips, + gdb_r9_mips, + gdb_r10_mips, + gdb_r11_mips, + gdb_r12_mips, + gdb_r13_mips, + gdb_r14_mips, + gdb_r15_mips, + gdb_r16_mips, + gdb_r17_mips, + gdb_r18_mips, + gdb_r19_mips, + gdb_r20_mips, + gdb_r21_mips, + gdb_r22_mips, + gdb_r23_mips, + gdb_r24_mips, + gdb_r25_mips, + gdb_r26_mips, + gdb_r27_mips, + gdb_gp_mips, + gdb_sp_mips, + gdb_r30_mips, + gdb_ra_mips, + gdb_lo_mips, + gdb_hi_mips, + gdb_pc_mips, + gdb_bad_mips, + gdb_sr_mips, + gdb_cause_mips, + gdb_f0_mips, + gdb_f1_mips, + gdb_f2_mips, + gdb_f3_mips, + gdb_f4_mips, + gdb_f5_mips, + gdb_f6_mips, + gdb_f7_mips, + gdb_f8_mips, + gdb_f9_mips, + gdb_f10_mips, + gdb_f11_mips, + gdb_f12_mips, + gdb_f13_mips, + gdb_f14_mips, + gdb_f15_mips, + gdb_f16_mips, + gdb_f17_mips, + gdb_f18_mips, + gdb_f19_mips, + gdb_f20_mips, + gdb_f21_mips, + gdb_f22_mips, + gdb_f23_mips, + gdb_f24_mips, + gdb_f25_mips, + gdb_f26_mips, + gdb_f27_mips, + gdb_f28_mips, + gdb_f29_mips, + gdb_f30_mips, + gdb_f31_mips, + gdb_fcsr_mips, + gdb_fir_mips, + gdb_ic_mips, + gdb_dummy_mips +}; + +enum +{ gdb_zero_mips64 = 0, gdb_r1_mips64, gdb_r2_mips64, @@ -97,8 +287,50 @@ enum gdb_bad_mips64, gdb_cause_mips64, gdb_pc_mips64, + gdb_f0_mips64, + gdb_f1_mips64, + gdb_f2_mips64, + gdb_f3_mips64, + gdb_f4_mips64, + gdb_f5_mips64, + gdb_f6_mips64, + gdb_f7_mips64, + gdb_f8_mips64, + gdb_f9_mips64, + gdb_f10_mips64, + gdb_f11_mips64, + gdb_f12_mips64, + gdb_f13_mips64, + gdb_f14_mips64, + gdb_f15_mips64, + gdb_f16_mips64, + gdb_f17_mips64, + gdb_f18_mips64, + gdb_f19_mips64, + gdb_f20_mips64, + gdb_f21_mips64, + gdb_f22_mips64, + gdb_f23_mips64, + gdb_f24_mips64, + gdb_f25_mips64, + gdb_f26_mips64, + gdb_f27_mips64, + gdb_f28_mips64, + gdb_f29_mips64, + gdb_f30_mips64, + gdb_f31_mips64, + gdb_fcsr_mips64, + gdb_fir_mips64, gdb_ic_mips64, gdb_dummy_mips64 }; +// FP registers +struct FPR_mips +{ + uint64_t fp_reg[32]; + uint32_t fcsr; /* FPU status register */ + uint32_t fir; /* FPU control register */ +}; + #endif // liblldb_RegisterContext_mips64_H_ diff --git a/source/Plugins/Process/Utility/RegisterInfos_arm.h b/source/Plugins/Process/Utility/RegisterInfos_arm.h new file mode 100644 index 000000000000..3d144d669415 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterInfos_arm.h @@ -0,0 +1,303 @@ +//===-- RegisterInfos_arm.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#ifdef DECLARE_REGISTER_INFOS_ARM_STRUCT + +#include <stddef.h> + +#include "lldb/lldb-private.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" + +#include "Utility/ARM_GCC_Registers.h" +#include "Utility/ARM_DWARF_Registers.h" + +using namespace lldb; +using namespace lldb_private; + +#ifndef GPR_OFFSET +#error GPR_OFFSET must be defined before including this header file +#endif + + +#ifndef FPU_OFFSET +#error FPU_OFFSET must be defined before including this header file +#endif + +#ifndef EXC_OFFSET +#error EXC_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef DBG_OFFSET +#error DBG_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef DEFINE_DBG +#error DEFINE_DBG must be defined before including this header file +#endif + +enum +{ + gpr_r0 = 0, + gpr_r1, + gpr_r2, + gpr_r3, + gpr_r4, + gpr_r5, + gpr_r6, + gpr_r7, + gpr_r8, + gpr_r9, + gpr_r10, + gpr_r11, + gpr_r12, + gpr_r13, gpr_sp = gpr_r13, + gpr_r14, gpr_lr = gpr_r14, + gpr_r15, gpr_pc = gpr_r15, + gpr_cpsr, + + fpu_s0, + fpu_s1, + fpu_s2, + fpu_s3, + fpu_s4, + fpu_s5, + fpu_s6, + fpu_s7, + fpu_s8, + fpu_s9, + fpu_s10, + fpu_s11, + fpu_s12, + fpu_s13, + fpu_s14, + fpu_s15, + fpu_s16, + fpu_s17, + fpu_s18, + fpu_s19, + fpu_s20, + fpu_s21, + fpu_s22, + fpu_s23, + fpu_s24, + fpu_s25, + fpu_s26, + fpu_s27, + fpu_s28, + fpu_s29, + fpu_s30, + fpu_s31, + fpu_fpscr, + + exc_exception, + exc_fsr, + exc_far, + + dbg_bvr0, + dbg_bvr1, + dbg_bvr2, + dbg_bvr3, + dbg_bvr4, + dbg_bvr5, + dbg_bvr6, + dbg_bvr7, + dbg_bvr8, + dbg_bvr9, + dbg_bvr10, + dbg_bvr11, + dbg_bvr12, + dbg_bvr13, + dbg_bvr14, + dbg_bvr15, + + dbg_bcr0, + dbg_bcr1, + dbg_bcr2, + dbg_bcr3, + dbg_bcr4, + dbg_bcr5, + dbg_bcr6, + dbg_bcr7, + dbg_bcr8, + dbg_bcr9, + dbg_bcr10, + dbg_bcr11, + dbg_bcr12, + dbg_bcr13, + dbg_bcr14, + dbg_bcr15, + + dbg_wvr0, + dbg_wvr1, + dbg_wvr2, + dbg_wvr3, + dbg_wvr4, + dbg_wvr5, + dbg_wvr6, + dbg_wvr7, + dbg_wvr8, + dbg_wvr9, + dbg_wvr10, + dbg_wvr11, + dbg_wvr12, + dbg_wvr13, + dbg_wvr14, + dbg_wvr15, + + dbg_wcr0, + dbg_wcr1, + dbg_wcr2, + dbg_wcr3, + dbg_wcr4, + dbg_wcr5, + dbg_wcr6, + dbg_wcr7, + dbg_wcr8, + dbg_wcr9, + dbg_wcr10, + dbg_wcr11, + dbg_wcr12, + dbg_wcr13, + dbg_wcr14, + dbg_wcr15, + + k_num_registers +}; + +static RegisterInfo g_register_infos_arm[] = { +// General purpose registers +// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS +// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== =============== +{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, gdb_arm_r0, gpr_r0 }, NULL, NULL}, +{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, gdb_arm_r1, gpr_r1 }, NULL, NULL}, +{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, gdb_arm_r2, gpr_r2 }, NULL, NULL}, +{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, gdb_arm_r3, gpr_r3 }, NULL, NULL}, +{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, gpr_r4 }, NULL, NULL}, +{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, gpr_r5 }, NULL, NULL}, +{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, gpr_r6 }, NULL, NULL}, +{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_INVALID_REGNUM, gdb_arm_r7, gpr_r7 }, NULL, NULL}, +{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, gpr_r8 }, NULL, NULL}, +{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, gpr_r9 }, NULL, NULL}, +{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, gpr_r10 }, NULL, NULL}, +{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, gdb_arm_r11, gpr_r11 }, NULL, NULL}, +{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, gpr_r12 }, NULL, NULL}, +{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, gpr_sp }, NULL, NULL}, +{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, gpr_lr }, NULL, NULL}, +{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, gpr_pc }, NULL, NULL}, +{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, gpr_cpsr }, NULL, NULL}, + +{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, fpu_s0 }, NULL, NULL}, +{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, fpu_s1 }, NULL, NULL}, +{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, fpu_s2 }, NULL, NULL}, +{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, fpu_s3 }, NULL, NULL}, +{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, fpu_s4 }, NULL, NULL}, +{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, fpu_s5 }, NULL, NULL}, +{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, fpu_s6 }, NULL, NULL}, +{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, fpu_s7 }, NULL, NULL}, +{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, fpu_s8 }, NULL, NULL}, +{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, fpu_s9 }, NULL, NULL}, +{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, fpu_s10 }, NULL, NULL}, +{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, fpu_s11 }, NULL, NULL}, +{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, fpu_s12 }, NULL, NULL}, +{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, fpu_s13 }, NULL, NULL}, +{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, fpu_s14 }, NULL, NULL}, +{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, fpu_s15 }, NULL, NULL}, +{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, fpu_s16 }, NULL, NULL}, +{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, fpu_s17 }, NULL, NULL}, +{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, fpu_s18 }, NULL, NULL}, +{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, fpu_s19 }, NULL, NULL}, +{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, fpu_s20 }, NULL, NULL}, +{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, fpu_s21 }, NULL, NULL}, +{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, fpu_s22 }, NULL, NULL}, +{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, fpu_s23 }, NULL, NULL}, +{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, fpu_s24 }, NULL, NULL}, +{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, fpu_s25 }, NULL, NULL}, +{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, fpu_s26 }, NULL, NULL}, +{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, fpu_s27 }, NULL, NULL}, +{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, fpu_s28 }, NULL, NULL}, +{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, fpu_s29 }, NULL, NULL}, +{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, fpu_s30 }, NULL, NULL}, +{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, fpu_s31 }, NULL, NULL}, +{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, fpu_fpscr }, NULL, NULL}, + +{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL}, +{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL}, +{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL}, + +{ DEFINE_DBG (bvr, 0) }, +{ DEFINE_DBG (bvr, 1) }, +{ DEFINE_DBG (bvr, 2) }, +{ DEFINE_DBG (bvr, 3) }, +{ DEFINE_DBG (bvr, 4) }, +{ DEFINE_DBG (bvr, 5) }, +{ DEFINE_DBG (bvr, 6) }, +{ DEFINE_DBG (bvr, 7) }, +{ DEFINE_DBG (bvr, 8) }, +{ DEFINE_DBG (bvr, 9) }, +{ DEFINE_DBG (bvr, 10) }, +{ DEFINE_DBG (bvr, 11) }, +{ DEFINE_DBG (bvr, 12) }, +{ DEFINE_DBG (bvr, 13) }, +{ DEFINE_DBG (bvr, 14) }, +{ DEFINE_DBG (bvr, 15) }, + +{ DEFINE_DBG (bcr, 0) }, +{ DEFINE_DBG (bcr, 1) }, +{ DEFINE_DBG (bcr, 2) }, +{ DEFINE_DBG (bcr, 3) }, +{ DEFINE_DBG (bcr, 4) }, +{ DEFINE_DBG (bcr, 5) }, +{ DEFINE_DBG (bcr, 6) }, +{ DEFINE_DBG (bcr, 7) }, +{ DEFINE_DBG (bcr, 8) }, +{ DEFINE_DBG (bcr, 9) }, +{ DEFINE_DBG (bcr, 10) }, +{ DEFINE_DBG (bcr, 11) }, +{ DEFINE_DBG (bcr, 12) }, +{ DEFINE_DBG (bcr, 13) }, +{ DEFINE_DBG (bcr, 14) }, +{ DEFINE_DBG (bcr, 15) }, + +{ DEFINE_DBG (wvr, 0) }, +{ DEFINE_DBG (wvr, 1) }, +{ DEFINE_DBG (wvr, 2) }, +{ DEFINE_DBG (wvr, 3) }, +{ DEFINE_DBG (wvr, 4) }, +{ DEFINE_DBG (wvr, 5) }, +{ DEFINE_DBG (wvr, 6) }, +{ DEFINE_DBG (wvr, 7) }, +{ DEFINE_DBG (wvr, 8) }, +{ DEFINE_DBG (wvr, 9) }, +{ DEFINE_DBG (wvr, 10) }, +{ DEFINE_DBG (wvr, 11) }, +{ DEFINE_DBG (wvr, 12) }, +{ DEFINE_DBG (wvr, 13) }, +{ DEFINE_DBG (wvr, 14) }, +{ DEFINE_DBG (wvr, 15) }, + +{ DEFINE_DBG (wcr, 0) }, +{ DEFINE_DBG (wcr, 1) }, +{ DEFINE_DBG (wcr, 2) }, +{ DEFINE_DBG (wcr, 3) }, +{ DEFINE_DBG (wcr, 4) }, +{ DEFINE_DBG (wcr, 5) }, +{ DEFINE_DBG (wcr, 6) }, +{ DEFINE_DBG (wcr, 7) }, +{ DEFINE_DBG (wcr, 8) }, +{ DEFINE_DBG (wcr, 9) }, +{ DEFINE_DBG (wcr, 10) }, +{ DEFINE_DBG (wcr, 11) }, +{ DEFINE_DBG (wcr, 12) }, +{ DEFINE_DBG (wcr, 13) }, +{ DEFINE_DBG (wcr, 14) }, +{ DEFINE_DBG (wcr, 15) } +}; + +#endif // DECLARE_REGISTER_INFOS_ARM_STRUCT diff --git a/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/source/Plugins/Process/Utility/RegisterInfos_arm64.h index b687423622a4..0255a3bc7d60 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_arm64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_arm64.h @@ -198,14 +198,14 @@ static lldb_private::RegisterInfo g_register_infos_arm64[] = { // General purpose registers // NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS // ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== =============== -{ "x0", NULL, 8, GPR_OFFSET(0), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x0, arm64_dwarf::x0, LLDB_INVALID_REGNUM, arm64_gcc::x0, gpr_x0 }, NULL, NULL}, -{ "x1", NULL, 8, GPR_OFFSET(1), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x1, arm64_dwarf::x1, LLDB_INVALID_REGNUM, arm64_gcc::x1, gpr_x1 }, NULL, NULL}, -{ "x2", NULL, 8, GPR_OFFSET(2), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x2, arm64_dwarf::x2, LLDB_INVALID_REGNUM, arm64_gcc::x2, gpr_x2 }, NULL, NULL}, -{ "x3", NULL, 8, GPR_OFFSET(3), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x3, arm64_dwarf::x3, LLDB_INVALID_REGNUM, arm64_gcc::x3, gpr_x3 }, NULL, NULL}, -{ "x4", NULL, 8, GPR_OFFSET(4), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x4, arm64_dwarf::x4, LLDB_INVALID_REGNUM, arm64_gcc::x4, gpr_x4 }, NULL, NULL}, -{ "x5", NULL, 8, GPR_OFFSET(5), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x5, arm64_dwarf::x5, LLDB_INVALID_REGNUM, arm64_gcc::x5, gpr_x5 }, NULL, NULL}, -{ "x6", NULL, 8, GPR_OFFSET(6), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x6, arm64_dwarf::x6, LLDB_INVALID_REGNUM, arm64_gcc::x6, gpr_x6 }, NULL, NULL}, -{ "x7", NULL, 8, GPR_OFFSET(7), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x7, arm64_dwarf::x7, LLDB_INVALID_REGNUM, arm64_gcc::x7, gpr_x7 }, NULL, NULL}, +{ "x0", NULL, 8, GPR_OFFSET(0), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x0, arm64_dwarf::x0, LLDB_REGNUM_GENERIC_ARG1, arm64_gcc::x0, gpr_x0 }, NULL, NULL}, +{ "x1", NULL, 8, GPR_OFFSET(1), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x1, arm64_dwarf::x1, LLDB_REGNUM_GENERIC_ARG2, arm64_gcc::x1, gpr_x1 }, NULL, NULL}, +{ "x2", NULL, 8, GPR_OFFSET(2), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x2, arm64_dwarf::x2, LLDB_REGNUM_GENERIC_ARG3, arm64_gcc::x2, gpr_x2 }, NULL, NULL}, +{ "x3", NULL, 8, GPR_OFFSET(3), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x3, arm64_dwarf::x3, LLDB_REGNUM_GENERIC_ARG4, arm64_gcc::x3, gpr_x3 }, NULL, NULL}, +{ "x4", NULL, 8, GPR_OFFSET(4), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x4, arm64_dwarf::x4, LLDB_REGNUM_GENERIC_ARG5, arm64_gcc::x4, gpr_x4 }, NULL, NULL}, +{ "x5", NULL, 8, GPR_OFFSET(5), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x5, arm64_dwarf::x5, LLDB_REGNUM_GENERIC_ARG6, arm64_gcc::x5, gpr_x5 }, NULL, NULL}, +{ "x6", NULL, 8, GPR_OFFSET(6), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x6, arm64_dwarf::x6, LLDB_REGNUM_GENERIC_ARG7, arm64_gcc::x6, gpr_x6 }, NULL, NULL}, +{ "x7", NULL, 8, GPR_OFFSET(7), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x7, arm64_dwarf::x7, LLDB_REGNUM_GENERIC_ARG8, arm64_gcc::x7, gpr_x7 }, NULL, NULL}, { "x8", NULL, 8, GPR_OFFSET(8), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x8, arm64_dwarf::x8, LLDB_INVALID_REGNUM, arm64_gcc::x8, gpr_x8 }, NULL, NULL}, { "x9", NULL, 8, GPR_OFFSET(9), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x9, arm64_dwarf::x9, LLDB_INVALID_REGNUM, arm64_gcc::x9, gpr_x9 }, NULL, NULL}, { "x10", NULL, 8, GPR_OFFSET(10), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x10, arm64_dwarf::x10, LLDB_INVALID_REGNUM, arm64_gcc::x10, gpr_x10 }, NULL, NULL}, diff --git a/source/Plugins/Process/Utility/RegisterInfos_i386.h b/source/Plugins/Process/Utility/RegisterInfos_i386.h index fc94b8b2a738..69825362134b 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_i386.h +++ b/source/Plugins/Process/Utility/RegisterInfos_i386.h @@ -18,12 +18,16 @@ // Computes the offset of the given FPR in the extended data area. #define FPR_OFFSET(regname) \ - (LLVM_EXTENSION offsetof(FPR, xstate) + \ - LLVM_EXTENSION offsetof(FXSAVE, regname)) + (LLVM_EXTENSION offsetof(UserArea, i387) + \ + LLVM_EXTENSION offsetof(FPR_i386, regname)) // Computes the offset of the YMM register assembled from register halves. -#define YMM_OFFSET(regname) \ - (LLVM_EXTENSION offsetof(YMM, regname)) +// Based on DNBArchImplI386.cpp from debugserver +#define YMM_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(UserArea, i387) + \ + LLVM_EXTENSION offsetof(FPR, xstate) + \ + LLVM_EXTENSION offsetof(FXSAVE, xmm[7]) + \ + sizeof(XMMReg) + (32 * reg_index)) // Number of bytes needed to represent a FPR. #if !defined(FPR_SIZE) @@ -70,7 +74,7 @@ // I believe the YMM registers use dwarf_xmm_%_i386 register numbers and then differentiate based on register size. #define DEFINE_YMM(reg, i) \ - { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \ + { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(i), \ eEncodingVector, eFormatVectorOfUInt8, \ { LLDB_INVALID_REGNUM, dwarf_xmm##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##h_i386, lldb_##reg##i##_i386 }, \ NULL, NULL } diff --git a/source/Plugins/Process/Utility/RegisterInfos_mips.h b/source/Plugins/Process/Utility/RegisterInfos_mips.h new file mode 100644 index 000000000000..0956b2ca9eca --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterInfos_mips.h @@ -0,0 +1,122 @@ +//===-- RegisterInfos_mips.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +#include "llvm/Support/Compiler.h" + +#include <stddef.h> + +#ifdef DECLARE_REGISTER_INFOS_MIPS_STRUCT + +// Computes the offset of the given GPR in the user data area. +#define GPR_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(GPR, regname)) + +// Computes the offset of the given FPR in the extended data area. +#define FPR_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(FPR_mips, regname)) + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips }, NULL, NULL } + +#define DEFINE_FPR(member, reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, sizeof(((FPR_mips*)NULL)->member) / 2, FPR_OFFSET(member), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL } + +#define DEFINE_FPR_INFO(member, reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, sizeof(((FPR_mips*)NULL)->member), FPR_OFFSET(member), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL } + +// RegisterKind: GCC, DWARF, Generic, GDB, LLDB + +static RegisterInfo +g_register_infos_mips[] = +{ + DEFINE_GPR (zero, "zero", gcc_dwarf_zero_mips, gcc_dwarf_zero_mips, LLDB_INVALID_REGNUM, gdb_zero_mips), + DEFINE_GPR (r1, "at", gcc_dwarf_r1_mips, gcc_dwarf_r1_mips, LLDB_INVALID_REGNUM, gdb_r1_mips), + DEFINE_GPR (r2, NULL, gcc_dwarf_r2_mips, gcc_dwarf_r2_mips, LLDB_INVALID_REGNUM, gdb_r2_mips), + DEFINE_GPR (r3, NULL, gcc_dwarf_r3_mips, gcc_dwarf_r3_mips, LLDB_INVALID_REGNUM, gdb_r3_mips), + DEFINE_GPR (r4, NULL, gcc_dwarf_r4_mips, gcc_dwarf_r4_mips, LLDB_REGNUM_GENERIC_ARG1, gdb_r4_mips), + DEFINE_GPR (r5, NULL, gcc_dwarf_r5_mips, gcc_dwarf_r5_mips, LLDB_REGNUM_GENERIC_ARG2, gdb_r5_mips), + DEFINE_GPR (r6, NULL, gcc_dwarf_r6_mips, gcc_dwarf_r6_mips, LLDB_REGNUM_GENERIC_ARG3, gdb_r6_mips), + DEFINE_GPR (r7, NULL, gcc_dwarf_r7_mips, gcc_dwarf_r7_mips, LLDB_REGNUM_GENERIC_ARG4, gdb_r7_mips), + DEFINE_GPR (r8, NULL, gcc_dwarf_r8_mips, gcc_dwarf_r8_mips, LLDB_INVALID_REGNUM, gdb_r8_mips), + DEFINE_GPR (r9, NULL, gcc_dwarf_r9_mips, gcc_dwarf_r9_mips, LLDB_INVALID_REGNUM, gdb_r9_mips), + DEFINE_GPR (r10, NULL, gcc_dwarf_r10_mips, gcc_dwarf_r10_mips, LLDB_INVALID_REGNUM, gdb_r10_mips), + DEFINE_GPR (r11, NULL, gcc_dwarf_r11_mips, gcc_dwarf_r11_mips, LLDB_INVALID_REGNUM, gdb_r11_mips), + DEFINE_GPR (r12, NULL, gcc_dwarf_r12_mips, gcc_dwarf_r12_mips, LLDB_INVALID_REGNUM, gdb_r12_mips), + DEFINE_GPR (r13, NULL, gcc_dwarf_r13_mips, gcc_dwarf_r13_mips, LLDB_INVALID_REGNUM, gdb_r13_mips), + DEFINE_GPR (r14, NULL, gcc_dwarf_r14_mips, gcc_dwarf_r14_mips, LLDB_INVALID_REGNUM, gdb_r14_mips), + DEFINE_GPR (r15, NULL, gcc_dwarf_r15_mips, gcc_dwarf_r15_mips, LLDB_INVALID_REGNUM, gdb_r15_mips), + DEFINE_GPR (r16, NULL, gcc_dwarf_r16_mips, gcc_dwarf_r16_mips, LLDB_INVALID_REGNUM, gdb_r16_mips), + DEFINE_GPR (r17, NULL, gcc_dwarf_r17_mips, gcc_dwarf_r17_mips, LLDB_INVALID_REGNUM, gdb_r17_mips), + DEFINE_GPR (r18, NULL, gcc_dwarf_r18_mips, gcc_dwarf_r18_mips, LLDB_INVALID_REGNUM, gdb_r18_mips), + DEFINE_GPR (r19, NULL, gcc_dwarf_r19_mips, gcc_dwarf_r19_mips, LLDB_INVALID_REGNUM, gdb_r19_mips), + DEFINE_GPR (r20, NULL, gcc_dwarf_r20_mips, gcc_dwarf_r20_mips, LLDB_INVALID_REGNUM, gdb_r20_mips), + DEFINE_GPR (r21, NULL, gcc_dwarf_r21_mips, gcc_dwarf_r21_mips, LLDB_INVALID_REGNUM, gdb_r21_mips), + DEFINE_GPR (r22, NULL, gcc_dwarf_r22_mips, gcc_dwarf_r22_mips, LLDB_INVALID_REGNUM, gdb_r22_mips), + DEFINE_GPR (r23, NULL, gcc_dwarf_r23_mips, gcc_dwarf_r23_mips, LLDB_INVALID_REGNUM, gdb_r23_mips), + DEFINE_GPR (r24, NULL, gcc_dwarf_r24_mips, gcc_dwarf_r24_mips, LLDB_INVALID_REGNUM, gdb_r24_mips), + DEFINE_GPR (r25, NULL, gcc_dwarf_r25_mips, gcc_dwarf_r25_mips, LLDB_INVALID_REGNUM, gdb_r25_mips), + DEFINE_GPR (r26, NULL, gcc_dwarf_r26_mips, gcc_dwarf_r26_mips, LLDB_INVALID_REGNUM, gdb_r26_mips), + DEFINE_GPR (r27, NULL, gcc_dwarf_r27_mips, gcc_dwarf_r27_mips, LLDB_INVALID_REGNUM, gdb_r27_mips), + DEFINE_GPR (gp, "gp", gcc_dwarf_gp_mips, gcc_dwarf_gp_mips, LLDB_INVALID_REGNUM, gdb_gp_mips), + DEFINE_GPR (sp, "sp", gcc_dwarf_sp_mips, gcc_dwarf_sp_mips, LLDB_REGNUM_GENERIC_SP, gdb_sp_mips), + DEFINE_GPR (r30, "fp", gcc_dwarf_r30_mips, gcc_dwarf_r30_mips, LLDB_REGNUM_GENERIC_FP, gdb_r30_mips), + DEFINE_GPR (ra, "ra", gcc_dwarf_ra_mips, gcc_dwarf_ra_mips, LLDB_REGNUM_GENERIC_RA, gdb_ra_mips), + DEFINE_GPR (mullo, NULL, gcc_dwarf_lo_mips, gcc_dwarf_lo_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR (mulhi, NULL, gcc_dwarf_hi_mips, gcc_dwarf_hi_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR (pc, NULL, gcc_dwarf_pc_mips, gcc_dwarf_pc_mips, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), + DEFINE_GPR (badvaddr, NULL, gcc_dwarf_bad_mips, gcc_dwarf_bad_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR (sr, "status", gcc_dwarf_sr_mips, gcc_dwarf_sr_mips, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), + DEFINE_GPR (cause, NULL, gcc_dwarf_cause_mips, gcc_dwarf_cause_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_FPR (fp_reg[0], f0, NULL, gcc_dwarf_f0_mips, gcc_dwarf_f0_mips, LLDB_INVALID_REGNUM, gdb_f0_mips), + DEFINE_FPR (fp_reg[1], f1, NULL, gcc_dwarf_f1_mips, gcc_dwarf_f1_mips, LLDB_INVALID_REGNUM, gdb_f1_mips), + DEFINE_FPR (fp_reg[2], f2, NULL, gcc_dwarf_f2_mips, gcc_dwarf_f2_mips, LLDB_INVALID_REGNUM, gdb_f2_mips), + DEFINE_FPR (fp_reg[3], f3, NULL, gcc_dwarf_f3_mips, gcc_dwarf_f3_mips, LLDB_INVALID_REGNUM, gdb_f3_mips), + DEFINE_FPR (fp_reg[4], f4, NULL, gcc_dwarf_f4_mips, gcc_dwarf_f4_mips, LLDB_INVALID_REGNUM, gdb_f4_mips), + DEFINE_FPR (fp_reg[5], f5, NULL, gcc_dwarf_f5_mips, gcc_dwarf_f5_mips, LLDB_INVALID_REGNUM, gdb_f5_mips), + DEFINE_FPR (fp_reg[6], f6, NULL, gcc_dwarf_f6_mips, gcc_dwarf_f6_mips, LLDB_INVALID_REGNUM, gdb_f6_mips), + DEFINE_FPR (fp_reg[7], f7, NULL, gcc_dwarf_f7_mips, gcc_dwarf_f7_mips, LLDB_INVALID_REGNUM, gdb_f7_mips), + DEFINE_FPR (fp_reg[8], f8, NULL, gcc_dwarf_f8_mips, gcc_dwarf_f8_mips, LLDB_INVALID_REGNUM, gdb_f8_mips), + DEFINE_FPR (fp_reg[9], f9, NULL, gcc_dwarf_f9_mips, gcc_dwarf_f9_mips, LLDB_INVALID_REGNUM, gdb_f9_mips), + DEFINE_FPR (fp_reg[10], f10, NULL, gcc_dwarf_f10_mips, gcc_dwarf_f10_mips, LLDB_INVALID_REGNUM, gdb_f10_mips), + DEFINE_FPR (fp_reg[11], f11, NULL, gcc_dwarf_f11_mips, gcc_dwarf_f11_mips, LLDB_INVALID_REGNUM, gdb_f11_mips), + DEFINE_FPR (fp_reg[12], f12, NULL, gcc_dwarf_f12_mips, gcc_dwarf_f12_mips, LLDB_INVALID_REGNUM, gdb_f12_mips), + DEFINE_FPR (fp_reg[13], f13, NULL, gcc_dwarf_f13_mips, gcc_dwarf_f13_mips, LLDB_INVALID_REGNUM, gdb_f13_mips), + DEFINE_FPR (fp_reg[14], f14, NULL, gcc_dwarf_f14_mips, gcc_dwarf_f14_mips, LLDB_INVALID_REGNUM, gdb_f14_mips), + DEFINE_FPR (fp_reg[15], f15, NULL, gcc_dwarf_f15_mips, gcc_dwarf_f15_mips, LLDB_INVALID_REGNUM, gdb_f15_mips), + DEFINE_FPR (fp_reg[16], f16, NULL, gcc_dwarf_f16_mips, gcc_dwarf_f16_mips, LLDB_INVALID_REGNUM, gdb_f16_mips), + DEFINE_FPR (fp_reg[17], f17, NULL, gcc_dwarf_f17_mips, gcc_dwarf_f17_mips, LLDB_INVALID_REGNUM, gdb_f17_mips), + DEFINE_FPR (fp_reg[18], f18, NULL, gcc_dwarf_f18_mips, gcc_dwarf_f18_mips, LLDB_INVALID_REGNUM, gdb_f18_mips), + DEFINE_FPR (fp_reg[19], f19, NULL, gcc_dwarf_f19_mips, gcc_dwarf_f19_mips, LLDB_INVALID_REGNUM, gdb_f19_mips), + DEFINE_FPR (fp_reg[20], f20, NULL, gcc_dwarf_f20_mips, gcc_dwarf_f20_mips, LLDB_INVALID_REGNUM, gdb_f20_mips), + DEFINE_FPR (fp_reg[21], f21, NULL, gcc_dwarf_f21_mips, gcc_dwarf_f21_mips, LLDB_INVALID_REGNUM, gdb_f21_mips), + DEFINE_FPR (fp_reg[22], f22, NULL, gcc_dwarf_f22_mips, gcc_dwarf_f22_mips, LLDB_INVALID_REGNUM, gdb_f22_mips), + DEFINE_FPR (fp_reg[23], f23, NULL, gcc_dwarf_f23_mips, gcc_dwarf_f23_mips, LLDB_INVALID_REGNUM, gdb_f23_mips), + DEFINE_FPR (fp_reg[24], f24, NULL, gcc_dwarf_f24_mips, gcc_dwarf_f24_mips, LLDB_INVALID_REGNUM, gdb_f24_mips), + DEFINE_FPR (fp_reg[25], f25, NULL, gcc_dwarf_f25_mips, gcc_dwarf_f25_mips, LLDB_INVALID_REGNUM, gdb_f25_mips), + DEFINE_FPR (fp_reg[26], f26, NULL, gcc_dwarf_f26_mips, gcc_dwarf_f26_mips, LLDB_INVALID_REGNUM, gdb_f26_mips), + DEFINE_FPR (fp_reg[27], f27, NULL, gcc_dwarf_f27_mips, gcc_dwarf_f27_mips, LLDB_INVALID_REGNUM, gdb_f27_mips), + DEFINE_FPR (fp_reg[28], f28, NULL, gcc_dwarf_f28_mips, gcc_dwarf_f28_mips, LLDB_INVALID_REGNUM, gdb_f28_mips), + DEFINE_FPR (fp_reg[29], f29, NULL, gcc_dwarf_f29_mips, gcc_dwarf_f29_mips, LLDB_INVALID_REGNUM, gdb_f29_mips), + DEFINE_FPR (fp_reg[30], f30, NULL, gcc_dwarf_f30_mips, gcc_dwarf_f30_mips, LLDB_INVALID_REGNUM, gdb_f30_mips), + DEFINE_FPR (fp_reg[31], f31, NULL, gcc_dwarf_f31_mips, gcc_dwarf_f31_mips, LLDB_INVALID_REGNUM, gdb_f31_mips), + DEFINE_FPR_INFO (fcsr, fcsr, NULL, gcc_dwarf_fcsr_mips, gcc_dwarf_fcsr_mips, LLDB_INVALID_REGNUM, gdb_fcsr_mips), + DEFINE_FPR_INFO (fir, fir, NULL, gcc_dwarf_fir_mips, gcc_dwarf_fir_mips, LLDB_INVALID_REGNUM, gdb_fir_mips) +}; +static_assert((sizeof(g_register_infos_mips) / sizeof(g_register_infos_mips[0])) == k_num_registers_mips, + "g_register_infos_mips has wrong number of register infos"); + +#undef GPR_OFFSET +#undef FPR_OFFSET +#undef DEFINE_GPR +#undef DEFINE_FPR + +#endif // DECLARE_REGISTER_INFOS_MIPS_STRUCT diff --git a/source/Plugins/Process/Utility/RegisterInfos_mips64.h b/source/Plugins/Process/Utility/RegisterInfos_mips64.h index 187b8e98332e..e03aea4e3f2c 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_mips64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_mips64.h @@ -6,20 +6,31 @@ // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// +#include "llvm/Support/Compiler.h" #include <stddef.h> +#ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT + // Computes the offset of the given GPR in the user data area. -#define GPR_OFFSET(regname) \ - (offsetof(GPR, regname)) +#define GPR_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(GPR, regname)) -#ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT +// Computes the offset of the given FPR in the extended data area. +#define FPR_OFFSET(regname) \ + LLVM_EXTENSION offsetof(FPR_mips, regname) \ + +// RegisterKind: GCC, DWARF, Generic, GDB, LLDB // Note that the size and offset will be updated by platform-specific classes. -#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, sizeof(((GPR*)0)->reg), GPR_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL } +#define DEFINE_FPR(member, reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, sizeof(((FPR_mips*)0)->member), FPR_OFFSET(member), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL } + static RegisterInfo g_register_infos_mips64[] = { @@ -28,14 +39,14 @@ g_register_infos_mips64[] = DEFINE_GPR(r1, NULL, gcc_dwarf_r1_mips64, gcc_dwarf_r1_mips64, LLDB_INVALID_REGNUM, gdb_r1_mips64), DEFINE_GPR(r2, NULL, gcc_dwarf_r2_mips64, gcc_dwarf_r2_mips64, LLDB_INVALID_REGNUM, gdb_r2_mips64), DEFINE_GPR(r3, NULL, gcc_dwarf_r3_mips64, gcc_dwarf_r3_mips64, LLDB_INVALID_REGNUM, gdb_r3_mips64), - DEFINE_GPR(r4, NULL, gcc_dwarf_r4_mips64, gcc_dwarf_r4_mips64, LLDB_INVALID_REGNUM, gdb_r4_mips64), - DEFINE_GPR(r5, NULL, gcc_dwarf_r5_mips64, gcc_dwarf_r5_mips64, LLDB_INVALID_REGNUM, gdb_r5_mips64), - DEFINE_GPR(r6, NULL, gcc_dwarf_r6_mips64, gcc_dwarf_r6_mips64, LLDB_INVALID_REGNUM, gdb_r6_mips64), - DEFINE_GPR(r7, NULL, gcc_dwarf_r7_mips64, gcc_dwarf_r7_mips64, LLDB_INVALID_REGNUM, gdb_r7_mips64), - DEFINE_GPR(r8, NULL, gcc_dwarf_r8_mips64, gcc_dwarf_r8_mips64, LLDB_INVALID_REGNUM, gdb_r8_mips64), - DEFINE_GPR(r9, NULL, gcc_dwarf_r9_mips64, gcc_dwarf_r9_mips64, LLDB_INVALID_REGNUM, gdb_r9_mips64), - DEFINE_GPR(r10, NULL, gcc_dwarf_r10_mips64, gcc_dwarf_r10_mips64, LLDB_INVALID_REGNUM, gdb_r10_mips64), - DEFINE_GPR(r11, NULL, gcc_dwarf_r11_mips64, gcc_dwarf_r11_mips64, LLDB_INVALID_REGNUM, gdb_r11_mips64), + DEFINE_GPR(r4, NULL, gcc_dwarf_r4_mips64, gcc_dwarf_r4_mips64, LLDB_REGNUM_GENERIC_ARG1, gdb_r4_mips64), + DEFINE_GPR(r5, NULL, gcc_dwarf_r5_mips64, gcc_dwarf_r5_mips64, LLDB_REGNUM_GENERIC_ARG2, gdb_r5_mips64), + DEFINE_GPR(r6, NULL, gcc_dwarf_r6_mips64, gcc_dwarf_r6_mips64, LLDB_REGNUM_GENERIC_ARG3, gdb_r6_mips64), + DEFINE_GPR(r7, NULL, gcc_dwarf_r7_mips64, gcc_dwarf_r7_mips64, LLDB_REGNUM_GENERIC_ARG4, gdb_r7_mips64), + DEFINE_GPR(r8, NULL, gcc_dwarf_r8_mips64, gcc_dwarf_r8_mips64, LLDB_REGNUM_GENERIC_ARG5, gdb_r8_mips64), + DEFINE_GPR(r9, NULL, gcc_dwarf_r9_mips64, gcc_dwarf_r9_mips64, LLDB_REGNUM_GENERIC_ARG6, gdb_r9_mips64), + DEFINE_GPR(r10, NULL, gcc_dwarf_r10_mips64, gcc_dwarf_r10_mips64, LLDB_REGNUM_GENERIC_ARG7, gdb_r10_mips64), + DEFINE_GPR(r11, NULL, gcc_dwarf_r11_mips64, gcc_dwarf_r11_mips64, LLDB_REGNUM_GENERIC_ARG8, gdb_r11_mips64), DEFINE_GPR(r12, NULL, gcc_dwarf_r12_mips64, gcc_dwarf_r12_mips64, LLDB_INVALID_REGNUM, gdb_r12_mips64), DEFINE_GPR(r13, NULL, gcc_dwarf_r13_mips64, gcc_dwarf_r13_mips64, LLDB_INVALID_REGNUM, gdb_r13_mips64), DEFINE_GPR(r14, NULL, gcc_dwarf_r14_mips64, gcc_dwarf_r14_mips64, LLDB_INVALID_REGNUM, gdb_r14_mips64), @@ -54,23 +65,58 @@ g_register_infos_mips64[] = DEFINE_GPR(r27, NULL, gcc_dwarf_r27_mips64, gcc_dwarf_r27_mips64, LLDB_INVALID_REGNUM, gdb_r27_mips64), DEFINE_GPR(gp, "r28", gcc_dwarf_gp_mips64, gcc_dwarf_gp_mips64, LLDB_INVALID_REGNUM, gdb_gp_mips64), DEFINE_GPR(sp, "r29", gcc_dwarf_sp_mips64, gcc_dwarf_sp_mips64, LLDB_REGNUM_GENERIC_SP, gdb_sp_mips64), - DEFINE_GPR(r30, NULL, gcc_dwarf_r30_mips64, gcc_dwarf_r30_mips64, LLDB_INVALID_REGNUM, gdb_r30_mips64), - DEFINE_GPR(ra, "r31", gcc_dwarf_ra_mips64, gcc_dwarf_ra_mips64, LLDB_INVALID_REGNUM, gdb_ra_mips64), - DEFINE_GPR(sr, NULL, gcc_dwarf_sr_mips64, gcc_dwarf_sr_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(r30, NULL, gcc_dwarf_r30_mips64, gcc_dwarf_r30_mips64, LLDB_REGNUM_GENERIC_FP, gdb_r30_mips64), + DEFINE_GPR(ra, "r31", gcc_dwarf_ra_mips64, gcc_dwarf_ra_mips64, LLDB_REGNUM_GENERIC_RA, gdb_ra_mips64), DEFINE_GPR(mullo, NULL, gcc_dwarf_lo_mips64, gcc_dwarf_lo_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(mulhi, NULL, gcc_dwarf_hi_mips64, gcc_dwarf_hi_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(pc, "pc", gcc_dwarf_pc_mips64, gcc_dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), DEFINE_GPR(badvaddr, NULL, gcc_dwarf_bad_mips64, gcc_dwarf_bad_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(sr, NULL, gcc_dwarf_sr_mips64, gcc_dwarf_sr_mips64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), DEFINE_GPR(cause, NULL, gcc_dwarf_cause_mips64, gcc_dwarf_cause_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(pc, "pc", gcc_dwarf_pc_mips64, gcc_dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), DEFINE_GPR(ic, NULL, gcc_dwarf_ic_mips64, gcc_dwarf_ic_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(dummy, NULL, gcc_dwarf_dummy_mips64, gcc_dwarf_dummy_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + + DEFINE_FPR (fp_reg[0], f0, NULL, gcc_dwarf_f0_mips64, gcc_dwarf_f0_mips64, LLDB_INVALID_REGNUM, gdb_f0_mips64), + DEFINE_FPR (fp_reg[1], f1, NULL, gcc_dwarf_f1_mips64, gcc_dwarf_f1_mips64, LLDB_INVALID_REGNUM, gdb_f1_mips64), + DEFINE_FPR (fp_reg[2], f2, NULL, gcc_dwarf_f2_mips64, gcc_dwarf_f2_mips64, LLDB_INVALID_REGNUM, gdb_f2_mips64), + DEFINE_FPR (fp_reg[3], f3, NULL, gcc_dwarf_f3_mips64, gcc_dwarf_f3_mips64, LLDB_INVALID_REGNUM, gdb_f3_mips64), + DEFINE_FPR (fp_reg[4], f4, NULL, gcc_dwarf_f4_mips64, gcc_dwarf_f4_mips64, LLDB_INVALID_REGNUM, gdb_f4_mips64), + DEFINE_FPR (fp_reg[5], f5, NULL, gcc_dwarf_f5_mips64, gcc_dwarf_f5_mips64, LLDB_INVALID_REGNUM, gdb_f5_mips64), + DEFINE_FPR (fp_reg[6], f6, NULL, gcc_dwarf_f6_mips64, gcc_dwarf_f6_mips64, LLDB_INVALID_REGNUM, gdb_f6_mips64), + DEFINE_FPR (fp_reg[7], f7, NULL, gcc_dwarf_f7_mips64, gcc_dwarf_f7_mips64, LLDB_INVALID_REGNUM, gdb_f7_mips64), + DEFINE_FPR (fp_reg[8], f8, NULL, gcc_dwarf_f8_mips64, gcc_dwarf_f8_mips64, LLDB_INVALID_REGNUM, gdb_f8_mips64), + DEFINE_FPR (fp_reg[9], f9, NULL, gcc_dwarf_f9_mips64, gcc_dwarf_f9_mips64, LLDB_INVALID_REGNUM, gdb_f9_mips64), + DEFINE_FPR (fp_reg[10], f10, NULL, gcc_dwarf_f10_mips64, gcc_dwarf_f10_mips64, LLDB_INVALID_REGNUM, gdb_f10_mips64), + DEFINE_FPR (fp_reg[11], f11, NULL, gcc_dwarf_f11_mips64, gcc_dwarf_f11_mips64, LLDB_INVALID_REGNUM, gdb_f11_mips64), + DEFINE_FPR (fp_reg[12], f12, NULL, gcc_dwarf_f12_mips64, gcc_dwarf_f12_mips64, LLDB_INVALID_REGNUM, gdb_f12_mips64), + DEFINE_FPR (fp_reg[13], f13, NULL, gcc_dwarf_f13_mips64, gcc_dwarf_f13_mips64, LLDB_INVALID_REGNUM, gdb_f13_mips64), + DEFINE_FPR (fp_reg[14], f14, NULL, gcc_dwarf_f14_mips64, gcc_dwarf_f14_mips64, LLDB_INVALID_REGNUM, gdb_f14_mips64), + DEFINE_FPR (fp_reg[15], f15, NULL, gcc_dwarf_f15_mips64, gcc_dwarf_f15_mips64, LLDB_INVALID_REGNUM, gdb_f15_mips64), + DEFINE_FPR (fp_reg[16], f16, NULL, gcc_dwarf_f16_mips64, gcc_dwarf_f16_mips64, LLDB_INVALID_REGNUM, gdb_f16_mips64), + DEFINE_FPR (fp_reg[17], f17, NULL, gcc_dwarf_f17_mips64, gcc_dwarf_f17_mips64, LLDB_INVALID_REGNUM, gdb_f17_mips64), + DEFINE_FPR (fp_reg[18], f18, NULL, gcc_dwarf_f18_mips64, gcc_dwarf_f18_mips64, LLDB_INVALID_REGNUM, gdb_f18_mips64), + DEFINE_FPR (fp_reg[19], f19, NULL, gcc_dwarf_f19_mips64, gcc_dwarf_f19_mips64, LLDB_INVALID_REGNUM, gdb_f19_mips64), + DEFINE_FPR (fp_reg[20], f20, NULL, gcc_dwarf_f20_mips64, gcc_dwarf_f20_mips64, LLDB_INVALID_REGNUM, gdb_f20_mips64), + DEFINE_FPR (fp_reg[21], f21, NULL, gcc_dwarf_f21_mips64, gcc_dwarf_f21_mips64, LLDB_INVALID_REGNUM, gdb_f21_mips64), + DEFINE_FPR (fp_reg[22], f22, NULL, gcc_dwarf_f22_mips64, gcc_dwarf_f22_mips64, LLDB_INVALID_REGNUM, gdb_f22_mips64), + DEFINE_FPR (fp_reg[23], f23, NULL, gcc_dwarf_f23_mips64, gcc_dwarf_f23_mips64, LLDB_INVALID_REGNUM, gdb_f23_mips64), + DEFINE_FPR (fp_reg[24], f24, NULL, gcc_dwarf_f24_mips64, gcc_dwarf_f24_mips64, LLDB_INVALID_REGNUM, gdb_f24_mips64), + DEFINE_FPR (fp_reg[25], f25, NULL, gcc_dwarf_f25_mips64, gcc_dwarf_f25_mips64, LLDB_INVALID_REGNUM, gdb_f25_mips64), + DEFINE_FPR (fp_reg[26], f26, NULL, gcc_dwarf_f26_mips64, gcc_dwarf_f26_mips64, LLDB_INVALID_REGNUM, gdb_f26_mips64), + DEFINE_FPR (fp_reg[27], f27, NULL, gcc_dwarf_f27_mips64, gcc_dwarf_f27_mips64, LLDB_INVALID_REGNUM, gdb_f27_mips64), + DEFINE_FPR (fp_reg[28], f28, NULL, gcc_dwarf_f28_mips64, gcc_dwarf_f28_mips64, LLDB_INVALID_REGNUM, gdb_f28_mips64), + DEFINE_FPR (fp_reg[29], f29, NULL, gcc_dwarf_f29_mips64, gcc_dwarf_f29_mips64, LLDB_INVALID_REGNUM, gdb_f29_mips64), + DEFINE_FPR (fp_reg[30], f30, NULL, gcc_dwarf_f30_mips64, gcc_dwarf_f30_mips64, LLDB_INVALID_REGNUM, gdb_f30_mips64), + DEFINE_FPR (fp_reg[31], f31, NULL, gcc_dwarf_f31_mips64, gcc_dwarf_f31_mips64, LLDB_INVALID_REGNUM, gdb_f31_mips64), + DEFINE_FPR (fcsr, fcsr, NULL, gcc_dwarf_fcsr_mips64, gcc_dwarf_fcsr_mips64, LLDB_INVALID_REGNUM, gdb_fcsr_mips64), + DEFINE_FPR (fir, fir, NULL, gcc_dwarf_fir_mips64, gcc_dwarf_fir_mips64, LLDB_INVALID_REGNUM, gdb_fir_mips64) }; static_assert((sizeof(g_register_infos_mips64) / sizeof(g_register_infos_mips64[0])) == k_num_registers_mips64, "g_register_infos_mips64 has wrong number of register infos"); #undef DEFINE_GPR - -#endif // DECLARE_REGISTER_INFOS_MIPS64_STRUCT - +#undef DEFINE_FPR #undef GPR_OFFSET +#undef FPR_OFFSET +#endif // DECLARE_REGISTER_INFOS_MIPS64_STRUCT diff --git a/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h index c1bcd27053c6..5da74ff83487 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_x86_64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_x86_64.h @@ -16,12 +16,17 @@ // Computes the offset of the given FPR in the extended data area. #define FPR_OFFSET(regname) \ - (LLVM_EXTENSION offsetof(FPR, xstate) + \ + (LLVM_EXTENSION offsetof(UserArea, fpr) + \ + LLVM_EXTENSION offsetof(FPR, xstate) + \ LLVM_EXTENSION offsetof(FXSAVE, regname)) // Computes the offset of the YMM register assembled from register halves. -#define YMM_OFFSET(regname) \ - (LLVM_EXTENSION offsetof(YMM, regname)) +// Based on DNBArchImplX86_64.cpp from debugserver +#define YMM_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(UserArea, fpr) + \ + LLVM_EXTENSION offsetof(FPR, xstate) + \ + LLVM_EXTENSION offsetof(XSAVE, ymmh[0]) + \ + (32 * reg_index)) #ifdef DECLARE_REGISTER_INFOS_X86_64_STRUCT @@ -37,6 +42,8 @@ // Number of bytes needed to represent a YMM register. #define YMM_SIZE sizeof(YMMReg) +#define DR_SIZE sizeof(((DBG*)NULL)->dr[0]) + // RegisterKind: GCC, DWARF, Generic, GDB, LLDB // Note that the size and offset will be updated by platform-specific classes. @@ -67,7 +74,7 @@ NULL, NULL } #define DEFINE_YMM(reg, i) \ - { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \ + { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(i), \ eEncodingVector, eFormatVectorOfUInt8, \ { gcc_dwarf_##reg##i##h_x86_64, gcc_dwarf_##reg##i##h_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##h_x86_64, lldb_##reg##i##_x86_64 }, \ NULL, NULL } @@ -298,7 +305,7 @@ do { #define UPDATE_YMM_INFO(reg, i) \ do { \ - g_register_infos[lldb_##reg##i##_i386].byte_offset = YMM_OFFSET(reg[i]); \ + g_register_infos[lldb_##reg##i##_i386].byte_offset = YMM_OFFSET(i); \ } while(false); #define UPDATE_DR_INFO(reg_index) \ diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp index a69b38b6c93e..7c68d0d07821 100644 --- a/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -498,12 +498,15 @@ StopInfoMachException::CreateStopReasonWithMachException // 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. - if (bp_site_sp->ValidForThisThread (&thread)) + // If we have an operating system plug-in, we might have set a thread specific breakpoint using the + // operating system thread ID, so we can't make any assumptions about the thread ID so we must always + // report the breakpoint regardless of the thread. + if (bp_site_sp->ValidForThisThread (&thread) || thread.GetProcess()->GetOperatingSystem () != NULL) return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID()); else return StopInfoSP(); } - + // Don't call this a trace if we weren't single stepping this thread. if (is_trace_if_actual_breakpoint_missing && thread.GetTemporaryResumeState() == eStateStepping) { diff --git a/source/Plugins/Process/Utility/ThreadMemory.cpp b/source/Plugins/Process/Utility/ThreadMemory.cpp index 56e5a9a59fab..6a7aa626bafc 100644 --- a/source/Plugins/Process/Utility/ThreadMemory.cpp +++ b/source/Plugins/Process/Utility/ThreadMemory.cpp @@ -105,7 +105,7 @@ ThreadMemory::CalculateStopInfo () if (m_backing_thread_sp) { lldb::StopInfoSP backing_stop_info_sp (m_backing_thread_sp->GetPrivateStopInfo()); - if (backing_stop_info_sp) + if (backing_stop_info_sp && backing_stop_info_sp->IsValidForOperatingSystemThread(*this)) { backing_stop_info_sp->SetThread (shared_from_this()); SetStopInfo (backing_stop_info_sp); diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index fc592e60d86d..02d3ecd7b3c5 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -12,6 +12,7 @@ #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/Thread.h" #include "lldb/Target/Target.h" #include "lldb/Target/Process.h" diff --git a/source/Plugins/Process/Utility/lldb-arm-register-enums.h b/source/Plugins/Process/Utility/lldb-arm-register-enums.h new file mode 100644 index 000000000000..a617f6550f65 --- /dev/null +++ b/source/Plugins/Process/Utility/lldb-arm-register-enums.h @@ -0,0 +1,153 @@ +//===-- lldb-arm-register-enums.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_arm_register_enums_h +#define lldb_arm_register_enums_h + +namespace lldb_private +{ + // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) + + //--------------------------------------------------------------------------- + // Internal codes for all ARM registers. + //--------------------------------------------------------------------------- + enum + { + k_first_gpr_arm = 0, + gpr_r0_arm = k_first_gpr_arm, + gpr_r1_arm, + gpr_r2_arm, + gpr_r3_arm, + gpr_r4_arm, + gpr_r5_arm, + gpr_r6_arm, + gpr_r7_arm, + gpr_r8_arm, + gpr_r9_arm, + gpr_r10_arm, + gpr_r11_arm, + gpr_r12_arm, + gpr_r13_arm, gpr_sp_arm = gpr_r13_arm, + gpr_r14_arm, gpr_lr_arm = gpr_r14_arm, + gpr_r15_arm, gpr_pc_arm = gpr_r15_arm, + gpr_cpsr_arm, + + k_last_gpr_arm = gpr_cpsr_arm, + + k_first_fpr_arm, + fpu_s0_arm = k_first_fpr_arm, + fpu_s1_arm, + fpu_s2_arm, + fpu_s3_arm, + fpu_s4_arm, + fpu_s5_arm, + fpu_s6_arm, + fpu_s7_arm, + fpu_s8_arm, + fpu_s9_arm, + fpu_s10_arm, + fpu_s11_arm, + fpu_s12_arm, + fpu_s13_arm, + fpu_s14_arm, + fpu_s15_arm, + fpu_s16_arm, + fpu_s17_arm, + fpu_s18_arm, + fpu_s19_arm, + fpu_s20_arm, + fpu_s21_arm, + fpu_s22_arm, + fpu_s23_arm, + fpu_s24_arm, + fpu_s25_arm, + fpu_s26_arm, + fpu_s27_arm, + fpu_s28_arm, + fpu_s29_arm, + fpu_s30_arm, + fpu_s31_arm, + fpu_fpscr_arm, + k_last_fpr_arm = fpu_fpscr_arm, + exc_exception_arm, + exc_fsr_arm, + exc_far_arm, + + dbg_bvr0_arm, + dbg_bvr1_arm, + dbg_bvr2_arm, + dbg_bvr3_arm, + dbg_bvr4_arm, + dbg_bvr5_arm, + dbg_bvr6_arm, + dbg_bvr7_arm, + dbg_bvr8_arm, + dbg_bvr9_arm, + dbg_bvr10_arm, + dbg_bvr11_arm, + dbg_bvr12_arm, + dbg_bvr13_arm, + dbg_bvr14_arm, + dbg_bvr15_arm, + dbg_bcr0_arm, + dbg_bcr1_arm, + dbg_bcr2_arm, + dbg_bcr3_arm, + dbg_bcr4_arm, + dbg_bcr5_arm, + dbg_bcr6_arm, + dbg_bcr7_arm, + dbg_bcr8_arm, + dbg_bcr9_arm, + dbg_bcr10_arm, + dbg_bcr11_arm, + dbg_bcr12_arm, + dbg_bcr13_arm, + dbg_bcr14_arm, + dbg_bcr15_arm, + dbg_wvr0_arm, + dbg_wvr1_arm, + dbg_wvr2_arm, + dbg_wvr3_arm, + dbg_wvr4_arm, + dbg_wvr5_arm, + dbg_wvr6_arm, + dbg_wvr7_arm, + dbg_wvr8_arm, + dbg_wvr9_arm, + dbg_wvr10_arm, + dbg_wvr11_arm, + dbg_wvr12_arm, + dbg_wvr13_arm, + dbg_wvr14_arm, + dbg_wvr15_arm, + dbg_wcr0_arm, + dbg_wcr1_arm, + dbg_wcr2_arm, + dbg_wcr3_arm, + dbg_wcr4_arm, + dbg_wcr5_arm, + dbg_wcr6_arm, + dbg_wcr7_arm, + dbg_wcr8_arm, + dbg_wcr9_arm, + dbg_wcr10_arm, + dbg_wcr11_arm, + dbg_wcr12_arm, + dbg_wcr13_arm, + dbg_wcr14_arm, + dbg_wcr15_arm, + + k_num_registers_arm, + k_num_gpr_registers_arm = k_last_gpr_arm - k_first_gpr_arm + 1, + k_num_fpr_registers_arm = k_last_fpr_arm - k_first_fpr_arm + 1 + }; +} + +#endif // #ifndef lldb_arm64_register_enums_h diff --git a/source/Plugins/Process/Utility/lldb-arm64-register-enums.h b/source/Plugins/Process/Utility/lldb-arm64-register-enums.h new file mode 100644 index 000000000000..a0c0db0f2786 --- /dev/null +++ b/source/Plugins/Process/Utility/lldb-arm64-register-enums.h @@ -0,0 +1,172 @@ +//===-- lldb-arm64-register-enums.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_arm64_register_enums_h +#define lldb_arm64_register_enums_h + +namespace lldb_private +{ + // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) + + //--------------------------------------------------------------------------- + // Internal codes for all ARM64 registers. + //--------------------------------------------------------------------------- + enum + { + k_first_gpr_arm64, + gpr_x0_arm64 = k_first_gpr_arm64, + gpr_x1_arm64, + gpr_x2_arm64, + gpr_x3_arm64, + gpr_x4_arm64, + gpr_x5_arm64, + gpr_x6_arm64, + gpr_x7_arm64, + gpr_x8_arm64, + gpr_x9_arm64, + gpr_x10_arm64, + gpr_x11_arm64, + gpr_x12_arm64, + gpr_x13_arm64, + gpr_x14_arm64, + gpr_x15_arm64, + gpr_x16_arm64, + gpr_x17_arm64, + gpr_x18_arm64, + gpr_x19_arm64, + gpr_x20_arm64, + gpr_x21_arm64, + gpr_x22_arm64, + gpr_x23_arm64, + gpr_x24_arm64, + gpr_x25_arm64, + gpr_x26_arm64, + gpr_x27_arm64, + gpr_x28_arm64, + gpr_fp_arm64, + gpr_lr_arm64, + gpr_sp_arm64, + gpr_pc_arm64, + gpr_cpsr_arm64, + + k_last_gpr_arm64 = gpr_cpsr_arm64, + + k_first_fpr_arm64, + fpu_v0_arm64 = k_first_fpr_arm64, + fpu_v1_arm64, + fpu_v2_arm64, + fpu_v3_arm64, + fpu_v4_arm64, + fpu_v5_arm64, + fpu_v6_arm64, + fpu_v7_arm64, + fpu_v8_arm64, + fpu_v9_arm64, + fpu_v10_arm64, + fpu_v11_arm64, + fpu_v12_arm64, + fpu_v13_arm64, + fpu_v14_arm64, + fpu_v15_arm64, + fpu_v16_arm64, + fpu_v17_arm64, + fpu_v18_arm64, + fpu_v19_arm64, + fpu_v20_arm64, + fpu_v21_arm64, + fpu_v22_arm64, + fpu_v23_arm64, + fpu_v24_arm64, + fpu_v25_arm64, + fpu_v26_arm64, + fpu_v27_arm64, + fpu_v28_arm64, + fpu_v29_arm64, + fpu_v30_arm64, + fpu_v31_arm64, + fpu_fpsr_arm64, + fpu_fpcr_arm64, + k_last_fpr_arm64 = fpu_fpcr_arm64, + + exc_far_arm64, + exc_esr_arm64, + exc_exception_arm64, + + dbg_bvr0_arm64, + dbg_bvr1_arm64, + dbg_bvr2_arm64, + dbg_bvr3_arm64, + dbg_bvr4_arm64, + dbg_bvr5_arm64, + dbg_bvr6_arm64, + dbg_bvr7_arm64, + dbg_bvr8_arm64, + dbg_bvr9_arm64, + dbg_bvr10_arm64, + dbg_bvr11_arm64, + dbg_bvr12_arm64, + dbg_bvr13_arm64, + dbg_bvr14_arm64, + dbg_bvr15_arm64, + dbg_bcr0_arm64, + dbg_bcr1_arm64, + dbg_bcr2_arm64, + dbg_bcr3_arm64, + dbg_bcr4_arm64, + dbg_bcr5_arm64, + dbg_bcr6_arm64, + dbg_bcr7_arm64, + dbg_bcr8_arm64, + dbg_bcr9_arm64, + dbg_bcr10_arm64, + dbg_bcr11_arm64, + dbg_bcr12_arm64, + dbg_bcr13_arm64, + dbg_bcr14_arm64, + dbg_bcr15_arm64, + dbg_wvr0_arm64, + dbg_wvr1_arm64, + dbg_wvr2_arm64, + dbg_wvr3_arm64, + dbg_wvr4_arm64, + dbg_wvr5_arm64, + dbg_wvr6_arm64, + dbg_wvr7_arm64, + dbg_wvr8_arm64, + dbg_wvr9_arm64, + dbg_wvr10_arm64, + dbg_wvr11_arm64, + dbg_wvr12_arm64, + dbg_wvr13_arm64, + dbg_wvr14_arm64, + dbg_wvr15_arm64, + dbg_wcr0_arm64, + dbg_wcr1_arm64, + dbg_wcr2_arm64, + dbg_wcr3_arm64, + dbg_wcr4_arm64, + dbg_wcr5_arm64, + dbg_wcr6_arm64, + dbg_wcr7_arm64, + dbg_wcr8_arm64, + dbg_wcr9_arm64, + dbg_wcr10_arm64, + dbg_wcr11_arm64, + dbg_wcr12_arm64, + dbg_wcr13_arm64, + dbg_wcr14_arm64, + dbg_wcr15_arm64, + + k_num_registers_arm64, + k_num_gpr_registers_arm64 = k_last_gpr_arm64 - k_first_gpr_arm64 + 1, + k_num_fpr_registers_arm64 = k_last_fpr_arm64 - k_first_fpr_arm64 + 1 + }; +} + +#endif // #ifndef lldb_arm64_register_enums_h diff --git a/source/Plugins/Process/Utility/lldb-mips64-register-enums.h b/source/Plugins/Process/Utility/lldb-mips64-register-enums.h new file mode 100644 index 000000000000..e8c93a6ec521 --- /dev/null +++ b/source/Plugins/Process/Utility/lldb-mips64-register-enums.h @@ -0,0 +1,199 @@ +//===-- lldb-mips64-register-enums.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_mips64_register_enums_h +#define lldb_mips64_register_enums_h + +namespace lldb_private +{ + // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) + + //--------------------------------------------------------------------------- + // Internal codes for all mips registers. + //--------------------------------------------------------------------------- + enum + { + k_first_gpr_mips, + gpr_zero_mips = k_first_gpr_mips, + gpr_r1_mips, + gpr_r2_mips, + gpr_r3_mips, + gpr_r4_mips, + gpr_r5_mips, + gpr_r6_mips, + gpr_r7_mips, + gpr_r8_mips, + gpr_r9_mips, + gpr_r10_mips, + gpr_r11_mips, + gpr_r12_mips, + gpr_r13_mips, + gpr_r14_mips, + gpr_r15_mips, + gpr_r16_mips, + gpr_r17_mips, + gpr_r18_mips, + gpr_r19_mips, + gpr_r20_mips, + gpr_r21_mips, + gpr_r22_mips, + gpr_r23_mips, + gpr_r24_mips, + gpr_r25_mips, + gpr_r26_mips, + gpr_r27_mips, + gpr_gp_mips, + gpr_sp_mips, + gpr_r30_mips, + gpr_ra_mips, + gpr_mullo_mips, + gpr_mulhi_mips, + gpr_pc_mips, + gpr_badvaddr_mips, + gpr_sr_mips, + gpr_cause_mips, + + k_last_gpr_mips = gpr_cause_mips, + + k_first_fpr_mips, + fpr_f0_mips = k_first_fpr_mips, + fpr_f1_mips, + fpr_f2_mips, + fpr_f3_mips, + fpr_f4_mips, + fpr_f5_mips, + fpr_f6_mips, + fpr_f7_mips, + fpr_f8_mips, + fpr_f9_mips, + fpr_f10_mips, + fpr_f11_mips, + fpr_f12_mips, + fpr_f13_mips, + fpr_f14_mips, + fpr_f15_mips, + fpr_f16_mips, + fpr_f17_mips, + fpr_f18_mips, + fpr_f19_mips, + fpr_f20_mips, + fpr_f21_mips, + fpr_f22_mips, + fpr_f23_mips, + fpr_f24_mips, + fpr_f25_mips, + fpr_f26_mips, + fpr_f27_mips, + fpr_f28_mips, + fpr_f29_mips, + fpr_f30_mips, + fpr_f31_mips, + fpr_fcsr_mips, + fpr_fir_mips, + k_last_fpr_mips = fpr_fir_mips, + + k_num_registers_mips, + k_num_gpr_registers_mips = k_last_gpr_mips - k_first_gpr_mips + 1, + k_num_fpr_registers_mips = k_last_fpr_mips - k_first_fpr_mips + 1, + k_num_user_registers_mips = k_num_gpr_registers_mips + k_num_fpr_registers_mips, + }; + + //--------------------------------------------------------------------------- + // Internal codes for all mips64 registers. + //--------------------------------------------------------------------------- + enum + { + k_first_gpr_mips64, + gpr_zero_mips64 = k_first_gpr_mips64, + gpr_r1_mips64, + gpr_r2_mips64, + gpr_r3_mips64, + gpr_r4_mips64, + gpr_r5_mips64, + gpr_r6_mips64, + gpr_r7_mips64, + gpr_r8_mips64, + gpr_r9_mips64, + gpr_r10_mips64, + gpr_r11_mips64, + gpr_r12_mips64, + gpr_r13_mips64, + gpr_r14_mips64, + gpr_r15_mips64, + gpr_r16_mips64, + gpr_r17_mips64, + gpr_r18_mips64, + gpr_r19_mips64, + gpr_r20_mips64, + gpr_r21_mips64, + gpr_r22_mips64, + gpr_r23_mips64, + gpr_r24_mips64, + gpr_r25_mips64, + gpr_r26_mips64, + gpr_r27_mips64, + gpr_gp_mips64, + gpr_sp_mips64, + gpr_r30_mips64, + gpr_ra_mips64, + gpr_mullo_mips64, + gpr_mulhi_mips64, + gpr_pc_mips64, + gpr_badvaddr_mips64, + gpr_sr_mips64, + gpr_cause_mips64, + gpr_ic_mips64, + gpr_dummy_mips64, + + k_last_gpr_mips64 = gpr_dummy_mips64, + + k_first_fpr_mips64, + fpr_f0_mips64 = k_first_fpr_mips64, + fpr_f1_mips64, + fpr_f2_mips64, + fpr_f3_mips64, + fpr_f4_mips64, + fpr_f5_mips64, + fpr_f6_mips64, + fpr_f7_mips64, + fpr_f8_mips64, + fpr_f9_mips64, + fpr_f10_mips64, + fpr_f11_mips64, + fpr_f12_mips64, + fpr_f13_mips64, + fpr_f14_mips64, + fpr_f15_mips64, + fpr_f16_mips64, + fpr_f17_mips64, + fpr_f18_mips64, + fpr_f19_mips64, + fpr_f20_mips64, + fpr_f21_mips64, + fpr_f22_mips64, + fpr_f23_mips64, + fpr_f24_mips64, + fpr_f25_mips64, + fpr_f26_mips64, + fpr_f27_mips64, + fpr_f28_mips64, + fpr_f29_mips64, + fpr_f30_mips64, + fpr_f31_mips64, + fpr_fcsr_mips64, + fpr_fir_mips64, + k_last_fpr_mips64 = fpr_fir_mips64, + + k_num_registers_mips64, + k_num_gpr_registers_mips64 = k_last_gpr_mips64 - k_first_gpr_mips64 + 1, + k_num_fpr_registers_mips64 = k_last_fpr_mips64 - k_first_fpr_mips64 + 1, + }; +} + +#endif // #ifndef fpr_mips64_register_enums_h diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index ead959508d88..2fff36dd4ee5 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -10,6 +10,9 @@ // C Includes #include <stdlib.h> +// C++ Includes +#include <mutex> + // Other libraries and framework includes #include "lldb/Core/PluginManager.h" #include "lldb/Core/Module.h" @@ -191,7 +194,7 @@ ProcessElfCore::DoLoadCore () const uint32_t num_segments = core->GetProgramHeaderCount(); if (num_segments == 0) { - error.SetErrorString ("core file has no sections"); + error.SetErrorString ("core file has no segments"); return error; } @@ -374,13 +377,13 @@ ProcessElfCore::Clear() void ProcessElfCore::Initialize() { - static bool g_initialized = false; + static std::once_flag g_once_flag; - if (g_initialized == false) + std::call_once(g_once_flag, []() { - g_initialized = true; - PluginManager::RegisterPlugin (GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); - } + PluginManager::RegisterPlugin (GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + }); } lldb::addr_t @@ -424,7 +427,8 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, ArchSpec &arch) { lldb::offset_t offset = 0; - bool lp64 = (arch.GetMachine() == llvm::Triple::mips64 || + bool lp64 = (arch.GetMachine() == llvm::Triple::aarch64 || + arch.GetMachine() == llvm::Triple::mips64 || arch.GetMachine() == llvm::Triple::ppc64 || arch.GetMachine() == llvm::Triple::x86_64); int pr_version = data.GetU32(&offset); diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.h b/source/Plugins/Process/elf-core/ProcessElfCore.h index 7988bee5ae53..775d9e94dd8e 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -66,54 +66,42 @@ public: //------------------------------------------------------------------ // Check if a given Process //------------------------------------------------------------------ - virtual bool - CanDebug (lldb_private::Target &target, - bool plugin_specified_by_name) override; + bool CanDebug(lldb_private::Target &target, bool plugin_specified_by_name) override; //------------------------------------------------------------------ // Creating a new process, or attaching to an existing one //------------------------------------------------------------------ - virtual lldb_private::Error - DoLoadCore () override; + lldb_private::Error DoLoadCore() override; - virtual lldb_private::DynamicLoader * - GetDynamicLoader () override; + lldb_private::DynamicLoader *GetDynamicLoader() override; //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ - virtual lldb_private::ConstString - GetPluginName() override; + lldb_private::ConstString GetPluginName() override; - virtual uint32_t - GetPluginVersion() override; + uint32_t GetPluginVersion() override; //------------------------------------------------------------------ // Process Control //------------------------------------------------------------------ - virtual lldb_private::Error - DoDestroy () override; + lldb_private::Error DoDestroy() override; - virtual void - RefreshStateAfterStop() override; + void RefreshStateAfterStop() override; //------------------------------------------------------------------ // Process Queries //------------------------------------------------------------------ - virtual bool - IsAlive () override; + bool IsAlive() override; //------------------------------------------------------------------ // Process Memory //------------------------------------------------------------------ - virtual size_t - ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override; + size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override; - virtual size_t - DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override; + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override; - virtual lldb::addr_t - GetImageInfoAddress () override; + lldb::addr_t GetImageInfoAddress() override; lldb_private::ArchSpec GetArchitecture(); @@ -126,9 +114,8 @@ protected: void Clear ( ); - virtual bool - UpdateThreadList (lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override; + bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; private: //------------------------------------------------------------------ diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp new file mode 100644 index 000000000000..f046c112d8b6 --- /dev/null +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp @@ -0,0 +1,94 @@ +//===-- RegisterContextCorePOSIX_arm.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX.h" +#include "RegisterContextPOSIXCore_arm.h" + +using namespace lldb_private; + +RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm(Thread &thread, + RegisterInfoInterface *register_info, + const DataExtractor &gpregset, + const DataExtractor &fpregset) + : RegisterContextPOSIX_arm(thread, 0, register_info) +{ + m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize())); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); +} + +RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm() +{ +} + +bool +RegisterContextCorePOSIX_arm::ReadGPR() +{ + return true; +} + +bool +RegisterContextCorePOSIX_arm::ReadFPR() +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm::WriteGPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_arm::WriteFPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + lldb::offset_t offset = reg_info->byte_offset; + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) + { + value = v; + return true; + } + return false; +} + +bool +RegisterContextCorePOSIX_arm::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm::HardwareSingleStep(bool enable) +{ + return false; +} diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h new file mode 100644 index 000000000000..73e2ef7c3a93 --- /dev/null +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h @@ -0,0 +1,60 @@ +//===-- RegisterContextCorePOSIX_arm.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_RegisterContextCorePOSIX_arm_H_ +#define liblldb_RegisterContextCorePOSIX_arm_H_ + +#include "lldb/Core/DataBufferHeap.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" + +class RegisterContextCorePOSIX_arm : + public RegisterContextPOSIX_arm +{ +public: + RegisterContextCorePOSIX_arm (lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset, + const lldb_private::DataExtractor &fpregset); + + ~RegisterContextCorePOSIX_arm(); + + virtual bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + virtual bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + bool + HardwareSingleStep(bool enable); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb_private::DataExtractor m_gpr; +}; + +#endif // #ifndef liblldb_RegisterContextCorePOSIX_arm_H_ diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp new file mode 100644 index 000000000000..53c0c83c264a --- /dev/null +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -0,0 +1,94 @@ +//===-- RegisterContextCorePOSIX_arm64.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX.h" +#include "RegisterContextPOSIXCore_arm64.h" + +using namespace lldb_private; + +RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(Thread &thread, + RegisterInfoInterface *register_info, + const DataExtractor &gpregset, + const DataExtractor &fpregset) + : RegisterContextPOSIX_arm64(thread, 0, register_info) +{ + m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize())); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); +} + +RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() +{ +} + +bool +RegisterContextCorePOSIX_arm64::ReadGPR() +{ + return true; +} + +bool +RegisterContextCorePOSIX_arm64::ReadFPR() +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm64::WriteGPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_arm64::WriteFPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + lldb::offset_t offset = reg_info->byte_offset; + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) + { + value = v; + return true; + } + return false; +} + +bool +RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) +{ + return false; +} diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h new file mode 100644 index 000000000000..2e1d6b4f9ca8 --- /dev/null +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h @@ -0,0 +1,60 @@ +//===-- RegisterContextCorePOSIX_arm64.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_RegisterContextCorePOSIX_arm64_H_ +#define liblldb_RegisterContextCorePOSIX_arm64_H_ + +#include "lldb/Core/DataBufferHeap.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" + +class RegisterContextCorePOSIX_arm64 : + public RegisterContextPOSIX_arm64 +{ +public: + RegisterContextCorePOSIX_arm64 (lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset, + const lldb_private::DataExtractor &fpregset); + + ~RegisterContextCorePOSIX_arm64(); + + virtual bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + virtual bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + bool + HardwareSingleStep(bool enable); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb_private::DataExtractor m_gpr; +}; + +#endif // #ifndef liblldb_RegisterContextCorePOSIX_arm64_H_ diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp index b16335fb8e1e..2abb6ba5decd 100644 --- a/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -16,11 +16,17 @@ #include "ThreadElfCore.h" #include "ProcessElfCore.h" +#include "Plugins/Process/Utility/RegisterContextLinux_arm.h" +#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" +#include "RegisterContextPOSIXCore_arm.h" +#include "RegisterContextPOSIXCore_arm64.h" #include "RegisterContextPOSIXCore_mips64.h" #include "RegisterContextPOSIXCore_powerpc.h" #include "RegisterContextPOSIXCore_x86_64.h" @@ -97,6 +103,12 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) { switch (arch.GetMachine()) { + case llvm::Triple::aarch64: + reg_interface = new RegisterContextFreeBSD_arm64(arch); + break; + case llvm::Triple::arm: + reg_interface = new RegisterContextFreeBSD_arm(arch); + break; case llvm::Triple::ppc: reg_interface = new RegisterContextFreeBSD_powerpc32(arch); break; @@ -122,6 +134,12 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) { switch (arch.GetMachine()) { + case llvm::Triple::arm: + reg_interface = new RegisterContextLinux_arm(arch); + break; + case llvm::Triple::aarch64: + reg_interface = new RegisterContextLinux_arm64(arch); + break; case llvm::Triple::x86_64: reg_interface = new RegisterContextLinux_x86_64(arch); break; @@ -144,6 +162,12 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) switch (arch.GetMachine()) { + case llvm::Triple::aarch64: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); + break; + case llvm::Triple::arm: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm (*this, reg_interface, m_gpregset_data, m_fpregset_data)); + break; case llvm::Triple::mips64: m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); break; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index d633b3eaf34c..1af3947a75f3 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -18,6 +18,7 @@ // C++ Includes // Other libraries and framework includes #include "lldb/Core/Log.h" +#include "lldb/Core/RegularExpression.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/ConnectionFileDescriptor.h" @@ -38,11 +39,20 @@ #if defined(__APPLE__) # define DEBUGSERVER_BASENAME "debugserver" #else -# define DEBUGSERVER_BASENAME "lldb-gdbserver" +# define DEBUGSERVER_BASENAME "lldb-server" +#endif + +#if defined (HAVE_LIBCOMPRESSION) +#include <compression.h> +#endif + +#if defined (HAVE_LIBZ) +#include <zlib.h> #endif using namespace lldb; using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; GDBRemoteCommunication::History::History (uint32_t size) : m_packets(), @@ -93,7 +103,7 @@ GDBRemoteCommunication::History::AddPacket (const std::string &src, } void -GDBRemoteCommunication::History::Dump (lldb_private::Stream &strm) const +GDBRemoteCommunication::History::Dump (Stream &strm) const { const uint32_t size = GetNumPacketsInHistory (); const uint32_t first_idx = GetFirstSavedPacketIndex (); @@ -114,7 +124,7 @@ GDBRemoteCommunication::History::Dump (lldb_private::Stream &strm) const } void -GDBRemoteCommunication::History::Dump (lldb_private::Log *log) const +GDBRemoteCommunication::History::Dump (Log *log) const { if (log && !m_dumped_to_log) { @@ -142,20 +152,21 @@ GDBRemoteCommunication::History::Dump (lldb_private::Log *log) const // GDBRemoteCommunication constructor //---------------------------------------------------------------------- GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, - const char *listener_name, - bool is_platform) : + const char *listener_name) : Communication(comm_name), #ifdef LLDB_CONFIGURATION_DEBUG m_packet_timeout (1000), #else m_packet_timeout (1), #endif + m_echo_number(0), + m_supports_qEcho (eLazyBoolCalculate), m_sequence_mutex (Mutex::eMutexTypeRecursive), m_public_is_running (false), m_private_is_running (false), m_history (512), m_send_acks (true), - m_is_platform (is_platform), + m_compression_type (CompressionType::None), m_listen_url () { } @@ -169,6 +180,12 @@ GDBRemoteCommunication::~GDBRemoteCommunication() { Disconnect(); } + + // Stop the communications read thread which is used to parse all + // incoming packets. This function will block until the read + // thread returns. + if (m_read_thread_enabled) + StopReadThread(); } char @@ -260,7 +277,7 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)binary_start_offset, packet_data); const uint8_t *p; // Print binary data exactly as sent - for (p = (uint8_t*)packet_data + binary_start_offset; *p != '#'; ++p) + for (p = (const uint8_t*)packet_data + binary_start_offset; *p != '#'; ++p) strm.Printf("\\x%2.2x", *p); // Print the checksum strm.Printf("%*s", (int)3, p); @@ -293,7 +310,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunication::GetAck () { StringExtractorGDBRemote packet; - PacketResult result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()); + PacketResult result = ReadPacket (packet, GetPacketTimeoutInMicroSeconds (), false); if (result == PacketResult::Success) { if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck) @@ -322,7 +339,63 @@ GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) } GDBRemoteCommunication::PacketResult -GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec) +GDBRemoteCommunication::ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout) +{ + if (m_read_thread_enabled) + return PopPacketFromQueue (response, timeout_usec); + else + return WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec, sync_on_timeout); +} + + +// This function is called when a packet is requested. +// A whole packet is popped from the packet queue and returned to the caller. +// Packets are placed into this queue from the communication read thread. +// See GDBRemoteCommunication::AppendBytesToCache. +GDBRemoteCommunication::PacketResult +GDBRemoteCommunication::PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec) +{ + // Calculate absolute timeout value + TimeValue timeout = TimeValue::Now(); + timeout.OffsetWithMicroSeconds(timeout_usec); + + do + { + // scope for the mutex + { + // lock down the packet queue + Mutex::Locker locker(m_packet_queue_mutex); + + // Wait on condition variable. + if (m_packet_queue.size() == 0) + m_condition_queue_not_empty.Wait(m_packet_queue_mutex, &timeout); + + if (m_packet_queue.size() > 0) + { + // get the front element of the queue + response = m_packet_queue.front(); + + // remove the front element + m_packet_queue.pop(); + + // we got a packet + return PacketResult::Success; + } + } + + // Disconnected + if (!IsConnected()) + return PacketResult::ErrorDisconnected; + + // Loop while not timed out + } while (TimeValue::Now() < timeout); + + return PacketResult::ErrorReplyTimeout; +} + + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec, bool sync_on_timeout) { uint8_t buffer[8192]; Error error; @@ -330,7 +403,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE)); // Check for a packet from our cache first without trying any reading... - if (CheckForPacket (NULL, 0, packet)) + if (CheckForPacket(NULL, 0, packet) != PacketType::Invalid) return PacketResult::Success; bool timed_out = false; @@ -350,7 +423,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac if (bytes_read > 0) { - if (CheckForPacket (buffer, bytes_read, packet)) + if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid) return PacketResult::Success; } else @@ -359,6 +432,104 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac { case eConnectionStatusTimedOut: case eConnectionStatusInterrupted: + if (sync_on_timeout) + { + //------------------------------------------------------------------ + /// Sync the remote GDB server and make sure we get a response that + /// corresponds to what we send. + /// + /// Sends a "qEcho" packet and makes sure it gets the exact packet + /// echoed back. If the qEcho packet isn't supported, we send a qC + /// packet and make sure we get a valid thread ID back. We use the + /// "qC" packet since its response if very unique: is responds with + /// "QC%x" where %x is the thread ID of the current thread. This + /// makes the response unique enough from other packet responses to + /// ensure we are back on track. + /// + /// This packet is needed after we time out sending a packet so we + /// can ensure that we are getting the response for the packet we + /// are sending. There are no sequence IDs in the GDB remote + /// protocol (there used to be, but they are not supported anymore) + /// so if you timeout sending packet "abc", you might then send + /// packet "cde" and get the response for the previous "abc" packet. + /// Many responses are "OK" or "" (unsupported) or "EXX" (error) so + /// many responses for packets can look like responses for other + /// packets. So if we timeout, we need to ensure that we can get + /// back on track. If we can't get back on track, we must + /// disconnect. + //------------------------------------------------------------------ + bool sync_success = false; + bool got_actual_response = false; + // We timed out, we need to sync back up with the + char echo_packet[32]; + int echo_packet_len = 0; + RegularExpression response_regex; + + if (m_supports_qEcho == eLazyBoolYes) + { + echo_packet_len = ::snprintf (echo_packet, sizeof(echo_packet), "qEcho:%u", ++m_echo_number); + std::string regex_str = "^"; + regex_str += echo_packet; + regex_str += "$"; + response_regex.Compile(regex_str.c_str()); + } + else + { + echo_packet_len = ::snprintf (echo_packet, sizeof(echo_packet), "qC"); + response_regex.Compile("^QC[0-9A-Fa-f]+$"); + } + + PacketResult echo_packet_result = SendPacketNoLock (echo_packet, echo_packet_len); + if (echo_packet_result == PacketResult::Success) + { + const uint32_t max_retries = 3; + uint32_t successful_responses = 0; + for (uint32_t i=0; i<max_retries; ++i) + { + StringExtractorGDBRemote echo_response; + echo_packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (echo_response, timeout_usec, false); + if (echo_packet_result == PacketResult::Success) + { + ++successful_responses; + if (response_regex.Execute(echo_response.GetStringRef().c_str())) + { + sync_success = true; + break; + } + else if (successful_responses == 1) + { + // We got something else back as the first successful response, it probably is + // the response to the packet we actually wanted, so copy it over if this + // is the first success and continue to try to get the qEcho response + packet = echo_response; + got_actual_response = true; + } + } + else if (echo_packet_result == PacketResult::ErrorReplyTimeout) + continue; // Packet timed out, continue waiting for a response + else + break; // Something else went wrong getting the packet back, we failed and are done trying + } + } + + // We weren't able to sync back up with the server, we must abort otherwise + // all responses might not be from the right packets... + if (sync_success) + { + // We timed out, but were able to recover + if (got_actual_response) + { + // We initially timed out, but we did get a response that came in before the successful + // reply to our qEcho packet, so lets say everything is fine... + return PacketResult::Success; + } + } + else + { + disconnected = true; + Disconnect(); + } + } timed_out = true; break; case eConnectionStatusSuccess: @@ -385,6 +556,226 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac } bool +GDBRemoteCommunication::DecompressPacket () +{ + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); + + if (!CompressionIsEnabled()) + return true; + + size_t pkt_size = m_bytes.size(); + if (pkt_size < 6) + return true; + if (m_bytes[0] != '$' && m_bytes[0] != '%') + return true; + if (m_bytes[1] != 'C' && m_bytes[1] != 'N') + return true; + if (m_bytes[pkt_size - 3] != '#') + return true; + if (!::isxdigit (m_bytes[pkt_size - 2]) || !::isxdigit (m_bytes[pkt_size - 1])) + return true; + + size_t content_length = pkt_size - 5; // not counting '$', 'C' | 'N', '#', & the two hex checksum chars + size_t content_start = 2; // The first character of the compressed/not-compressed text of the packet + size_t hash_mark_idx = pkt_size - 3; // The '#' character marking the end of the packet + size_t checksum_idx = pkt_size - 2; // The first character of the two hex checksum characters + + // Compressed packets ("$C") start with a base10 number which is the size of the uncompressed payload, + // then a : and then the compressed data. e.g. $C1024:<binary>#00 + // Update content_start and content_length to only include the <binary> part of the packet. + + uint64_t decompressed_bufsize = ULONG_MAX; + if (m_bytes[1] == 'C') + { + size_t i = content_start; + while (i < hash_mark_idx && isdigit(m_bytes[i])) + i++; + if (i < hash_mark_idx && m_bytes[i] == ':') + { + i++; + content_start = i; + content_length = hash_mark_idx - content_start; + std::string bufsize_str (m_bytes.data() + 2, i - 2 - 1); + errno = 0; + decompressed_bufsize = ::strtoul (bufsize_str.c_str(), NULL, 10); + if (errno != 0 || decompressed_bufsize == ULONG_MAX) + { + m_bytes.erase (0, pkt_size); + return false; + } + } + } + + if (GetSendAcks ()) + { + char packet_checksum_cstr[3]; + packet_checksum_cstr[0] = m_bytes[checksum_idx]; + packet_checksum_cstr[1] = m_bytes[checksum_idx + 1]; + packet_checksum_cstr[2] = '\0'; + long packet_checksum = strtol (packet_checksum_cstr, NULL, 16); + + long actual_checksum = CalculcateChecksum (m_bytes.data() + 1, hash_mark_idx - 1); + bool success = packet_checksum == actual_checksum; + if (!success) + { + if (log) + log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", + (int)(pkt_size), + m_bytes.c_str(), + (uint8_t)packet_checksum, + (uint8_t)actual_checksum); + } + // Send the ack or nack if needed + if (!success) + { + SendNack(); + m_bytes.erase (0, pkt_size); + return false; + } + else + { + SendAck(); + } + } + + if (m_bytes[1] == 'N') + { + // This packet was not compressed -- delete the 'N' character at the + // start and the packet may be processed as-is. + m_bytes.erase(1, 1); + return true; + } + + // Reverse the gdb-remote binary escaping that was done to the compressed text to + // guard characters like '$', '#', '}', etc. + std::vector<uint8_t> unescaped_content; + unescaped_content.reserve (content_length); + size_t i = content_start; + while (i < hash_mark_idx) + { + if (m_bytes[i] == '}') + { + i++; + unescaped_content.push_back (m_bytes[i] ^ 0x20); + } + else + { + unescaped_content.push_back (m_bytes[i]); + } + i++; + } + + uint8_t *decompressed_buffer = nullptr; + size_t decompressed_bytes = 0; + + if (decompressed_bufsize != ULONG_MAX) + { + decompressed_buffer = (uint8_t *) malloc (decompressed_bufsize + 1); + if (decompressed_buffer == nullptr) + { + m_bytes.erase (0, pkt_size); + return false; + } + + } + +#if defined (HAVE_LIBCOMPRESSION) + // libcompression is weak linked so check that compression_decode_buffer() is available + if (compression_decode_buffer != NULL && + (m_compression_type == CompressionType::ZlibDeflate + || m_compression_type == CompressionType::LZFSE + || m_compression_type == CompressionType::LZ4)) + { + compression_algorithm compression_type; + if (m_compression_type == CompressionType::ZlibDeflate) + compression_type = COMPRESSION_ZLIB; + else if (m_compression_type == CompressionType::LZFSE) + compression_type = COMPRESSION_LZFSE; + else if (m_compression_type == CompressionType::LZ4) + compression_type = COMPRESSION_LZ4_RAW; + else if (m_compression_type == CompressionType::LZMA) + compression_type = COMPRESSION_LZMA; + + + // If we have the expected size of the decompressed payload, we can allocate + // the right-sized buffer and do it. If we don't have that information, we'll + // need to try decoding into a big buffer and if the buffer wasn't big enough, + // increase it and try again. + + if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr) + { + decompressed_bytes = compression_decode_buffer (decompressed_buffer, decompressed_bufsize + 10 , + (uint8_t*) unescaped_content.data(), + unescaped_content.size(), + NULL, + compression_type); + } + } +#endif + +#if defined (HAVE_LIBZ) + if (decompressed_bytes == 0 + && decompressed_bufsize != ULONG_MAX + && decompressed_buffer != nullptr + && m_compression_type == CompressionType::ZlibDeflate) + { + z_stream stream; + memset (&stream, 0, sizeof (z_stream)); + stream.next_in = (Bytef *) unescaped_content.data(); + stream.avail_in = (uInt) unescaped_content.size(); + stream.total_in = 0; + stream.next_out = (Bytef *) decompressed_buffer; + stream.avail_out = decompressed_bufsize; + stream.total_out = 0; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + if (inflateInit2 (&stream, -15) == Z_OK) + { + int status = inflate (&stream, Z_NO_FLUSH); + inflateEnd (&stream); + if (status == Z_STREAM_END) + { + decompressed_bytes = stream.total_out; + } + } + } +#endif + + if (decompressed_bytes == 0 || decompressed_buffer == nullptr) + { + if (decompressed_buffer) + free (decompressed_buffer); + m_bytes.erase (0, pkt_size); + return false; + } + + std::string new_packet; + new_packet.reserve (decompressed_bytes + 6); + new_packet.push_back (m_bytes[0]); + new_packet.append ((const char *) decompressed_buffer, decompressed_bytes); + new_packet.push_back ('#'); + if (GetSendAcks ()) + { + uint8_t decompressed_checksum = CalculcateChecksum ((const char *) decompressed_buffer, decompressed_bytes); + char decompressed_checksum_str[3]; + snprintf (decompressed_checksum_str, 3, "%02x", decompressed_checksum); + new_packet.append (decompressed_checksum_str); + } + else + { + new_packet.push_back ('0'); + new_packet.push_back ('0'); + } + + m_bytes = new_packet; + + free (decompressed_buffer); + return true; +} + +GDBRemoteCommunication::PacketType GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet) { // Put the packet data into the buffer in a thread safe fashion @@ -406,6 +797,8 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri m_bytes.append ((const char *)src, src_len); } + bool isNotifyPacket = false; + // Parse up the packets into gdb remote packets if (!m_bytes.empty()) { @@ -417,6 +810,17 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri size_t total_length = 0; size_t checksum_idx = std::string::npos; + // Size of packet before it is decompressed, for logging purposes + size_t original_packet_size = m_bytes.size(); + if (CompressionIsEnabled()) + { + if (DecompressPacket() == false) + { + packet.Clear(); + return GDBRemoteCommunication::PacketType::Standard; + } + } + switch (m_bytes[0]) { case '+': // Look for ack @@ -425,6 +829,10 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri content_length = total_length = 1; // The command is one byte long... break; + case '%': // Async notify packet + isNotifyPacket = true; + // Intentional fall through + case '$': // Look for a standard gdb packet? { @@ -467,6 +875,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri case '+': case '-': case '\x03': + case '%': case '$': done = true; break; @@ -486,7 +895,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri if (content_length == std::string::npos) { packet.Clear(); - return false; + return GDBRemoteCommunication::PacketType::Invalid; } else if (total_length > 0) { @@ -495,12 +904,10 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri assert (content_length <= m_bytes.size()); assert (total_length <= m_bytes.size()); assert (content_length <= total_length); - const size_t content_end = content_start + content_length; + size_t content_end = content_start + content_length; bool success = true; std::string &packet_str = packet.GetStringRef(); - - if (log) { // If logging was just enabled and we have history, then dump out what @@ -524,7 +931,10 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri { StreamString strm; // Packet header... - strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]); + if (CompressionIsEnabled()) + strm.Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %c", (uint64_t) original_packet_size, (uint64_t)total_length, m_bytes[0]); + else + strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]); for (size_t i=content_start; i<content_end; ++i) { // Remove binary escaped bytes when displaying the packet... @@ -547,7 +957,10 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri } else { - log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); + if (CompressionIsEnabled()) + log->Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %.*s", (uint64_t) original_packet_size, (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); + else + log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); } } @@ -587,7 +1000,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri } } - if (m_bytes[0] == '$') + if (m_bytes[0] == '$' || m_bytes[0] == '%') { assert (checksum_idx < m_bytes.size()); if (::isxdigit (m_bytes[checksum_idx+0]) || @@ -625,11 +1038,15 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri m_bytes.erase(0, total_length); packet.SetFilePos(0); - return success; + + if (isNotifyPacket) + return GDBRemoteCommunication::PacketType::Notify; + else + return GDBRemoteCommunication::PacketType::Standard; } } packet.Clear(); - return false; + return GDBRemoteCommunication::PacketType::Invalid; } Error @@ -681,7 +1098,7 @@ GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg) Error GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, uint16_t in_port, - lldb_private::ProcessLaunchInfo &launch_info, + ProcessLaunchInfo &launch_info, uint16_t &out_port) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); @@ -741,10 +1158,15 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, Args &debugserver_args = launch_info.GetArguments(); debugserver_args.Clear(); char arg_cstr[PATH_MAX]; - + // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(debugserver_path); +#if !defined(__APPLE__) + // First argument to lldb-server must be mode in which to run. + debugserver_args.AppendArgument("gdbserver"); +#endif + // If a host and port is supplied then use it char host_and_port[128]; if (hostname) @@ -766,28 +1188,42 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, } llvm::SmallString<PATH_MAX> named_pipe_path; - Pipe port_named_pipe; + Pipe port_pipe; - bool listen = false; - if (host_and_port[0]) + if (host_and_port[0] && in_port == 0) { // Create a temporary file to get the stdout/stderr and redirect the // output of the command into this file. We will later read this file // if all goes well and fill the data into "command_output_ptr" - if (in_port == 0) + // Binding to port zero, we need to figure out what port it ends up + // using using a named pipe... + error = port_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); + if (error.Success()) { - // Binding to port zero, we need to figure out what port it ends up - // using using a named pipe... - error = port_named_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); - if (error.Fail()) - return error; debugserver_args.AppendArgument("--named-pipe"); debugserver_args.AppendArgument(named_pipe_path.c_str()); } else { - listen = true; + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "named pipe creation failed: %s", + __FUNCTION__, error.AsCString()); + // let's try an unnamed pipe + error = port_pipe.CreateNew(true); + if (error.Fail()) + { + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "unnamed pipe creation failed: %s", + __FUNCTION__, error.AsCString()); + return error; + } + int write_fd = port_pipe.GetWriteFileDescriptor(); + debugserver_args.AppendArgument("--pipe"); + debugserver_args.AppendArgument(std::to_string(write_fd).c_str()); + launch_info.AppendCloseFileAction(port_pipe.GetReadFileDescriptor()); } } else @@ -796,7 +1232,11 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, // connect to us.. error = StartListenThread ("127.0.0.1", 0); if (error.Fail()) + { + if (log) + log->Printf ("GDBRemoteCommunication::%s() unable to start listen thread: %s", __FUNCTION__, error.AsCString()); return error; + } ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); // Wait for 10 seconds to resolve the bound port @@ -813,6 +1253,8 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, else { error.SetErrorString ("failed to bind to port 0 on 127.0.0.1"); + if (log) + log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); return error; } } @@ -824,12 +1266,21 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, debugserver_args.AppendArgument(arg_cstr); } +#if defined(__APPLE__) const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); if (env_debugserver_log_flags) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } +#else + const char *env_debugserver_log_channels = getenv("LLDB_SERVER_LOG_CHANNELS"); + if (env_debugserver_log_channels) + { + ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-channels=%s", env_debugserver_log_channels); + debugserver_args.AppendArgument(arg_cstr); + } +#endif // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back. uint32_t env_var_index = 1; @@ -865,56 +1316,70 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, { if (named_pipe_path.size() > 0) { - error = port_named_pipe.OpenAsReader(named_pipe_path, false); + error = port_pipe.OpenAsReader(named_pipe_path, false); + if (error.Fail()) + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "failed to open named pipe %s for reading: %s", + __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); + } + + if (port_pipe.CanWrite()) + port_pipe.CloseWriteFileDescriptor(); + if (port_pipe.CanRead()) + { + char port_cstr[256]; + port_cstr[0] = '\0'; + size_t num_bytes = sizeof(port_cstr); + // Read port from pipe with 10 second timeout. + error = port_pipe.ReadWithTimeout(port_cstr, num_bytes, + std::chrono::seconds{10}, num_bytes); if (error.Success()) { - char port_cstr[256]; - port_cstr[0] = '\0'; - size_t num_bytes = sizeof(port_cstr); - // Read port from pipe with 10 second timeout. - error = port_named_pipe.ReadWithTimeout(port_cstr, num_bytes, std::chrono::microseconds(10 * 1000000), num_bytes); - if (error.Success()) - { - assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); - out_port = StringConvert::ToUInt32(port_cstr, 0); - if (log) - log->Printf("GDBRemoteCommunication::%s() debugserver listens %u port", __FUNCTION__, out_port); - } - else - { - if (log) - log->Printf("GDBRemoteCommunication::%s() failed to read a port value from named pipe %s: %s", __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); - - } - port_named_pipe.Close(); + assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); + out_port = StringConvert::ToUInt32(port_cstr, 0); + if (log) + log->Printf("GDBRemoteCommunication::%s() " + "debugserver listens %u port", + __FUNCTION__, out_port); } else { if (log) - log->Printf("GDBRemoteCommunication::%s() failed to open named pipe %s for reading: %s", __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); + log->Printf("GDBRemoteCommunication::%s() " + "failed to read a port value from pipe %s: %s", + __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); + } - const auto err = port_named_pipe.Delete(named_pipe_path); + port_pipe.Close(); + } + + if (named_pipe_path.size() > 0) + { + const auto err = port_pipe.Delete(named_pipe_path); if (err.Fail()) { if (log) - log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s", __FUNCTION__, named_pipe_path.c_str(), err.AsCString()); + log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s", + __FUNCTION__, named_pipe_path.c_str(), err.AsCString()); } } - else if (listen) - { - - } - else - { - // Make sure we actually connect with the debugserver... - JoinListenThread(); - } + + // Make sure we actually connect with the debugserver... + JoinListenThread(); } } else { error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); } + + if (error.Fail()) + { + if (log) + log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); + } + return error; } @@ -923,3 +1388,65 @@ GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump (strm); } + +GDBRemoteCommunication::ScopedTimeout::ScopedTimeout (GDBRemoteCommunication& gdb_comm, + uint32_t timeout) : + m_gdb_comm (gdb_comm) +{ + m_saved_timeout = m_gdb_comm.SetPacketTimeout (timeout); +} + +GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout () +{ + m_gdb_comm.SetPacketTimeout (m_saved_timeout); +} + +// This function is called via the Communications class read thread when bytes become available +// for this connection. This function will consume all incoming bytes and try to parse whole +// packets as they become available. Full packets are placed in a queue, so that all packet +// requests can simply pop from this queue. Async notification packets will be dispatched +// immediately to the ProcessGDBRemote Async thread via an event. +void GDBRemoteCommunication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, lldb::ConnectionStatus status) +{ + StringExtractorGDBRemote packet; + + while (true) + { + PacketType type = CheckForPacket(bytes, len, packet); + + // scrub the data so we do not pass it back to CheckForPacket + // on future passes of the loop + bytes = nullptr; + len = 0; + + // we may have received no packet so lets bail out + if (type == PacketType::Invalid) + break; + + if (type == PacketType::Standard) + { + // scope for the mutex + { + // lock down the packet queue + Mutex::Locker locker(m_packet_queue_mutex); + // push a new packet into the queue + m_packet_queue.push(packet); + // Signal condition variable that we have a packet + m_condition_queue_not_empty.Signal(); + + } + } + + if (type == PacketType::Notify) + { + // put this packet into an event + const char *pdata = packet.GetStringRef().c_str(); + + // as the communication class, we are a broadcaster and the + // async thread is tuned to listen to us + BroadcastEvent( + eBroadcastBitGdbReadThreadGotNotify, + new EventDataBytes(pdata)); + } + } +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index ee2f3276513d..7379bb3aa09b 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -14,6 +14,7 @@ // C++ Includes #include <list> #include <string> +#include <queue> // Other libraries and framework includes // Project includes @@ -27,6 +28,9 @@ #include "Utility/StringExtractorGDBRemote.h" +namespace lldb_private { +namespace process_gdb_remote { + typedef enum { eStoppointInvalid = -1, @@ -37,16 +41,33 @@ typedef enum eWatchpointReadWrite } GDBStoppointType; +enum class CompressionType +{ + None = 0, // no compression + ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's libcompression + LZFSE, // an Apple compression scheme, requires Apple's libcompression + LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with https://code.google.com/p/lz4/ + LZMA, // Lempel–Ziv–Markov chain algorithm +}; + class ProcessGDBRemote; -class GDBRemoteCommunication : public lldb_private::Communication +class GDBRemoteCommunication : public Communication { public: enum { - eBroadcastBitRunPacketSent = kLoUserBroadcastBit + eBroadcastBitRunPacketSent = kLoUserBroadcastBit, + eBroadcastBitGdbReadThreadGotNotify = kLoUserBroadcastBit << 1 // Sent when we received a notify packet. }; - + + enum class PacketType + { + Invalid = 0, + Standard, + Notify + }; + enum class PacketResult { Success = 0, // Success @@ -59,12 +80,25 @@ public: ErrorDisconnected, // We were disconnected ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet request }; + + // Class to change the timeout for a given scope and restore it to the original value when the + // created ScopedTimeout object got out of scope + class ScopedTimeout + { + public: + ScopedTimeout (GDBRemoteCommunication& gdb_comm, uint32_t timeout); + ~ScopedTimeout (); + + private: + GDBRemoteCommunication& m_gdb_comm; + uint32_t m_saved_timeout; + }; + //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ GDBRemoteCommunication(const char *comm_name, - const char *listener_name, - bool is_platform); + const char *listener_name); virtual ~GDBRemoteCommunication(); @@ -83,9 +117,9 @@ public: size_t payload_length); bool - GetSequenceMutex (lldb_private::Mutex::Locker& locker, const char *failure_message = NULL); + GetSequenceMutex (Mutex::Locker& locker, const char *failure_message = NULL); - bool + PacketType CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet); @@ -126,20 +160,20 @@ public: uint32_t GetPacketTimeoutInMicroSeconds () const { - return m_packet_timeout * lldb_private::TimeValue::MicroSecPerSec; + return m_packet_timeout * TimeValue::MicroSecPerSec; } //------------------------------------------------------------------ // Start a debugserver instance on the current host using the // supplied connection URL. //------------------------------------------------------------------ - lldb_private::Error + Error StartDebugserverProcess (const char *hostname, uint16_t in_port, // If set to zero, then out_port will contain the bound port on exit - lldb_private::ProcessLaunchInfo &launch_info, + ProcessLaunchInfo &launch_info, uint16_t &out_port); void - DumpHistory(lldb_private::Stream &strm); + DumpHistory(Stream &strm); protected: @@ -196,10 +230,10 @@ protected: uint32_t bytes_transmitted); void - Dump (lldb_private::Stream &strm) const; + Dump (Stream &strm) const; void - Dump (lldb_private::Log *log) const; + Dump (Log *log) const; bool DidDumpToLog () const @@ -257,33 +291,59 @@ protected: size_t payload_length); PacketResult + ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout); + + // Pop a packet from the queue in a thread safe manner + PacketResult + PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec); + + PacketResult WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response, - uint32_t timeout_usec); + uint32_t timeout_usec, + bool sync_on_timeout); + + bool + WaitForNotRunningPrivate (const TimeValue *timeout_ptr); + + bool + CompressionIsEnabled () + { + return m_compression_type != CompressionType::None; + } + // If compression is enabled, decompress the packet in m_bytes and update + // m_bytes with the uncompressed version. + // Returns 'true' packet was decompressed and m_bytes is the now-decompressed text. + // Returns 'false' if unable to decompress or if the checksum was invalid. + // + // NB: Once the packet has been decompressed, checksum cannot be computed based + // on m_bytes. The checksum was for the compressed packet. bool - WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr); + DecompressPacket (); //------------------------------------------------------------------ // Classes that inherit from GDBRemoteCommunication can see and modify these //------------------------------------------------------------------ uint32_t m_packet_timeout; + uint32_t m_echo_number; + LazyBool m_supports_qEcho; #ifdef ENABLE_MUTEX_ERROR_CHECKING - lldb_private::TrackingMutex m_sequence_mutex; + TrackingMutex m_sequence_mutex; #else - lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time + Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time #endif - lldb_private::Predicate<bool> m_public_is_running; - lldb_private::Predicate<bool> m_private_is_running; + Predicate<bool> m_public_is_running; + Predicate<bool> m_private_is_running; History m_history; bool m_send_acks; bool m_is_platform; // Set to true if this class represents a platform, // false if this class represents a debug session for // a single process + CompressionType m_compression_type; - lldb_private::Error - StartListenThread (const char *hostname = "127.0.0.1", - uint16_t port = 0); + Error + StartListenThread (const char *hostname = "127.0.0.1", uint16_t port = 0); bool JoinListenThread (); @@ -291,8 +351,25 @@ protected: static lldb::thread_result_t ListenThread (lldb::thread_arg_t arg); + // GDB-Remote read thread + // . this thread constantly tries to read from the communication + // class and stores all packets received in a queue. The usual + // threads read requests simply pop packets off the queue in the + // usual order. + // This setup allows us to intercept and handle async packets, such + // as the notify packet. + + // This method is defined as part of communication.h + // when the read thread gets any bytes it will pass them on to this function + virtual void AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, lldb::ConnectionStatus status); + private: - lldb_private::HostThread m_listen_thread; + + std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue + lldb_private::Mutex m_packet_queue_mutex; // Mutex for accessing queue + Condition m_condition_queue_not_empty; // Condition variable to wait for packets + + HostThread m_listen_thread; std::string m_listen_url; //------------------------------------------------------------------ @@ -301,4 +378,7 @@ private: DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication); }; +} // namespace process_gdb_remote +} // namespace lldb_private + #endif // liblldb_GDBRemoteCommunication_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 0f99688fc823..ae0a2f5e66c5 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -11,16 +11,19 @@ #include "GDBRemoteCommunicationClient.h" // C Includes +#include <math.h> #include <sys/stat.h> // C++ Includes #include <sstream> +#include <numeric> // Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "lldb/Interpreter/Args.h" #include "lldb/Core/Log.h" +#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" @@ -30,7 +33,10 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Symbol/Symbol.h" #include "lldb/Target/Target.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/UnixSignals.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -38,18 +44,19 @@ #include "ProcessGDBRemoteLog.h" #include "lldb/Host/Config.h" +#if defined (HAVE_LIBCOMPRESSION) +#include <compression.h> +#endif + using namespace lldb; using namespace lldb_private; - -#if defined(LLDB_DISABLE_POSIX) && !defined(SIGSTOP) -#define SIGSTOP 17 -#endif +using namespace lldb_private::process_gdb_remote; //---------------------------------------------------------------------- // GDBRemoteCommunicationClient constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : - GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet", is_platform), +GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : + GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet"), m_supports_not_sending_acks (eLazyBoolCalculate), m_supports_thread_suffix (eLazyBoolCalculate), m_supports_threads_in_stop_reply (eLazyBoolCalculate), @@ -77,6 +84,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_supports_qXfer_auxv_read (eLazyBoolCalculate), m_supports_qXfer_libraries_read (eLazyBoolCalculate), m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate), + m_supports_qXfer_features_read (eLazyBoolCalculate), m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate), m_supports_jThreadExtendedInfo (eLazyBoolCalculate), m_supports_qProcessInfoPID (true), @@ -91,6 +99,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_supports_z4 (true), m_supports_QEnvironment (true), m_supports_QEnvironmentHexEncoded (true), + m_supports_qSymbol (true), + m_supports_jThreadsInfo (true), m_curr_pid (LLDB_INVALID_PROCESS_ID), m_curr_tid (LLDB_INVALID_THREAD_ID), m_curr_tid_run (LLDB_INVALID_THREAD_ID), @@ -130,7 +140,7 @@ GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() bool GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) { - ResetDiscoverableSettings(); + ResetDiscoverableSettings(false); // Start the read thread after we send the handshake ack since if we // fail to send the handshake ack, there is no reason to continue... @@ -142,7 +152,7 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) PacketResult packet_result = PacketResult::Success; const uint32_t timeout_usec = 10 * 1000; // Wait for 10 ms for a response while (packet_result == PacketResult::Success) - packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec); + packet_result = ReadPacket (response, timeout_usec, false); // The return value from QueryNoAckModeSupported() is true if the packet // was sent and _any_ response (including UNIMPLEMENTED) was received), @@ -150,11 +160,6 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) // a live connection to a remote GDB server... if (QueryNoAckModeSupported()) { -#if 0 - // Set above line to "#if 1" to test packet speed if remote GDB server - // supports the qSpeedTest packet... - TestPacketSpeed(10000); -#endif return true; } else @@ -172,13 +177,24 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) } bool +GDBRemoteCommunicationClient::GetEchoSupported () +{ + if (m_supports_qEcho == eLazyBoolCalculate) + { + GetRemoteQSupported(); + } + return m_supports_qEcho == eLazyBoolYes; +} + + +bool GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported () { if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) { GetRemoteQSupported(); } - return (m_supports_augmented_libraries_svr4_read == eLazyBoolYes); + return m_supports_augmented_libraries_svr4_read == eLazyBoolYes; } bool @@ -188,7 +204,7 @@ GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported () { GetRemoteQSupported(); } - return (m_supports_qXfer_libraries_svr4_read == eLazyBoolYes); + return m_supports_qXfer_libraries_svr4_read == eLazyBoolYes; } bool @@ -198,7 +214,7 @@ GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported () { GetRemoteQSupported(); } - return (m_supports_qXfer_libraries_read == eLazyBoolYes); + return m_supports_qXfer_libraries_read == eLazyBoolYes; } bool @@ -208,7 +224,17 @@ GDBRemoteCommunicationClient::GetQXferAuxvReadSupported () { GetRemoteQSupported(); } - return (m_supports_qXfer_auxv_read == eLazyBoolYes); + return m_supports_qXfer_auxv_read == eLazyBoolYes; +} + +bool +GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported () +{ + if (m_supports_qXfer_features_read == eLazyBoolCalculate) + { + GetRemoteQSupported(); + } + return m_supports_qXfer_features_read == eLazyBoolYes; } uint64_t @@ -234,13 +260,10 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported () const uint32_t minimum_timeout = 6; uint32_t old_timeout = GetPacketTimeoutInMicroSeconds() / lldb_private::TimeValue::MicroSecPerSec; - SetPacketTimeout (std::max (old_timeout, minimum_timeout)); + GDBRemoteCommunication::ScopedTimeout timeout (*this, std::max (old_timeout, minimum_timeout)); StringExtractorGDBRemote response; - PacketResult packet_send_result = SendPacketAndWaitForResponse("QStartNoAckMode", response, false); - SetPacketTimeout (old_timeout); - - if (packet_send_result == PacketResult::Success) + if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { @@ -311,58 +334,64 @@ GDBRemoteCommunicationClient::GetSyncThreadStateSupported () void -GDBRemoteCommunicationClient::ResetDiscoverableSettings() -{ - m_supports_not_sending_acks = eLazyBoolCalculate; - m_supports_thread_suffix = eLazyBoolCalculate; - m_supports_threads_in_stop_reply = eLazyBoolCalculate; - m_supports_vCont_c = eLazyBoolCalculate; - m_supports_vCont_C = eLazyBoolCalculate; - m_supports_vCont_s = eLazyBoolCalculate; - m_supports_vCont_S = eLazyBoolCalculate; - m_supports_p = eLazyBoolCalculate; - m_supports_x = eLazyBoolCalculate; - m_supports_QSaveRegisterState = eLazyBoolCalculate; - m_qHostInfo_is_valid = eLazyBoolCalculate; - m_curr_pid_is_valid = eLazyBoolCalculate; +GDBRemoteCommunicationClient::ResetDiscoverableSettings (bool did_exec) +{ + if (did_exec == false) + { + // Hard reset everything, this is when we first connect to a GDB server + m_supports_not_sending_acks = eLazyBoolCalculate; + m_supports_thread_suffix = eLazyBoolCalculate; + m_supports_threads_in_stop_reply = eLazyBoolCalculate; + m_supports_vCont_c = eLazyBoolCalculate; + m_supports_vCont_C = eLazyBoolCalculate; + m_supports_vCont_s = eLazyBoolCalculate; + m_supports_vCont_S = eLazyBoolCalculate; + m_supports_p = eLazyBoolCalculate; + m_supports_x = eLazyBoolCalculate; + m_supports_QSaveRegisterState = eLazyBoolCalculate; + m_qHostInfo_is_valid = eLazyBoolCalculate; + m_curr_pid_is_valid = eLazyBoolCalculate; + m_qGDBServerVersion_is_valid = eLazyBoolCalculate; + m_supports_alloc_dealloc_memory = eLazyBoolCalculate; + m_supports_memory_region_info = eLazyBoolCalculate; + m_prepare_for_reg_writing_reply = eLazyBoolCalculate; + m_attach_or_wait_reply = eLazyBoolCalculate; + m_avoid_g_packets = eLazyBoolCalculate; + m_supports_qXfer_auxv_read = eLazyBoolCalculate; + m_supports_qXfer_libraries_read = eLazyBoolCalculate; + m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; + m_supports_qXfer_features_read = eLazyBoolCalculate; + m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; + m_supports_qProcessInfoPID = true; + m_supports_qfProcessInfo = true; + m_supports_qUserName = true; + m_supports_qGroupName = true; + m_supports_qThreadStopInfo = true; + m_supports_z0 = true; + m_supports_z1 = true; + m_supports_z2 = true; + m_supports_z3 = true; + m_supports_z4 = true; + m_supports_QEnvironment = true; + m_supports_QEnvironmentHexEncoded = true; + m_supports_qSymbol = true; + m_host_arch.Clear(); + m_os_version_major = UINT32_MAX; + m_os_version_minor = UINT32_MAX; + m_os_version_update = UINT32_MAX; + m_os_build.clear(); + m_os_kernel.clear(); + m_hostname.clear(); + m_gdb_server_name.clear(); + m_gdb_server_version = UINT32_MAX; + m_default_packet_timeout = 0; + m_max_packet_size = 0; + } + + // These flags should be reset when we first connect to a GDB server + // and when our inferior process execs m_qProcessInfo_is_valid = eLazyBoolCalculate; - m_qGDBServerVersion_is_valid = eLazyBoolCalculate; - m_supports_alloc_dealloc_memory = eLazyBoolCalculate; - m_supports_memory_region_info = eLazyBoolCalculate; - m_prepare_for_reg_writing_reply = eLazyBoolCalculate; - m_attach_or_wait_reply = eLazyBoolCalculate; - m_avoid_g_packets = eLazyBoolCalculate; - m_supports_qXfer_auxv_read = eLazyBoolCalculate; - m_supports_qXfer_libraries_read = eLazyBoolCalculate; - m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; - m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; - - m_supports_qProcessInfoPID = true; - m_supports_qfProcessInfo = true; - m_supports_qUserName = true; - m_supports_qGroupName = true; - m_supports_qThreadStopInfo = true; - m_supports_z0 = true; - m_supports_z1 = true; - m_supports_z2 = true; - m_supports_z3 = true; - m_supports_z4 = true; - m_supports_QEnvironment = true; - m_supports_QEnvironmentHexEncoded = true; - - m_host_arch.Clear(); m_process_arch.Clear(); - m_os_version_major = UINT32_MAX; - m_os_version_minor = UINT32_MAX; - m_os_version_update = UINT32_MAX; - m_os_build.clear(); - m_os_kernel.clear(); - m_hostname.clear(); - m_gdb_server_name.clear(); - m_gdb_server_version = UINT32_MAX; - m_default_packet_timeout = 0; - - m_max_packet_size = 0; } void @@ -373,10 +402,21 @@ GDBRemoteCommunicationClient::GetRemoteQSupported () m_supports_qXfer_libraries_read = eLazyBoolNo; m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; m_supports_augmented_libraries_svr4_read = eLazyBoolNo; + m_supports_qXfer_features_read = eLazyBoolNo; m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit + // build the qSupported packet + std::vector<std::string> features = {"xmlRegisters=i386,arm,mips"}; + StreamString packet; + packet.PutCString( "qSupported" ); + for ( uint32_t i = 0; i < features.size( ); ++i ) + { + packet.PutCString( i==0 ? ":" : ";"); + packet.PutCString( features[i].c_str( ) ); + } + StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qSupported", + if (SendPacketAndWaitForResponse(packet.GetData(), response, /*send_async=*/false) == PacketResult::Success) { @@ -392,6 +432,66 @@ GDBRemoteCommunicationClient::GetRemoteQSupported () } if (::strstr (response_cstr, "qXfer:libraries:read+")) m_supports_qXfer_libraries_read = eLazyBoolYes; + if (::strstr (response_cstr, "qXfer:features:read+")) + m_supports_qXfer_features_read = eLazyBoolYes; + + + // Look for a list of compressions in the features list e.g. + // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma + const char *features_list = ::strstr (response_cstr, "qXfer:features:"); + if (features_list) + { + const char *compressions = ::strstr (features_list, "SupportedCompressions="); + if (compressions) + { + std::vector<std::string> supported_compressions; + compressions += sizeof ("SupportedCompressions=") - 1; + const char *end_of_compressions = strchr (compressions, ';'); + if (end_of_compressions == NULL) + { + end_of_compressions = strchr (compressions, '\0'); + } + const char *current_compression = compressions; + while (current_compression < end_of_compressions) + { + const char *next_compression_name = strchr (current_compression, ','); + const char *end_of_this_word = next_compression_name; + if (next_compression_name == NULL || end_of_compressions < next_compression_name) + { + end_of_this_word = end_of_compressions; + } + + if (end_of_this_word) + { + if (end_of_this_word == current_compression) + { + current_compression++; + } + else + { + std::string this_compression (current_compression, end_of_this_word - current_compression); + supported_compressions.push_back (this_compression); + current_compression = end_of_this_word + 1; + } + } + else + { + supported_compressions.push_back (current_compression); + current_compression = end_of_compressions; + } + } + + if (supported_compressions.size() > 0) + { + MaybeEnableCompression (supported_compressions); + } + } + } + + if (::strstr (response_cstr, "qEcho")) + m_supports_qEcho = eLazyBoolYes; + else + m_supports_qEcho = eLazyBoolNo; const char *packet_size_str = ::strstr (response_cstr, "PacketSize="); if (packet_size_str) @@ -509,6 +609,32 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) return m_supports_p; } +StructuredData::ObjectSP +GDBRemoteCommunicationClient::GetThreadsInfo() +{ + // Get information on all threads at one using the "jThreadsInfo" packet + StructuredData::ObjectSP object_sp; + + if (m_supports_jThreadsInfo) + { + StringExtractorGDBRemote response; + m_supports_jThreadExtendedInfo = eLazyBoolNo; + if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == PacketResult::Success) + { + if (response.IsUnsupportedResponse()) + { + m_supports_jThreadsInfo = false; + } + else if (!response.Empty()) + { + object_sp = StructuredData::ParseJSON (response.GetStringRef()); + } + } + } + return object_sp; +} + + bool GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported () { @@ -619,7 +745,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponseNoLock (const char *pa { PacketResult packet_result = SendPacketNoLock (payload, payload_length); if (packet_result == PacketResult::Success) - packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); + packet_result = ReadPacket (response, GetPacketTimeoutInMicroSeconds (), true); return packet_result; } @@ -635,6 +761,12 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse PacketResult packet_result = PacketResult::ErrorSendFailed; Mutex::Locker locker; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + + // In order to stop async notifications from being processed in the middle of the + // send/recieve sequence Hijack the broadcast. Then rebroadcast any events when we are done. + static Listener hijack_listener("lldb.NotifyHijacker"); + HijackBroadcaster(&hijack_listener, eBroadcastBitGdbReadThreadGotNotify); + if (GetSequenceMutex (locker)) { packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); @@ -726,6 +858,15 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload); } } + + // Remove our Hijacking listner from the broadcast. + RestoreBroadcaster(); + + // If a notification event occured, rebroadcast since it can now be processed safely. + EventSP event_sp; + if (hijack_listener.GetNextEvent(event_sp)) + BroadcastEvent(event_sp); + return packet_result; } @@ -822,6 +963,57 @@ GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData return final_output.str(); } +bool +GDBRemoteCommunicationClient::SendvContPacket +( + ProcessGDBRemote *process, + const char *payload, + size_t packet_length, + StringExtractorGDBRemote &response +) +{ + + m_curr_tid = LLDB_INVALID_THREAD_ID; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); + + // we want to lock down packet sending while we continue + Mutex::Locker locker(m_sequence_mutex); + + // here we broadcast this before we even send the packet!! + // this signals doContinue() to exit + BroadcastEvent(eBroadcastBitRunPacketSent, NULL); + + // set the public state to running + m_public_is_running.SetValue(true, eBroadcastNever); + + // Set the starting continue packet into "continue_packet". This packet + // may change if we are interrupted and we continue after an async packet... + std::string continue_packet(payload, packet_length); + + if (log) + log->Printf("GDBRemoteCommunicationClient::%s () sending vCont packet: %s", __FUNCTION__, continue_packet.c_str()); + + if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) + return false; + + // set the private state to running and broadcast this + m_private_is_running.SetValue(true, eBroadcastAlways); + + if (log) + log->Printf("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); + + // wait for the response to the vCont + if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + return true; + } + + return false; +} + StateType GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse ( @@ -844,7 +1036,10 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse // Set the starting continue packet into "continue_packet". This packet // may change if we are interrupted and we continue after an async packet... std::string continue_packet(payload, packet_length); - + + const auto sigstop_signo = process->GetUnixSignals().GetSignalNumberFromName("SIGSTOP"); + const auto sigint_signo = process->GetUnixSignals().GetSignalNumberFromName("SIGINT"); + bool got_async_packet = false; while (state == eStateRunning) @@ -864,9 +1059,9 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse got_async_packet = false; if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%s)", __FUNCTION__, continue_packet.c_str()); + log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); - if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX) == PacketResult::Success) + if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success) { if (response.Empty()) state = eStateInvalid; @@ -914,16 +1109,16 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse // packet. If we don't do this, then the reply for our // async packet will be the repeat stop reply packet and cause // a lot of trouble for us! - if (signo != SIGINT && signo != SIGSTOP) + if (signo != sigint_signo && signo != sigstop_signo) { continue_after_async = false; - // We didn't get a a SIGINT or SIGSTOP, so try for a + // We didn't get a SIGINT or SIGSTOP, so try for a // very brief time (1 ms) to get another stop reply // packet to make sure it doesn't get in the way StringExtractorGDBRemote extra_stop_reply_packet; uint32_t timeout_usec = 1000; - if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec) == PacketResult::Success) + if (ReadPacket (extra_stop_reply_packet, timeout_usec, false) == PacketResult::Success) { switch (extra_stop_reply_packet.GetChar()) { @@ -1101,7 +1296,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse else { if (log) - log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(...) => false", __FUNCTION__); + log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(...) => false", __FUNCTION__); state = eStateInvalid; } } @@ -1287,7 +1482,7 @@ GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &laun const char *arg = NULL; const Args &launch_args = launch_info.GetArguments(); if (exe_file) - exe_path = exe_file.GetPath(); + exe_path = exe_file.GetPath(false); else { arg = launch_args.GetArgumentAtIndex(0); @@ -1576,6 +1771,105 @@ GDBRemoteCommunicationClient::GetGDBServerVersion() return m_qGDBServerVersion_is_valid == eLazyBoolYes; } +void +GDBRemoteCommunicationClient::MaybeEnableCompression (std::vector<std::string> supported_compressions) +{ + CompressionType avail_type = CompressionType::None; + std::string avail_name; + +#if defined (HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is available + if (compression_decode_buffer != NULL && avail_type == CompressionType::None) + { + for (auto compression : supported_compressions) + { + if (compression == "lzfse") + { + avail_type = CompressionType::LZFSE; + avail_name = compression; + break; + } + } + } +#endif + +#if defined (HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is available + if (compression_decode_buffer != NULL && avail_type == CompressionType::None) + { + for (auto compression : supported_compressions) + { + if (compression == "zlib-deflate") + { + avail_type = CompressionType::ZlibDeflate; + avail_name = compression; + break; + } + } + } +#endif + +#if defined (HAVE_LIBZ) + if (avail_type == CompressionType::None) + { + for (auto compression : supported_compressions) + { + if (compression == "zlib-deflate") + { + avail_type = CompressionType::ZlibDeflate; + avail_name = compression; + break; + } + } + } +#endif + +#if defined (HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is available + if (compression_decode_buffer != NULL && avail_type == CompressionType::None) + { + for (auto compression : supported_compressions) + { + if (compression == "lz4") + { + avail_type = CompressionType::LZ4; + avail_name = compression; + break; + } + } + } +#endif + +#if defined (HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is available + if (compression_decode_buffer != NULL && avail_type == CompressionType::None) + { + for (auto compression : supported_compressions) + { + if (compression == "lzma") + { + avail_type = CompressionType::LZMA; + avail_name = compression; + break; + } + } + } +#endif + + if (avail_type != CompressionType::None) + { + StringExtractorGDBRemote response; + std::string packet = "QEnableCompression:type:" + avail_name + ";"; + if (SendPacketAndWaitForResponse (packet.c_str(), response, false) != PacketResult::Success) + return; + + if (response.IsOKResponse()) + { + m_compression_type = avail_type; + } + } +} + const char * GDBRemoteCommunicationClient::GetGDBServerProgramName() { @@ -1596,6 +1890,22 @@ GDBRemoteCommunicationClient::GetGDBServerProgramVersion() } bool +GDBRemoteCommunicationClient::GetDefaultThreadId (lldb::tid_t &tid) +{ + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qC",response,false) != PacketResult::Success) + return false; + + if (!response.IsNormalResponse()) + return false; + + if (response.GetChar() == 'Q' && response.GetChar() == 'C') + tid = response.GetHexMaxU32(true, -1); + + return true; +} + +bool GDBRemoteCommunicationClient::GetHostInfo (bool force) { Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS)); @@ -2167,13 +2477,14 @@ GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after } int -GDBRemoteCommunicationClient::SetSTDIN (char const *path) +GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec) { - if (path && path[0]) + if (file_spec) { + std::string path{file_spec.GetPath(false)}; StreamString packet; packet.PutCString("QSetSTDIN:"); - packet.PutBytesAsRawHex8(path, strlen(path)); + packet.PutCStringAsRawHex8(path.c_str()); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) @@ -2189,14 +2500,15 @@ GDBRemoteCommunicationClient::SetSTDIN (char const *path) } int -GDBRemoteCommunicationClient::SetSTDOUT (char const *path) +GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec) { - if (path && path[0]) + if (file_spec) { + std::string path{file_spec.GetPath(false)}; StreamString packet; packet.PutCString("QSetSTDOUT:"); - packet.PutBytesAsRawHex8(path, strlen(path)); - + packet.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { @@ -2211,14 +2523,15 @@ GDBRemoteCommunicationClient::SetSTDOUT (char const *path) } int -GDBRemoteCommunicationClient::SetSTDERR (char const *path) +GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec) { - if (path && path[0]) + if (file_spec) { + std::string path{file_spec.GetPath(false)}; StreamString packet; packet.PutCString("QSetSTDERR:"); - packet.PutBytesAsRawHex8(path, strlen(path)); - + packet.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { @@ -2233,7 +2546,7 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path) } bool -GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd) +GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) { StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success) @@ -2242,21 +2555,24 @@ GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd) return false; if (response.IsErrorResponse()) return false; - response.GetHexByteString (cwd); + std::string cwd; + response.GetHexByteString(cwd); + working_dir.SetFile(cwd, false, GetHostArchitecture()); return !cwd.empty(); } return false; } int -GDBRemoteCommunicationClient::SetWorkingDir (char const *path) +GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir) { - if (path && path[0]) + if (working_dir) { + std::string path{working_dir.GetPath(false)}; StreamString packet; packet.PutCString("QSetWorkingDir:"); - packet.PutBytesAsRawHex8(path, strlen(path)); - + packet.PutCStringAsRawHex8(path.c_str()); + StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { @@ -2653,6 +2969,9 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat } } StringExtractorGDBRemote response; + // Increase timeout as the first qfProcessInfo packet takes a long time + // on Android. The value of 1min was arrived at empirically. + GDBRemoteCommunication::ScopedTimeout timeout (*this, 60); if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { do @@ -2734,87 +3053,184 @@ GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name) return false; } +bool +GDBRemoteCommunicationClient::SetNonStopMode (const bool enable) +{ + // Form non-stop packet request + char packet[32]; + const int packet_len = ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable); + assert(packet_len < (int)sizeof(packet)); + + StringExtractorGDBRemote response; + // Send to target + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) + if (response.IsOKResponse()) + return true; + + // Failed or not supported + return false; + +} + +static void +MakeSpeedTestPacket(StreamString &packet, uint32_t send_size, uint32_t recv_size) +{ + packet.Clear(); + packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size); + uint32_t bytes_left = send_size; + while (bytes_left > 0) + { + if (bytes_left >= 26) + { + packet.PutCString("abcdefghijklmnopqrstuvwxyz"); + bytes_left -= 26; + } + else + { + packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); + bytes_left = 0; + } + } +} + +template<typename T> +T calculate_standard_deviation(const std::vector<T> &v) +{ + T sum = std::accumulate(std::begin(v), std::end(v), T(0)); + T mean = sum / (T)v.size(); + T accum = T(0); + std::for_each (std::begin(v), std::end(v), [&](const T d) { + T delta = d - mean; + accum += delta * delta; + }); + + T stdev = sqrt(accum / (v.size()-1)); + return stdev; +} + void -GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets) +GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm) { uint32_t i; TimeValue start_time, end_time; uint64_t total_time_nsec; if (SendSpeedTestPacket (0, 0)) { - static uint32_t g_send_sizes[] = { 0, 64, 128, 512, 1024 }; - static uint32_t g_recv_sizes[] = { 0, 64, 128, 512, 1024 }; //, 4*1024, 8*1024, 16*1024, 32*1024, 48*1024, 64*1024, 96*1024, 128*1024 }; - const size_t k_num_send_sizes = llvm::array_lengthof(g_send_sizes); - const size_t k_num_recv_sizes = llvm::array_lengthof(g_recv_sizes); - const uint64_t k_recv_amount = 4*1024*1024; // Receive 4MB - for (uint32_t send_idx = 0; send_idx < k_num_send_sizes; ++send_idx) - { - const uint32_t send_size = g_send_sizes[send_idx]; - for (uint32_t recv_idx = 0; recv_idx < k_num_recv_sizes; ++recv_idx) - { - const uint32_t recv_size = g_recv_sizes[recv_idx]; - StreamString packet; - packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size); - uint32_t bytes_left = send_size; - while (bytes_left > 0) + StreamString packet; + if (json) + strm.Printf("{ \"packet_speeds\" : {\n \"num_packets\" : %u,\n \"results\" : [", num_packets); + else + strm.Printf("Testing sending %u packets of various sizes:\n", num_packets); + strm.Flush(); + + uint32_t result_idx = 0; + uint32_t send_size; + std::vector<float> packet_times; + + for (send_size = 0; send_size <= max_send; send_size ? send_size *= 2 : send_size = 4) + { + for (uint32_t recv_size = 0; recv_size <= max_recv; recv_size ? recv_size *= 2 : recv_size = 4) + { + MakeSpeedTestPacket (packet, send_size, recv_size); + + packet_times.clear(); + // Test how long it takes to send 'num_packets' packets + start_time = TimeValue::Now(); + for (i=0; i<num_packets; ++i) { - if (bytes_left >= 26) - { - packet.PutCString("abcdefghijklmnopqrstuvwxyz"); - bytes_left -= 26; - } - else - { - packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); - bytes_left = 0; - } + TimeValue packet_start_time = TimeValue::Now(); + StringExtractorGDBRemote response; + SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); + TimeValue packet_end_time = TimeValue::Now(); + uint64_t packet_time_nsec = packet_end_time.GetAsNanoSecondsSinceJan1_1970() - packet_start_time.GetAsNanoSecondsSinceJan1_1970(); + packet_times.push_back((float)packet_time_nsec); } + end_time = TimeValue::Now(); + total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); - start_time = TimeValue::Now(); - if (recv_size == 0) + float packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; + float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec; + float average_ms_per_packet = total_ms / num_packets; + const float standard_deviation = calculate_standard_deviation<float>(packet_times); + if (json) { - for (i=0; i<num_packets; ++i) - { - StringExtractorGDBRemote response; - SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); - } + strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 ", \"standard_deviation_nsec\" : %9" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec, (uint64_t)standard_deviation); + ++result_idx; } else { - uint32_t bytes_read = 0; - while (bytes_read < k_recv_amount) - { - StringExtractorGDBRemote response; - SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); - bytes_read += recv_size; - } + strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) in %" PRIu64 ".%9.9" PRIu64 " sec for %9.2f packets/sec (%10.6f ms per packet) with standard deviation of %10.6f ms\n", + send_size, + recv_size, + total_time_nsec / TimeValue::NanoSecPerSec, + total_time_nsec % TimeValue::NanoSecPerSec, + packets_per_second, + average_ms_per_packet, + standard_deviation/(float)TimeValue::NanoSecPerMilliSec); + } + strm.Flush(); + } + } + + const uint64_t k_recv_amount = 4*1024*1024; // Receive amount in bytes + + const float k_recv_amount_mb = (float)k_recv_amount/(1024.0f*1024.0f); + if (json) + strm.Printf("\n ]\n },\n \"download_speed\" : {\n \"byte_size\" : %" PRIu64 ",\n \"results\" : [", k_recv_amount); + else + strm.Printf("Testing receiving %2.1fMB of data using varying receive packet sizes:\n", k_recv_amount_mb); + strm.Flush(); + send_size = 0; + result_idx = 0; + for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2) + { + MakeSpeedTestPacket (packet, send_size, recv_size); + + // If we have a receive size, test how long it takes to receive 4MB of data + if (recv_size > 0) + { + start_time = TimeValue::Now(); + uint32_t bytes_read = 0; + uint32_t packet_count = 0; + while (bytes_read < k_recv_amount) + { + StringExtractorGDBRemote response; + SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); + bytes_read += recv_size; + ++packet_count; } end_time = TimeValue::Now(); total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); - if (recv_size == 0) + float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0); + float packets_per_second = (((float)packet_count)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; + float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec; + float average_ms_per_packet = total_ms / packet_count; + + if (json) { - float packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; - printf ("%u qSpeedTest(send=%-7u, recv=%-7u) in %" PRIu64 ".%9.9" PRIu64 " sec for %f packets/sec.\n", - num_packets, - send_size, - recv_size, - total_time_nsec / TimeValue::NanoSecPerSec, - total_time_nsec % TimeValue::NanoSecPerSec, - packets_per_second); + strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec); + ++result_idx; } else { - float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0); - printf ("%u qSpeedTest(send=%-7u, recv=%-7u) sent 4MB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec.\n", - num_packets, - send_size, - recv_size, - total_time_nsec / TimeValue::NanoSecPerSec, - total_time_nsec % TimeValue::NanoSecPerSec, - mb_second); + strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) %6u packets needed to receive %2.1fMB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec for %9.2f packets/sec (%10.6f ms per packet)\n", + send_size, + recv_size, + packet_count, + k_recv_amount_mb, + total_time_nsec / TimeValue::NanoSecPerSec, + total_time_nsec % TimeValue::NanoSecPerSec, + mb_second, + packets_per_second, + average_ms_per_packet); } + strm.Flush(); } } + if (json) + strm.Printf("\n ]\n }\n}\n"); + else + strm.EOL(); } } @@ -2869,10 +3285,9 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const int packet_len = stream.GetSize(); // give the process a few seconds to startup - const uint32_t old_packet_timeout = SetPacketTimeout (10); - auto result = SendPacketAndWaitForResponse(packet, packet_len, response, false); - SetPacketTimeout (old_packet_timeout); - if (result == PacketResult::Success) + GDBRemoteCommunication::ScopedTimeout timeout (*this, 10); + + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { std::string name; std::string value; @@ -3109,22 +3524,23 @@ GDBRemoteCommunicationClient::GetShlibInfoAddr() } lldb_private::Error -GDBRemoteCommunicationClient::RunShellCommand (const char *command, // Shouldn't be NULL - const char *working_dir, // Pass NULL to use the current working directory - int *status_ptr, // Pass NULL if you don't want the process exit status - int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit - std::string *command_output, // Pass NULL if you don't want the command output - uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish +GDBRemoteCommunicationClient::RunShellCommand(const char *command, // Shouldn't be NULL + const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit + std::string *command_output, // Pass NULL if you don't want the command output + uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish { lldb_private::StreamString stream; stream.PutCString("qPlatform_shell:"); stream.PutBytesAsRawHex8(command, strlen(command)); stream.PutChar(','); stream.PutHex32(timeout_sec); - if (working_dir && *working_dir) + if (working_dir) { + std::string path{working_dir.GetPath(false)}; stream.PutChar(','); - stream.PutBytesAsRawHex8(working_dir, strlen(working_dir)); + stream.PutCStringAsRawHex8(path.c_str()); } const char *packet = stream.GetData(); int packet_len = stream.GetSize(); @@ -3157,43 +3573,49 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, // } Error -GDBRemoteCommunicationClient::MakeDirectory (const char *path, - uint32_t file_permissions) +GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec, + uint32_t file_permissions) { + std::string path{file_spec.GetPath(false)}; lldb_private::StreamString stream; stream.PutCString("qPlatform_mkdir:"); stream.PutHex32(file_permissions); stream.PutChar(','); - stream.PutBytesAsRawHex8(path, strlen(path)); + stream.PutCStringAsRawHex8(path.c_str()); const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); - } - return Error(); + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success) + return Error("failed to send '%s' packet", packet); + + if (response.GetChar() != 'F') + return Error("invalid response to '%s' packet", packet); + + return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); } Error -GDBRemoteCommunicationClient::SetFilePermissions (const char *path, - uint32_t file_permissions) +GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec, + uint32_t file_permissions) { + std::string path{file_spec.GetPath(false)}; lldb_private::StreamString stream; stream.PutCString("qPlatform_chmod:"); stream.PutHex32(file_permissions); stream.PutChar(','); - stream.PutBytesAsRawHex8(path, strlen(path)); + stream.PutCStringAsRawHex8(path.c_str()); const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) - { - return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); - } - return Error(); - + + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success) + return Error("failed to send '%s' packet", packet); + + if (response.GetChar() != 'F') + return Error("invalid response to '%s' packet", packet); + + return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); } static uint64_t @@ -3225,15 +3647,14 @@ GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec, mode_t mode, Error &error) { + std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:open:"); - std::string path (file_spec.GetPath()); if (path.empty()) return UINT64_MAX; stream.PutCStringAsRawHex8(path.c_str()); stream.PutChar(','); - const uint32_t posix_open_flags = File::ConvertOpenOptionsForPOSIXOpen(flags); - stream.PutHex32(posix_open_flags); + stream.PutHex32(flags); stream.PutChar(','); stream.PutHex32(mode); const char* packet = stream.GetData(); @@ -3266,9 +3687,9 @@ GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd, lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec) { + std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:size:"); - std::string path (file_spec.GetPath()); stream.PutCStringAsRawHex8(path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); @@ -3284,12 +3705,14 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp } Error -GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &file_permissions) +GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec, + uint32_t &file_permissions) { + std::string path{file_spec.GetPath(false)}; Error error; lldb_private::StreamString stream; stream.PutCString("vFile:mode:"); - stream.PutCStringAsRawHex8(path); + stream.PutCStringAsRawHex8(path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; @@ -3408,16 +3831,18 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, } Error -GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst) +GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, const FileSpec &dst) { + std::string src_path{src.GetPath(false)}, + dst_path{dst.GetPath(false)}; Error error; lldb_private::StreamGDBRemote stream; stream.PutCString("vFile:symlink:"); // the unix symlink() command reverses its parameters where the dst if first, // so we follow suit here - stream.PutCStringAsRawHex8(dst); + stream.PutCStringAsRawHex8(dst_path.c_str()); stream.PutChar(','); - stream.PutCStringAsRawHex8(src); + stream.PutCStringAsRawHex8(src_path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; @@ -3451,14 +3876,15 @@ GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst) } Error -GDBRemoteCommunicationClient::Unlink (const char *path) +GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) { + std::string path{file_spec.GetPath(false)}; Error error; lldb_private::StreamGDBRemote stream; stream.PutCString("vFile:unlink:"); // the unix symlink() command reverses its parameters where the dst if first, // so we follow suit here - stream.PutCStringAsRawHex8(path); + stream.PutCStringAsRawHex8(path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; @@ -3495,9 +3921,9 @@ GDBRemoteCommunicationClient::Unlink (const char *path) bool GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec) { + std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:exists:"); - std::string path (file_spec.GetPath()); stream.PutCStringAsRawHex8(path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); @@ -3519,9 +3945,9 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s uint64_t &high, uint64_t &low) { + std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:MD5:"); - std::string path (file_spec.GetPath()); stream.PutCStringAsRawHex8(path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); @@ -3639,7 +4065,7 @@ GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save if (thread_suffix_supported) ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid); else - ::strncpy (packet, "QSaveRegisterState", sizeof(packet)); + ::snprintf(packet, sizeof(packet), "QSaveRegisterState"); StringExtractorGDBRemote response; @@ -3703,3 +4129,274 @@ GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t sa } return false; } + +bool +GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec, + const lldb_private::ArchSpec& arch_spec, + ModuleSpec &module_spec) +{ + std::string module_path = module_file_spec.GetPath (false); + if (module_path.empty ()) + return false; + + StreamString packet; + packet.PutCString("qModuleInfo:"); + packet.PutCStringAsRawHex8(module_path.c_str()); + packet.PutCString(";"); + const auto& triple = arch_spec.GetTriple().getTriple(); + packet.PutCStringAsRawHex8(triple.c_str()); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) != PacketResult::Success) + return false; + + if (response.IsErrorResponse () || response.IsUnsupportedResponse ()) + return false; + + std::string name; + std::string value; + bool success; + StringExtractor extractor; + + module_spec.Clear (); + module_spec.GetFileSpec () = module_file_spec; + + while (response.GetNameColonValue (name, value)) + { + if (name == "uuid" || name == "md5") + { + extractor.GetStringRef ().swap (value); + extractor.SetFilePos (0); + extractor.GetHexByteString (value); + module_spec.GetUUID().SetFromCString (value.c_str(), value.size() / 2); + } + else if (name == "triple") + { + extractor.GetStringRef ().swap (value); + extractor.SetFilePos (0); + extractor.GetHexByteString (value); + module_spec.GetArchitecture().SetTriple (value.c_str ()); + } + else if (name == "file_offset") + { + const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); + if (success) + module_spec.SetObjectOffset (ival); + } + else if (name == "file_size") + { + const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); + if (success) + module_spec.SetObjectSize (ival); + } + else if (name == "file_path") + { + extractor.GetStringRef ().swap (value); + extractor.SetFilePos (0); + extractor.GetHexByteString (value); + module_spec.GetFileSpec() = FileSpec(value.c_str(), false, arch_spec); + } + } + + return true; +} + +// query the target remote for extended information using the qXfer packet +// +// example: object='features', annex='target.xml', out=<xml output> +// return: 'true' on success +// 'false' on failure (err set) +bool +GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString object, + const lldb_private::ConstString annex, + std::string & out, + lldb_private::Error & err) { + + std::stringstream output; + StringExtractorGDBRemote chunk; + + uint64_t size = GetRemoteMaxPacketSize(); + if (size == 0) + size = 0x1000; + size = size - 1; // Leave space for the 'm' or 'l' character in the response + int offset = 0; + bool active = true; + + // loop until all data has been read + while ( active ) { + + // send query extended feature packet + std::stringstream packet; + packet << "qXfer:" + << object.AsCString("") << ":read:" + << annex.AsCString("") << ":" + << std::hex << offset << "," + << std::hex << size; + + GDBRemoteCommunication::PacketResult res = + SendPacketAndWaitForResponse( packet.str().c_str(), + chunk, + false ); + + if ( res != GDBRemoteCommunication::PacketResult::Success ) { + err.SetErrorString( "Error sending $qXfer packet" ); + return false; + } + + const std::string & str = chunk.GetStringRef( ); + if ( str.length() == 0 ) { + // should have some data in chunk + err.SetErrorString( "Empty response from $qXfer packet" ); + return false; + } + + // check packet code + switch ( str[0] ) { + // last chunk + case ( 'l' ): + active = false; + // fall through intentional + + // more chunks + case ( 'm' ) : + if ( str.length() > 1 ) + output << &str[1]; + offset += size; + break; + + // unknown chunk + default: + err.SetErrorString( "Invalid continuation code from $qXfer packet" ); + return false; + } + } + + out = output.str( ); + err.Success( ); + return true; +} + +// Notify the target that gdb is prepared to serve symbol lookup requests. +// packet: "qSymbol::" +// reply: +// OK The target does not need to look up any (more) symbols. +// qSymbol:<sym_name> The target requests the value of symbol sym_name (hex encoded). +// LLDB may provide the value by sending another qSymbol packet +// in the form of"qSymbol:<sym_value>:<sym_name>". + +void +GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) +{ + if (m_supports_qSymbol) + { + Mutex::Locker locker; + if (GetSequenceMutex(locker, "GDBRemoteCommunicationClient::ServeSymbolLookups() failed due to not getting the sequence mutex")) + { + StreamString packet; + packet.PutCString ("qSymbol::"); + while (1) + { + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponseNoLock(packet.GetData(), packet.GetSize(), response) == PacketResult::Success) + { + if (response.IsOKResponse()) + { + // We are done serving symbols requests + return; + } + + if (response.IsUnsupportedResponse()) + { + // qSymbol is not supported by the current GDB server we are connected to + m_supports_qSymbol = false; + return; + } + else + { + llvm::StringRef response_str(response.GetStringRef()); + if (response_str.startswith("qSymbol:")) + { + response.SetFilePos(strlen("qSymbol:")); + std::string symbol_name; + if (response.GetHexByteString(symbol_name)) + { + if (symbol_name.empty()) + return; + + addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; + lldb_private::SymbolContextList sc_list; + if (process->GetTarget().GetImages().FindSymbolsWithNameAndType(ConstString(symbol_name), eSymbolTypeAny, sc_list)) + { + const size_t num_scs = sc_list.GetSize(); + for (size_t sc_idx=0; sc_idx<num_scs && symbol_load_addr == LLDB_INVALID_ADDRESS; ++sc_idx) + { + SymbolContext sc; + if (sc_list.GetContextAtIndex(sc_idx, sc)) + { + if (sc.symbol) + { + switch (sc.symbol->GetType()) + { + case eSymbolTypeInvalid: + case eSymbolTypeAbsolute: + case eSymbolTypeUndefined: + case eSymbolTypeSourceFile: + case eSymbolTypeHeaderFile: + case eSymbolTypeObjectFile: + case eSymbolTypeCommonBlock: + case eSymbolTypeBlock: + case eSymbolTypeLocal: + case eSymbolTypeParam: + case eSymbolTypeVariable: + case eSymbolTypeVariableType: + case eSymbolTypeLineEntry: + case eSymbolTypeLineHeader: + case eSymbolTypeScopeBegin: + case eSymbolTypeScopeEnd: + case eSymbolTypeAdditional: + case eSymbolTypeCompiler: + case eSymbolTypeInstrumentation: + case eSymbolTypeTrampoline: + break; + + case eSymbolTypeCode: + case eSymbolTypeResolver: + case eSymbolTypeData: + case eSymbolTypeRuntime: + case eSymbolTypeException: + case eSymbolTypeObjCClass: + case eSymbolTypeObjCMetaClass: + case eSymbolTypeObjCIVar: + case eSymbolTypeReExported: + symbol_load_addr = sc.symbol->GetLoadAddress(&process->GetTarget()); + break; + } + } + } + } + } + // This is the normal path where our symbol lookup was successful and we want + // to send a packet with the new symbol value and see if another lookup needs to be + // done. + + // Change "packet" to contain the requested symbol value and name + packet.Clear(); + packet.PutCString("qSymbol:"); + if (symbol_load_addr != LLDB_INVALID_ADDRESS) + packet.Printf("%" PRIx64, symbol_load_addr); + packet.PutCString(":"); + packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size()); + continue; // go back to the while loop and send "packet" and wait for another response + } + } + } + } + } + // If we make it here, the symbol request packet response wasn't valid or + // our symbol lookup failed so we must abort + return; + + } + } +} + diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index d90614bce88b..65a2981018ea 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -17,17 +17,21 @@ // Other libraries and framework includes // Project includes #include "lldb/Core/ArchSpec.h" +#include "lldb/Core/StructuredData.h" #include "lldb/Target/Process.h" #include "GDBRemoteCommunication.h" +namespace lldb_private { +namespace process_gdb_remote { + class GDBRemoteCommunicationClient : public GDBRemoteCommunication { public: //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - GDBRemoteCommunicationClient(bool is_platform); + GDBRemoteCommunicationClient(); ~GDBRemoteCommunicationClient(); @@ -36,7 +40,7 @@ public: // we are communicating with it. //------------------------------------------------------------------ bool - HandshakeWithServer (lldb_private::Error *error_ptr); + HandshakeWithServer (Error *error_ptr); PacketResult SendPacketAndWaitForResponse (const char *send_payload, @@ -75,9 +79,14 @@ public: const char *packet_payload, size_t packet_length, StringExtractorGDBRemote &response); + bool + SendvContPacket (ProcessGDBRemote *process, + const char *payload, + size_t packet_length, + StringExtractorGDBRemote &response); bool - GetThreadSuffixSupported (); + GetThreadSuffixSupported () override; // This packet is usually sent first and the boolean return value // indicates if the packet was send and any response was received @@ -95,7 +104,7 @@ public: SendAsyncSignal (int signo); bool - SendInterrupt (lldb_private::Mutex::Locker &locker, + SendInterrupt (Mutex::Locker &locker, uint32_t seconds_to_wait_for_stop, bool &timed_out); @@ -126,7 +135,7 @@ public: /// response was received. //------------------------------------------------------------------ int - SendArgumentsPacket (const lldb_private::ProcessLaunchInfo &launch_info); + SendArgumentsPacket (const ProcessLaunchInfo &launch_info); //------------------------------------------------------------------ /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the @@ -202,11 +211,11 @@ public: /// Zero if the for success, or an error code for failure. //------------------------------------------------------------------ int - SetSTDIN (char const *path); + SetSTDIN(const FileSpec &file_spec); int - SetSTDOUT (char const *path); + SetSTDOUT(const FileSpec &file_spec); int - SetSTDERR (char const *path); + SetSTDERR(const FileSpec &file_spec); //------------------------------------------------------------------ /// Sets the disable ASLR flag to \a enable for a process that will @@ -240,27 +249,27 @@ public: /// implements the platform, it will change the current working /// directory for the platform process. /// - /// @param[in] path + /// @param[in] working_dir /// The path to a directory to use when launching our process /// /// @return /// Zero if the for success, or an error code for failure. //------------------------------------------------------------------ int - SetWorkingDir (char const *path); + SetWorkingDir(const FileSpec &working_dir); //------------------------------------------------------------------ /// Gets the current working directory of a remote platform GDB /// server. /// - /// @param[out] cwd + /// @param[out] working_dir /// The current working directory on the remote platform. /// /// @return /// Boolean for success //------------------------------------------------------------------ bool - GetWorkingDir (std::string &cwd); + GetWorkingDir(FileSpec &working_dir); lldb::addr_t AllocateMemory (size_t size, uint32_t permissions); @@ -268,29 +277,28 @@ public: bool DeallocateMemory (lldb::addr_t addr); - lldb_private::Error + Error Detach (bool keep_stopped); - lldb_private::Error - GetMemoryRegionInfo (lldb::addr_t addr, - lldb_private::MemoryRegionInfo &range_info); + Error + GetMemoryRegionInfo (lldb::addr_t addr, MemoryRegionInfo &range_info); - lldb_private::Error + Error GetWatchpointSupportInfo (uint32_t &num); - lldb_private::Error + Error GetWatchpointSupportInfo (uint32_t &num, bool& after); - lldb_private::Error + Error GetWatchpointsTriggerAfterInstruction (bool &after); - const lldb_private::ArchSpec & + const ArchSpec & GetHostArchitecture (); uint32_t GetHostDefaultPacketTimeout(); - const lldb_private::ArchSpec & + const ArchSpec & GetProcessArchitecture (); void @@ -312,10 +320,13 @@ public: GetSyncThreadStateSupported(); void - ResetDiscoverableSettings(); + ResetDiscoverableSettings (bool did_exec); bool GetHostInfo (bool force = false); + + bool + GetDefaultThreadId (lldb::tid_t &tid); bool GetOSVersion (uint32_t &major, @@ -328,7 +339,7 @@ public: bool GetOSKernelDescription (std::string &s); - lldb_private::ArchSpec + ArchSpec GetSystemArchitecture (); bool @@ -341,12 +352,11 @@ public: GetSupportsThreadSuffix (); bool - GetProcessInfo (lldb::pid_t pid, - lldb_private::ProcessInstanceInfo &process_info); + GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info); uint32_t - FindProcesses (const lldb_private::ProcessInstanceInfoMatch &process_match_info, - lldb_private::ProcessInstanceInfoList &process_infos); + FindProcesses (const ProcessInstanceInfoMatch &process_match_info, + ProcessInstanceInfoList &process_infos); bool GetUserName (uint32_t uid, std::string &name); @@ -383,7 +393,7 @@ public: case eWatchpointWrite: return m_supports_z2; case eWatchpointRead: return m_supports_z3; case eWatchpointReadWrite: return m_supports_z4; - case eStoppointInvalid: return false; + default: return false; } } uint8_t @@ -392,8 +402,11 @@ public: lldb::addr_t addr, // Address of breakpoint or watchpoint uint32_t length); // Byte Size of breakpoint or watchpoint + bool + SetNonStopMode (const bool enable); + void - TestPacketSpeed (const uint32_t num_packets); + TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm); // This packet is for testing the speed of the interface only. Both // the client and server need to support it, but this allows us to @@ -423,9 +436,15 @@ public: GetRemoteMaxPacketSize(); bool + GetEchoSupported (); + + bool GetAugmentedLibrariesSVR4ReadSupported (); - lldb_private::LazyBool + bool + GetQXferFeaturesReadSupported (); + + LazyBool SupportsAllocDeallocMemory () // const { // Uncomment this to have lldb pretend the debug server doesn't respond to alloc/dealloc memory packets. @@ -444,64 +463,57 @@ public: } lldb::user_id_t - OpenFile (const lldb_private::FileSpec& file_spec, - uint32_t flags, - mode_t mode, - lldb_private::Error &error); + OpenFile (const FileSpec& file_spec, uint32_t flags, mode_t mode, Error &error); bool - CloseFile (lldb::user_id_t fd, - lldb_private::Error &error); + CloseFile (lldb::user_id_t fd, Error &error); lldb::user_id_t - GetFileSize (const lldb_private::FileSpec& file_spec); + GetFileSize (const FileSpec& file_spec); - lldb_private::Error - GetFilePermissions(const char *path, uint32_t &file_permissions); + Error + GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions); - lldb_private::Error - SetFilePermissions(const char *path, uint32_t file_permissions); + Error + SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions); uint64_t ReadFile (lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, - lldb_private::Error &error); + Error &error); uint64_t WriteFile (lldb::user_id_t fd, uint64_t offset, const void* src, uint64_t src_len, - lldb_private::Error &error); + Error &error); - lldb_private::Error - CreateSymlink (const char *src, - const char *dst); + Error + CreateSymlink(const FileSpec &src, + const FileSpec &dst); - lldb_private::Error - Unlink (const char *path); + Error + Unlink(const FileSpec &file_spec); + + Error + MakeDirectory(const FileSpec &file_spec, uint32_t mode); - lldb_private::Error - MakeDirectory (const char *path, - uint32_t mode); - bool - GetFileExists (const lldb_private::FileSpec& file_spec); - - lldb_private::Error - RunShellCommand (const char *command, // Shouldn't be NULL - const char *working_dir, // Pass NULL to use the current working directory - int *status_ptr, // Pass NULL if you don't want the process exit status - int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit - std::string *command_output, // Pass NULL if you don't want the command output - uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish + GetFileExists (const FileSpec& file_spec); + Error + RunShellCommand(const char *command, // Shouldn't be NULL + const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit + std::string *command_output, // Pass NULL if you don't want the command output + uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish + bool - CalculateMD5 (const lldb_private::FileSpec& file_spec, - uint64_t &high, - uint64_t &low); + CalculateMD5 (const FileSpec& file_spec, uint64_t &high, uint64_t &low); std::string HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process, @@ -531,9 +543,26 @@ public: bool AvoidGPackets(ProcessGDBRemote *process); + StructuredData::ObjectSP + GetThreadsInfo(); + bool GetThreadExtendedInfoSupported(); + bool + GetModuleInfo (const FileSpec& module_file_spec, + const ArchSpec& arch_spec, + ModuleSpec &module_spec); + + bool + ReadExtFeature (const lldb_private::ConstString object, + const lldb_private::ConstString annex, + std::string & out, + lldb_private::Error & err); + + void + ServeSymbolLookups(lldb_private::Process *process); + protected: PacketResult @@ -547,38 +576,44 @@ protected: bool GetGDBServerVersion(); + // Given the list of compression types that the remote debug stub can support, + // possibly enable compression if we find an encoding we can handle. + void + MaybeEnableCompression (std::vector<std::string> supported_compressions); + //------------------------------------------------------------------ // Classes that inherit from GDBRemoteCommunicationClient can see and modify these //------------------------------------------------------------------ - lldb_private::LazyBool m_supports_not_sending_acks; - lldb_private::LazyBool m_supports_thread_suffix; - lldb_private::LazyBool m_supports_threads_in_stop_reply; - lldb_private::LazyBool m_supports_vCont_all; - lldb_private::LazyBool m_supports_vCont_any; - lldb_private::LazyBool m_supports_vCont_c; - lldb_private::LazyBool m_supports_vCont_C; - lldb_private::LazyBool m_supports_vCont_s; - lldb_private::LazyBool m_supports_vCont_S; - lldb_private::LazyBool m_qHostInfo_is_valid; - lldb_private::LazyBool m_curr_pid_is_valid; - lldb_private::LazyBool m_qProcessInfo_is_valid; - lldb_private::LazyBool m_qGDBServerVersion_is_valid; - lldb_private::LazyBool m_supports_alloc_dealloc_memory; - lldb_private::LazyBool m_supports_memory_region_info; - lldb_private::LazyBool m_supports_watchpoint_support_info; - lldb_private::LazyBool m_supports_detach_stay_stopped; - lldb_private::LazyBool m_watchpoints_trigger_after_instruction; - lldb_private::LazyBool m_attach_or_wait_reply; - lldb_private::LazyBool m_prepare_for_reg_writing_reply; - lldb_private::LazyBool m_supports_p; - lldb_private::LazyBool m_supports_x; - lldb_private::LazyBool m_avoid_g_packets; - lldb_private::LazyBool m_supports_QSaveRegisterState; - lldb_private::LazyBool m_supports_qXfer_auxv_read; - lldb_private::LazyBool m_supports_qXfer_libraries_read; - lldb_private::LazyBool m_supports_qXfer_libraries_svr4_read; - lldb_private::LazyBool m_supports_augmented_libraries_svr4_read; - lldb_private::LazyBool m_supports_jThreadExtendedInfo; + LazyBool m_supports_not_sending_acks; + LazyBool m_supports_thread_suffix; + LazyBool m_supports_threads_in_stop_reply; + LazyBool m_supports_vCont_all; + LazyBool m_supports_vCont_any; + LazyBool m_supports_vCont_c; + LazyBool m_supports_vCont_C; + LazyBool m_supports_vCont_s; + LazyBool m_supports_vCont_S; + LazyBool m_qHostInfo_is_valid; + LazyBool m_curr_pid_is_valid; + LazyBool m_qProcessInfo_is_valid; + LazyBool m_qGDBServerVersion_is_valid; + LazyBool m_supports_alloc_dealloc_memory; + LazyBool m_supports_memory_region_info; + LazyBool m_supports_watchpoint_support_info; + LazyBool m_supports_detach_stay_stopped; + LazyBool m_watchpoints_trigger_after_instruction; + LazyBool m_attach_or_wait_reply; + LazyBool m_prepare_for_reg_writing_reply; + LazyBool m_supports_p; + LazyBool m_supports_x; + LazyBool m_avoid_g_packets; + LazyBool m_supports_QSaveRegisterState; + LazyBool m_supports_qXfer_auxv_read; + LazyBool m_supports_qXfer_libraries_read; + LazyBool m_supports_qXfer_libraries_svr4_read; + LazyBool m_supports_qXfer_features_read; + LazyBool m_supports_augmented_libraries_svr4_read; + LazyBool m_supports_jThreadExtendedInfo; bool m_supports_qProcessInfoPID:1, @@ -592,7 +627,9 @@ protected: m_supports_z3:1, m_supports_z4:1, m_supports_QEnvironment:1, - m_supports_QEnvironmentHexEncoded:1; + m_supports_QEnvironmentHexEncoded:1, + m_supports_qSymbol:1, + m_supports_jThreadsInfo:1; lldb::pid_t m_curr_pid; lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations @@ -603,8 +640,8 @@ protected: // If we need to send a packet while the target is running, the m_async_XXX // member variables take care of making this happen. - lldb_private::Mutex m_async_mutex; - lldb_private::Predicate<bool> m_async_packet_predicate; + Mutex m_async_mutex; + Predicate<bool> m_async_packet_predicate; std::string m_async_packet; PacketResult m_async_result; StringExtractorGDBRemote m_async_response; @@ -613,8 +650,8 @@ protected: std::string m_partial_profile_data; std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map; - lldb_private::ArchSpec m_host_arch; - lldb_private::ArchSpec m_process_arch; + ArchSpec m_host_arch; + ArchSpec m_process_arch; uint32_t m_os_version_major; uint32_t m_os_version_minor; uint32_t m_os_version_update; @@ -625,10 +662,11 @@ protected: uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported uint32_t m_default_packet_timeout; uint64_t m_max_packet_size; // as returned by qSupported + bool DecodeProcessInfoResponse (StringExtractorGDBRemote &response, - lldb_private::ProcessInstanceInfo &process_info); + ProcessInstanceInfo &process_info); private: //------------------------------------------------------------------ // For GDBRemoteCommunicationClient only @@ -636,4 +674,7 @@ private: DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationClient); }; +} // namespace process_gdb_remote +} // namespace lldb_private + #endif // liblldb_GDBRemoteCommunicationClient_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index dd920c0df0ca..13ce9b2dc5c3 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -12,133 +12,35 @@ #include "lldb/Host/Config.h" #include "GDBRemoteCommunicationServer.h" -#include "lldb/Core/StreamGDBRemote.h" // C Includes // C++ Includes #include <cstring> -#include <chrono> -#include <thread> - -// Other libraries and framework includes -#include "llvm/ADT/Triple.h" -#include "lldb/Interpreter/Args.h" -#include "lldb/Core/Debugger.h" -#include "lldb/Core/Log.h" -#include "lldb/Core/State.h" -#include "lldb/Core/StreamString.h" -#include "lldb/Host/ConnectionFileDescriptor.h" -#include "lldb/Host/Debug.h" -#include "lldb/Host/Endian.h" -#include "lldb/Host/File.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Host/StringConvert.h" -#include "lldb/Host/TimeValue.h" -#include "lldb/Target/FileAction.h" -#include "lldb/Target/Platform.h" -#include "lldb/Target/Process.h" -#include "lldb/Host/common/NativeRegisterContext.h" -#include "lldb/Host/common/NativeProcessProtocol.h" -#include "lldb/Host/common/NativeThreadProtocol.h" // Project includes -#include "Utility/StringExtractorGDBRemote.h" -#include "Utility/UriParser.h" -#include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" +#include "Utility/StringExtractorGDBRemote.h" using namespace lldb; using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; -//---------------------------------------------------------------------- -// GDBRemote Errors -//---------------------------------------------------------------------- - -namespace -{ - enum GDBRemoteServerError - { - // Set to the first unused error number in literal form below - eErrorFirst = 29, - eErrorNoProcess = eErrorFirst, - eErrorResume, - eErrorExitStatus - }; -} - -//---------------------------------------------------------------------- -// GDBRemoteCommunicationServer constructor -//---------------------------------------------------------------------- -GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : - GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), - m_platform_sp (Platform::GetHostPlatform ()), - m_async_thread (LLDB_INVALID_HOST_THREAD), - m_process_launch_info (), - m_process_launch_error (), - m_spawned_pids (), - m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), - m_proc_infos (), - m_proc_infos_index (0), - m_port_map (), - m_port_offset(0), - m_current_tid (LLDB_INVALID_THREAD_ID), - m_continue_tid (LLDB_INVALID_THREAD_ID), - m_debugged_process_mutex (Mutex::eMutexTypeRecursive), - m_debugged_process_sp (), - m_debugger_sp (), - m_stdio_communication ("process.stdio"), - m_exit_now (false), - m_inferior_prev_state (StateType::eStateInvalid), - m_thread_suffix_supported (false), - m_list_threads_in_stop_reply (false), - m_active_auxv_buffer_sp (), - m_saved_registers_mutex (), - m_saved_registers_map (), - m_next_saved_registers_id (1) +GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(const char *comm_name, + const char *listener_name) : + GDBRemoteCommunication (comm_name, listener_name), + m_exit_now (false) { - assert(is_platform && "must be lldb-platform if debugger is not specified"); } -GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform, - const lldb::PlatformSP& platform_sp, - lldb::DebuggerSP &debugger_sp) : - GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), - m_platform_sp (platform_sp), - m_async_thread (LLDB_INVALID_HOST_THREAD), - m_process_launch_info (), - m_process_launch_error (), - m_spawned_pids (), - m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), - m_proc_infos (), - m_proc_infos_index (0), - m_port_map (), - m_port_offset(0), - m_current_tid (LLDB_INVALID_THREAD_ID), - m_continue_tid (LLDB_INVALID_THREAD_ID), - m_debugged_process_mutex (Mutex::eMutexTypeRecursive), - m_debugged_process_sp (), - m_debugger_sp (debugger_sp), - m_stdio_communication ("process.stdio"), - m_exit_now (false), - m_inferior_prev_state (StateType::eStateInvalid), - m_thread_suffix_supported (false), - m_list_threads_in_stop_reply (false), - m_active_auxv_buffer_sp (), - m_saved_registers_mutex (), - m_saved_registers_map (), - m_next_saved_registers_id (1) +GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() { - assert(platform_sp); - assert((is_platform || debugger_sp) && "must specify non-NULL debugger_sp when lldb-gdbserver"); } -//---------------------------------------------------------------------- -// Destructor -//---------------------------------------------------------------------- -GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() +void GDBRemoteCommunicationServer::RegisterPacketHandler( + StringExtractorGDBRemote::ServerPacketType packet_type, + PacketHandler handler) { + m_packet_handlers[packet_type] = std::move(handler); } GDBRemoteCommunication::PacketResult @@ -149,7 +51,7 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, { StringExtractorGDBRemote packet; - PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec); + PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec, false); if (packet_result == PacketResult::Success) { const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType (); @@ -164,288 +66,16 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, quit = true; break; - default: case StringExtractorGDBRemote::eServerPacketType_unimplemented: packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); break; - case StringExtractorGDBRemote::eServerPacketType_A: - packet_result = Handle_A (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo: - packet_result = Handle_qfProcessInfo (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo: - packet_result = Handle_qsProcessInfo (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qC: - packet_result = Handle_qC (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qHostInfo: - packet_result = Handle_qHostInfo (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer: - packet_result = Handle_qLaunchGDBServer (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess: - packet_result = Handle_qKillSpawnedProcess (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_k: - packet_result = Handle_k (packet); - quit = true; - break; - - case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: - packet_result = Handle_qLaunchSuccess (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qGroupName: - packet_result = Handle_qGroupName (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qProcessInfo: - packet_result = Handle_qProcessInfo (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: - packet_result = Handle_qProcessInfoPID (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qSpeedTest: - packet_result = Handle_qSpeedTest (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qUserName: - packet_result = Handle_qUserName (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir: - packet_result = Handle_qGetWorkingDir(packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QEnvironment: - packet_result = Handle_QEnvironment (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QLaunchArch: - packet_result = Handle_QLaunchArch (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR: - packet_result = Handle_QSetDisableASLR (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError: - packet_result = Handle_QSetDetachOnError (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: - packet_result = Handle_QSetSTDIN (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT: - packet_result = Handle_QSetSTDOUT (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR: - packet_result = Handle_QSetSTDERR (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir: - packet_result = Handle_QSetWorkingDir (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: - packet_result = Handle_QStartNoAckMode (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir: - packet_result = Handle_qPlatform_mkdir (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod: - packet_result = Handle_qPlatform_chmod (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell: - packet_result = Handle_qPlatform_shell (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo: - packet_result = Handle_qWatchpointSupportInfo (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_C: - packet_result = Handle_C (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_c: - packet_result = Handle_c (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vCont: - packet_result = Handle_vCont (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vCont_actions: - packet_result = Handle_vCont_actions (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_stop_reason: // ? - packet_result = Handle_stop_reason (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_open: - packet_result = Handle_vFile_Open (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_close: - packet_result = Handle_vFile_Close (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_pread: - packet_result = Handle_vFile_pRead (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite: - packet_result = Handle_vFile_pWrite (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_size: - packet_result = Handle_vFile_Size (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_mode: - packet_result = Handle_vFile_Mode (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_exists: - packet_result = Handle_vFile_Exists (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_stat: - packet_result = Handle_vFile_Stat (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_md5: - packet_result = Handle_vFile_MD5 (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_symlink: - packet_result = Handle_vFile_symlink (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: - packet_result = Handle_vFile_unlink (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qRegisterInfo: - packet_result = Handle_qRegisterInfo (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qfThreadInfo: - packet_result = Handle_qfThreadInfo (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qsThreadInfo: - packet_result = Handle_qsThreadInfo (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_p: - packet_result = Handle_p (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_P: - packet_result = Handle_P (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_H: - packet_result = Handle_H (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_I: - packet_result = Handle_I (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_m: - packet_result = Handle_m (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_M: - packet_result = Handle_M (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported: - packet_result = Handle_qMemoryRegionInfoSupported (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo: - packet_result = Handle_qMemoryRegionInfo (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_interrupt: - if (IsGdbServer ()) - packet_result = Handle_interrupt (packet); + default: + auto handler_it = m_packet_handlers.find(packet_type); + if (handler_it == m_packet_handlers.end()) + packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); else - { - error.SetErrorString("interrupt received"); - interrupt = true; - } - break; - - case StringExtractorGDBRemote::eServerPacketType_Z: - packet_result = Handle_Z (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_z: - packet_result = Handle_z (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_s: - packet_result = Handle_s (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qSupported: - packet_result = Handle_qSupported (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported: - packet_result = Handle_QThreadSuffixSupported (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply: - packet_result = Handle_QListThreadsInStopReply (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read: - packet_result = Handle_qXfer_auxv_read (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState: - packet_result = Handle_QSaveRegisterState (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState: - packet_result = Handle_QRestoreRegisterState (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_vAttach: - packet_result = Handle_vAttach (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_D: - packet_result = Handle_D (packet); - break; - - case StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo: - packet_result = Handle_qThreadStopInfo (packet); + packet_result = handler_it->second (packet, error, interrupt, quit); break; } } @@ -469,729 +99,6 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, return packet_result; } -lldb_private::Error -GDBRemoteCommunicationServer::SetLaunchArguments (const char *const args[], int argc) -{ - if ((argc < 1) || !args || !args[0] || !args[0][0]) - return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); - - m_process_launch_info.SetArguments (const_cast<const char**> (args), true); - return lldb_private::Error (); -} - -lldb_private::Error -GDBRemoteCommunicationServer::SetLaunchFlags (unsigned int launch_flags) -{ - m_process_launch_info.GetFlags ().Set (launch_flags); - return lldb_private::Error (); -} - -lldb_private::Error -GDBRemoteCommunicationServer::LaunchProcess () -{ - // FIXME This looks an awful lot like we could override this in - // derived classes, one for lldb-platform, the other for lldb-gdbserver. - if (IsGdbServer ()) - return LaunchProcessForDebugging (); - else - return LaunchPlatformProcess (); -} - -bool -GDBRemoteCommunicationServer::ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const -{ - // Retrieve the file actions specified for stdout and stderr. - auto stdout_file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); - auto stderr_file_action = launch_info.GetFileActionForFD (STDERR_FILENO); - - // If neither stdout and stderr file actions are specified, we're not doing anything special, so - // assume we want to redirect stdout/stderr over gdb-remote $O messages. - if ((stdout_file_action == nullptr) && (stderr_file_action == nullptr)) - { - // Send stdout/stderr over the gdb-remote protocol. - return true; - } - - // Any other setting for either stdout or stderr implies we are either suppressing - // it (with /dev/null) or we've got it set to a PTY. Either way, we don't want the - // output over gdb-remote. - return false; -} - -lldb_private::Error -GDBRemoteCommunicationServer::LaunchProcessForDebugging () -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) - return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); - - lldb_private::Error error; - { - Mutex::Locker locker (m_debugged_process_mutex); - assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists"); - error = m_platform_sp->LaunchNativeProcess ( - m_process_launch_info, - *this, - m_debugged_process_sp); - } - - if (!error.Success ()) - { - fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); - return error; - } - - // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as needed. - // llgs local-process debugging may specify PTYs, which will eliminate the need to reflect inferior - // stdout/stderr over the gdb-remote protocol. - if (ShouldRedirectInferiorOutputOverGdbRemote (m_process_launch_info)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands", __FUNCTION__, m_debugged_process_sp->GetID ()); - - // Setup stdout/stderr mapping from inferior to $O - auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); - if (terminal_fd >= 0) - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); - error = SetSTDIOFileDescriptor (terminal_fd); - if (error.Fail ()) - return error; - } - else - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); - } - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " skipping stdout/stderr redirection via $O: inferior will communicate over client-provided file descriptors", __FUNCTION__, m_debugged_process_sp->GetID ()); - } - - printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ()); - - // Add to list of spawned processes. - lldb::pid_t pid; - if ((pid = m_process_launch_info.GetProcessID ()) != LLDB_INVALID_PROCESS_ID) - { - // add to spawned pids - Mutex::Locker locker (m_spawned_pids_mutex); - // On an lldb-gdbserver, we would expect there to be only one. - assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed"); - m_spawned_pids.insert (pid); - } - - return error; -} - -lldb_private::Error -GDBRemoteCommunicationServer::LaunchPlatformProcess () -{ - if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) - return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); - - // specify the process monitor if not already set. This should - // generally be what happens since we need to reap started - // processes. - if (!m_process_launch_info.GetMonitorProcessCallback ()) - m_process_launch_info.SetMonitorProcessCallback(ReapDebuggedProcess, this, false); - - lldb_private::Error error = m_platform_sp->LaunchProcess (m_process_launch_info); - if (!error.Success ()) - { - fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); - return error; - } - - printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID()); - - // add to list of spawned processes. On an lldb-gdbserver, we - // would expect there to be only one. - const auto pid = m_process_launch_info.GetProcessID(); - if (pid != LLDB_INVALID_PROCESS_ID) - { - // add to spawned pids - Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(pid); - } - - return error; -} - -lldb_private::Error -GDBRemoteCommunicationServer::AttachToProcess (lldb::pid_t pid) -{ - Error error; - - if (!IsGdbServer ()) - { - error.SetErrorString("cannot AttachToProcess () unless process is lldb-gdbserver"); - return error; - } - - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64, __FUNCTION__, pid); - - // Scope for mutex locker. - { - // Before we try to attach, make sure we aren't already monitoring something else. - Mutex::Locker locker (m_spawned_pids_mutex); - if (!m_spawned_pids.empty ()) - { - error.SetErrorStringWithFormat ("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, *m_spawned_pids.begin()); - return error; - } - - // Try to attach. - error = m_platform_sp->AttachNativeProcess (pid, *this, m_debugged_process_sp); - if (!error.Success ()) - { - fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ()); - return error; - } - - // Setup stdout/stderr mapping from inferior. - auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); - if (terminal_fd >= 0) - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); - error = SetSTDIOFileDescriptor (terminal_fd); - if (error.Fail ()) - return error; - } - else - { - if (log) - log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); - } - - printf ("Attached to process %" PRIu64 "...\n", pid); - - // Add to list of spawned processes. - assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed"); - m_spawned_pids.insert (pid); - - return error; - } -} - -void -GDBRemoteCommunicationServer::InitializeDelegate (lldb_private::NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - { - log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s", - __FUNCTION__, - process->GetID (), - StateAsCString (process->GetState ())); - } -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendWResponse (lldb_private::NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // send W notification - ExitType exit_type = ExitType::eExitTypeInvalid; - int return_code = 0; - std::string exit_description; - - const bool got_exit_info = process->GetExitStatus (&exit_type, &return_code, exit_description); - if (!got_exit_info) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", failed to retrieve process exit status", __FUNCTION__, process->GetID ()); - - StreamGDBRemote response; - response.PutChar ('E'); - response.PutHex8 (GDBRemoteServerError::eErrorExitStatus); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", returning exit type %d, return code %d [%s]", __FUNCTION__, process->GetID (), exit_type, return_code, exit_description.c_str ()); - - StreamGDBRemote response; - - char return_type_code; - switch (exit_type) - { - case ExitType::eExitTypeExit: - return_type_code = 'W'; - break; - case ExitType::eExitTypeSignal: - return_type_code = 'X'; - break; - case ExitType::eExitTypeStop: - return_type_code = 'S'; - break; - case ExitType::eExitTypeInvalid: - return_type_code = 'E'; - break; - } - response.PutChar (return_type_code); - - // POSIX exit status limited to unsigned 8 bits. - response.PutHex8 (return_code); - - return SendPacketNoLock(response.GetData(), response.GetSize()); - } -} - -static void -AppendHexValue (StreamString &response, const uint8_t* buf, uint32_t buf_size, bool swap) -{ - int64_t i; - if (swap) - { - for (i = buf_size-1; i >= 0; i--) - response.PutHex8 (buf[i]); - } - else - { - for (i = 0; i < buf_size; i++) - response.PutHex8 (buf[i]); - } -} - -static void -WriteRegisterValueInHexFixedWidth (StreamString &response, - NativeRegisterContextSP ®_ctx_sp, - const RegisterInfo ®_info, - const RegisterValue *reg_value_p) -{ - RegisterValue reg_value; - if (!reg_value_p) - { - Error error = reg_ctx_sp->ReadRegister (®_info, reg_value); - if (error.Success ()) - reg_value_p = ®_value; - // else log. - } - - if (reg_value_p) - { - AppendHexValue (response, (const uint8_t*) reg_value_p->GetBytes (), reg_value_p->GetByteSize (), false); - } - else - { - // Zero-out any unreadable values. - if (reg_info.byte_size > 0) - { - std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0'); - AppendHexValue (response, zeros.data(), zeros.size(), false); - } - } -} - -// WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value); - - -static void -WriteGdbRegnumWithFixedWidthHexRegisterValue (StreamString &response, - NativeRegisterContextSP ®_ctx_sp, - const RegisterInfo ®_info, - const RegisterValue ®_value) -{ - // Output the register number as 'NN:VVVVVVVV;' where NN is a 2 bytes HEX - // gdb register number, and VVVVVVVV is the correct number of hex bytes - // as ASCII for the register value. - if (reg_info.kinds[eRegisterKindGDB] == LLDB_INVALID_REGNUM) - return; - - response.Printf ("%.02x:", reg_info.kinds[eRegisterKindGDB]); - WriteRegisterValueInHexFixedWidth (response, reg_ctx_sp, reg_info, ®_value); - response.PutChar (';'); -} - - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendStopReplyPacketForThread (lldb::tid_t tid) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); - - // Ensure we're llgs. - if (!IsGdbServer ()) - { - // Only supported on llgs - return SendUnimplementedResponse (""); - } - - // Ensure we have a debugged process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (50); - - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s preparing packet for pid %" PRIu64 " tid %" PRIu64, - __FUNCTION__, m_debugged_process_sp->GetID (), tid); - - // Ensure we can get info on the given thread. - NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); - if (!thread_sp) - return SendErrorResponse (51); - - // Grab the reason this thread stopped. - struct ThreadStopInfo tid_stop_info; - std::string description; - if (!thread_sp->GetStopReason (tid_stop_info, description)) - return SendErrorResponse (52); - - // FIXME implement register handling for exec'd inferiors. - // if (tid_stop_info.reason == eStopReasonExec) - // { - // const bool force = true; - // InitializeRegisters(force); - // } - - StreamString response; - // Output the T packet with the thread - response.PutChar ('T'); - int signum = tid_stop_info.details.signal.signo; - if (log) - { - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, - __FUNCTION__, - m_debugged_process_sp->GetID (), - tid, - signum, - tid_stop_info.reason, - tid_stop_info.details.exception.type); - } - - // Print the signal number. - response.PutHex8 (signum & 0xff); - - // Include the tid. - response.Printf ("thread:%" PRIx64 ";", tid); - - // Include the thread name if there is one. - const std::string thread_name = thread_sp->GetName (); - if (!thread_name.empty ()) - { - size_t thread_name_len = thread_name.length (); - - if (::strcspn (thread_name.c_str (), "$#+-;:") == thread_name_len) - { - response.PutCString ("name:"); - response.PutCString (thread_name.c_str ()); - } - else - { - // The thread name contains special chars, send as hex bytes. - response.PutCString ("hexname:"); - response.PutCStringAsRawHex8 (thread_name.c_str ()); - } - response.PutChar (';'); - } - - // If a 'QListThreadsInStopReply' was sent to enable this feature, we - // will send all thread IDs back in the "threads" key whose value is - // a list of hex thread IDs separated by commas: - // "threads:10a,10b,10c;" - // This will save the debugger from having to send a pair of qfThreadInfo - // and qsThreadInfo packets, but it also might take a lot of room in the - // stop reply packet, so it must be enabled only on systems where there - // are no limits on packet lengths. - if (m_list_threads_in_stop_reply) - { - response.PutCString ("threads:"); - - uint32_t thread_index = 0; - NativeThreadProtocolSP listed_thread_sp; - for (listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); listed_thread_sp; ++thread_index, listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) - { - if (thread_index > 0) - response.PutChar (','); - response.Printf ("%" PRIx64, listed_thread_sp->GetID ()); - } - response.PutChar (';'); - } - - // - // Expedite registers. - // - - // Grab the register context. - NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext (); - if (reg_ctx_sp) - { - // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers. - const RegisterSet *reg_set_p; - if (reg_ctx_sp->GetRegisterSetCount () > 0 && ((reg_set_p = reg_ctx_sp->GetRegisterSet (0)) != nullptr)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s expediting registers from set '%s' (registers set count: %zu)", __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", reg_set_p->num_registers); - - for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) - { - const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex (*reg_num_p); - if (reg_info_p == nullptr) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to get register info for register set '%s', register index %" PRIu32, __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", *reg_num_p); - } - else if (reg_info_p->value_regs == nullptr) - { - // Only expediate registers that are not contained in other registers. - RegisterValue reg_value; - Error error = reg_ctx_sp->ReadRegister (reg_info_p, reg_value); - if (error.Success ()) - WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value); - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "<unnamed-register>", *reg_num_p, error.AsCString ()); - - } - } - } - } - } - - const char* reason_str = nullptr; - switch (tid_stop_info.reason) - { - case eStopReasonTrace: - reason_str = "trace"; - break; - case eStopReasonBreakpoint: - reason_str = "breakpoint"; - break; - case eStopReasonWatchpoint: - reason_str = "watchpoint"; - break; - case eStopReasonSignal: - reason_str = "signal"; - break; - case eStopReasonException: - reason_str = "exception"; - break; - case eStopReasonExec: - reason_str = "exec"; - break; - case eStopReasonInstrumentation: - case eStopReasonInvalid: - case eStopReasonPlanComplete: - case eStopReasonThreadExiting: - case eStopReasonNone: - break; - } - if (reason_str != nullptr) - { - response.Printf ("reason:%s;", reason_str); - } - - if (!description.empty()) - { - // Description may contains special chars, send as hex bytes. - response.PutCString ("description:"); - response.PutCStringAsRawHex8 (description.c_str ()); - response.PutChar (';'); - } - else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) - { - response.PutCString ("metype:"); - response.PutHex64 (tid_stop_info.details.exception.type); - response.PutCString (";mecount:"); - response.PutHex32 (tid_stop_info.details.exception.data_count); - response.PutChar (';'); - - for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) - { - response.PutCString ("medata:"); - response.PutHex64 (tid_stop_info.details.exception.data[i]); - response.PutChar (';'); - } - } - - return SendPacketNoLock (response.GetData(), response.GetSize()); -} - -void -GDBRemoteCommunicationServer::HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); - - // Send the exit result, and don't flush output. - // Note: flushing output here would join the inferior stdio reflection thread, which - // would gunk up the waitpid monitor thread that is calling this. - PacketResult result = SendStopReasonForState (StateType::eStateExited, false); - if (result != PacketResult::Success) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); - } - - // Remove the process from the list of spawned pids. - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.erase (process->GetID ()) < 1) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to remove PID %" PRIu64 " from the spawned pids list", __FUNCTION__, process->GetID ()); - - } - } - - // FIXME can't do this yet - since process state propagation is currently - // synchronous, it is running off the NativeProcessProtocol's innards and - // will tear down the NPP while it still has code to execute. -#if 0 - // Clear the NativeProcessProtocol pointer. - { - Mutex::Locker locker (m_debugged_process_mutex); - m_debugged_process_sp.reset(); - } -#endif - - // Close the pipe to the inferior terminal i/o if we launched it - // and set one up. Otherwise, 'k' and its flush of stdio could - // end up waiting on a thread join that will never end. Consider - // adding a timeout to the connection thread join call so we - // can avoid that scenario altogether. - MaybeCloseInferiorTerminalConnection (); - - // We are ready to exit the debug monitor. - m_exit_now = true; -} - -void -GDBRemoteCommunicationServer::HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process) -{ - assert (process && "process cannot be NULL"); - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); - - // Send the stop reason unless this is the stop after the - // launch or attach. - switch (m_inferior_prev_state) - { - case eStateLaunching: - case eStateAttaching: - // Don't send anything per debugserver behavior. - break; - default: - // In all other cases, send the stop reason. - PacketResult result = SendStopReasonForState (StateType::eStateStopped, false); - if (result != PacketResult::Success) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); - } - break; - } -} - -void -GDBRemoteCommunicationServer::ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state) -{ - assert (process && "process cannot be NULL"); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - { - log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s", - __FUNCTION__, - process->GetID (), - StateAsCString (state)); - } - - switch (state) - { - case StateType::eStateExited: - HandleInferiorState_Exited (process); - break; - - case StateType::eStateStopped: - HandleInferiorState_Stopped (process); - break; - - default: - if (log) - { - log->Printf ("GDBRemoteCommunicationServer::%s didn't handle state change for pid %" PRIu64 ", new state: %s", - __FUNCTION__, - process->GetID (), - StateAsCString (state)); - } - break; - } - - // Remember the previous state reported to us. - m_inferior_prev_state = state; -} - -void -GDBRemoteCommunicationServer::DidExec (NativeProcessProtocol *process) -{ - ClearProcessSpecificData (); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendONotification (const char *buffer, uint32_t len) -{ - if ((buffer == nullptr) || (len == 0)) - { - // Nothing to send. - return PacketResult::Success; - } - - StreamString response; - response.PutChar ('O'); - response.PutBytesAsRawHex8 (buffer, len); - - return SendPacketNoLock (response.GetData (), response.GetSize ()); -} - -lldb_private::Error -GDBRemoteCommunicationServer::SetSTDIOFileDescriptor (int fd) -{ - Error error; - - // Set up the Read Thread for reading/handling process I/O - std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true)); - if (!conn_up) - { - error.SetErrorString ("failed to create ConnectionFileDescriptor"); - return error; - } - - m_stdio_communication.SetConnection (conn_up.release()); - if (!m_stdio_communication.IsConnected ()) - { - error.SetErrorString ("failed to set connection for inferior I/O communication"); - return error; - } - - m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this); - m_stdio_communication.StartReadThread(); - - return error; -} - -void -GDBRemoteCommunicationServer::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len) -{ - GDBRemoteCommunicationServer *server = reinterpret_cast<GDBRemoteCommunicationServer*> (baton); - static_cast<void> (server->SendONotification (static_cast<const char *>(src), src_len)); -} - GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *) { @@ -1229,3334 +136,3 @@ GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr) { return GetAck() == PacketResult::Success; } - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet) -{ - StreamString response; - - // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 - - ArchSpec host_arch(HostInfo::GetArchitecture()); - const llvm::Triple &host_triple = host_arch.GetTriple(); - response.PutCString("triple:"); - response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); - response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize()); - - const char* distribution_id = host_arch.GetDistributionId ().AsCString (); - if (distribution_id) - { - response.PutCString("distribution_id:"); - response.PutCStringAsRawHex8(distribution_id); - response.PutCString(";"); - } - - // Only send out MachO info when lldb-platform/llgs is running on a MachO host. -#if defined(__APPLE__) - uint32_t cpu = host_arch.GetMachOCPUType(); - uint32_t sub = host_arch.GetMachOCPUSubType(); - if (cpu != LLDB_INVALID_CPUTYPE) - response.Printf ("cputype:%u;", cpu); - if (sub != LLDB_INVALID_CPUTYPE) - response.Printf ("cpusubtype:%u;", sub); - - if (cpu == ArchSpec::kCore_arm_any) - response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. - else - response.Printf("watchpoint_exceptions_received:after;"); -#else - response.Printf("watchpoint_exceptions_received:after;"); -#endif - - switch (lldb::endian::InlHostByteOrder()) - { - case eByteOrderBig: response.PutCString ("endian:big;"); break; - case eByteOrderLittle: response.PutCString ("endian:little;"); break; - case eByteOrderPDP: response.PutCString ("endian:pdp;"); break; - default: response.PutCString ("endian:unknown;"); break; - } - - uint32_t major = UINT32_MAX; - uint32_t minor = UINT32_MAX; - uint32_t update = UINT32_MAX; - if (HostInfo::GetOSVersion(major, minor, update)) - { - if (major != UINT32_MAX) - { - response.Printf("os_version:%u", major); - if (minor != UINT32_MAX) - { - response.Printf(".%u", minor); - if (update != UINT32_MAX) - response.Printf(".%u", update); - } - response.PutChar(';'); - } - } - - std::string s; - if (HostInfo::GetOSBuildString(s)) - { - response.PutCString ("os_build:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); - } - if (HostInfo::GetOSKernelDescription(s)) - { - response.PutCString ("os_kernel:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); - } - -#if defined(__APPLE__) - -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - // For iOS devices, we are connected through a USB Mux so we never pretend - // to actually have a hostname as far as the remote lldb that is connecting - // to this lldb-platform is concerned - response.PutCString ("hostname:"); - response.PutCStringAsRawHex8("127.0.0.1"); - response.PutChar(';'); -#else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - if (HostInfo::GetHostname(s)) - { - response.PutCString ("hostname:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); - } -#endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - -#else // #if defined(__APPLE__) - if (HostInfo::GetHostname(s)) - { - response.PutCString ("hostname:"); - response.PutCStringAsRawHex8(s.c_str()); - response.PutChar(';'); - } -#endif // #if defined(__APPLE__) - - return SendPacketNoLock (response.GetData(), response.GetSize()); -} - -static void -CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response) -{ - response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;", - proc_info.GetProcessID(), - proc_info.GetParentProcessID(), - proc_info.GetUserID(), - proc_info.GetGroupID(), - proc_info.GetEffectiveUserID(), - proc_info.GetEffectiveGroupID()); - response.PutCString ("name:"); - response.PutCStringAsRawHex8(proc_info.GetName()); - response.PutChar(';'); - const ArchSpec &proc_arch = proc_info.GetArchitecture(); - if (proc_arch.IsValid()) - { - const llvm::Triple &proc_triple = proc_arch.GetTriple(); - response.PutCString("triple:"); - response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); - response.PutChar(';'); - } -} - -static void -CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info, StreamString &response) -{ - response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;", - proc_info.GetProcessID(), - proc_info.GetParentProcessID(), - proc_info.GetUserID(), - proc_info.GetGroupID(), - proc_info.GetEffectiveUserID(), - proc_info.GetEffectiveGroupID()); - - const ArchSpec &proc_arch = proc_info.GetArchitecture(); - if (proc_arch.IsValid()) - { - const llvm::Triple &proc_triple = proc_arch.GetTriple(); -#if defined(__APPLE__) - // We'll send cputype/cpusubtype. - const uint32_t cpu_type = proc_arch.GetMachOCPUType(); - if (cpu_type != 0) - response.Printf ("cputype:%" PRIx32 ";", cpu_type); - - const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType(); - if (cpu_subtype != 0) - response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype); - - - const std::string vendor = proc_triple.getVendorName (); - if (!vendor.empty ()) - response.Printf ("vendor:%s;", vendor.c_str ()); -#else - // We'll send the triple. - response.PutCString("triple:"); - response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); - response.PutChar(';'); - -#endif - std::string ostype = proc_triple.getOSName (); - // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. - if (proc_triple.getVendor () == llvm::Triple::Apple) - { - switch (proc_triple.getArch ()) - { - case llvm::Triple::arm: - case llvm::Triple::aarch64: - ostype = "ios"; - break; - default: - // No change. - break; - } - } - response.Printf ("ostype:%s;", ostype.c_str ()); - - - switch (proc_arch.GetByteOrder ()) - { - case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break; - case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break; - case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break; - default: - // Nothing. - break; - } - - if (proc_triple.isArch64Bit ()) - response.PutCString ("ptrsize:8;"); - else if (proc_triple.isArch32Bit ()) - response.PutCString ("ptrsize:4;"); - else if (proc_triple.isArch16Bit ()) - response.PutCString ("ptrsize:2;"); - } - -} - - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qProcessInfo (StringExtractorGDBRemote &packet) -{ - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - - if (IsGdbServer ()) - { - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (68); - - pid = m_debugged_process_sp->GetID (); - } - else if (m_is_platform) - { - pid = m_process_launch_info.GetProcessID (); - m_process_launch_info.Clear (); - } - else - return SendUnimplementedResponse (packet.GetStringRef ().c_str ()); - - if (pid == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse (1); - - ProcessInstanceInfo proc_info; - if (!Host::GetProcessInfo (pid, proc_info)) - return SendErrorResponse (1); - - StreamString response; - CreateProcessInfoResponse_DebugServerStyle(proc_info, response); - return SendPacketNoLock (response.GetData (), response.GetSize ()); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet) -{ - // Packet format: "qProcessInfoPID:%i" where %i is the pid - packet.SetFilePos(::strlen ("qProcessInfoPID:")); - lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID); - if (pid != LLDB_INVALID_PROCESS_ID) - { - ProcessInstanceInfo proc_info; - if (Host::GetProcessInfo(pid, proc_info)) - { - StreamString response; - CreateProcessInfoResponse (proc_info, response); - return SendPacketNoLock (response.GetData(), response.GetSize()); - } - } - return SendErrorResponse (1); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet) -{ - m_proc_infos_index = 0; - m_proc_infos.Clear(); - - ProcessInstanceInfoMatch match_info; - packet.SetFilePos(::strlen ("qfProcessInfo")); - if (packet.GetChar() == ':') - { - - std::string key; - std::string value; - while (packet.GetNameColonValue(key, value)) - { - bool success = true; - if (key.compare("name") == 0) - { - StringExtractor extractor; - extractor.GetStringRef().swap(value); - extractor.GetHexByteString (value); - match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false); - } - else if (key.compare("name_match") == 0) - { - if (value.compare("equals") == 0) - { - match_info.SetNameMatchType (eNameMatchEquals); - } - else if (value.compare("starts_with") == 0) - { - match_info.SetNameMatchType (eNameMatchStartsWith); - } - else if (value.compare("ends_with") == 0) - { - match_info.SetNameMatchType (eNameMatchEndsWith); - } - else if (value.compare("contains") == 0) - { - match_info.SetNameMatchType (eNameMatchContains); - } - else if (value.compare("regex") == 0) - { - match_info.SetNameMatchType (eNameMatchRegularExpression); - } - else - { - success = false; - } - } - else if (key.compare("pid") == 0) - { - match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); - } - else if (key.compare("parent_pid") == 0) - { - match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); - } - else if (key.compare("uid") == 0) - { - match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("gid") == 0) - { - match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("euid") == 0) - { - match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("egid") == 0) - { - match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); - } - else if (key.compare("all_users") == 0) - { - match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success)); - } - else if (key.compare("triple") == 0) - { - match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL); - } - else - { - success = false; - } - - if (!success) - return SendErrorResponse (2); - } - } - - if (Host::FindProcesses (match_info, m_proc_infos)) - { - // We found something, return the first item by calling the get - // subsequent process info packet handler... - return Handle_qsProcessInfo (packet); - } - return SendErrorResponse (3); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet) -{ - if (m_proc_infos_index < m_proc_infos.GetSize()) - { - StreamString response; - CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response); - ++m_proc_infos_index; - return SendPacketNoLock (response.GetData(), response.GetSize()); - } - return SendErrorResponse (4); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet) -{ -#if !defined(LLDB_DISABLE_POSIX) - // Packet format: "qUserName:%i" where %i is the uid - packet.SetFilePos(::strlen ("qUserName:")); - uint32_t uid = packet.GetU32 (UINT32_MAX); - if (uid != UINT32_MAX) - { - std::string name; - if (HostInfo::LookupUserName(uid, name)) - { - StreamString response; - response.PutCStringAsRawHex8 (name.c_str()); - return SendPacketNoLock (response.GetData(), response.GetSize()); - } - } -#endif - return SendErrorResponse (5); - -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet) -{ -#if !defined(LLDB_DISABLE_POSIX) - // Packet format: "qGroupName:%i" where %i is the gid - packet.SetFilePos(::strlen ("qGroupName:")); - uint32_t gid = packet.GetU32 (UINT32_MAX); - if (gid != UINT32_MAX) - { - std::string name; - if (HostInfo::LookupGroupName(gid, name)) - { - StreamString response; - response.PutCStringAsRawHex8 (name.c_str()); - return SendPacketNoLock (response.GetData(), response.GetSize()); - } - } -#endif - return SendErrorResponse (6); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("qSpeedTest:")); - - std::string key; - std::string value; - bool success = packet.GetNameColonValue(key, value); - if (success && key.compare("response_size") == 0) - { - uint32_t response_size = StringConvert::ToUInt32(value.c_str(), 0, 0, &success); - if (success) - { - if (response_size == 0) - return SendOKResponse(); - StreamString response; - uint32_t bytes_left = response_size; - response.PutCString("data:"); - while (bytes_left > 0) - { - if (bytes_left >= 26) - { - response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - bytes_left -= 26; - } - else - { - response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - bytes_left = 0; - } - } - return SendPacketNoLock (response.GetData(), response.GetSize()); - } - } - return SendErrorResponse (7); -} - -// -//static bool -//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds) -//{ -// const int time_delta_usecs = 100000; -// const int num_retries = timeout_in_seconds/time_delta_usecs; -// for (int i=0; i<num_retries; i++) -// { -// struct proc_bsdinfo bsd_info; -// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO, -// (uint64_t) 0, -// &bsd_info, -// PROC_PIDTBSDINFO_SIZE); -// -// switch (error) -// { -// case EINVAL: -// case ENOTSUP: -// case ESRCH: -// case EPERM: -// return false; -// -// default: -// break; -// -// case 0: -// if (bsd_info.pbi_status == SSTOP) -// return true; -// } -// ::usleep (time_delta_usecs); -// } -// return false; -//} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) -{ - // The 'A' packet is the most over designed packet ever here with - // redundant argument indexes, redundant argument lengths and needed hex - // encoded argument string values. Really all that is needed is a comma - // separated hex encoded argument value list, but we will stay true to the - // documented version of the 'A' packet here... - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - int actual_arg_index = 0; - - packet.SetFilePos(1); // Skip the 'A' - bool success = true; - while (success && packet.GetBytesLeft() > 0) - { - // Decode the decimal argument string length. This length is the - // number of hex nibbles in the argument string value. - const uint32_t arg_len = packet.GetU32(UINT32_MAX); - if (arg_len == UINT32_MAX) - success = false; - else - { - // Make sure the argument hex string length is followed by a comma - if (packet.GetChar() != ',') - success = false; - else - { - // Decode the argument index. We ignore this really because - // who would really send down the arguments in a random order??? - const uint32_t arg_idx = packet.GetU32(UINT32_MAX); - if (arg_idx == UINT32_MAX) - success = false; - else - { - // Make sure the argument index is followed by a comma - if (packet.GetChar() != ',') - success = false; - else - { - // Decode the argument string value from hex bytes - // back into a UTF8 string and make sure the length - // matches the one supplied in the packet - std::string arg; - if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2)) - success = false; - else - { - // If there are any bytes left - if (packet.GetBytesLeft()) - { - if (packet.GetChar() != ',') - success = false; - } - - if (success) - { - if (arg_idx == 0) - m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); - m_process_launch_info.GetArguments().AppendArgument(arg.c_str()); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ()); - ++actual_arg_index; - } - } - } - } - } - } - } - - if (success) - { - m_process_launch_error = LaunchProcess (); - if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) - { - return SendOKResponse (); - } - else - { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("GDBRemoteCommunicationServer::%s failed to launch exe: %s", - __FUNCTION__, - m_process_launch_error.AsCString()); - - } - } - return SendErrorResponse (8); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet) -{ - StreamString response; - - if (IsGdbServer ()) - { - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (68); - - // Make sure we set the current thread so g and p packets return - // the data the gdb will expect. - lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); - SetCurrentThreadID (tid); - - NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread (); - if (!thread_sp) - return SendErrorResponse (69); - - response.Printf ("QC%" PRIx64, thread_sp->GetID ()); - } - else - { - // NOTE: lldb should now be using qProcessInfo for process IDs. This path here - // should not be used. It is reporting process id instead of thread id. The - // correct answer doesn't seem to make much sense for lldb-platform. - // CONSIDER: flip to "unsupported". - lldb::pid_t pid = m_process_launch_info.GetProcessID(); - response.Printf("QC%" PRIx64, pid); - - // this should always be platform here - assert (m_is_platform && "this code path should only be traversed for lldb-platform"); - - if (m_is_platform) - { - // If we launch a process and this GDB server is acting as a platform, - // then we need to clear the process launch state so we can start - // launching another process. In order to launch a process a bunch or - // packets need to be sent: environment packets, working directory, - // disable ASLR, and many more settings. When we launch a process we - // then need to know when to clear this information. Currently we are - // selecting the 'qC' packet as that packet which seems to make the most - // sense. - if (pid != LLDB_INVALID_PROCESS_ID) - { - m_process_launch_info.Clear(); - } - } - } - return SendPacketNoLock (response.GetData(), response.GetSize()); -} - -bool -GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid) -{ - Mutex::Locker locker (m_spawned_pids_mutex); - FreePortForProcess(pid); - return m_spawned_pids.erase(pid) > 0; -} -bool -GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton, - lldb::pid_t pid, - bool exited, - int signal, // Zero for no signal - int status) // Exit value of process if signal is zero -{ - GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton; - server->DebugserverProcessReaped (pid); - return true; -} - -bool -GDBRemoteCommunicationServer::DebuggedProcessReaped (lldb::pid_t pid) -{ - // reap a process that we were debugging (but not debugserver) - Mutex::Locker locker (m_spawned_pids_mutex); - return m_spawned_pids.erase(pid) > 0; -} - -bool -GDBRemoteCommunicationServer::ReapDebuggedProcess (void *callback_baton, - lldb::pid_t pid, - bool exited, - int signal, // Zero for no signal - int status) // Exit value of process if signal is zero -{ - GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton; - server->DebuggedProcessReaped (pid); - return true; -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) -{ -#ifdef _WIN32 - return SendErrorResponse(9); -#else - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); - - // Spawn a local debugserver as a platform so we can then attach or launch - // a process... - - if (m_is_platform) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s() called", __FUNCTION__); - - // Sleep and wait a bit for debugserver to start to listen... - ConnectionFileDescriptor file_conn; - std::string hostname; - // TODO: /tmp/ should not be hardcoded. User might want to override /tmp - // with the TMPDIR environment variable - packet.SetFilePos(::strlen ("qLaunchGDBServer;")); - std::string name; - std::string value; - uint16_t port = UINT16_MAX; - while (packet.GetNameColonValue(name, value)) - { - if (name.compare ("host") == 0) - hostname.swap(value); - else if (name.compare ("port") == 0) - port = StringConvert::ToUInt32(value.c_str(), 0, 0); - } - if (port == UINT16_MAX) - port = GetNextAvailablePort(); - - // Spawn a new thread to accept the port that gets bound after - // binding to port 0 (zero). - - // ignore the hostname send from the remote end, just use the ip address - // that we're currently communicating with as the hostname - - // Spawn a debugserver and try to get the port it listens to. - ProcessLaunchInfo debugserver_launch_info; - if (hostname.empty()) - hostname = "127.0.0.1"; - if (log) - log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port); - - // Do not run in a new session so that it can not linger after the - // platform closes. - debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); - debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); - - std::string platform_scheme; - std::string platform_ip; - int platform_port; - std::string platform_path; - bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path); - assert(ok); - Error error = StartDebugserverProcess ( - platform_ip.c_str(), - port, - debugserver_launch_info, - port); - - lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); - - - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - { - Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(debugserver_pid); - if (port > 0) - AssociatePortWithProcess(port, debugserver_pid); - } - else - { - if (port > 0) - FreePort (port); - } - - if (error.Success()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); - - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < (int)sizeof(response)); - PacketResult packet_result = SendPacketNoLock (response, response_len); - - if (packet_result != PacketResult::Success) - { - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill (debugserver_pid, SIGINT); - } - return packet_result; - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); - } - } - return SendErrorResponse (9); -#endif -} - -bool -GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid) -{ - // make sure we know about this process - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return false; - } - - // first try a SIGTERM (standard kill) - Host::Kill (pid, SIGTERM); - - // check if that worked - for (size_t i=0; i<10; ++i) - { - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - { - // it is now killed - return true; - } - } - usleep (10000); - } - - // check one more time after the final usleep - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; - } - - // the launched process still lives. Now try killing it again, - // this time with an unblockable signal. - Host::Kill (pid, SIGKILL); - - for (size_t i=0; i<10; ++i) - { - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - { - // it is now killed - return true; - } - } - usleep (10000); - } - - // check one more time after the final usleep - // Scope for locker - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; - } - - // no luck - the process still lives - return false; -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); - - lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); - - // verify that we know anything about this pid. - // Scope for locker - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - { - // not a pid we know about - return SendErrorResponse (10); - } - } - - // go ahead and attempt to kill the spawned process - if (KillSpawnedProcess (pid)) - return SendOKResponse (); - else - return SendErrorResponse (11); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet) -{ - // ignore for now if we're lldb_platform - if (m_is_platform) - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - - // shutdown all spawned processes - std::set<lldb::pid_t> spawned_pids_copy; - - // copy pids - { - Mutex::Locker locker (m_spawned_pids_mutex); - spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ()); - } - - // nuke the spawned processes - for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it) - { - lldb::pid_t spawned_pid = *it; - if (!KillSpawnedProcess (spawned_pid)) - { - fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid); - } - } - - FlushInferiorOutput (); - - // No OK response for kill packet. - // return SendOKResponse (); - return PacketResult::Success; -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet) -{ - if (m_process_launch_error.Success()) - return SendOKResponse(); - StreamString response; - response.PutChar('E'); - response.PutCString(m_process_launch_error.AsCString("<unknown error>")); - return SendPacketNoLock (response.GetData(), response.GetSize()); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QEnvironment:")); - const uint32_t bytes_left = packet.GetBytesLeft(); - if (bytes_left > 0) - { - m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek()); - return SendOKResponse (); - } - return SendErrorResponse (12); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QLaunchArch:")); - const uint32_t bytes_left = packet.GetBytesLeft(); - if (bytes_left > 0) - { - const char* arch_triple = packet.Peek(); - ArchSpec arch_spec(arch_triple,NULL); - m_process_launch_info.SetArchitecture(arch_spec); - return SendOKResponse(); - } - return SendErrorResponse(13); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetDisableASLR:")); - if (packet.GetU32(0)) - m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR); - else - m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR); - return SendOKResponse (); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetWorkingDir:")); - std::string path; - packet.GetHexByteString(path); - if (m_is_platform) - { -#ifdef _WIN32 - // Not implemented on Windows - return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_QSetWorkingDir unimplemented"); -#else - // If this packet is sent to a platform, then change the current working directory - if (::chdir(path.c_str()) != 0) - return SendErrorResponse(errno); -#endif - } - else - { - m_process_launch_info.SwapWorkingDirectory (path); - } - return SendOKResponse (); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) -{ - StreamString response; - - if (m_is_platform) - { - // If this packet is sent to a platform, then change the current working directory - char cwd[PATH_MAX]; - if (getcwd(cwd, sizeof(cwd)) == NULL) - { - return SendErrorResponse(errno); - } - else - { - response.PutBytesAsRawHex8(cwd, strlen(cwd)); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - } - else - { - const char *working_dir = m_process_launch_info.GetWorkingDirectory(); - if (working_dir && working_dir[0]) - { - response.PutBytesAsRawHex8(working_dir, strlen(working_dir)); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - else - { - return SendErrorResponse(14); - } - } -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetSTDIN:")); - FileAction file_action; - std::string path; - packet.GetHexByteString(path); - const bool read = false; - const bool write = true; - if (file_action.Open(STDIN_FILENO, path.c_str(), read, write)) - { - m_process_launch_info.AppendFileAction(file_action); - return SendOKResponse (); - } - return SendErrorResponse (15); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetSTDOUT:")); - FileAction file_action; - std::string path; - packet.GetHexByteString(path); - const bool read = true; - const bool write = false; - if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write)) - { - m_process_launch_info.AppendFileAction(file_action); - return SendOKResponse (); - } - return SendErrorResponse (16); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetSTDERR:")); - FileAction file_action; - std::string path; - packet.GetHexByteString(path); - const bool read = true; - const bool write = false; - if (file_action.Open(STDERR_FILENO, path.c_str(), read, write)) - { - m_process_launch_info.AppendFileAction(file_action); - return SendOKResponse (); - } - return SendErrorResponse (17); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_C (StringExtractorGDBRemote &packet) -{ - if (!IsGdbServer ()) - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); - - // Ensure we have a native process. - if (!m_debugged_process_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__); - return SendErrorResponse (0x36); - } - - // Pull out the signal number. - packet.SetFilePos (::strlen ("C")); - if (packet.GetBytesLeft () < 1) - { - // Shouldn't be using a C without a signal. - return SendIllFormedResponse (packet, "C packet specified without signal."); - } - const uint32_t signo = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (signo == std::numeric_limits<uint32_t>::max ()) - return SendIllFormedResponse (packet, "failed to parse signal number"); - - // Handle optional continue address. - if (packet.GetBytesLeft () > 0) - { - // FIXME add continue at address support for $C{signo}[;{continue-address}]. - if (*packet.Peek () == ';') - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - else - return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}"); - } - - lldb_private::ResumeActionList resume_actions (StateType::eStateRunning, 0); - Error error; - - // We have two branches: what to do if a continue thread is specified (in which case we target - // sending the signal to that thread), or when we don't have a continue thread set (in which - // case we send a signal to the process). - - // TODO discuss with Greg Clayton, make sure this makes sense. - - lldb::tid_t signal_tid = GetContinueThreadID (); - if (signal_tid != LLDB_INVALID_THREAD_ID) - { - // The resume action for the continue thread (or all threads if a continue thread is not set). - lldb_private::ResumeAction action = { GetContinueThreadID (), StateType::eStateRunning, static_cast<int> (signo) }; - - // Add the action for the continue thread (or all threads when the continue thread isn't present). - resume_actions.Append (action); - } - else - { - // Send the signal to the process since we weren't targeting a specific continue thread with the signal. - error = m_debugged_process_sp->Signal (signo); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to send signal for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - - return SendErrorResponse (0x52); - } - } - - // Resume the threads. - error = m_debugged_process_sp->Resume (resume_actions); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to resume threads for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - - return SendErrorResponse (0x38); - } - - // Don't send an "OK" packet; response is the stopped/exited message. - return PacketResult::Success; -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment) -{ - if (!IsGdbServer ()) - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); - - // We reuse this method in vCont - don't double adjust the file position. - if (!skip_file_pos_adjustment) - packet.SetFilePos (::strlen ("c")); - - // For now just support all continue. - const bool has_continue_address = (packet.GetBytesLeft () > 0); - if (has_continue_address) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ()); - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - } - - // Ensure we have a native process. - if (!m_debugged_process_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__); - return SendErrorResponse (0x36); - } - - // Build the ResumeActionList - lldb_private::ResumeActionList actions (StateType::eStateRunning, 0); - - Error error = m_debugged_process_sp->Resume (actions); - if (error.Fail ()) - { - if (log) - { - log->Printf ("GDBRemoteCommunicationServer::%s c failed for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - } - return SendErrorResponse (GDBRemoteServerError::eErrorResume); - } - - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); - - // No response required from continue. - return PacketResult::Success; -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vCont_actions (StringExtractorGDBRemote &packet) -{ - if (!IsGdbServer ()) - { - // only llgs supports $vCont. - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - } - - StreamString response; - response.Printf("vCont;c;C;s;S"); - - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vCont (StringExtractorGDBRemote &packet) -{ - if (!IsGdbServer ()) - { - // only llgs supports $vCont - return SendUnimplementedResponse (packet.GetStringRef().c_str()); - } - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s handling vCont packet", __FUNCTION__); - - packet.SetFilePos (::strlen ("vCont")); - - // Check if this is all continue (no options or ";c"). - if (!packet.GetBytesLeft () || (::strcmp (packet.Peek (), ";c") == 0)) - { - // Move the packet past the ";c". - if (packet.GetBytesLeft ()) - packet.SetFilePos (packet.GetFilePos () + ::strlen (";c")); - - const bool skip_file_pos_adjustment = true; - return Handle_c (packet, skip_file_pos_adjustment); - } - else if (::strcmp (packet.Peek (), ";s") == 0) - { - // Move past the ';', then do a simple 's'. - packet.SetFilePos (packet.GetFilePos () + 1); - return Handle_s (packet); - } - - // Ensure we have a native process. - if (!m_debugged_process_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__); - return SendErrorResponse (0x36); - } - - ResumeActionList thread_actions; - - while (packet.GetBytesLeft () && *packet.Peek () == ';') - { - // Skip the semi-colon. - packet.GetChar (); - - // Build up the thread action. - ResumeAction thread_action; - thread_action.tid = LLDB_INVALID_THREAD_ID; - thread_action.state = eStateInvalid; - thread_action.signal = 0; - - const char action = packet.GetChar (); - switch (action) - { - case 'C': - thread_action.signal = packet.GetHexMaxU32 (false, 0); - if (thread_action.signal == 0) - return SendIllFormedResponse (packet, "Could not parse signal in vCont packet C action"); - // Fall through to next case... - - case 'c': - // Continue - thread_action.state = eStateRunning; - break; - - case 'S': - thread_action.signal = packet.GetHexMaxU32 (false, 0); - if (thread_action.signal == 0) - return SendIllFormedResponse (packet, "Could not parse signal in vCont packet S action"); - // Fall through to next case... - - case 's': - // Step - thread_action.state = eStateStepping; - break; - - default: - return SendIllFormedResponse (packet, "Unsupported vCont action"); - break; - } - - // Parse out optional :{thread-id} value. - if (packet.GetBytesLeft () && (*packet.Peek () == ':')) - { - // Consume the separator. - packet.GetChar (); - - thread_action.tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); - if (thread_action.tid == LLDB_INVALID_THREAD_ID) - return SendIllFormedResponse (packet, "Could not parse thread number in vCont packet"); - } - - thread_actions.Append (thread_action); - } - - Error error = m_debugged_process_sp->Resume (thread_actions); - if (error.Fail ()) - { - if (log) - { - log->Printf ("GDBRemoteCommunicationServer::%s vCont failed for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - } - return SendErrorResponse (GDBRemoteServerError::eErrorResume); - } - - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); - - // No response required from vCont. - return PacketResult::Success; -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) -{ - // Send response first before changing m_send_acks to we ack this packet - PacketResult packet_result = SendOKResponse (); - m_send_acks = false; - return packet_result; -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("qPlatform_mkdir:")); - mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); - if (packet.GetChar() == ',') - { - std::string path; - packet.GetHexByteString(path); - Error error = FileSystem::MakeDirectory(path.c_str(), mode); - if (error.Success()) - return SendPacketNoLock ("OK", 2); - else - return SendErrorResponse(error.GetError()); - } - return SendErrorResponse(20); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("qPlatform_chmod:")); - - mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); - if (packet.GetChar() == ',') - { - std::string path; - packet.GetHexByteString(path); - Error error = FileSystem::SetFilePermissions(path.c_str(), mode); - if (error.Success()) - return SendPacketNoLock ("OK", 2); - else - return SendErrorResponse(error.GetError()); - } - return SendErrorResponse(19); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:open:")); - std::string path; - packet.GetHexByteStringTerminatedBy(path,','); - if (!path.empty()) - { - if (packet.GetChar() == ',') - { - uint32_t flags = packet.GetHexMaxU32(false, 0); - if (packet.GetChar() == ',') - { - mode_t mode = packet.GetHexMaxU32(false, 0600); - Error error; - int fd = ::open (path.c_str(), flags, mode); - const int save_errno = fd == -1 ? errno : 0; - StreamString response; - response.PutChar('F'); - response.Printf("%i", fd); - if (save_errno) - response.Printf(",%i", save_errno); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - } - } - return SendErrorResponse(18); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:close:")); - int fd = packet.GetS32(-1); - Error error; - int err = -1; - int save_errno = 0; - if (fd >= 0) - { - err = close(fd); - save_errno = err == -1 ? errno : 0; - } - else - { - save_errno = EINVAL; - } - StreamString response; - response.PutChar('F'); - response.Printf("%i", err); - if (save_errno) - response.Printf(",%i", save_errno); - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet) -{ -#ifdef _WIN32 - // Not implemented on Windows - return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented"); -#else - StreamGDBRemote response; - packet.SetFilePos(::strlen("vFile:pread:")); - int fd = packet.GetS32(-1); - if (packet.GetChar() == ',') - { - uint64_t count = packet.GetU64(UINT64_MAX); - if (packet.GetChar() == ',') - { - uint64_t offset = packet.GetU64(UINT32_MAX); - if (count == UINT64_MAX) - { - response.Printf("F-1:%i", EINVAL); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - - std::string buffer(count, 0); - const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); - const int save_errno = bytes_read == -1 ? errno : 0; - response.PutChar('F'); - response.Printf("%zi", bytes_read); - if (save_errno) - response.Printf(",%i", save_errno); - else - { - response.PutChar(';'); - response.PutEscapedBytes(&buffer[0], bytes_read); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - } - return SendErrorResponse(21); - -#endif -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet) -{ -#ifdef _WIN32 - return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented"); -#else - packet.SetFilePos(::strlen("vFile:pwrite:")); - - StreamGDBRemote response; - response.PutChar('F'); - - int fd = packet.GetU32(UINT32_MAX); - if (packet.GetChar() == ',') - { - off_t offset = packet.GetU64(UINT32_MAX); - if (packet.GetChar() == ',') - { - std::string buffer; - if (packet.GetEscapedBinaryData(buffer)) - { - const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset); - const int save_errno = bytes_written == -1 ? errno : 0; - response.Printf("%zi", bytes_written); - if (save_errno) - response.Printf(",%i", save_errno); - } - else - { - response.Printf ("-1,%i", EINVAL); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - } - return SendErrorResponse(27); -#endif -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:size:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false)); - StreamString response; - response.PutChar('F'); - response.PutHex64(retcode); - if (retcode == UINT64_MAX) - { - response.PutChar(','); - response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode() - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(22); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:mode:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - Error error; - const uint32_t mode = File::GetPermissions(path.c_str(), error); - StreamString response; - response.Printf("F%u", mode); - if (mode == 0 || error.Fail()) - response.Printf(",%i", (int)error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(23); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:exists:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false)); - StreamString response; - response.PutChar('F'); - response.PutChar(','); - if (retcode) - response.PutChar('1'); - else - response.PutChar('0'); - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(24); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:symlink:")); - std::string dst, src; - packet.GetHexByteStringTerminatedBy(dst, ','); - packet.GetChar(); // Skip ',' char - packet.GetHexByteString(src); - Error error = FileSystem::Symlink(src.c_str(), dst.c_str()); - StreamString response; - response.Printf("F%u,%u", error.GetError(), error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:unlink:")); - std::string path; - packet.GetHexByteString(path); - Error error = FileSystem::Unlink(path.c_str()); - StreamString response; - response.Printf("F%u,%u", error.GetError(), error.GetError()); - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("qPlatform_shell:")); - std::string path; - std::string working_dir; - packet.GetHexByteStringTerminatedBy(path,','); - if (!path.empty()) - { - if (packet.GetChar() == ',') - { - // FIXME: add timeout to qPlatform_shell packet - // uint32_t timeout = packet.GetHexMaxU32(false, 32); - uint32_t timeout = 10; - if (packet.GetChar() == ',') - packet.GetHexByteString(working_dir); - int status, signo; - std::string output; - Error err = Host::RunShellCommand(path.c_str(), - working_dir.empty() ? NULL : working_dir.c_str(), - &status, &signo, &output, timeout); - StreamGDBRemote response; - if (err.Fail()) - { - response.PutCString("F,"); - response.PutHex32(UINT32_MAX); - } - else - { - response.PutCString("F,"); - response.PutHex32(status); - response.PutChar(','); - response.PutHex32(signo); - response.PutChar(','); - response.PutEscapedBytes(output.c_str(), output.size()); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - } - return SendErrorResponse(24); -} - -void -GDBRemoteCommunicationServer::SetCurrentThreadID (lldb::tid_t tid) -{ - assert (IsGdbServer () && "SetCurrentThreadID() called when not GdbServer code"); - - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s setting current thread id to %" PRIu64, __FUNCTION__, tid); - - m_current_tid = tid; - if (m_debugged_process_sp) - m_debugged_process_sp->SetCurrentThreadID (m_current_tid); -} - -void -GDBRemoteCommunicationServer::SetContinueThreadID (lldb::tid_t tid) -{ - assert (IsGdbServer () && "SetContinueThreadID() called when not GdbServer code"); - - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid); - - m_continue_tid = tid; -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_stop_reason (StringExtractorGDBRemote &packet) -{ - // Handle the $? gdbremote command. - if (!IsGdbServer ()) - return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_stop_reason() unimplemented"); - - // If no process, indicate error - if (!m_debugged_process_sp) - return SendErrorResponse (02); - - return SendStopReasonForState (m_debugged_process_sp->GetState (), true); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - switch (process_state) - { - case eStateAttaching: - case eStateLaunching: - case eStateRunning: - case eStateStepping: - case eStateDetached: - // NOTE: gdb protocol doc looks like it should return $OK - // when everything is running (i.e. no stopped result). - return PacketResult::Success; // Ignore - - case eStateSuspended: - case eStateStopped: - case eStateCrashed: - { - lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); - // Make sure we set the current thread so g and p packets return - // the data the gdb will expect. - SetCurrentThreadID (tid); - return SendStopReplyPacketForThread (tid); - } - - case eStateInvalid: - case eStateUnloaded: - case eStateExited: - if (flush_on_exit) - FlushInferiorOutput (); - return SendWResponse(m_debugged_process_sp.get()); - - default: - if (log) - { - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", current state reporting not handled: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - StateAsCString (process_state)); - } - break; - } - - return SendErrorResponse (0); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet) -{ - return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented"); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen("vFile:MD5:")); - std::string path; - packet.GetHexByteString(path); - if (!path.empty()) - { - uint64_t a,b; - StreamGDBRemote response; - if (FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b) == false) - { - response.PutCString("F,"); - response.PutCString("x"); - } - else - { - response.PutCString("F,"); - response.PutHex64(a); - response.PutHex64(b); - } - return SendPacketNoLock(response.GetData(), response.GetSize()); - } - return SendErrorResponse(25); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qRegisterInfo (StringExtractorGDBRemote &packet) -{ - // Ensure we're llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qRegisterInfo() unimplemented"); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse (68); - - // Ensure we have a thread. - NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadAtIndex (0)); - if (!thread_sp) - return SendErrorResponse (69); - - // Get the register context for the first thread. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - return SendErrorResponse (69); - - // Parse out the register number from the request. - packet.SetFilePos (strlen("qRegisterInfo")); - const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (reg_index == std::numeric_limits<uint32_t>::max ()) - return SendErrorResponse (69); - - // Return the end of registers response if we've iterated one past the end of the register set. - if (reg_index >= reg_context_sp->GetUserRegisterCount ()) - return SendErrorResponse (69); - - const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); - if (!reg_info) - return SendErrorResponse (69); - - // Build the reginfos response. - StreamGDBRemote response; - - response.PutCString ("name:"); - response.PutCString (reg_info->name); - response.PutChar (';'); - - if (reg_info->alt_name && reg_info->alt_name[0]) - { - response.PutCString ("alt-name:"); - response.PutCString (reg_info->alt_name); - response.PutChar (';'); - } - - response.Printf ("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset); - - switch (reg_info->encoding) - { - case eEncodingUint: response.PutCString ("encoding:uint;"); break; - case eEncodingSint: response.PutCString ("encoding:sint;"); break; - case eEncodingIEEE754: response.PutCString ("encoding:ieee754;"); break; - case eEncodingVector: response.PutCString ("encoding:vector;"); break; - default: break; - } - - switch (reg_info->format) - { - case eFormatBinary: response.PutCString ("format:binary;"); break; - case eFormatDecimal: response.PutCString ("format:decimal;"); break; - case eFormatHex: response.PutCString ("format:hex;"); break; - case eFormatFloat: response.PutCString ("format:float;"); break; - case eFormatVectorOfSInt8: response.PutCString ("format:vector-sint8;"); break; - case eFormatVectorOfUInt8: response.PutCString ("format:vector-uint8;"); break; - case eFormatVectorOfSInt16: response.PutCString ("format:vector-sint16;"); break; - case eFormatVectorOfUInt16: response.PutCString ("format:vector-uint16;"); break; - case eFormatVectorOfSInt32: response.PutCString ("format:vector-sint32;"); break; - case eFormatVectorOfUInt32: response.PutCString ("format:vector-uint32;"); break; - case eFormatVectorOfFloat32: response.PutCString ("format:vector-float32;"); break; - case eFormatVectorOfUInt128: response.PutCString ("format:vector-uint128;"); break; - default: break; - }; - - const char *const register_set_name = reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index); - if (register_set_name) - { - response.PutCString ("set:"); - response.PutCString (register_set_name); - response.PutChar (';'); - } - - if (reg_info->kinds[RegisterKind::eRegisterKindGCC] != LLDB_INVALID_REGNUM) - response.Printf ("gcc:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindGCC]); - - if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM) - response.Printf ("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]); - - switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric]) - { - case LLDB_REGNUM_GENERIC_PC: response.PutCString("generic:pc;"); break; - case LLDB_REGNUM_GENERIC_SP: response.PutCString("generic:sp;"); break; - case LLDB_REGNUM_GENERIC_FP: response.PutCString("generic:fp;"); break; - case LLDB_REGNUM_GENERIC_RA: response.PutCString("generic:ra;"); break; - case LLDB_REGNUM_GENERIC_FLAGS: response.PutCString("generic:flags;"); break; - case LLDB_REGNUM_GENERIC_ARG1: response.PutCString("generic:arg1;"); break; - case LLDB_REGNUM_GENERIC_ARG2: response.PutCString("generic:arg2;"); break; - case LLDB_REGNUM_GENERIC_ARG3: response.PutCString("generic:arg3;"); break; - case LLDB_REGNUM_GENERIC_ARG4: response.PutCString("generic:arg4;"); break; - case LLDB_REGNUM_GENERIC_ARG5: response.PutCString("generic:arg5;"); break; - case LLDB_REGNUM_GENERIC_ARG6: response.PutCString("generic:arg6;"); break; - case LLDB_REGNUM_GENERIC_ARG7: response.PutCString("generic:arg7;"); break; - case LLDB_REGNUM_GENERIC_ARG8: response.PutCString("generic:arg8;"); break; - default: break; - } - - if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) - { - response.PutCString ("container-regs:"); - int i = 0; - for (const uint32_t *reg_num = reg_info->value_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) - { - if (i > 0) - response.PutChar (','); - response.Printf ("%" PRIx32, *reg_num); - } - response.PutChar (';'); - } - - if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) - { - response.PutCString ("invalidate-regs:"); - int i = 0; - for (const uint32_t *reg_num = reg_info->invalidate_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) - { - if (i > 0) - response.PutChar (','); - response.Printf ("%" PRIx32, *reg_num); - } - response.PutChar (';'); - } - - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qfThreadInfo (StringExtractorGDBRemote &packet) -{ - // Ensure we're llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qfThreadInfo() unimplemented"); - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s() no process (%s), returning OK", __FUNCTION__, m_debugged_process_sp ? "invalid process id" : "null m_debugged_process_sp"); - return SendOKResponse (); - } - - StreamGDBRemote response; - response.PutChar ('m'); - - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s() starting thread iteration", __FUNCTION__); - - NativeThreadProtocolSP thread_sp; - uint32_t thread_index; - for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); - thread_sp; - ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s() iterated thread %" PRIu32 "(%s, tid=0x%" PRIx64 ")", __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", thread_sp ? thread_sp->GetID () : LLDB_INVALID_THREAD_ID); - if (thread_index > 0) - response.PutChar(','); - response.Printf ("%" PRIx64, thread_sp->GetID ()); - } - - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s() finished thread iteration", __FUNCTION__); - - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_qsThreadInfo (StringExtractorGDBRemote &packet) -{ - // Ensure we're llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_qsThreadInfo() unimplemented"); - - // FIXME for now we return the full thread list in the initial packet and always do nothing here. - return SendPacketNoLock ("l", 1); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_p (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Ensure we're llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_p() unimplemented"); - - // Parse out the register number from the request. - packet.SetFilePos (strlen("p")); - const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (reg_index == std::numeric_limits<uint32_t>::max ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); - return SendErrorResponse (0x15); - } - - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Get the thread's register context. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); - } - - // Return the end of registers response if we've iterated one past the end of the register set. - if (reg_index >= reg_context_sp->GetUserRegisterCount ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ()); - return SendErrorResponse (0x15); - } - - const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); - if (!reg_info) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); - return SendErrorResponse (0x15); - } - - // Build the reginfos response. - StreamGDBRemote response; - - // Retrieve the value - RegisterValue reg_value; - Error error = reg_context_sp->ReadRegister (reg_info, reg_value); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, read of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); - return SendErrorResponse (0x15); - } - - const uint8_t *const data = reinterpret_cast<const uint8_t*> (reg_value.GetBytes ()); - if (!data) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to get data bytes from requested register %" PRIu32, __FUNCTION__, reg_index); - return SendErrorResponse (0x15); - } - - // FIXME flip as needed to get data in big/little endian format for this host. - for (uint32_t i = 0; i < reg_value.GetByteSize (); ++i) - response.PutHex8 (data[i]); - - return SendPacketNoLock (response.GetData (), response.GetSize ()); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_P (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Ensure we're llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_P() unimplemented"); - - // Ensure there is more content. - if (packet.GetBytesLeft () < 1) - return SendIllFormedResponse (packet, "Empty P packet"); - - // Parse out the register number from the request. - packet.SetFilePos (strlen("P")); - const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (reg_index == std::numeric_limits<uint32_t>::max ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); - return SendErrorResponse (0x29); - } - - // Note debugserver would send an E30 here. - if ((packet.GetBytesLeft () < 1) || (packet.GetChar () != '=')) - return SendIllFormedResponse (packet, "P packet missing '=' char after register number"); - - // Get process architecture. - ArchSpec process_arch; - if (!m_debugged_process_sp || !m_debugged_process_sp->GetArchitecture (process_arch)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to retrieve inferior architecture", __FUNCTION__); - return SendErrorResponse (0x49); - } - - // Parse out the value. - uint8_t reg_bytes[32]; // big enough to support up to 256 bit ymmN register - size_t reg_size = packet.GetHexBytesAvail (reg_bytes, sizeof(reg_bytes)); - - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available (thread index 0)", __FUNCTION__); - return SendErrorResponse (0x28); - } - - // Get the thread's register context. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); - } - - const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex (reg_index); - if (!reg_info) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); - return SendErrorResponse (0x48); - } - - // Return the end of registers response if we've iterated one past the end of the register set. - if (reg_index >= reg_context_sp->GetUserRegisterCount ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ()); - return SendErrorResponse (0x47); - } - - if (reg_size != reg_info->byte_size) - { - return SendIllFormedResponse (packet, "P packet register size is incorrect"); - } - - // Build the reginfos response. - StreamGDBRemote response; - - RegisterValue reg_value (reg_bytes, reg_size, process_arch.GetByteOrder ()); - Error error = reg_context_sp->WriteRegister (reg_info, reg_value); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); - return SendErrorResponse (0x32); - } - - return SendOKResponse(); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_H (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Ensure we're llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_H() unimplemented"); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out which variant of $H is requested. - packet.SetFilePos (strlen("H")); - if (packet.GetBytesLeft () < 1) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, H command missing {g,c} variant", __FUNCTION__); - return SendIllFormedResponse (packet, "H command missing {g,c} variant"); - } - - const char h_variant = packet.GetChar (); - switch (h_variant) - { - case 'g': - break; - - case 'c': - break; - - default: - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, invalid $H variant %c", __FUNCTION__, h_variant); - return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); - } - - // Parse out the thread number. - // FIXME return a parse success/fail value. All values are valid here. - const lldb::tid_t tid = packet.GetHexMaxU64 (false, std::numeric_limits<lldb::tid_t>::max ()); - - // Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread). - if (tid != LLDB_INVALID_THREAD_ID && tid != 0) - { - NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); - if (!thread_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, tid %" PRIu64 " not found", __FUNCTION__, tid); - return SendErrorResponse (0x15); - } - } - - // Now switch the given thread type. - switch (h_variant) - { - case 'g': - SetCurrentThreadID (tid); - break; - - case 'c': - SetContinueThreadID (tid); - break; - - default: - assert (false && "unsupported $H variant - shouldn't get here"); - return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); - } - - return SendOKResponse(); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_I (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Ensure we're llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_I() unimplemented"); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - packet.SetFilePos (::strlen("I")); - char tmp[4096]; - for (;;) - { - size_t read = packet.GetHexBytesAvail(tmp, sizeof(tmp)); - if (read == 0) - { - break; - } - // write directly to stdin *this might block if stdin buffer is full* - // TODO: enqueue this block in circular buffer and send window size to remote host - ConnectionStatus status; - Error error; - m_stdio_communication.Write(tmp, read, status, &error); - if (error.Fail()) - { - return SendErrorResponse (0x15); - } - } - - return SendOKResponse(); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_interrupt (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); - - // Ensure we're llgs. - if (!IsGdbServer()) - { - // Only supported on llgs - return SendUnimplementedResponse (""); - } - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Interrupt the process. - Error error = m_debugged_process_sp->Interrupt (); - if (error.Fail ()) - { - if (log) - { - log->Printf ("GDBRemoteCommunicationServer::%s failed for process %" PRIu64 ": %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - } - return SendErrorResponse (GDBRemoteServerError::eErrorResume); - } - - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); - - // No response required from stop all. - return PacketResult::Success; -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_m (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Ensure we're llgs. - if (!IsGdbServer()) - { - // Only supported on llgs - return SendUnimplementedResponse (""); - } - - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out the memory address. - packet.SetFilePos (strlen("m")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short m packet"); - - // Read the address. Punting on validation. - // FIXME replace with Hex U64 read with no default value that fails on failed read. - const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); - - // Validate comma. - if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) - return SendIllFormedResponse(packet, "Comma sep missing in m packet"); - - // Get # bytes to read. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Length missing in m packet"); - - const uint64_t byte_count = packet.GetHexMaxU64(false, 0); - if (byte_count == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s nothing to read: zero-length packet", __FUNCTION__); - return PacketResult::Success; - } - - // Allocate the response buffer. - std::string buf(byte_count, '\0'); - if (buf.empty()) - return SendErrorResponse (0x78); - - - // Retrieve the process memory. - lldb::addr_t bytes_read = 0; - lldb_private::Error error = m_debugged_process_sp->ReadMemory (read_addr, &buf[0], byte_count, bytes_read); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, error.AsCString ()); - return SendErrorResponse (0x08); - } - - if (bytes_read == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, bytes_read, byte_count); - return SendErrorResponse (0x08); - } - - StreamGDBRemote response; - for (lldb::addr_t i = 0; i < bytes_read; ++i) - response.PutHex8(buf[i]); - - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServer::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet) -{ - packet.SetFilePos(::strlen ("QSetDetachOnError:")); - if (packet.GetU32(0)) - m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError); - else - m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError); - return SendOKResponse (); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_M (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Ensure we're llgs. - if (!IsGdbServer()) - { - // Only supported on llgs - return SendUnimplementedResponse (""); - } - - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out the memory address. - packet.SetFilePos (strlen("M")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short M packet"); - - // Read the address. Punting on validation. - // FIXME replace with Hex U64 read with no default value that fails on failed read. - const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0); - - // Validate comma. - if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) - return SendIllFormedResponse(packet, "Comma sep missing in M packet"); - - // Get # bytes to read. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Length missing in M packet"); - - const uint64_t byte_count = packet.GetHexMaxU64(false, 0); - if (byte_count == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s nothing to write: zero-length packet", __FUNCTION__); - return PacketResult::Success; - } - - // Validate colon. - if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':')) - return SendIllFormedResponse(packet, "Comma sep missing in M packet after byte length"); - - // Allocate the conversion buffer. - std::vector<uint8_t> buf(byte_count, 0); - if (buf.empty()) - return SendErrorResponse (0x78); - - // Convert the hex memory write contents to bytes. - StreamGDBRemote response; - const uint64_t convert_count = static_cast<uint64_t> (packet.GetHexBytes (&buf[0], byte_count, 0)); - if (convert_count != byte_count) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": asked to write %" PRIu64 " bytes, but only found %" PRIu64 " to convert.", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count, convert_count); - return SendIllFormedResponse (packet, "M content byte length specified did not match hex-encoded content length"); - } - - // Write the process memory. - lldb::addr_t bytes_written = 0; - lldb_private::Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to write. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, error.AsCString ()); - return SendErrorResponse (0x09); - } - - if (bytes_written == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, bytes_written, byte_count); - return SendErrorResponse (0x09); - } - - return SendOKResponse (); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse (""); - - // Currently only the NativeProcessProtocol knows if it can handle a qMemoryRegionInfoSupported - // request, but we're not guaranteed to be attached to a process. For now we'll assume the - // client only asks this when a process is being debugged. - - // Ensure we have a process running; otherwise, we can't figure this out - // since we won't have a NativeProcessProtocol. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Test if we can get any region back when asking for the region around NULL. - MemoryRegionInfo region_info; - const Error error = m_debugged_process_sp->GetMemoryRegionInfo (0, region_info); - if (error.Fail ()) - { - // We don't support memory region info collection for this NativeProcessProtocol. - return SendUnimplementedResponse (""); - } - - return SendOKResponse(); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse (""); - - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out the memory address. - packet.SetFilePos (strlen("qMemoryRegionInfo:")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet"); - - // Read the address. Punting on validation. - const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); - - StreamGDBRemote response; - - // Get the memory region info for the target address. - MemoryRegionInfo region_info; - const Error error = m_debugged_process_sp->GetMemoryRegionInfo (read_addr, region_info); - if (error.Fail ()) - { - // Return the error message. - - response.PutCString ("error:"); - response.PutCStringAsRawHex8 (error.AsCString ()); - response.PutChar (';'); - } - else - { - // Range start and size. - response.Printf ("start:%" PRIx64 ";size:%" PRIx64 ";", region_info.GetRange ().GetRangeBase (), region_info.GetRange ().GetByteSize ()); - - // Permissions. - if (region_info.GetReadable () || - region_info.GetWritable () || - region_info.GetExecutable ()) - { - // Write permissions info. - response.PutCString ("permissions:"); - - if (region_info.GetReadable ()) - response.PutChar ('r'); - if (region_info.GetWritable ()) - response.PutChar('w'); - if (region_info.GetExecutable()) - response.PutChar ('x'); - - response.PutChar (';'); - } - } - - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_Z (StringExtractorGDBRemote &packet) -{ - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse (""); - - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out software or hardware breakpoint or watchpoint requested. - packet.SetFilePos (strlen("Z")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier"); - - bool want_breakpoint = true; - bool want_hardware = false; - - const GDBStoppointType stoppoint_type = - GDBStoppointType(packet.GetS32 (eStoppointInvalid)); - switch (stoppoint_type) - { - case eBreakpointSoftware: - want_hardware = false; want_breakpoint = true; break; - case eBreakpointHardware: - want_hardware = true; want_breakpoint = true; break; - case eWatchpointWrite: - want_hardware = true; want_breakpoint = false; break; - case eWatchpointRead: - want_hardware = true; want_breakpoint = false; break; - case eWatchpointReadWrite: - want_hardware = true; want_breakpoint = false; break; - case eStoppointInvalid: - return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier"); - - } - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after stoppoint type"); - - // Parse out the stoppoint address. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short Z packet, missing address"); - const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address"); - - // Parse out the stoppoint size (i.e. size hint for opcode size). - const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (size == std::numeric_limits<uint32_t>::max ()) - return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse size argument"); - - if (want_breakpoint) - { - // Try to set the breakpoint. - const Error error = m_debugged_process_sp->SetBreakpoint (addr, size, want_hardware); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 - " failed to set breakpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } - else - { - uint32_t watch_flags = - stoppoint_type == eWatchpointWrite - ? watch_flags = 0x1 // Write - : watch_flags = 0x3; // ReadWrite - - // Try to set the watchpoint. - const Error error = m_debugged_process_sp->SetWatchpoint ( - addr, size, watch_flags, want_hardware); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 - " failed to set watchpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet) -{ - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse (""); - - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - // Parse out software or hardware breakpoint or watchpoint requested. - packet.SetFilePos (strlen("z")); - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier"); - - bool want_breakpoint = true; - - const GDBStoppointType stoppoint_type = - GDBStoppointType(packet.GetS32 (eStoppointInvalid)); - switch (stoppoint_type) - { - case eBreakpointHardware: want_breakpoint = true; break; - case eBreakpointSoftware: want_breakpoint = true; break; - case eWatchpointWrite: want_breakpoint = false; break; - case eWatchpointRead: want_breakpoint = false; break; - case eWatchpointReadWrite: want_breakpoint = false; break; - default: - return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier"); - - } - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after stoppoint type"); - - // Parse out the stoppoint address. - if (packet.GetBytesLeft() < 1) - return SendIllFormedResponse(packet, "Too short z packet, missing address"); - const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); - - if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') - return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address"); - - /* - // Parse out the stoppoint size (i.e. size hint for opcode size). - const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); - if (size == std::numeric_limits<uint32_t>::max ()) - return SendIllFormedResponse(packet, "Malformed z packet, failed to parse size argument"); - */ - - if (want_breakpoint) - { - // Try to clear the breakpoint. - const Error error = m_debugged_process_sp->RemoveBreakpoint (addr); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 - " failed to remove breakpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } - else - { - // Try to clear the watchpoint. - const Error error = m_debugged_process_sp->RemoveWatchpoint (addr); - if (error.Success ()) - return SendOKResponse (); - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 - " failed to remove watchpoint: %s", - __FUNCTION__, - m_debugged_process_sp->GetID (), - error.AsCString ()); - return SendErrorResponse (0x09); - } -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_s (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); - - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse (""); - - // Ensure we have a process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x32); - } - - // We first try to use a continue thread id. If any one or any all set, use the current thread. - // Bail out if we don't have a thread id. - lldb::tid_t tid = GetContinueThreadID (); - if (tid == 0 || tid == LLDB_INVALID_THREAD_ID) - tid = GetCurrentThreadID (); - if (tid == LLDB_INVALID_THREAD_ID) - return SendErrorResponse (0x33); - - // Double check that we have such a thread. - // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. - NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID (tid); - if (!thread_sp || thread_sp->GetID () != tid) - return SendErrorResponse (0x33); - - // Create the step action for the given thread. - lldb_private::ResumeAction action = { tid, eStateStepping, 0 }; - - // Setup the actions list. - lldb_private::ResumeActionList actions; - actions.Append (action); - - // All other threads stop while we're single stepping a thread. - actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); - Error error = m_debugged_process_sp->Resume (actions); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), tid, error.AsCString ()); - return SendErrorResponse(0x49); - } - - // No response here - the stop or exit will come from the resulting action. - return PacketResult::Success; -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_qSupported (StringExtractorGDBRemote &packet) -{ - StreamGDBRemote response; - - // Features common to lldb-platform and llgs. - uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less - response.Printf ("PacketSize=%x", max_packet_size); - - response.PutCString (";QStartNoAckMode+"); - response.PutCString (";QThreadSuffixSupported+"); - response.PutCString (";QListThreadsInStopReply+"); -#if defined(__linux__) - response.PutCString (";qXfer:auxv:read+"); -#endif - - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet) -{ - m_thread_suffix_supported = true; - return SendOKResponse(); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet) -{ - m_list_threads_in_stop_reply = true; - return SendOKResponse(); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet) -{ - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse ("only supported for lldb-gdbserver"); - - // *BSD impls should be able to do this too. -#if defined(__linux__) - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Parse out the offset. - packet.SetFilePos (strlen("qXfer:auxv:read::")); - if (packet.GetBytesLeft () < 1) - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); - - const uint64_t auxv_offset = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ()); - if (auxv_offset == std::numeric_limits<uint64_t>::max ()) - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); - - // Parse out comma. - if (packet.GetBytesLeft () < 1 || packet.GetChar () != ',') - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing comma after offset"); - - // Parse out the length. - const uint64_t auxv_length = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ()); - if (auxv_length == std::numeric_limits<uint64_t>::max ()) - return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing length"); - - // Grab the auxv data if we need it. - if (!m_active_auxv_buffer_sp) - { - // Make sure we have a valid process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x10); - } - - // Grab the auxv data. - m_active_auxv_buffer_sp = Host::GetAuxvData (m_debugged_process_sp->GetID ()); - if (!m_active_auxv_buffer_sp || m_active_auxv_buffer_sp->GetByteSize () == 0) - { - // Hmm, no auxv data, call that an error. - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no auxv data retrieved", __FUNCTION__); - m_active_auxv_buffer_sp.reset (); - return SendErrorResponse (0x11); - } - } - - // FIXME find out if/how I lock the stream here. - - StreamGDBRemote response; - bool done_with_buffer = false; - - if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize ()) - { - // We have nothing left to send. Mark the buffer as complete. - response.PutChar ('l'); - done_with_buffer = true; - } - else - { - // Figure out how many bytes are available starting at the given offset. - const uint64_t bytes_remaining = m_active_auxv_buffer_sp->GetByteSize () - auxv_offset; - - // Figure out how many bytes we're going to read. - const uint64_t bytes_to_read = (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length; - - // Mark the response type according to whether we're reading the remainder of the auxv data. - if (bytes_to_read >= bytes_remaining) - { - // There will be nothing left to read after this - response.PutChar ('l'); - done_with_buffer = true; - } - else - { - // There will still be bytes to read after this request. - response.PutChar ('m'); - } - - // Now write the data in encoded binary form. - response.PutEscapedBytes (m_active_auxv_buffer_sp->GetBytes () + auxv_offset, bytes_to_read); - } - - if (done_with_buffer) - m_active_auxv_buffer_sp.reset (); - - return SendPacketNoLock(response.GetData(), response.GetSize()); -#else - return SendUnimplementedResponse ("not implemented on this platform"); -#endif -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_QSaveRegisterState (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse ("only supported for lldb-gdbserver"); - - // Move past packet name. - packet.SetFilePos (strlen ("QSaveRegisterState")); - - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (m_thread_suffix_supported) - return SendIllFormedResponse (packet, "No thread specified in QSaveRegisterState packet"); - else - return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); - } - - // Grab the register context for the thread. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); - } - - // Save registers to a buffer. - DataBufferSP register_data_sp; - Error error = reg_context_sp->ReadAllRegisterValues (register_data_sp); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to save all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); - return SendErrorResponse (0x75); - } - - // Allocate a new save id. - const uint32_t save_id = GetNextSavedRegistersID (); - assert ((m_saved_registers_map.find (save_id) == m_saved_registers_map.end ()) && "GetNextRegisterSaveID() returned an existing register save id"); - - // Save the register data buffer under the save id. - { - Mutex::Locker locker (m_saved_registers_mutex); - m_saved_registers_map[save_id] = register_data_sp; - } - - // Write the response. - StreamGDBRemote response; - response.Printf ("%" PRIu32, save_id); - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse ("only supported for lldb-gdbserver"); - - // Parse out save id. - packet.SetFilePos (strlen ("QRestoreRegisterState:")); - if (packet.GetBytesLeft () < 1) - return SendIllFormedResponse (packet, "QRestoreRegisterState packet missing register save id"); - - const uint32_t save_id = packet.GetU32 (0); - if (save_id == 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t", __FUNCTION__); - return SendErrorResponse (0x76); - } - - // Get the thread to use. - NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); - if (!thread_sp) - { - if (m_thread_suffix_supported) - return SendIllFormedResponse (packet, "No thread specified in QRestoreRegisterState packet"); - else - return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); - } - - // Grab the register context for the thread. - NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); - if (!reg_context_sp) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); - return SendErrorResponse (0x15); - } - - // Retrieve register state buffer, then remove from the list. - DataBufferSP register_data_sp; - { - Mutex::Locker locker (m_saved_registers_mutex); - - // Find the register set buffer for the given save id. - auto it = m_saved_registers_map.find (save_id); - if (it == m_saved_registers_map.end ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " does not have a register set save buffer for id %" PRIu32, __FUNCTION__, m_debugged_process_sp->GetID (), save_id); - return SendErrorResponse (0x77); - } - register_data_sp = it->second; - - // Remove it from the map. - m_saved_registers_map.erase (it); - } - - Error error = reg_context_sp->WriteAllRegisterValues (register_data_sp); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); - return SendErrorResponse (0x77); - } - - return SendOKResponse(); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_vAttach (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse ("only supported for lldb-gdbserver"); - - // Consume the ';' after vAttach. - packet.SetFilePos (strlen ("vAttach")); - if (!packet.GetBytesLeft () || packet.GetChar () != ';') - return SendIllFormedResponse (packet, "vAttach missing expected ';'"); - - // Grab the PID to which we will attach (assume hex encoding). - lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); - if (pid == LLDB_INVALID_PROCESS_ID) - return SendIllFormedResponse (packet, "vAttach failed to parse the process id"); - - // Attempt to attach. - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s attempting to attach to pid %" PRIu64, __FUNCTION__, pid); - - Error error = AttachToProcess (pid); - - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to attach to pid %" PRIu64 ": %s\n", __FUNCTION__, pid, error.AsCString()); - return SendErrorResponse (0x01); - } - - // Notify we attached by sending a stop packet. - return SendStopReasonForState (m_debugged_process_sp->GetState (), true); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_D (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); - - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse ("only supported for lldb-gdbserver"); - - // Scope for mutex locker. - Mutex::Locker locker (m_spawned_pids_mutex); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); - return SendErrorResponse (0x15); - } - - if (m_spawned_pids.find(m_debugged_process_sp->GetID ()) == m_spawned_pids.end()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to find PID %" PRIu64 " in spawned pids list", - __FUNCTION__, m_debugged_process_sp->GetID ()); - return SendErrorResponse (0x1); - } - - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - - // Consume the ';' after D. - packet.SetFilePos (1); - if (packet.GetBytesLeft ()) - { - if (packet.GetChar () != ';') - return SendIllFormedResponse (packet, "D missing expected ';'"); - - // Grab the PID from which we will detach (assume hex encoding). - pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); - if (pid == LLDB_INVALID_PROCESS_ID) - return SendIllFormedResponse (packet, "D failed to parse the process id"); - } - - if (pid != LLDB_INVALID_PROCESS_ID && - m_debugged_process_sp->GetID () != pid) - { - return SendIllFormedResponse (packet, "Invalid pid"); - } - - if (m_stdio_communication.IsConnected ()) - { - m_stdio_communication.StopReadThread (); - } - - const Error error = m_debugged_process_sp->Detach (); - if (error.Fail ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed to detach from pid %" PRIu64 ": %s\n", - __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); - return SendErrorResponse (0x01); - } - - m_spawned_pids.erase (m_debugged_process_sp->GetID ()); - return SendOKResponse (); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_qThreadStopInfo (StringExtractorGDBRemote &packet) -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // We don't support if we're not llgs. - if (!IsGdbServer()) - return SendUnimplementedResponse ("only supported for lldb-gdbserver"); - - packet.SetFilePos (strlen("qThreadStopInfo")); - const lldb::tid_t tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); - if (tid == LLDB_INVALID_THREAD_ID) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse thread id from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); - return SendErrorResponse (0x15); - } - return SendStopReplyPacketForThread (tid); -} - -GDBRemoteCommunicationServer::PacketResult -GDBRemoteCommunicationServer::Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet) -{ - // Only the gdb server handles this. - if (!IsGdbServer ()) - return SendUnimplementedResponse (packet.GetStringRef ().c_str ()); - - // Fail if we don't have a current process. - if (!m_debugged_process_sp || - m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) - return SendErrorResponse (68); - - packet.SetFilePos(strlen("qWatchpointSupportInfo")); - if (packet.GetBytesLeft() == 0) - return SendOKResponse(); - if (packet.GetChar() != ':') - return SendErrorResponse(67); - - uint32_t num = m_debugged_process_sp->GetMaxWatchpoints(); - StreamGDBRemote response; - response.Printf ("num:%d;", num); - return SendPacketNoLock(response.GetData(), response.GetSize()); -} - -void -GDBRemoteCommunicationServer::FlushInferiorOutput () -{ - // If we're not monitoring an inferior's terminal, ignore this. - if (!m_stdio_communication.IsConnected()) - return; - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s() called", __FUNCTION__); - - // FIXME implement a timeout on the join. - m_stdio_communication.JoinReadThread(); -} - -void -GDBRemoteCommunicationServer::MaybeCloseInferiorTerminalConnection () -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Tell the stdio connection to shut down. - if (m_stdio_communication.IsConnected()) - { - auto connection = m_stdio_communication.GetConnection(); - if (connection) - { - Error error; - connection->Disconnect (&error); - - if (error.Success ()) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__); - } - else - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ()); - } - } - } -} - - -lldb_private::NativeThreadProtocolSP -GDBRemoteCommunicationServer::GetThreadFromSuffix (StringExtractorGDBRemote &packet) -{ - NativeThreadProtocolSP thread_sp; - - // We have no thread if we don't have a process. - if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) - return thread_sp; - - // If the client hasn't asked for thread suffix support, there will not be a thread suffix. - // Use the current thread in that case. - if (!m_thread_suffix_supported) - { - const lldb::tid_t current_tid = GetCurrentThreadID (); - if (current_tid == LLDB_INVALID_THREAD_ID) - return thread_sp; - else if (current_tid == 0) - { - // Pick a thread. - return m_debugged_process_sp->GetThreadAtIndex (0); - } - else - return m_debugged_process_sp->GetThreadByID (current_tid); - } - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - - // Parse out the ';'. - if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';') - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); - return thread_sp; - } - - if (!packet.GetBytesLeft ()) - return thread_sp; - - // Parse out thread: portion. - if (strncmp (packet.Peek (), "thread:", strlen("thread:")) != 0) - { - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); - return thread_sp; - } - packet.SetFilePos (packet.GetFilePos () + strlen("thread:")); - const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); - if (tid != 0) - return m_debugged_process_sp->GetThreadByID (tid); - - return thread_sp; -} - -lldb::tid_t -GDBRemoteCommunicationServer::GetCurrentThreadID () const -{ - if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) - { - // Use whatever the debug process says is the current thread id - // since the protocol either didn't specify or specified we want - // any/all threads marked as the current thread. - if (!m_debugged_process_sp) - return LLDB_INVALID_THREAD_ID; - return m_debugged_process_sp->GetCurrentThreadID (); - } - // Use the specific current thread id set by the gdb remote protocol. - return m_current_tid; -} - -uint32_t -GDBRemoteCommunicationServer::GetNextSavedRegistersID () -{ - Mutex::Locker locker (m_saved_registers_mutex); - return m_next_saved_registers_id++; -} - -void -GDBRemoteCommunicationServer::ClearProcessSpecificData () -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|GDBR_LOG_PROCESS)); - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s()", __FUNCTION__); - - // Clear any auxv cached data. - // *BSD impls should be able to do this too. -#if defined(__linux__) - if (log) - log->Printf ("GDBRemoteCommunicationServer::%s clearing auxv buffer (previously %s)", - __FUNCTION__, - m_active_auxv_buffer_sp ? "was set" : "was not set"); - m_active_auxv_buffer_sp.reset (); -#endif -} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index dcf07844527e..992c6dffaf54 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -12,236 +12,53 @@ // C Includes // C++ Includes -#include <vector> -#include <set> -#include <unordered_map> +#include <functional> +#include <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 "lldb/Host/common/NativeProcessProtocol.h" +class StringExtractorGDBRemote; + +namespace lldb_private { +namespace process_gdb_remote { class ProcessGDBRemote; -class StringExtractorGDBRemote; -class GDBRemoteCommunicationServer : - public GDBRemoteCommunication, - public lldb_private::NativeProcessProtocol::NativeDelegate +class GDBRemoteCommunicationServer : public GDBRemoteCommunication { public: - typedef std::map<uint16_t, lldb::pid_t> PortMap; - - enum - { - eBroadcastBitRunPacketSent = kLoUserBroadcastBit - }; - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - GDBRemoteCommunicationServer(bool is_platform); + using PortMap = std::map<uint16_t, lldb::pid_t>; + using PacketHandler = std::function<PacketResult(StringExtractorGDBRemote &packet, + Error &error, + bool &interrupt, + bool &quit)>; - GDBRemoteCommunicationServer(bool is_platform, - const lldb::PlatformSP& platform_sp, - lldb::DebuggerSP& debugger_sp); + GDBRemoteCommunicationServer(const char *comm_name, + const char *listener_name); virtual ~GDBRemoteCommunicationServer(); + void RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type, + PacketHandler handler); + PacketResult GetPacketAndSendResponse (uint32_t timeout_usec, - lldb_private::Error &error, + Error &error, bool &interrupt, bool &quit); - virtual bool - GetThreadSuffixSupported () override - { - 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; + HandshakeWithClient (Error *error_ptr); 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; + std::map<StringExtractorGDBRemote::ServerPacketType, PacketHandler> m_packet_handlers; 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); @@ -255,306 +72,14 @@ protected: 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_I (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_D (StringExtractorGDBRemote &packet); - - PacketResult - Handle_qThreadStopInfo (StringExtractorGDBRemote &packet); - - PacketResult - Handle_qWatchpointSupportInfo (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); }; +} // namespace process_gdb_remote +} // namespace lldb_private + #endif // liblldb_GDBRemoteCommunicationServer_h_ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp new file mode 100644 index 000000000000..698854e5dfbd --- /dev/null +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -0,0 +1,1341 @@ +//===-- GDBRemoteCommunicationServerCommon.cpp ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "GDBRemoteCommunicationServerCommon.h" + +#include <errno.h> + +// C Includes +// C++ Includes +#include <cstring> +#include <chrono> + +// Other libraries and framework includes +#include "llvm/ADT/Triple.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/StreamGDBRemote.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Host/Config.h" +#include "lldb/Host/Endian.h" +#include "lldb/Host/File.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/StringConvert.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/FileAction.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Process.h" + +// Project includes +#include "ProcessGDBRemoteLog.h" +#include "Utility/StringExtractorGDBRemote.h" + +#ifdef __ANDROID__ +#include "lldb/Host/android/HostInfoAndroid.h" +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; + +#ifdef __ANDROID__ + const static uint32_t g_default_packet_timeout_sec = 20; // seconds +#else + const static uint32_t g_default_packet_timeout_sec = 0; // not specified +#endif + +//---------------------------------------------------------------------- +// GDBRemoteCommunicationServerCommon constructor +//---------------------------------------------------------------------- +GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name) : + GDBRemoteCommunicationServer (comm_name, listener_name), + m_spawned_pids (), + m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), + m_process_launch_info (), + m_process_launch_error (), + m_proc_infos (), + m_proc_infos_index (0), + m_thread_suffix_supported (false), + m_list_threads_in_stop_reply (false) +{ + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A, + &GDBRemoteCommunicationServerCommon::Handle_A); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironment, + &GDBRemoteCommunicationServerCommon::Handle_QEnvironment); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironmentHexEncoded, + &GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfProcessInfo, + &GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGroupName, + &GDBRemoteCommunicationServerCommon::Handle_qGroupName); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qHostInfo, + &GDBRemoteCommunicationServerCommon::Handle_qHostInfo); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, + &GDBRemoteCommunicationServerCommon::Handle_qKillSpawnedProcess); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QLaunchArch, + &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess, + &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply, + &GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qEcho, + &GDBRemoteCommunicationServerCommon::Handle_qEcho); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qModuleInfo, + &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod, + &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir, + &GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_shell, + &GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID, + &GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError, + &GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDERR, + &GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDIN, + &GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT, + &GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSpeedTest, + &GDBRemoteCommunicationServerCommon::Handle_qSpeedTest); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsProcessInfo, + &GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode, + &GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSupported, + &GDBRemoteCommunicationServerCommon::Handle_qSupported); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported, + &GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qUserName, + &GDBRemoteCommunicationServerCommon::Handle_qUserName); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_close, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Close); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_exists, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Exists); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_md5, + &GDBRemoteCommunicationServerCommon::Handle_vFile_MD5); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_mode, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Mode); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_open, + &GDBRemoteCommunicationServerCommon::Handle_vFile_Open); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pread, + &GDBRemoteCommunicationServerCommon::Handle_vFile_pRead); + RegisterMemberFunctionHandl |