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.
10 #include <kglobalsettings.h>
11 #include <klocale.h> /* i18n */
12 #include <kiconloader.h>
15 #include <QStringList>
16 #include <QHeaderView>
17 #include <QContextMenuEvent>
18 #include <stdlib.h> /* strtoul */
21 * Register display modes
23 class RegisterDisplay
{
46 RegisterDisplay() : mode(bitsUnknown
|nada
) { }
47 RegisterDisplay(uint newMode
) : mode(newMode
) { }
49 bool contains(uint pmode
) const {
50 bool val
=((mode
&0xf0)==pmode
)||((mode
&0x0f)==pmode
);
53 uint
bitsFlag() { return mode
&0xf0; }
54 uint
presentationFlag() const { return mode
&0x0f; }
55 uint
bits() const { return bitMap
[(mode
>>4)&0x07]; }
56 void changeFlag(uint code
) {
57 uint mask
=((code
&0xf0)==code
)?0x0f:0xf0;
58 mode
= code
| (mode
& mask
);
70 bool isSeparator() { return name
== 0; }
73 static MenuPair menuitems
[] = {
75 { I18N_NOOP("&GDB default"), RegisterDisplay::nada
},
76 { I18N_NOOP("&Binary"), RegisterDisplay::binary
},
77 { I18N_NOOP("&Octal"), RegisterDisplay::octal
},
78 { I18N_NOOP("&Decimal"), RegisterDisplay::decimal
},
79 { I18N_NOOP("He&xadecimal"), RegisterDisplay::hex
},
80 { I18N_NOOP("Real (&e)"), RegisterDisplay::realE
},
81 { I18N_NOOP("Real (&f)"), RegisterDisplay::realF
},
82 { I18N_NOOP("&Real (g)"), RegisterDisplay::realG
},
84 { "8 bits", RegisterDisplay::bits8
},
85 { "16 bits", RegisterDisplay::bits16
},
86 { "32 bits", RegisterDisplay::bits32
},
87 { "64 bits", RegisterDisplay::bits64
},
88 { "80 bits", RegisterDisplay::bits80
},
89 { "128 bits",RegisterDisplay::bits128
},
92 uint
RegisterDisplay::bitMap
[] = {
94 64, 80, 128, /*default*/32,
97 class ModeItem
: public QTreeWidgetItem
100 ModeItem(QTreeWidget
* parent
, const QString
& name
) : QTreeWidgetItem(parent
, QStringList(name
)) {}
101 ModeItem(QTreeWidgetItem
* parent
) : QTreeWidgetItem(parent
) {}
103 virtual void setMode(RegisterDisplay mode
) = 0;
104 virtual RegisterDisplay
mode() = 0;
107 class GroupingViewItem
: public ModeItem
110 GroupingViewItem(RegisterView
* parent
,
111 const QString
& name
, const QString
& pattern
,
112 RegisterDisplay mode
) :
113 ModeItem(parent
, name
), matcher(pattern
), gmode(mode
)
118 bool matchName(const QString
& str
) const
120 return matcher
.exactMatch(str
);
123 virtual void setMode(RegisterDisplay mode
)
126 for(int i
= 0; i
< childCount(); i
++)
128 static_cast<ModeItem
*>(child(i
))->setMode(gmode
);
132 virtual RegisterDisplay
mode()
139 RegisterDisplay gmode
;
142 class RegisterViewItem
: public ModeItem
145 RegisterViewItem(GroupingViewItem
* parent
,
146 const RegisterInfo
& regInfo
);
149 void setValue(const RegisterInfo
& regInfo
);
150 virtual void setMode(RegisterDisplay mode
);
151 virtual RegisterDisplay
mode() { return m_mode
; }
153 RegisterDisplay m_mode
; /* display mode */
159 RegisterViewItem::RegisterViewItem(GroupingViewItem
* parent
,
160 const RegisterInfo
& regInfo
) :
167 setText(0, m_reg
.regName
);
168 setMode(parent
->mode());
171 RegisterViewItem::~RegisterViewItem()
176 * We must be careful when converting the hex value because
177 * it may exceed this computer's long values.
179 inline int hexCharToDigit(char h
)
188 return h
- ('A' - 10);
192 return h
- ('a' - 10);
196 static QString
toBinary(QString hex
)
198 static const char digits
[16][8] = {
199 "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
200 "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
204 for (int i
= 2; i
< hex
.length(); i
++) {
205 int idx
= hexCharToDigit(hex
[i
].toLatin1());
207 // not a hex digit; no conversion
210 const char* bindigits
= digits
[idx
];
213 // remove leading zeros
214 switch (hexCharToDigit(hex
[2].toLatin1())) {
215 case 0: case 1: result
.remove(0, 3); break;
216 case 2: case 3: result
.remove(0, 2); break;
218 case 6: case 7: result
.remove(0, 1); break;
223 static QString
toOctal(QString hex
)
228 for (int i
= hex
.length()-1; i
>= 2; i
--) {
229 int idx
= hexCharToDigit(hex
[i
].toLatin1());
233 result
.insert(0, (v
& 7) + '0');
237 // an extra digit this round
238 result
.insert(0, v
+ '0');
243 result
.insert(0, v
+ '0');
248 static QString
toDecimal(QString hex
)
251 * We convert only numbers that are small enough for this computer's
252 * size of long integers.
254 if (hex
.length() > int(sizeof(unsigned long)*2+2)) /* count in leading "0x" */
258 unsigned long val
= hex
.toULong(&ok
, 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; ) {
285 data
[j
/2]=hexCharToDigit(hex
[i
].toLatin1());
287 data
[j
/2]|=(hexCharToDigit(hex
[i
].toLatin1())<<4);
290 } else { // big endian
292 if (hex
.length()<=2) return 0;
293 for (int i
=2; i
<hex
.length(); ) {
295 data
[j
/2]=hexCharToDigit(hex
[i
].toLatin1())<<4;
297 data
[j
/2]|=hexCharToDigit(hex
[i
].toLatin1());
304 static long double extractNumber(const QString
& hex
)
307 char* data
=toRaw(hex
, length
);
309 if (length
==4) { // float
311 } else if (length
==8) { // double
312 val
=*((double*)data
);
313 } else if (length
==10) { // long double
314 val
=*((long double*)data
);
323 static QString
toFloat(const QString
& hex
, char p
)
327 if (hex
.length()<=10) { bits
=32; prec
=6; }
328 else if (hex
.length()<=18) { bits
=64; prec
=17; }
329 else { bits
=80; prec
=20; }
331 char fmt
[8] = "%.*Lf";
334 sprintf(buf
, fmt
, prec
, extractNumber(hex
));
335 QString cooked
= QString::fromLatin1(buf
);
338 while (cooked
.length()<prec
) cooked
=cooked
.prepend(" ");
343 static QString
convertSingle(const QString
& raw
, const RegisterDisplay mode
)
345 switch (mode
.presentationFlag()) {
346 case RegisterDisplay::binary
: return toBinary(raw
);
347 case RegisterDisplay::octal
: return toOctal(raw
);
348 case RegisterDisplay::decimal
: return toDecimal(raw
);
349 case RegisterDisplay::hex
: return raw
;
350 case RegisterDisplay::bcd
: return toBCD(raw
);
351 case RegisterDisplay::realE
: return toFloat(raw
, 'e');
352 case RegisterDisplay::realG
: return toFloat(raw
, 'g');
353 case RegisterDisplay::realF
: return toFloat(raw
, 'f');
358 QString
convertRaw(const RegisterInfo reg
, RegisterDisplay mode
)
361 int totalNibles
=0, nibles
=mode
.bits()>>2;
362 if (RegisterDisplay::nada
!=mode
.presentationFlag() &&
363 reg
.rawValue
.length() > 2 && reg
.rawValue
[0] == '0' && reg
.rawValue
[1] == 'x')
365 if ("uint128"==reg
.type
) totalNibles
=32;
366 else if ("uint64"==reg
.type
) totalNibles
=16;
367 else if (reg
.type
.isEmpty()) totalNibles
=nibles
;
369 return "don't know how to handle vector type <"+reg
.type
+">";
371 if (0==nibles
) nibles
=8; // default to 4 byte, 32 bits values
372 if (nibles
>totalNibles
) totalNibles
=nibles
; // minimum one value
374 QString raw
=reg
.rawValue
.right(reg
.rawValue
.length()-2); // clip off "0x"
375 while (raw
.length()<totalNibles
) raw
.prepend("0"); // pad out to totalNibles
377 QString separator
=","; // locale-specific?
378 for (int nib
=totalNibles
-nibles
; nib
>=0; nib
-=nibles
) {
379 QString qstr
=convertSingle(raw
.mid(nib
, nibles
).prepend("0x"), mode
);
381 if (nib
==int(totalNibles
-nibles
)) cooked
=qstr
+cooked
;
382 else cooked
=qstr
+separator
+cooked
;
387 cooked
= reg
.cookedValue
;
389 if (cooked
.at(0)!=' ' && cooked
.at(0)!='-' && cooked
.at(0)!='+')
394 void RegisterViewItem::setValue(const RegisterInfo
& reg
)
398 setText(1, reg
.rawValue
);
399 QString cookedValue
= convertRaw(reg
, m_mode
);
400 setText(2, cookedValue
);
403 void RegisterViewItem::setMode(RegisterDisplay mode
)
407 QString cookedValue
= convertRaw(m_reg
, mode
);
408 setText(2, cookedValue
);
412 RegisterView::RegisterView(QWidget
* parent
) :
415 setFont(KGlobalSettings::fixedFont());
417 QPixmap iconRegs
= UserIcon("regs.xpm");
418 QPixmap iconWatchcoded
= UserIcon("watchcoded.xpm");
419 QPixmap iconWatch
= UserIcon("watch.xpm");
421 QTreeWidgetItem
* header
= headerItem();
422 header
->setText(0, i18n("Register"));
423 header
->setIcon(0, QIcon(iconRegs
));
425 header
->setText(1, i18n("Value"));
426 header
->setIcon(1, QIcon(iconWatchcoded
));
428 header
->setText(2, i18n("Decoded value"));
429 header
->setIcon(2, QIcon(iconWatch
));
431 setAllColumnsShowFocus(true);
433 m_modemenu
= new QMenu("ERROR", this);
434 for (uint i
=0; i
<sizeof(menuitems
)/sizeof(MenuPair
); i
++) {
435 if (menuitems
[i
].isSeparator())
436 m_modemenu
->addSeparator();
438 QAction
* action
= m_modemenu
->addAction(i18n(menuitems
[i
].name
));
439 action
->setData(menuitems
[i
].mode
);
440 action
->setCheckable(true);
443 connect(m_modemenu
, SIGNAL(triggered(QAction
*)), SLOT(slotModeChange(QAction
*)));
445 new GroupingViewItem(this, i18n("GP and others"), "^$",
446 RegisterDisplay::nada
);
447 new GroupingViewItem(this, i18n("Flags"),
448 "(^eflags$|^fctrl$|^mxcsr$|^cr$|^fpscr$|^vscr$|^ftag$|^fstat$)",
449 RegisterDisplay::bits32
|RegisterDisplay::binary
);
450 new GroupingViewItem(this, i18n("x86/x87 segment"),
451 "(^cs$|^ss$|^ds$|^es$|^fs$|^gs$|^fiseg$|^foseg$)",
452 RegisterDisplay::nada
);
453 new GroupingViewItem(this, "x87", "^st.*",
454 RegisterDisplay::bits80
|RegisterDisplay::realE
);
455 new GroupingViewItem(this, "SSE", "^xmm.*",
456 RegisterDisplay::bits32
|RegisterDisplay::realE
);
457 new GroupingViewItem(this, "MMX", "^mm.*",
458 RegisterDisplay::bits32
|RegisterDisplay::realE
);
459 new GroupingViewItem(this, "POWER real", "^fpr.*",
460 RegisterDisplay::bits32
|RegisterDisplay::realE
);
461 new GroupingViewItem(this, "AltiVec", "^vr.*",
462 RegisterDisplay::bits32
|RegisterDisplay::realE
);
463 new GroupingViewItem(this, "MIPS VU", "^vu.*",
464 RegisterDisplay::bits32
|RegisterDisplay::realE
);
466 updateGroupVisibility();
467 setRootIsDecorated(true);
472 RegisterView::~RegisterView()
476 GroupingViewItem
* RegisterView::findMatchingGroup(const QString
& regName
)
478 for (int i
= 0; i
< topLevelItemCount(); i
++)
480 GroupingViewItem
* it
= static_cast<GroupingViewItem
*>(topLevelItem(i
));
481 if (it
->matchName(regName
))
484 // not better match found, so return "GP and others"
485 return static_cast<GroupingViewItem
*>(topLevelItem(0));
488 GroupingViewItem
* RegisterView::findGroup(const QString
& groupName
)
490 for (int i
= 0; i
< topLevelItemCount(); i
++)
492 QTreeWidgetItem
* it
= topLevelItem(i
);
493 if (it
->text(0) == groupName
)
494 return static_cast<GroupingViewItem
*>(it
);
496 // return that nothing was found.
500 // only show a group if it has subitems.
501 void RegisterView::updateGroupVisibility()
503 for(int i
= 0; i
< topLevelItemCount(); i
++)
505 QTreeWidgetItem
* item
= topLevelItem(i
);
506 item
->setHidden(item
->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 for (std::list
<RegisterInfo
>::const_iterator reg
= regs
.begin(); reg
!= regs
.end(); ++reg
)
523 // check if this is a new register
524 RegMap::iterator i
= m_registers
.find(reg
->regName
);
526 if (i
!= m_registers
.end())
528 RegisterViewItem
* it
= i
->second
;
530 if (it
->m_reg
.rawValue
!= reg
->rawValue
||
531 it
->m_reg
.cookedValue
!= reg
->cookedValue
)
533 it
->m_changes
= true;
536 it
->setForeground(0,Qt::red
);
537 it
->setForeground(1,Qt::red
);
538 it
->setForeground(2,Qt::red
);
542 * If there was a change last time, but not now, we
543 * must revert the color.
546 it
->m_changes
= false;
547 it
->setForeground(0,Qt::black
);
548 it
->setForeground(1,Qt::black
);
549 it
->setForeground(2,Qt::black
);
555 GroupingViewItem
* group
= findMatchingGroup(reg
->regName
);
556 m_registers
[reg
->regName
] =
557 new RegisterViewItem(group
, *reg
);
561 // remove all 'not found' items;
563 for (RegMap::iterator i
= m_registers
.begin(); i
!= m_registers
.end(); ++i
)
565 if (!i
->second
->m_found
) {
566 del
.push_back(i
->first
);
569 for (QStringList::Iterator i
= del
.begin(); i
!= del
.end(); ++i
)
571 RegMap::iterator it
= m_registers
.find(*i
);
573 m_registers
.erase(it
);
576 updateGroupVisibility();
577 setUpdatesEnabled(true);
581 void RegisterView::contextMenuEvent(QContextMenuEvent
* event
)
583 QTreeWidgetItem
*item
= itemAt(event
->pos());
586 RegisterDisplay mode
=static_cast<ModeItem
*>(item
)->mode();
588 foreach(QAction
* action
, m_modemenu
->actions())
590 action
->setChecked(mode
.contains(menuitems
[i
].mode
));
593 m_modemenu
->setTitle(item
->text(0));
594 m_modemenu
->popup(event
->globalPos());
600 void RegisterView::slotModeChange(QAction
* action
)
602 RegMap::iterator it
=m_registers
.find(m_modemenu
->title());
604 if (it
!= m_registers
.end())
607 view
= findGroup(m_modemenu
->title());
610 RegisterDisplay mode
= view
->mode();
611 mode
.changeFlag(action
->data().toInt());
616 void RegisterView::paletteChange(const QPalette
&)
618 setFont(KGlobalSettings::fixedFont());
621 #include "regwnd.moc"