size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Error &error) { llvm::sys::ScopedLock lock(m_mutex); WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory attempting to write %u bytes into address 0x%I64x", size, vm_addr); if (!m_session_data) { WINERR_IFANY(WINDOWS_LOG_MEMORY, "DoWriteMemory cannot write, there is no active debugger connection."); return 0; } HostProcess process = m_session_data->m_debugger->GetProcess(); void *addr = reinterpret_cast<void *>(vm_addr); SIZE_T bytes_written = 0; lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); if (WriteProcessMemory(handle, addr, buf, size, &bytes_written)) FlushInstructionCache(handle, addr, bytes_written); else { error.SetError(GetLastError(), eErrorTypeWin32); WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory failed with error code %u", error.GetError()); } return bytes_written; }
Error ProcessWindows::DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) { // Even though m_session_data is accessed here, it is before a debugger thread has been // kicked off. So there's no race conditions, and it shouldn't be necessary to acquire // the mutex. Error result; if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) { StreamString stream; stream.Printf("ProcessWindows unable to launch '%s'. ProcessWindows can only be used for debug launches.", launch_info.GetExecutableFile().GetPath().c_str()); std::string message = stream.GetString(); result.SetErrorString(message.c_str()); WINERR_IFALL(WINDOWS_LOG_PROCESS, message.c_str()); return result; } bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); m_session_data.reset(new ProcessWindowsData(stop_at_entry)); SetPrivateState(eStateLaunching); DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); m_session_data->m_debugger.reset(new DebuggerThread(delegate)); DebuggerThreadSP debugger = m_session_data->m_debugger; // Kick off the DebugLaunch asynchronously and wait for it to complete. result = debugger->DebugLaunch(launch_info); if (result.Fail()) { WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", launch_info.GetExecutableFile().GetPath().c_str(), result.AsCString()); return result; } HostProcess process; Error error = WaitForDebuggerConnection(debugger, process); if (error.Fail()) { WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch failed launching '%s'. %s", launch_info.GetExecutableFile().GetPath().c_str(), error.AsCString()); return error; } WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoLaunch successfully launched '%s'", launch_info.GetExecutableFile().GetPath().c_str()); // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the private state // should already be set to eStateStopped as a result of hitting the initial breakpoint. If // it was not set, the breakpoint should have already been resumed from and the private state // should already be eStateRunning. launch_info.SetProcessID(process.GetProcessId()); SetID(process.GetProcessId()); return result; }
Error ProcessWindows::DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) { // Even though m_session_data is accessed here, it is before a debugger thread has been // kicked off. So there's no race conditions, and it shouldn't be necessary to acquire // the mutex. Error result; if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) { result.SetErrorString("ProcessWindows can only be used to launch processes for debugging."); return result; } m_session_data.reset(new ProcessWindowsData(launch_info)); SetPrivateState(eStateLaunching); DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); m_session_data->m_debugger.reset(new DebuggerThread(delegate)); DebuggerThreadSP debugger = m_session_data->m_debugger; // Kick off the DebugLaunch asynchronously and wait for it to complete. result = debugger->DebugLaunch(launch_info); HostProcess process; if (result.Success()) { // Block this function until we receive the initial stop from the process. if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == WAIT_OBJECT_0) { process = debugger->GetProcess(); if (m_session_data->m_launch_error.Fail()) result = m_session_data->m_launch_error; } else result.SetError(::GetLastError(), eErrorTypeWin32); } if (!result.Success()) return result; // We've hit the initial stop. The private state should already be set to stopped as a result // of encountering the breakpoint exception in ProcessWindows::OnDebugException. launch_info.SetProcessID(process.GetProcessId()); SetID(process.GetProcessId()); return result; }
Error ProcessWindowsLive::GetMemoryRegionInfo(lldb::addr_t vm_addr, MemoryRegionInfo &info) { Error error; llvm::sys::ScopedLock lock(m_mutex); if (!m_session_data) { error.SetErrorString("GetMemoryRegionInfo called with no debugging session."); WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString()); return error; } HostProcess process = m_session_data->m_debugger->GetProcess(); lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); if (handle == nullptr || handle == LLDB_INVALID_PROCESS) { error.SetErrorString("GetMemoryRegionInfo called with an invalid target process."); WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString()); return error; } WINLOG_IFALL(WINDOWS_LOG_MEMORY, "GetMemoryRegionInfo getting info for address 0x%I64x", vm_addr); void *addr = reinterpret_cast<void *>(vm_addr); MEMORY_BASIC_INFORMATION mem_info = {0}; SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info)); if (result == 0) { error.SetError(::GetLastError(), eErrorTypeWin32); WINERR_IFALL(WINDOWS_LOG_MEMORY, "VirtualQueryEx returned error %u while getting memory region info for address 0x%I64x", error.GetError(), vm_addr); return error; } const bool readable = IsPageReadable(mem_info.Protect); const bool executable = IsPageExecutable(mem_info.Protect); const bool writable = IsPageWritable(mem_info.Protect); info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); info.SetExecutable(executable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); error.SetError(::GetLastError(), eErrorTypeWin32); WINLOGV_IFALL(WINDOWS_LOG_MEMORY, "Memory region info for address 0x%I64u: readable=%s, executable=%s, writable=%s", BOOL_STR(readable), BOOL_STR(executable), BOOL_STR(writable)); return error; }
void Session::default_service (const char *addrspec) { const char *equal = ACE_OS::strchr(addrspec,'='); if (equal == 0) return; ACE_CString name (addrspec,(equal - addrspec)); Endpoint ep (equal+1); static long next_def_pid = 0; --next_def_pid; HostProcess *hp = new HostProcess ("defaulted",next_def_pid); hp->proc_name(name); hp->add_listen_endpoint (ep); this->processes_.bind(next_def_pid,hp); this->procs_by_name_.bind(name,hp); }
size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Error &error) { llvm::sys::ScopedLock lock(m_mutex); if (!m_session_data) return 0; HostProcess process = m_session_data->m_debugger->GetProcess(); void *addr = reinterpret_cast<void *>(vm_addr); SIZE_T bytes_written = 0; lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); if (WriteProcessMemory(handle, addr, buf, size, &bytes_written)) FlushInstructionCache(handle, addr, bytes_written); else error.SetError(GetLastError(), eErrorTypeWin32); return bytes_written; }
size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Error &error) { llvm::sys::ScopedLock lock(m_mutex); if (!m_session_data) return 0; HostProcess process = m_session_data->m_debugger->GetProcess(); void *addr = reinterpret_cast<void *>(vm_addr); SIZE_T bytes_read = 0; if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, buf, size, &bytes_read)) error.SetError(GetLastError(), eErrorTypeWin32); return bytes_read; }
Error Host::LaunchProcess(ProcessLaunchInfo &launch_info) { std::unique_ptr<ProcessLauncher> delegate_launcher; #if defined(_WIN32) delegate_launcher.reset(new ProcessLauncherWindows()); #elif defined(__linux__) delegate_launcher.reset(new ProcessLauncherLinux()); #else delegate_launcher.reset(new ProcessLauncherPosix()); #endif MonitoringProcessLauncher launcher(std::move(delegate_launcher)); Error error; HostProcess process = launcher.LaunchProcess(launch_info, error); // TODO(zturner): It would be better if the entire HostProcess were returned // instead of writing // it into this structure. launch_info.SetProcessID(process.GetProcessId()); return error; }
Error ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid, const ProcessAttachInfo &attach_info) { m_session_data.reset(new ProcessWindowsData(!attach_info.GetContinueOnceAttached())); DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); DebuggerThreadSP debugger(new DebuggerThread(delegate)); m_session_data->m_debugger = debugger; DWORD process_id = static_cast<DWORD>(pid); Error error = debugger->DebugAttach(process_id, attach_info); if (error.Fail()) { WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID encountered an error occurred initiating the asynchronous attach. %s", error.AsCString()); return error; } HostProcess process; error = WaitForDebuggerConnection(debugger, process); if (error.Fail()) { WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID encountered an error waiting for the debugger to connect. %s", error.AsCString()); return error; } WINLOG_IFALL(WINDOWS_LOG_PROCESS, "DoAttachToProcessWithID successfully attached to process with pid=%u", process_id); // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the private state // should already be set to eStateStopped as a result of hitting the initial breakpoint. If // it was not set, the breakpoint should have already been resumed from and the private state // should already be eStateRunning. SetID(process.GetProcessId()); return error; }
size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Error &error) { llvm::sys::ScopedLock lock(m_mutex); if (!m_session_data) return 0; WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory attempting to read %u bytes from address 0x%I64x", size, vm_addr); HostProcess process = m_session_data->m_debugger->GetProcess(); void *addr = reinterpret_cast<void *>(vm_addr); SIZE_T bytes_read = 0; if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, buf, size, &bytes_read)) { error.SetError(GetLastError(), eErrorTypeWin32); WINERR_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory failed with error code %u", error.GetError()); } return bytes_read; }
Error ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr, MemoryRegionInfo &info) { Error error; llvm::sys::ScopedLock lock(m_mutex); if (!m_session_data) { error.SetErrorString("ProcessWindows::GetMemoryRegionInfo called with no debugging session."); return error; } HostProcess process = m_session_data->m_debugger->GetProcess(); lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); if (handle == nullptr || handle == LLDB_INVALID_PROCESS) { error.SetErrorString("ProcessWindows::GetMemoryRegionInfo called with an invalid target process."); return error; } void *addr = reinterpret_cast<void *>(vm_addr); MEMORY_BASIC_INFORMATION mem_info = {0}; SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info)); if (result == 0) { error.SetError(::GetLastError(), eErrorTypeWin32); return error; } bool readable = !(mem_info.Protect & PAGE_NOACCESS); bool executable = mem_info.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); bool writable = mem_info.Protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_READWRITE | PAGE_WRITECOPY); info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); info.SetExecutable(executable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); return error; }
void Log::get_preamble () { char * p = ACE_OS::strstr (this->line_, "("); char * t = 0; this->info_ = this->line_; if (p == 0) return; if (p != this->line_) { char * x = ACE_OS::strstr (this->line_, "TAO ("); if (x+4 != p) { x = ACE_OS::strstr (this->line_, "@("); if (x + 1 != p) return; } } long pid = ACE_OS::strtol(p + 1, &t, 10); if (pid == 0) return; long tid = 0; if ( *t == '|' ) tid = ACE_OS::strtol(t + 1, 0, 10); else if ( *t != ')') return; // not either (pid) or (pid|tid) this->info_ = ACE_OS::strstr (p, ")") + 1; this->hostproc_ = 0; for (ACE_DLList_Iterator<HostProcess> i (this->procs_); !i.done(); i.advance()) { i.next(this->hostproc_); if (this->hostproc_->pid() == pid) { break; } this->hostproc_ = 0; } if (this->hostproc_ == 0) this->hostproc_ = this->session_.find_process(pid); if (this->hostproc_ == 0) { size_t numprocs = this->procs_.size(); this->hostproc_ = new HostProcess (this->origin_,pid); this->procs_.insert_tail(this->hostproc_); ACE_CString &procname = this->alias_.length() > 0 ? this->alias_ : this->origin_; switch (numprocs) { case 0: this->hostproc_->proc_name(procname); break; case 1: { ACE_CString a2 = procname + "_1"; HostProcess *first; if (this->procs_.get(first) == 0) first->proc_name(a2); } //fallthru default: { char ext[10]; ACE_OS::sprintf(ext,"_" ACE_SIZE_T_FORMAT_SPECIFIER_ASCII,numprocs+1); ACE_CString a2 = procname + ext; this->hostproc_->proc_name(a2); } } this->session_.add_process (this->hostproc_); } this->thr_ = this->hostproc_->find_thread (tid, this->offset_); return; }
HostProcess MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, Status &error) { ProcessLaunchInfo resolved_info(launch_info); error.Clear(); char exe_path[PATH_MAX]; PlatformSP host_platform_sp(Platform::GetHostPlatform()); const ArchSpec &arch_spec = resolved_info.GetArchitecture(); FileSpec exe_spec(resolved_info.GetExecutableFile()); llvm::sys::fs::file_status stats; status(exe_spec.GetPath(), stats); if (!is_regular_file(stats)) { ModuleSpec module_spec(exe_spec, arch_spec); lldb::ModuleSP exe_module_sp; error = host_platform_sp->ResolveExecutable(module_spec, exe_module_sp, NULL); if (error.Fail()) return HostProcess(); if (exe_module_sp) { exe_spec = exe_module_sp->GetFileSpec(); status(exe_spec.GetPath(), stats); } } if (exists(stats)) { exe_spec.GetPath(exe_path, sizeof(exe_path)); } else { resolved_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); error.SetErrorStringWithFormat("executable doesn't exist: '%s'", exe_path); return HostProcess(); } resolved_info.SetExecutableFile(exe_spec, false); assert(!resolved_info.GetFlags().Test(eLaunchFlagLaunchInTTY)); HostProcess process = m_delegate_launcher->LaunchProcess(resolved_info, error); if (process.GetProcessId() != LLDB_INVALID_PROCESS_ID) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); Host::MonitorChildProcessCallback callback = launch_info.GetMonitorProcessCallback(); bool monitor_signals = false; if (callback) { // If the ProcessLaunchInfo specified a callback, use that. monitor_signals = launch_info.GetMonitorSignals(); } else { callback = Process::SetProcessExitStatus; } process.StartMonitoring(callback, monitor_signals); if (log) log->PutCString("started monitoring child process."); } else { // Invalid process ID, something didn't go well if (error.Success()) error.SetErrorString("process launch failed for unknown reasons"); } return process; }