2 * Copyright Max Judin, Johannes Sixt, Daniel Kristjansson
3 * This file is licensed under the GNU General Public License Version 2.
4 * See the file COPYING in the toplevel directory of the source directory.
11 #include <kglobalsettings.h>
12 #include <klocale.h> /* i18n */
13 #include <kiconloader.h>
14 #include <Q3PopupMenu>
16 #include <QStringList>
17 #include <stdlib.h> /* strtoul */
20 * Register display modes
22 class RegisterDisplay
{
45 RegisterDisplay() : mode(bitsUnknown
|nada
) { }
46 RegisterDisplay(uint newMode
) : mode(newMode
) { }
48 bool contains(uint pmode
) const {
49 bool val
=((mode
&0xf0)==pmode
)||((mode
&0x0f)==pmode
);
52 uint
bitsFlag() { return mode
&0xf0; }
53 uint
presentationFlag() const { return mode
&0x0f; }
54 uint
bits() const { return bitMap
[(mode
>>4)&0x07]; }
55 void changeFlag(uint code
) {
56 uint mask
=((code
&0xf0)==code
)?0x0f:0xf0;
57 mode
= code
| (mode
& mask
);
69 bool isSeparator() { return name
== 0; }
72 static MenuPair menuitems
[] = {
74 { I18N_NOOP("&GDB default"), RegisterDisplay::nada
},
75 { I18N_NOOP("&Binary"), RegisterDisplay::binary
},
76 { I18N_NOOP("&Octal"), RegisterDisplay::octal
},
77 { I18N_NOOP("&Decimal"), RegisterDisplay::decimal
},
78 { I18N_NOOP("He&xadecimal"), RegisterDisplay::hex
},
79 { I18N_NOOP("Real (&e)"), RegisterDisplay::realE
},
80 { I18N_NOOP("Real (&f)"), RegisterDisplay::realF
},
81 { I18N_NOOP("&Real (g)"), RegisterDisplay::realG
},
83 { "8 bits", RegisterDisplay::bits8
},
84 { "16 bits", RegisterDisplay::bits16
},
85 { "32 bits", RegisterDisplay::bits32
},
86 { "64 bits", RegisterDisplay::bits64
},
87 { "80 bits", RegisterDisplay::bits80
},
88 { "128 bits",RegisterDisplay::bits128
},
91 uint
RegisterDisplay::bitMap
[] = {
93 64, 80, 128, /*default*/32,
96 class ModeItem
: public Q3ListViewItem
99 ModeItem(Q3ListView
* parent
, const QString
& name
) : Q3ListViewItem(parent
, name
) {}
100 ModeItem(Q3ListViewItem
* parent
) : Q3ListViewItem(parent
) {}
102 virtual void setMode(RegisterDisplay mode
) = 0;
103 virtual RegisterDisplay
mode() = 0;
106 class GroupingViewItem
: public ModeItem
109 GroupingViewItem(RegisterView
* parent
,
110 const QString
& name
, const QString
& pattern
,
111 RegisterDisplay mode
) :
112 ModeItem(parent
, name
), matcher(pattern
), gmode(mode
)
117 bool matchName(const QString
& str
) const
119 return matcher
.exactMatch(str
);
121 virtual void setMode(RegisterDisplay mode
)
124 Q3ListViewItem
*it
=firstChild();
125 for (; 0!=it
; it
=it
->nextSibling()) {
126 (static_cast<ModeItem
*>(it
))->setMode(gmode
);
129 virtual RegisterDisplay
mode() { return gmode
; }
133 RegisterDisplay gmode
;
136 class RegisterViewItem
: public ModeItem
139 RegisterViewItem(GroupingViewItem
* parent
,
140 const RegisterInfo
& regInfo
);
143 void setValue(const RegisterInfo
& regInfo
);
144 virtual void setMode(RegisterDisplay mode
);
145 virtual RegisterDisplay
mode() { return m_mode
; }
147 RegisterDisplay m_mode
; /* display mode */
152 virtual void paintCell(QPainter
*, const QColorGroup
& cg
,
153 int column
, int width
, int alignment
);
158 RegisterViewItem::RegisterViewItem(GroupingViewItem
* parent
,
159 const RegisterInfo
& regInfo
) :
166 setText(0, m_reg
.regName
);
167 setMode(parent
->mode());
170 RegisterViewItem::~RegisterViewItem()
175 * We must be careful when converting the hex value because
176 * it may exceed this computer's long values.
178 inline int hexCharToDigit(char h
)
187 return h
- ('A' - 10);
191 return h
- ('a' - 10);
195 static QString
toBinary(QString hex
)
197 static const char digits
[16][8] = {
198 "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
199 "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
203 for (int i
= 2; i
< hex
.length(); i
++) {
204 int idx
= hexCharToDigit(hex
[i
].latin1());
206 // not a hex digit; no conversion
209 const char* bindigits
= digits
[idx
];
212 // remove leading zeros
213 switch (hexCharToDigit(hex
[2].latin1())) {
214 case 0: case 1: result
.remove(0, 3); break;
215 case 2: case 3: result
.remove(0, 2); break;
217 case 6: case 7: result
.remove(0, 1); break;
222 static QString
toOctal(QString hex
)
227 for (int i
= hex
.length()-1; i
>= 2; i
--) {
228 int idx
= hexCharToDigit(hex
[i
].latin1());
232 result
.insert(0, (v
& 7) + '0');
236 // an extra digit this round
237 result
.insert(0, v
+ '0');
242 result
.insert(0, v
+ '0');
247 static QString
toDecimal(QString hex
)
250 * We convert only numbers that are small enough for this computer's
251 * size of long integers.
253 if (hex
.length() > int(sizeof(unsigned long)*2+2)) /* count in leading "0x" */
256 const char* start
= hex
.latin1();
258 unsigned long val
= strtoul(start
, &end
, 0);
262 return QString().setNum(val
);
265 static QString
toBCD(const QString
& hex
)
270 static char* toRaw(const QString
& hex
, uint
& length
)
272 static uint testNum
=1;
273 static void* testVoid
=(void*)&testNum
;
274 static char* testChar
=(char*)testVoid
;
275 static bool littleendian
=(*testChar
==1);
277 length
=((hex
.length()-2)%2)+((hex
.length()-2)/2);
278 char* data
=new char[length
];
282 if (hex
.length()<=2) return 0;
283 for (int i
=hex
.length()-1; i
>=2; ) {
284 if (j
%2==0) data
[j
/2]=hexCharToDigit(hex
[i
].latin1());
285 else data
[j
/2]|=(hexCharToDigit(hex
[i
].latin1())<<4);
288 } else { // big endian
290 if (hex
.length()<=2) return 0;
291 for (int i
=2; i
<hex
.length(); ) {
292 if (j
%2==0) data
[j
/2]=hexCharToDigit(hex
[i
].latin1())<<4;
293 else data
[j
/2]|=hexCharToDigit(hex
[i
].latin1());
300 static long double extractNumber(const QString
& hex
)
303 char* data
=toRaw(hex
, length
);
305 if (length
==4) { // float
307 } else if (length
==8) { // double
308 val
=*((double*)data
);
309 } else if (length
==10) { // long double
310 val
=*((long double*)data
);
319 static QString
toFloat(const QString
& hex
, char p
)
323 if (hex
.length()<=10) { bits
=32; prec
=6; }
324 else if (hex
.length()<=18) { bits
=64; prec
=17; }
325 else { bits
=80; prec
=20; }
327 QString cooked
=QString::number(extractNumber(hex
), p
, prec
);
330 while (cooked
.length()<prec
) cooked
=cooked
.prepend(" ");
335 static QString
convertSingle(const QString
& raw
, const RegisterDisplay mode
)
337 switch (mode
.presentationFlag()) {
338 case RegisterDisplay::binary
: return toBinary(raw
);
339 case RegisterDisplay::octal
: return toOctal(raw
);
340 case RegisterDisplay::decimal
: return toDecimal(raw
);
341 case RegisterDisplay::hex
: return raw
;
342 case RegisterDisplay::bcd
: return toBCD(raw
);
343 case RegisterDisplay::realE
: return toFloat(raw
, 'e');
344 case RegisterDisplay::realG
: return toFloat(raw
, 'g');
345 case RegisterDisplay::realF
: return toFloat(raw
, 'f');
350 QString
convertRaw(const RegisterInfo reg
, RegisterDisplay mode
)
353 int totalNibles
=0, nibles
=mode
.bits()>>2;
354 if (RegisterDisplay::nada
!=mode
.presentationFlag() &&
355 reg
.rawValue
.length() > 2 && reg
.rawValue
[0] == '0' && reg
.rawValue
[1] == 'x')
357 if ("uint128"==reg
.type
) totalNibles
=32;
358 else if ("uint64"==reg
.type
) totalNibles
=16;
359 else if (reg
.type
.isEmpty()) totalNibles
=nibles
;
361 return "don't know how to handle vector type <"+reg
.type
+">";
363 if (0==nibles
) nibles
=8; // default to 4 byte, 32 bits values
364 if (nibles
>totalNibles
) totalNibles
=nibles
; // minimum one value
366 QString raw
=reg
.rawValue
.right(reg
.rawValue
.length()-2); // clip off "0x"
367 while (raw
.length()<totalNibles
) raw
.prepend("0"); // pad out to totalNibles
369 QString separator
=","; // locale-specific?
370 for (int nib
=totalNibles
-nibles
; nib
>=0; nib
-=nibles
) {
371 QString qstr
=convertSingle(raw
.mid(nib
, nibles
).prepend("0x"), mode
);
373 if (nib
==int(totalNibles
-nibles
)) cooked
=qstr
+cooked
;
374 else cooked
=qstr
+separator
+cooked
;
379 cooked
= reg
.cookedValue
;
381 if (cooked
.at(0)!=' ' && cooked
.at(0)!='-' && cooked
.at(0)!='+')
386 void RegisterViewItem::setValue(const RegisterInfo
& reg
)
390 setText(1, reg
.rawValue
);
391 QString cookedValue
= convertRaw(reg
, m_mode
);
392 setText(2, cookedValue
);
395 void RegisterViewItem::setMode(RegisterDisplay mode
)
399 QString cookedValue
= convertRaw(m_reg
, mode
);
400 setText(2, cookedValue
);
403 void RegisterViewItem::paintCell(QPainter
* p
, const QColorGroup
& cg
,
404 int column
, int width
, int alignment
)
407 QColorGroup newcg
= cg
;
408 newcg
.setColor(QColorGroup::Text
, Qt::red
);
409 Q3ListViewItem::paintCell(p
, newcg
, column
, width
, alignment
);
411 Q3ListViewItem::paintCell(p
, cg
, column
, width
, alignment
);
416 RegisterView::RegisterView(QWidget
* parent
) :
420 setFont(KGlobalSettings::fixedFont());
422 QPixmap iconRegs
= UserIcon("regs.xpm");
423 QPixmap iconWatchcoded
= UserIcon("watchcoded.xpm");
424 QPixmap iconWatch
= UserIcon("watch.xpm");
426 addColumn(QIcon(iconRegs
), i18n("Register"));
427 addColumn(QIcon(iconWatchcoded
), i18n("Value"));
428 addColumn(QIcon(iconWatch
), i18n("Decoded value"));
430 setColumnAlignment(0, Qt::AlignLeft
);
431 setColumnAlignment(1, Qt::AlignLeft
);
432 setColumnAlignment(2, Qt::AlignLeft
);
434 setAllColumnsShowFocus( true );
435 header()->setClickEnabled(false);
437 connect(this, SIGNAL(contextMenuRequested(Q3ListViewItem
*, const QPoint
&, int)),
438 SLOT(rightButtonClicked(Q3ListViewItem
*,const QPoint
&,int)));
440 m_modemenu
= new Q3PopupMenu(this, "ERROR");
441 for (uint i
=0; i
<sizeof(menuitems
)/sizeof(MenuPair
); i
++) {
442 if (menuitems
[i
].isSeparator())
443 m_modemenu
->insertSeparator();
445 m_modemenu
->insertItem(i18n(menuitems
[i
].name
), menuitems
[i
].mode
);
447 connect(m_modemenu
,SIGNAL(activated(int)),SLOT(slotModeChange(int)));
449 new GroupingViewItem(this, "MIPS VU", "^vu.*",
450 RegisterDisplay::bits32
|RegisterDisplay::realE
);
451 new GroupingViewItem(this, "AltiVec", "^vr.*",
452 RegisterDisplay::bits32
|RegisterDisplay::realE
);
453 new GroupingViewItem(this, "POWER real", "^fpr.*",
454 RegisterDisplay::bits32
|RegisterDisplay::realE
);
455 new GroupingViewItem(this, "MMX", "^mm.*",
456 RegisterDisplay::bits32
|RegisterDisplay::realE
);
457 new GroupingViewItem(this, "SSE", "^xmm.*",
458 RegisterDisplay::bits32
|RegisterDisplay::realE
);
459 new GroupingViewItem(this, "x87", "^st.*",
460 RegisterDisplay::bits80
|RegisterDisplay::realE
);
461 new GroupingViewItem(this, i18n("x86/x87 segment"),
462 "(^cs$|^ss$|^ds$|^es$|^fs$|^gs$|^fiseg$|^foseg$)",
463 RegisterDisplay::nada
);
464 new GroupingViewItem(this, i18n("Flags"),
465 "(^eflags$|^fctrl$|^mxcsr$|^cr$|^fpscr$|^vscr$|^ftag$|^fstat$)",
466 RegisterDisplay::bits32
|RegisterDisplay::binary
);
467 new GroupingViewItem(this, i18n("GP and others"), "^$",
468 RegisterDisplay::nada
);
470 updateGroupVisibility();
471 setRootIsDecorated(true);
476 RegisterView::~RegisterView()
480 GroupingViewItem
* RegisterView::findMatchingGroup(const QString
& regName
)
482 for (Q3ListViewItem
* it
= firstChild(); it
!= 0; it
= it
->nextSibling())
484 GroupingViewItem
* i
= static_cast<GroupingViewItem
*>(it
);
485 if (i
->matchName(regName
))
488 // not better match found, so return "GP and others"
489 return static_cast<GroupingViewItem
*>(firstChild());
492 GroupingViewItem
* RegisterView::findGroup(const QString
& groupName
)
494 for (Q3ListViewItem
* it
= firstChild(); it
!= 0; it
= it
->nextSibling())
496 if (it
->text(0) == groupName
)
497 return static_cast<GroupingViewItem
*>(it
);
502 void RegisterView::updateGroupVisibility()
504 for (Q3ListViewItem
* it
= firstChild(); it
!= 0; it
= it
->nextSibling())
506 it
->setVisible(it
->childCount() > 0);
510 void RegisterView::updateRegisters(const std::list
<RegisterInfo
>& regs
)
512 setUpdatesEnabled(false);
514 // mark all items as 'not found'
515 for (RegMap::iterator i
= m_registers
.begin(); i
!= m_registers
.end(); ++i
)
517 i
->second
->m_found
= false;
520 // parse register values
521 // must iterate last to first, since QListView inserts at the top
522 for (std::list
<RegisterInfo
>::const_reverse_iterator reg
= regs
.rbegin(); reg
!= regs
.rend(); ++reg
)
524 // check if this is a new register
525 RegMap::iterator i
= m_registers
.find(reg
->regName
);
527 if (i
!= m_registers
.end())
529 RegisterViewItem
* it
= i
->second
;
531 if (it
->m_reg
.rawValue
!= reg
->rawValue
||
532 it
->m_reg
.cookedValue
!= reg
->cookedValue
)
534 it
->m_changes
= true;
539 * If there was a change last time, but not now, we
540 * must revert the color.
543 it
->m_changes
= false;
550 GroupingViewItem
* group
= findMatchingGroup(reg
->regName
);
551 m_registers
[reg
->regName
] =
552 new RegisterViewItem(group
, *reg
);
556 // remove all 'not found' items;
558 for (RegMap::iterator i
= m_registers
.begin(); i
!= m_registers
.end(); ++i
)
560 if (!i
->second
->m_found
) {
561 del
.push_back(i
->first
);
564 for (QStringList::Iterator i
= del
.begin(); i
!= del
.end(); ++i
)
566 RegMap::iterator it
= m_registers
.find(*i
);
568 m_registers
.erase(it
);
571 updateGroupVisibility();
572 setUpdatesEnabled(true);
577 void RegisterView::rightButtonClicked(Q3ListViewItem
* item
, const QPoint
& p
, int)
580 RegisterDisplay mode
=static_cast<ModeItem
*>(item
)->mode();
581 for (unsigned int i
= 0; i
<sizeof(menuitems
)/sizeof(MenuPair
); i
++) {
582 m_modemenu
->setItemChecked(menuitems
[i
].mode
,
583 mode
.contains(menuitems
[i
].mode
));
585 m_modemenu
->setCaption(item
->text(0));
586 m_modemenu
->popup(p
);
590 void RegisterView::slotModeChange(int pcode
)
592 RegMap::iterator it
=m_registers
.find(m_modemenu
->caption());
594 if (it
!= m_registers
.end())
597 view
= findGroup(m_modemenu
->caption());
600 RegisterDisplay mode
= view
->mode();
601 mode
.changeFlag(pcode
);
606 void RegisterView::paletteChange(const QPalette
& oldPal
)
608 setFont(KGlobalSettings::fixedFont());
609 Q3ListView::paletteChange(oldPal
);
612 #include "regwnd.moc"