/* * Copyright Max Judin, Johannes Sixt, Daniel Kristjansson * This file is licensed under the GNU General Public License Version 2. * See the file COPYING in the toplevel directory of the source directory. */ #include #include #include /* i18n */ #include #include #include #include #include #include #include /* strtoul */ #include "regwnd.h" #include "dbgdriver.h" /** * Register display modes */ class RegisterDisplay { public: enum BitSize { bits8 = 0x10, bits16 = 0x20, bits32 = 0x30, bits64 = 0x40, bits80 = 0x50, bits128 = 0x60, bitsUnknown = 0x70 }; enum Format { nada = 0x01, binary = 0x02, octal = 0x03, decimal = 0x04, hex = 0x05, bcd = 0x06, realE = 0x07, realG = 0x08, realF = 0x09 }; RegisterDisplay() : mode(bitsUnknown|nada) { } RegisterDisplay(uint newMode) : mode(newMode) { } bool contains(uint pmode) const { bool val=((mode&0xf0)==pmode)||((mode&0x0f)==pmode); return val; } uint bitsFlag() { return mode&0xf0; } uint presentationFlag() const { return mode&0x0f; } uint bits() const { return bitMap[(mode>>4)&0x07]; } void changeFlag(uint code) { uint mask=((code&0xf0)==code)?0x0f:0xf0; mode = code | (mode & mask); } private: uint mode; static uint bitMap[]; }; // helper struct struct MenuPair { const char* name; uint mode; bool isSeparator() { return name == 0; } }; static MenuPair menuitems[] = { // treat as { I18N_NOOP("&GDB default"), RegisterDisplay::nada }, { I18N_NOOP("&Binary"), RegisterDisplay::binary }, { I18N_NOOP("&Octal"), RegisterDisplay::octal }, { I18N_NOOP("&Decimal"), RegisterDisplay::decimal }, { I18N_NOOP("He&xadecimal"), RegisterDisplay::hex }, { I18N_NOOP("Real (&e)"), RegisterDisplay::realE }, { I18N_NOOP("Real (&f)"), RegisterDisplay::realF }, { I18N_NOOP("&Real (g)"), RegisterDisplay::realG }, { 0, 0 }, { "8 bits", RegisterDisplay::bits8 }, { "16 bits", RegisterDisplay::bits16 }, { "32 bits", RegisterDisplay::bits32 }, { "64 bits", RegisterDisplay::bits64 }, { "80 bits", RegisterDisplay::bits80 }, { "128 bits",RegisterDisplay::bits128 }, }; uint RegisterDisplay::bitMap[] = { 0, 8, 16, 32, 64, 80, 128, /*default*/32, }; class ModeItem : public TQListViewItem { public: ModeItem(TQListView* parent, const TQString& name) : TQListViewItem(parent, name) {} ModeItem(TQListViewItem* parent) : TQListViewItem(parent) {} virtual void setMode(RegisterDisplay mode) = 0; virtual RegisterDisplay mode() = 0; }; class GroupingViewItem : public ModeItem { public: GroupingViewItem(RegisterView* parent, const TQString& name, const TQString& pattern, RegisterDisplay mode) : ModeItem(parent, name), matcher(pattern), gmode(mode) { setExpandable(true); setOpen(true); } bool matchName(const TQString& str) const { return matcher.exactMatch(str); } virtual void setMode(RegisterDisplay mode) { gmode=mode; TQListViewItem *it=firstChild(); for (; 0!=it; it=it->nextSibling()) { (static_cast(it))->setMode(gmode); } } virtual RegisterDisplay mode() { return gmode; } private: TQRegExp matcher; RegisterDisplay gmode; }; class RegisterViewItem : public ModeItem { public: RegisterViewItem(GroupingViewItem* parent, const RegisterInfo& regInfo); ~RegisterViewItem(); void setValue(const RegisterInfo& regInfo); virtual void setMode(RegisterDisplay mode); virtual RegisterDisplay mode() { return m_mode; } RegisterInfo m_reg; RegisterDisplay m_mode; /* display mode */ bool m_changes; bool m_found; protected: virtual void paintCell(TQPainter*, const TQColorGroup& cg, int column, int width, int alignment); }; RegisterViewItem::RegisterViewItem(GroupingViewItem* parent, const RegisterInfo& regInfo) : ModeItem(parent), m_reg(regInfo), m_changes(false), m_found(true) { setValue(m_reg); setText(0, m_reg.regName); setMode(parent->mode()); } RegisterViewItem::~RegisterViewItem() { } /* * We must be careful when converting the hex value because * it may exceed this computer's long values. */ inline int hexCharToDigit(char h) { if (h < '0') return -1; if (h <= '9') return h - '0'; if (h < 'A') return -1; if (h <= 'F') return h - ('A' - 10); if (h < 'a') return -1; if (h <= 'f') return h - ('a' - 10); return -1; } static TQString toBinary(TQString hex) { static const char digits[16][8] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" }; TQString result; for (unsigned i = 2; i < hex.length(); i++) { int idx = hexCharToDigit(hex[i].latin1()); if (idx < 0) { // not a hex digit; no conversion return hex; } const char* bindigits = digits[idx]; result += bindigits; } // remove leading zeros switch (hexCharToDigit(hex[2].latin1())) { case 0: case 1: result.remove(0, 3); break; case 2: case 3: result.remove(0, 2); break; case 4: case 5: case 6: case 7: result.remove(0, 1); break; } return result; } static TQString toOctal(TQString hex) { TQString result; int shift = 0; unsigned v = 0; for (int i = hex.length()-1; i >= 2; i--) { int idx = hexCharToDigit(hex[i].latin1()); if (idx < 0) return hex; v += idx << shift; result.insert(0, (v & 7) + '0'); v >>= 3; shift++; if (shift == 3) { // an extra digit this round result.insert(0, v + '0'); shift = v = 0; } } if (v != 0) { result.insert(0, v + '0'); } return "0" + result; } static TQString toDecimal(TQString hex) { /* * We convert only numbers that are small enough for this computer's * size of long integers. */ if (hex.length() > sizeof(unsigned long)*2+2) /* count in leading "0x" */ return hex; const char* start = hex.latin1(); char* end; unsigned long val = strtoul(start, &end, 0); if (start == end) return hex; else return TQString().setNum(val); } static TQString toBCD(const TQString& hex) { return hex.right(2); } static char* toRaw(const TQString& hex, uint& length) { static uint testNum=1; static void* testVoid=(void*)&testNum; static char* testChar=(char*)testVoid; static bool littleendian=(*testChar==1); length=((hex.length()-2)%2)+((hex.length()-2)/2); char* data=new char[length]; if (littleendian) { uint j=0; if (hex.length()<=2) return 0; for (int i=hex.length()-1; i>=2; ) { if (j%2==0) data[j/2]=hexCharToDigit(hex[i].latin1()); else data[j/2]|=(hexCharToDigit(hex[i].latin1())<<4); i--;j++; } } else { // big endian uint j=0; if (hex.length()<=2) return 0; for (uint i=2; i>2; if (RegisterDisplay::nada!=mode.presentationFlag() && reg.rawValue.length() > 2 && reg.rawValue[0] == '0' && reg.rawValue[1] == 'x') { if ("uint128"==reg.type) totalNibles=32; else if ("uint64"==reg.type) totalNibles=16; else if (reg.type.isEmpty()) totalNibles=nibles; else { return "don't know how to handle vector type <"+reg.type+">"; } if (0==nibles) nibles=8; // default to 4 byte, 32 bits values if (nibles>totalNibles) totalNibles=nibles; // minimum one value TQString raw=reg.rawValue.right(reg.rawValue.length()-2); // clip off "0x" while (raw.length()=0; nib-=nibles) { TQString qstr=convertSingle(raw.mid(nib, nibles).prepend("0x"), mode); if (nib==int(totalNibles-nibles)) cooked=qstr+cooked; else cooked=qstr+separator+cooked; } } else { cooked = reg.cookedValue; } if (cooked.at(0)!=' ' && cooked.at(0)!='-' && cooked.at(0)!='+') cooked.prepend(" "); return cooked; } void RegisterViewItem::setValue(const RegisterInfo& reg) { m_reg = reg; setText(1, reg.rawValue); TQString cookedValue = convertRaw(reg, m_mode); setText(2, cookedValue); } void RegisterViewItem::setMode(RegisterDisplay mode) { m_mode = mode; TQString cookedValue = convertRaw(m_reg, mode); setText(2, cookedValue); } void RegisterViewItem::paintCell(TQPainter* p, const TQColorGroup& cg, int column, int width, int alignment) { if (m_changes) { TQColorGroup newcg = cg; newcg.setColor(TQColorGroup::Text, red); TQListViewItem::paintCell(p, newcg, column, width, alignment); } else { TQListViewItem::paintCell(p, cg, column, width, alignment); } } RegisterView::RegisterView(TQWidget* parent, const char* name) : TQListView(parent, name) { setSorting(-1); setFont(TDEGlobalSettings::fixedFont()); TQPixmap iconRegs = UserIcon("regs.xpm"); TQPixmap iconWatchcoded = UserIcon("watchcoded.xpm"); TQPixmap iconWatch = UserIcon("watch.xpm"); addColumn(TQIconSet(iconRegs), i18n("Register")); addColumn(TQIconSet(iconWatchcoded), i18n("Value")); addColumn(TQIconSet(iconWatch), i18n("Decoded value")); setColumnAlignment(0,AlignLeft); setColumnAlignment(1,AlignLeft); setColumnAlignment(2,AlignLeft); setAllColumnsShowFocus( true ); header()->setClickEnabled(false); connect(this, TQ_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint&, int)), TQ_SLOT(rightButtonClicked(TQListViewItem*,const TQPoint&,int))); m_modemenu = new TQPopupMenu(this, "ERROR"); for (uint i=0; iinsertSeparator(); else m_modemenu->insertItem(i18n(menuitems[i].name), menuitems[i].mode); } connect(m_modemenu,TQ_SIGNAL(activated(int)),TQ_SLOT(slotModeChange(int))); new GroupingViewItem(this, "MIPS VU", "^vu.*", RegisterDisplay::bits32|RegisterDisplay::realE); new GroupingViewItem(this, "AltiVec", "^vr.*", RegisterDisplay::bits32|RegisterDisplay::realE); new GroupingViewItem(this, "POWER real", "^fpr.*", RegisterDisplay::bits32|RegisterDisplay::realE); new GroupingViewItem(this, "MMX", "^mm.*", RegisterDisplay::bits32|RegisterDisplay::realE); new GroupingViewItem(this, "SSE", "^xmm.*", RegisterDisplay::bits32|RegisterDisplay::realE); new GroupingViewItem(this, "x87", "^st.*", RegisterDisplay::bits80|RegisterDisplay::realE); new GroupingViewItem(this, i18n("x86/x87 segment"), "(^cs$|^ss$|^ds$|^es$|^fs$|^gs$|^fiseg$|^foseg$)", RegisterDisplay::nada); new GroupingViewItem(this, i18n("Flags"), "(^eflags$|^fctrl$|^mxcsr$|^cr$|^fpscr$|^vscr$|^ftag$|^fstat$)", RegisterDisplay::bits32|RegisterDisplay::binary); new GroupingViewItem(this, i18n("GP and others"), "^$", RegisterDisplay::nada); updateGroupVisibility(); setRootIsDecorated(true); resize(200,300); } RegisterView::~RegisterView() { } GroupingViewItem* RegisterView::findMatchingGroup(const TQString& regName) { for (TQListViewItem* it = firstChild(); it != 0; it = it->nextSibling()) { GroupingViewItem* i = static_cast(it); if (i->matchName(regName)) return i; } // not better match found, so return "GP and others" return static_cast(firstChild()); } GroupingViewItem* RegisterView::findGroup(const TQString& groupName) { for (TQListViewItem* it = firstChild(); it != 0; it = it->nextSibling()) { if (it->text(0) == groupName) return static_cast(it); } return 0; } void RegisterView::updateGroupVisibility() { for (TQListViewItem* it = firstChild(); it != 0; it = it->nextSibling()) { it->setVisible(it->childCount() > 0); } } void RegisterView::updateRegisters(const std::list& regs) { setUpdatesEnabled(false); // mark all items as 'not found' for (RegMap::iterator i = m_registers.begin(); i != m_registers.end(); ++i) { i->second->m_found = false; } // parse register values // must iterate last to first, since TQListView inserts at the top for (std::list::const_reverse_iterator reg = regs.rbegin(); reg != regs.rend(); ++reg) { // check if this is a new register RegMap::iterator i = m_registers.find(reg->regName); if (i != m_registers.end()) { RegisterViewItem* it = i->second; it->m_found = true; if (it->m_reg.rawValue != reg->rawValue || it->m_reg.cookedValue != reg->cookedValue) { it->m_changes = true; it->setValue(*reg); repaintItem(it); } else { /* * If there was a change last time, but not now, we * must revert the color. */ if (it->m_changes) { it->m_changes = false; repaintItem(it); } } } else { GroupingViewItem* group = findMatchingGroup(reg->regName); m_registers[reg->regName] = new RegisterViewItem(group, *reg); } } // remove all 'not found' items; TQStringList del; for (RegMap::iterator i = m_registers.begin(); i != m_registers.end(); ++i) { if (!i->second->m_found) { del.push_back(i->first); } } for (TQStringList::Iterator i = del.begin(); i != del.end(); ++i) { RegMap::iterator it = m_registers.find(*i); delete it->second; m_registers.erase(it); } updateGroupVisibility(); setUpdatesEnabled(true); triggerUpdate(); } void RegisterView::rightButtonClicked(TQListViewItem* item, const TQPoint& p, int) { if (item) { RegisterDisplay mode=static_cast(item)->mode(); for (unsigned int i = 0; isetItemChecked(menuitems[i].mode, mode.contains(menuitems[i].mode)); } m_modemenu->setCaption(item->text(0)); m_modemenu->popup(p); } } void RegisterView::slotModeChange(int pcode) { RegMap::iterator it=m_registers.find(m_modemenu->caption()); ModeItem* view; if (it != m_registers.end()) view = it->second; else view = findGroup(m_modemenu->caption()); if (view) { RegisterDisplay mode = view->mode(); mode.changeFlag(pcode); view->setMode(mode); } } void RegisterView::paletteChange(const TQPalette& oldPal) { setFont(TDEGlobalSettings::fixedFont()); TQListView::paletteChange(oldPal); } #include "regwnd.moc"