/** * Attaches to the target process. * * @param tids The thread IDs of the threads that belong to the target process. * * @return A NaviError code that describes whether the operation was successful or not. */ NaviError LinuxSystem::attachToProcess() { msglog->log(LOG_VERBOSE, "Trying to attach to process %d", getPID()); int result = ptrace(PTRACE_ATTACH, getPID(), 0, 0); if (result) { msglog->log(LOG_ALWAYS, "Error: Couldn't attach to process"); return errno; } // TODO: Right now multi-threading is not supported Thread ts(getPID(), SUSPENDED); tids.push_back(ts); setActiveThread (getPID()); std ::string path; NaviError pathError = getExecutablePath(getPID(), path); if (pathError) { msglog->log( LOG_ALWAYS, "Error: Unable to determine the executable path of the debuggee."); return pathError; } // Generate processStart message and send it to BinNavi. fillModules(getPID(), this->modules); std::map<std::string, Module>::const_iterator cit = this->modules.find(path); if (cit != this->modules.end()) { Module processModule = cit->second; processStart(processModule, ts); } else { msglog->log(LOG_ALWAYS, "Error: Unable to determine main process module for '%s'", path.c_str()); exit(0); } return NaviErrors::SUCCESS; }
/** * Attaches to the target process. * * @param tids The thread IDs of the threads that belong to the target process. * * @return A NaviError code that describes whether the operation was successful * or not. */ NaviError GdbSystem::attachToProcess() { std::vector < Thread > tids; NaviError attachResult = cpu->attach(tids, this); if (attachResult) { msglog->log(LOG_VERBOSE, "Error: Couldn't attach to GDB server (Code: %d)", attachResult); } else { unsigned int activeThread; cpu->getActiveThread(activeThread, this); setActiveThread(activeThread); // The module constructor parameters are an optimistic over-approximation // since // Gdb can not provide us with better info about the executable image. processStart(Module("", "", 0, 0xFFFFFFFF), Thread(activeThread, SUSPENDED)); } return attachResult; }
/** * Starts a new process for debugging. * * @param path The path to the executable of the process. * @param tids The thread IDs of the threads that belong to the target process. * * @return A NaviError code that describes whether the operation was successful or not. */ NaviError LinuxSystem::startProcess( const NATIVE_STRING path, const std::vector<const NATIVE_STRING>& commands) { pid_t pid = fork(); if (pid == -1) { msglog->log(LOG_ALWAYS, "Error: Couldn't fork process"); return NaviErrors::COULDNT_OPEN_TARGET_PROCESS; } else if (pid == 0) { ptrace(PTRACE_TRACEME, 0, 0, 0); char** child_arguments = new char*[1 + commands.size() + 1]; child_arguments[0] = new char[strlen(path) + 1]; strcpy(child_arguments[0], path); for (unsigned int i = 0; i < commands.size(); i++) { child_arguments[i + 1] = new char[strlen(commands[i]) + 1]; strcpy(child_arguments[i + 1], commands[i]); } child_arguments[1 + commands.size()] = 0; // Child process if (execvp(path, child_arguments) == -1) { msglog->log(LOG_ALWAYS, "Error: Could not start the child process '%s'", path); exit(0); } return NaviErrors::SUCCESS; } else { int status; if (waitpid(pid, &status, __WALL) == -1) { msglog->log(LOG_ALWAYS, "Error: Wait for target process failed '%s'", path); exit(0); } if (WIFSTOPPED(status)) { if (WSTOPSIG(status) == SIGTRAP) { msglog->log(LOG_VERBOSE, "Initial STOP signal received"); } else { msglog->log(LOG_ALWAYS, "Error: Received unexpected STOP signal"); exit(0); } } else { msglog->log(LOG_ALWAYS, "Error: Did not receive initial STOP signal"); exit(0); } if (ptrace( PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE) == -1) { msglog->log(LOG_ALWAYS, "Error: Could not set ptrace options"); exit(0); } msglog->log(LOG_VERBOSE, "PID of the child process is %d", pid); setPID(pid); Thread ts(pid, SUSPENDED); tids.push_back(ts); setActiveThread(pid); lastMapFileSize = getFileSize( "/proc/" + zylib::zycon::toString(pid) + "/maps"); fillModules(pid, modules); this->modules = modules; std::map<std::string, Module>::const_iterator cit = this->modules.find( getTargetApplicationPath().string()); if (cit != this->modules.end()) { Module processModule = cit->second; processStart(processModule, ts); } else { msglog->log(LOG_ALWAYS, "Error: Unable to determine main process module for '%s'", getTargetApplicationPath().string().c_str()); exit(0); } return NaviErrors::SUCCESS; } }
void draw() { if (!gIsVisible) { return; } ImGui::SetNextWindowSize(ImVec2(600, 300), ImGuiSetCond_FirstUseEver); if (!ImGui::Begin("Threads", &gIsVisible)) { ImGui::End(); return; } sThreadsCache.clear(); coreinit::internal::lockScheduler(); auto core0Thread = coreinit::internal::getCoreRunningThread(0); auto core1Thread = coreinit::internal::getCoreRunningThread(1); auto core2Thread = coreinit::internal::getCoreRunningThread(2); auto firstThread = coreinit::internal::getFirstActiveThread(); for (auto thread = firstThread; thread; thread = thread->activeLink.next) { ThreadInfo tinfo; tinfo.thread = thread; tinfo.id = thread->id; tinfo.name = thread->name ? thread->name.get() : ""; tinfo.state = thread->state; tinfo.priority = thread->priority; tinfo.basePriority = thread->basePriority; tinfo.affinity = thread->attr & coreinit::OSThreadAttributes::AffinityAny; if (thread == core0Thread) { tinfo.coreId = 0; } else if (thread == core1Thread) { tinfo.coreId = 1; } else if (thread == core2Thread) { tinfo.coreId = 2; } else { tinfo.coreId = -1; } tinfo.coreTimeNs = thread->coreTimeConsumedNs; if (tinfo.coreId != -1) { tinfo.coreTimeNs += coreinit::internal::getCoreThreadRunningTime(0); } sThreadsCache.push_back(tinfo); } coreinit::internal::unlockScheduler(); ImGui::Columns(8, "threadList", false); ImGui::SetColumnOffset(0, ImGui::GetWindowWidth() * 0.00f); ImGui::SetColumnOffset(1, ImGui::GetWindowWidth() * 0.05f); ImGui::SetColumnOffset(2, ImGui::GetWindowWidth() * 0.35f); ImGui::SetColumnOffset(3, ImGui::GetWindowWidth() * 0.50f); ImGui::SetColumnOffset(4, ImGui::GetWindowWidth() * 0.60f); ImGui::SetColumnOffset(5, ImGui::GetWindowWidth() * 0.70f); ImGui::SetColumnOffset(6, ImGui::GetWindowWidth() * 0.75f); ImGui::SetColumnOffset(7, ImGui::GetWindowWidth() * 0.84f); ImGui::Text("ID"); ImGui::NextColumn(); ImGui::Text("Name"); ImGui::NextColumn(); ImGui::Text("NIA"); ImGui::NextColumn(); ImGui::Text("State"); ImGui::NextColumn(); ImGui::Text("Prio"); ImGui::NextColumn(); ImGui::Text("Aff"); ImGui::NextColumn(); ImGui::Text("Core"); ImGui::NextColumn(); ImGui::Text("Core Time"); ImGui::NextColumn(); ImGui::Separator(); for (auto &thread : sThreadsCache) { // ID if (thread.thread == getActiveThread()) { // Highlight the currently active thread // TODO: Clean this up auto idStr = fmt::format("{}", thread.id); auto drawList = ImGui::GetWindowDrawList(); auto lineHeight = ImGui::GetTextLineHeight(); float glyphWidth = ImGui::CalcTextSize("FF").x - ImGui::CalcTextSize("F").x; float idWidth = glyphWidth * idStr.length(); auto rootPos = ImGui::GetCursorScreenPos(); auto idMin = ImVec2(rootPos.x - 1, rootPos.y); auto idMax = ImVec2(rootPos.x + idWidth + 2, rootPos.y + lineHeight + 1); drawList->AddRectFilled(idMin, idMax, ImColor(CurrentBgColor), 2.0f); ImGui::TextColored(CurrentColor, "%s", idStr.c_str()); } else { ImGui::Text("%d", thread.id); } ImGui::NextColumn(); // Name if (isPaused()) { auto threadName = thread.name; if (thread.name.size() == 0) { threadName = fmt::format("(Unnamed Thread {})", thread.id); } if (ImGui::Selectable(threadName.c_str())) { setActiveThread(thread.thread); } } else { ImGui::Text("%s", thread.name.c_str()); } ImGui::NextColumn(); // NIA if (isPaused()) { ImGui::Text("%08x", getThreadNia(thread.thread)); } else { ImGui::Text(" "); } ImGui::NextColumn(); // Thread State ImGui::Text("%s", coreinit::enumAsString(thread.state).c_str()); ImGui::NextColumn(); // Priority ImGui::Text("%d (%d)", thread.priority, thread.basePriority); ImGui::NextColumn(); // Affinity std::string coreAff; if (thread.affinity & coreinit::OSThreadAttributes::AffinityCPU0) { coreAff += "0"; } if (thread.affinity & coreinit::OSThreadAttributes::AffinityCPU1) { if (coreAff.size() != 0) { coreAff += "|1"; } else { coreAff += "1"; } } if (thread.affinity & coreinit::OSThreadAttributes::AffinityCPU2) { if (coreAff.size() != 0) { coreAff += "|2"; } else { coreAff += "2"; } } ImGui::Text("%s", coreAff.c_str()); ImGui::NextColumn(); // Core Id if (thread.coreId != -1) { ImGui::Text("%d", thread.coreId); } ImGui::NextColumn(); // Core Time ImGui::Text("%" PRIu64, thread.coreTimeNs / 1000); ImGui::NextColumn(); } ImGui::Columns(1); ImGui::End(); }