void FrameState::assertValidRegisterState() const { Registers checkedFreeRegs; FrameEntry *tos = tosFe(); for (uint32 i = 0; i < tracker.nentries; i++) { FrameEntry *fe = tracker[i]; if (fe >= tos) continue; JS_ASSERT(i == fe->trackerIndex()); JS_ASSERT_IF(fe->isCopy(), fe->trackerIndex() > fe->copyOf()->trackerIndex()); JS_ASSERT_IF(fe->isCopy(), !fe->type.inRegister() && !fe->data.inRegister()); JS_ASSERT_IF(fe->isCopy(), fe->copyOf() < tos); JS_ASSERT_IF(fe->isCopy(), fe->copyOf()->isCopied()); if (fe->isCopy()) continue; if (fe->type.inRegister()) { checkedFreeRegs.takeReg(fe->type.reg()); JS_ASSERT(regstate[fe->type.reg()].fe == fe); } if (fe->data.inRegister()) { checkedFreeRegs.takeReg(fe->data.reg()); JS_ASSERT(regstate[fe->data.reg()].fe == fe); } } JS_ASSERT(checkedFreeRegs == freeRegs); }
unsigned int Node::calculateTotalSize(const Registers& regs)const{ unsigned int acum=0; for(Registers::iterator it=regs.begin();it!=regs.end();++it){ acum+=(*it)->getSize(); } return acum; }
void FrameState::syncAndKill(Registers kill, Uses uses, Uses ignore) { /* Backwards, so we can allocate registers to backing slots better. */ FrameEntry *tos = tosFe(); FrameEntry *bottom = tos - uses.nuses; tos -= ignore.nuses; if (inTryBlock) bottom = NULL; for (uint32 i = tracker.nentries - 1; i < tracker.nentries; i--) { FrameEntry *fe = tracker[i]; if (fe >= tos) continue; Address address = addressOf(fe); FrameEntry *backing = fe; if (fe->isCopy()) { if (!inTryBlock && fe < bottom) continue; backing = fe->copyOf(); } JS_ASSERT_IF(i == 0, !fe->isCopy()); bool killData = fe->data.inRegister() && kill.hasReg(fe->data.reg()); if (!fe->data.synced() && (killData || fe >= bottom)) { if (backing != fe && backing->data.inMemory()) tempRegForData(backing); syncData(backing, address, masm); fe->data.sync(); if (fe->isConstant() && !fe->type.synced()) fe->type.sync(); } if (killData) { JS_ASSERT(backing == fe); JS_ASSERT(fe->data.synced()); if (regstate[fe->data.reg()].fe) forgetReg(fe->data.reg()); fe->data.setMemory(); } bool killType = fe->type.inRegister() && kill.hasReg(fe->type.reg()); if (!fe->type.synced() && (killType || fe >= bottom)) { if (backing != fe && backing->type.inMemory()) tempRegForType(backing); syncType(backing, address, masm); fe->type.sync(); } if (killType) { JS_ASSERT(backing == fe); JS_ASSERT(fe->type.synced()); if (regstate[fe->type.reg()].fe) forgetReg(fe->type.reg()); fe->type.setMemory(); } } }
bool Liveness::SrcRegisterIs(const Registers& regs, myTemp reg) const { assert (reg != nullptr); assert (regs.size() >= 0 && regs.size() <= 1); if (regs.size() == 1) return regs.at(0) == reg; else return false; }
Registers TwoOperandOperate::GetSrcRegs() const { Registers result = GetDstRegs(); if (srcRep.kind == BinaryUnion::Kind::Reg) result.push_back(srcRep.u.reg); return result; }
void Liveness::SortOneRegisters(Registers& regs) { struct myTempComp { bool operator () (myTemp lhs, myTemp rhs) { return Temp_getTempNum(lhs) < Temp_getTempNum(rhs); } } tempComparator; sort(regs.begin(), regs.end(), tempComparator); }
// Compare register sets by name static inline bool compareRegisterSet(const Registers &r1, const Registers &r2) { if (r1.size() != r2.size()) return false; const int size = r1.size(); for (int r = 0; r < size; r++) if (r1.at(r).name != r2.at(r).name) return false; return true; }
// NOTE: // This function also recognize conditions when either of the destination // register or the source register is used as a memory location: // mov [reg], reg | mov [reg], [reg] | mov reg, [reg] // On these conditions, the move instructions are not treated as move pairs. bool Liveness::IsTwoContentRegOperandMove( Node node, Registers& leftOperand, Registers& rightOperand) const { if (!cfGraph.IsMoveIns(node) || leftOperand.size() != 1 || rightOperand.size() != 1) return false; // check memory operand type from "[]" characters string insStr = cfGraph.GetNodeIns(node)->ToString(); return insStr.find('[') == string::npos; }
Registers Call::GetDstRegs() const { Registers result; // caller-save contains eax register which is also the result value register. myTempList temps = Frame_callerSaveRegs(); while (temps) result.push_back(temps->head), temps = temps->tail; return result; }
Registers Liveness::GetSetDiff(Registers& lhs, Registers& rhs) { struct myTempComp { bool operator () (myTemp lhs, myTemp rhs) { return Temp_getTempNum(lhs) < Temp_getTempNum(rhs); } } tempComparator; Registers result; set_difference( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), back_inserter(result), tempComparator); return result; }
void RegisterHandler::setAndMarkRegisters(const Registers ®isters) { if (!compareRegisterSet(m_registers, registers)) { setRegisters(registers); return; } const int size = m_registers.size(); for (int r = 0; r != size; ++r) { const QModelIndex regIndex = index(r, 1, QModelIndex()); if (m_registers.at(r).value != registers.at(r).value) { // Indicate red if values change, keep changed. m_registers[r].changed = m_registers.at(r).changed || !m_registers.at(r).value.isEmpty(); m_registers[r].value = registers.at(r).value; emit dataChanged(regIndex, regIndex); } emit registerSet(regIndex); // Notify attached memory views. } }
std::string gdbmiRegisters(CIDebugRegisters *regs, CIDebugControl *control, bool humanReadable, unsigned flags, std::string *errorMessage) { if (regs == 0 || control == 0) { *errorMessage = "Required interfaces missing for registers dump."; return std::string(); } const Registers registers = getRegisters(regs, flags, errorMessage); if (registers.empty()) return std::string(); std::ostringstream str; str << '['; if (humanReadable) str << '\n'; const Registers::size_type size = registers.size(); for (Registers::size_type r = 0; r < size; ++r) { const Register ® = registers.at(r); if (r) str << ','; str << "{number=\"" << r << "\",name=\"" << gdbmiWStringFormat(reg.name) << '"'; if (!reg.description.empty()) str << ",description=\"" << gdbmiWStringFormat(reg.description) << '"'; if (reg.subRegister) str << ",subregister=\"true\""; if (reg.pseudoRegister) str << ",pseudoregister=\"true\""; str << ",value=\""; formatDebugValue(str, reg.value, control); str << "\"}"; if (humanReadable) str << '\n'; } str << ']'; if (humanReadable) str << '\n'; return str.str(); }
void Liveness::GenerateMovePairs() { for (auto oneNode : cfGraph.GetDirectedGraph().GetNodes()) { Registers leftOperand = cfGraph.GetNodeIns(oneNode)->GetDstRegs(); Registers rightOperand = cfGraph.GetNodeIns(oneNode)->GetSrcRegs(); if (IsTwoContentRegOperandMove(oneNode, leftOperand, rightOperand) && !IsSelfMove(leftOperand, rightOperand)) { assert (leftOperand.at(0) != nullptr && rightOperand.at(0) != nullptr); Node leftNode = interferenceGraph.GetRegNode(leftOperand.at(0)); Node rightNode = interferenceGraph.GetRegNode(rightOperand.at(0)); if(!MovePairContains(leftNode, rightNode)) movePairs.push_back(Edge(leftNode, rightNode)); } } }
bool Liveness::IsSelfMove(Registers& leftOperand, Registers& rightOperand) const { assert (leftOperand.size() == 1 && rightOperand.size() == 1); return leftOperand.at(0) == rightOperand.at(0); }
Registers getRegisters(CIDebugRegisters *regs, unsigned flags, std::string *errorMessage) { enum { bufSize= 128 }; WCHAR buf[bufSize]; ULONG registerCount = 0; HRESULT hr = regs->GetNumberRegisters(®isterCount); if (FAILED(hr)) { *errorMessage = msgDebugEngineComFailed("GetNumberRegisters", hr); return Registers(); } ULONG pseudoRegisterCount = 0; if (flags & IncludePseudoRegisters) { hr = regs->GetNumberPseudoRegisters(&pseudoRegisterCount); if (FAILED(hr)) { *errorMessage = msgDebugEngineComFailed("GetNumberPseudoRegisters", hr); return Registers(); } } Registers rc; rc.reserve(registerCount + pseudoRegisterCount); // Standard registers DEBUG_REGISTER_DESCRIPTION description; DEBUG_VALUE value; for (ULONG r = 0; r < registerCount; ++r) { hr = regs->GetDescriptionWide(r, buf, bufSize, NULL, &description); if (FAILED(hr)) { *errorMessage = msgDebugEngineComFailed("GetDescription", hr); return Registers(); } hr = regs->GetValue(r, &value); if (FAILED(hr)) { *errorMessage = msgDebugEngineComFailed("GetValue", hr); return Registers(); } const bool isSubRegister = (description.Flags & DEBUG_REGISTER_SUB_REGISTER); if (!isSubRegister || (flags & IncludeSubRegisters)) { Register reg; reg.name = buf; reg.description = registerDescription(description); reg.subRegister = isSubRegister; reg.value = value; rc.push_back(reg); } } // Pseudo for (ULONG r = 0; r < pseudoRegisterCount; ++r) { ULONG type; hr = regs->GetPseudoDescriptionWide(r, buf, bufSize, NULL, NULL, &type); if (FAILED(hr)) continue; // Fails for some pseudo registers hr = regs->GetValue(r, &value); if (FAILED(hr)) continue; // Fails for some pseudo registers Register reg; reg.pseudoRegister = true; reg.name = buf; reg.description = valueType(type); reg.value = value; rc.push_back(reg); } return rc; }
static void general_signal_handler(int signum, siginfo_t* info, void* context) { Registers regs; if (!context) return; // Convert OS context to Registers port_thread_context_to_regs(®s, (ucontext_t*)context); void* fault_addr = info ? info->si_addr : NULL; // Check if SIGSEGV is produced by port_read/write_memory port_tls_data_t* tlsdata = get_private_tls_data(); if (tlsdata && tlsdata->violation_flag) { tlsdata->violation_flag = 0; regs.set_ip(tlsdata->restart_address); return; } if (!tlsdata) // Tread is not attached - attach thread temporarily { int res; tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t)); if (tlsdata) // Try to attach the thread res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0); if (!tlsdata || res != 0) { // Can't process correctly; perform default actions if (FLAG_DBG) { bool result = gdb_crash_handler(®s); _exit(-1); // Exit process if not sucessful... } if (FLAG_CORE && signum != SIGABRT) // SIGABRT can't be rethrown { signal(signum, SIG_DFL); // setup default handler return; } _exit(-1); } // SIGSEGV can represent SO which can't be processed out of signal handler if (signum == SIGSEGV && // This can occur only when a user set an alternative stack is_stack_overflow(tlsdata, fault_addr)) { int result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, ®s, fault_addr, FALSE); if (result == 0) { if (port_thread_detach_temporary() == 0) STD_FREE(tlsdata); return; } if (result > 0) tlsdata->debugger = TRUE; else { if (FLAG_CORE) { // Rethrow crash to generate core signal(signum, SIG_DFL); // setup default handler return; } _exit(-1); } } } if (tlsdata->debugger) { bool result = gdb_crash_handler(®s); _exit(-1); // Exit process if not sucessful... } if (signum == SIGABRT && // SIGABRT can't be trown again from c_handler FLAG_DBG) { // So attaching GDB right here bool result = gdb_crash_handler(®s); _exit(-1); // Exit process if not sucessful... } if (signum == SIGSEGV && is_stack_overflow(tlsdata, fault_addr)) { // Second SO while previous SO is not processed yet - is GPF if (tlsdata->restore_guard_page) tlsdata->restore_guard_page = FALSE; else { // To process signal on protected stack area port_thread_clear_guard_page(); // Note: the call above does not disable alternative stack // It can't be made while we are on alternative stack // Alt stack will be disabled explicitly in c_handler() tlsdata->restore_guard_page = TRUE; } } // Prepare registers for transfering control out of signal handler void* callback = (void*)&c_handler; port_set_longjump_regs(callback, ®s, 3, ®s, (void*)(size_t)signum, fault_addr); // Convert prepared Registers back to OS context port_thread_regs_to_context((ucontext_t*)context, ®s); // Return from signal handler to go to C handler }