ErrorCode ProcessBase::resume(int signal, std::set<Thread *> const &excluded) { enumerateThreads([&](Thread *thread) { if (excluded.find(thread) != excluded.end()) return; switch (thread->state()) { case Thread::kInvalid: case Thread::kTerminated: DS2BUG("trying to resume tid %" PRI_PID " in state %s", thread->tid(), Stringify::ThreadState(thread->state())); break; case Thread::kRunning: DS2LOG(Debug, "not resuming tid %" PRI_PID ", already in state %s", thread->tid(), Stringify::ThreadState(thread->state())); break; case Thread::kStopped: case Thread::kStepped: { Architecture::CPUState state; thread->readCPUState(state); DS2LOG(Debug, "resuming tid %" PRI_PID " from pc %" PRI_PTR " with signal %d", thread->tid(), PRI_PTR_CAST(state.pc()), signal); ErrorCode error = thread->resume(signal); if (error != kSuccess) { DS2LOG(Warning, "failed resuming tid %" PRI_PID ", error=%s", thread->tid(), Stringify::Error(error)); } } break; } }); return kSuccess; }
void ProcessBase::insert(ThreadBase *thread) { if (!_threads .insert(std::make_pair(thread->tid(), static_cast<Thread *>(thread))) .second) return; DS2LOG(Debug, "[new Thread %" PRI_PTR " (LWP %" PRIu64 ")]", PRI_PTR_CAST(thread), (uint64_t)thread->tid()); }
void ProcessBase::removeThread(ThreadId tid) { auto it = _threads.find(tid); if (it == _threads.end()) return; Thread *thread = it->second; _threads.erase(it); DS2LOG(Debug, "[delete Thread %" PRI_PTR " (LWP %" PRIu64 ") exited]", PRI_PTR_CAST(thread), (uint64_t)thread->tid()); delete thread; }
void PrintBacktrace() { static const int kStackSize = 100; static void *stack[kStackSize]; int stackEntries = ::backtrace(stack, kStackSize); for (int i = 0; i < stackEntries; ++i) { Dl_info info; int res; res = ::dladdr(stack[i], &info); if (res < 0) { PrintBacktraceEntrySimple(stack[i]); continue; } char *demangled = nullptr; const char *name; if (info.dli_sname != nullptr) { demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &res); if (res == 0) { name = demangled; } else { name = info.dli_sname; } } else { name = "<unknown>"; } DS2LOG(Error, "%" PRI_PTR " %s+%#" PRIxPTR " (%s)", PRI_PTR_CAST(stack[i]), name, static_cast<char *>(stack[i]) - static_cast<char *>(info.dli_saddr), info.dli_fname); ::free(demangled); } }
static void PrintBacktraceEntrySimple(void *address) { DS2LOG(Error, "%" PRI_PTR, PRI_PTR_CAST(address)); }
void Thread::updateState(DEBUG_EVENT const &de) { DS2ASSERT(de.dwThreadId == _tid); switch (de.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: _state = kStopped; DS2LOG( Debug, "exception from inferior, tid=%lu, code=%s, address=%" PRI_PTR, tid(), Stringify::ExceptionCode(de.u.Exception.ExceptionRecord.ExceptionCode), PRI_PTR_CAST(de.u.Exception.ExceptionRecord.ExceptionAddress)); switch (de.u.Exception.ExceptionRecord.ExceptionCode) { case STATUS_BREAKPOINT: case STATUS_SINGLE_STEP: _stopInfo.event = StopInfo::kEventStop; _stopInfo.reason = StopInfo::kReasonBreakpoint; break; case STATUS_ACCESS_VIOLATION: case STATUS_ARRAY_BOUNDS_EXCEEDED: case STATUS_IN_PAGE_ERROR: case STATUS_STACK_OVERFLOW: case STATUS_STACK_BUFFER_OVERRUN: _stopInfo.event = StopInfo::kEventStop; _stopInfo.reason = StopInfo::kReasonMemoryError; break; case STATUS_DATATYPE_MISALIGNMENT: _stopInfo.event = StopInfo::kEventStop; _stopInfo.reason = StopInfo::kReasonMemoryAlignment; break; case STATUS_FLOAT_DENORMAL_OPERAND: case STATUS_FLOAT_DIVIDE_BY_ZERO: case STATUS_FLOAT_INEXACT_RESULT: case STATUS_FLOAT_INVALID_OPERATION: case STATUS_FLOAT_OVERFLOW: case STATUS_FLOAT_STACK_CHECK: case STATUS_FLOAT_UNDERFLOW: case STATUS_INTEGER_DIVIDE_BY_ZERO: case STATUS_INTEGER_OVERFLOW: _stopInfo.event = StopInfo::kEventStop; _stopInfo.reason = StopInfo::kReasonMathError; break; case STATUS_ILLEGAL_INSTRUCTION: case STATUS_PRIVILEGED_INSTRUCTION: _stopInfo.event = StopInfo::kEventStop; _stopInfo.reason = StopInfo::kReasonInstructionError; break; default: DS2LOG(Warning, "unsupported exception code: %lx", de.u.Exception.ExceptionRecord.ExceptionCode); case STATUS_INVALID_DISPOSITION: case STATUS_NONCONTINUABLE_EXCEPTION: case DS2_EXCEPTION_UNCAUGHT_COM: case DS2_EXCEPTION_UNCAUGHT_USER: case DS2_EXCEPTION_UNCAUGHT_WINRT: _stopInfo.event = StopInfo::kEventStop; _stopInfo.reason = StopInfo::kReasonInstructionError; break; } break; case LOAD_DLL_DEBUG_EVENT: { #define CHK_SKIP(C) CHK_ACTION(C, goto skip_name) std::wstring name = L"<unknown>"; ProcessInfo pi; CHK_SKIP(process()->getInfo(pi)); if (de.u.LoadDll.lpImageName == nullptr) { goto skip_name; } uint64_t ptr; // ptr needs to be set to 0 or `if (ptr != 0)` might be true even if the // pointer is null, on 32-bit targets. ptr = 0; CHK_SKIP(process()->readMemory( reinterpret_cast<uint64_t>(de.u.LoadDll.lpImageName), &ptr, pi.pointerSize)); if (ptr == 0) { goto skip_name; } // It seems like all strings passed by the kernel here are guaranteed to be // unicode. DS2ASSERT(de.u.LoadDll.fUnicode); name.clear(); wchar_t c; do { if (process()->readMemory(ptr, &c, sizeof(c)) != kSuccess) { break; } name.append(1, c); ptr += sizeof(c); } while (c != '\0'); skip_name: DS2LOG(Debug, "new DLL loaded: %s, base=%" PRI_PTR, Host::Platform::WideToNarrowString(name).c_str(), PRI_PTR_CAST(de.u.LoadDll.lpBaseOfDll)); if (de.u.LoadDll.hFile != NULL) { ::CloseHandle(de.u.LoadDll.hFile); } _state = kStopped; _stopInfo.event = StopInfo::kEventStop; _stopInfo.reason = StopInfo::kReasonLibraryEvent; } break; case UNLOAD_DLL_DEBUG_EVENT: DS2LOG(Debug, "DLL unloaded, base=%" PRI_PTR, PRI_PTR_CAST(de.u.UnloadDll.lpBaseOfDll)); _state = kStopped; _stopInfo.event = StopInfo::kEventStop; _stopInfo.reason = StopInfo::kReasonLibraryEvent; break; case EXIT_THREAD_DEBUG_EVENT: _state = kStopped; _stopInfo.event = StopInfo::kEventStop; _stopInfo.reason = StopInfo::kReasonThreadExit; break; case OUTPUT_DEBUG_STRING_EVENT: { auto const &dsInfo = de.u.DebugString; DS2LOG(Debug, "inferior output a debug string: %" PRI_PTR "[%d]", PRI_PTR_CAST(dsInfo.lpDebugStringData), dsInfo.nDebugStringLength); // The length includes terminating null character. DS2ASSERT(dsInfo.nDebugStringLength >= 1); std::string buffer((dsInfo.fUnicode ? sizeof(WCHAR) : 1) * (dsInfo.nDebugStringLength - 1), 0); CHKV(process()->readMemory( reinterpret_cast<uint64_t>(dsInfo.lpDebugStringData), const_cast<char *>(buffer.c_str()), buffer.size())); _stopInfo.debugString = dsInfo.fUnicode ? Platform::WideToNarrowString(std::wstring( reinterpret_cast<const wchar_t *>(buffer.c_str()), dsInfo.nDebugStringLength - 1)) : std::move(buffer); _state = kStopped; _stopInfo.event = StopInfo::kEventStop; _stopInfo.reason = StopInfo::kReasonDebugOutput; } break; default: DS2BUG("unknown debug event code: %lu", de.dwDebugEventCode); } }