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.
9 #include <kglobalsettings.h>
10 #include <klocale.h> /* i18n */
13 #include <QStringList>
14 #include <QHeaderView>
15 #include <QContextMenuEvent>
16 #include <stdlib.h> /* strtoul */
19 * Register display modes
21 class RegisterDisplay
{
44 RegisterDisplay() : mode(bitsUnknown
|nada
) { }
45 RegisterDisplay(uint newMode
) : mode(newMode
) { }
47 bool contains(uint pmode
) const {
48 bool val
=((mode
&0xf0)==pmode
)||((mode
&0x0f)==pmode
);
51 uint
bitsFlag() { return mode
&0xf0; }
52 uint
presentationFlag() const { return mode
&0x0f; }
53 uint
bits() const { return bitMap
[(mode
>>4)&0x07]; }
54 void changeFlag(uint code
) {
55 uint mask
=((code
&0xf0)==code
)?0x0f:0xf0;
56 mode
= code
| (mode
& mask
);
68 bool isSeparator() { return name
== 0; }
71 static MenuPair menuitems
[] = {
73 { I18N_NOOP("&GDB default"), RegisterDisplay::nada
},
74 { I18N_NOOP("&Binary"), RegisterDisplay::binary
},
75 { I18N_NOOP("&Octal"), RegisterDisplay::octal
},
76 { I18N_NOOP("&Decimal"), RegisterDisplay::decimal
},
77 { I18N_NOOP("He&xadecimal"), RegisterDisplay::hex
},
78 { I18N_NOOP("Real (&e)"), RegisterDisplay::realE
},
79 { I18N_NOOP("Real (&f)"), RegisterDisplay::realF
},
80 { I18N_NOOP("&Real (g)"), RegisterDisplay::realG
},
82 { "8 bits", RegisterDisplay::bits8
},
83 { "16 bits", RegisterDisplay::bits16
},
84 { "32 bits", RegisterDisplay::bits32
},
85 { "64 bits", RegisterDisplay::bits64
},
86 { "80 bits", RegisterDisplay::bits80
},
87 { "128 bits",RegisterDisplay::bits128
},
90 uint
RegisterDisplay::bitMap
[] = {
92 64, 80, 128, /*default*/32,
95 class ModeItem
: public QTreeWidgetItem
98 ModeItem(QTreeWidget
* parent
, const QString
& name
) : QTreeWidgetItem(parent
, QStringList(name
)) {}
99 ModeItem(QTreeWidgetItem
* parent
) : QTreeWidgetItem(parent
) {}
101 virtual void setMode(RegisterDisplay mode
) = 0;
102 virtual RegisterDisplay
mode() = 0;
105 class GroupingViewItem
: public ModeItem
108 GroupingViewItem(RegisterView
* parent
,
109 const QString
& name
, const QString
& pattern
,
110 RegisterDisplay mode
) :
111 ModeItem(parent
, name
), matcher(pattern
), gmode(mode
)
116 bool matchName(const QString
& str
) const
118 return matcher
.exactMatch(str
);
121 virtual void setMode(RegisterDisplay mode
)
124 for(int i
= 0; i
< childCount(); i
++)
126 static_cast<ModeItem
*>(child(i
))->setMode(gmode
);
130 virtual RegisterDisplay
mode()
137 RegisterDisplay gmode
;
140 class RegisterViewItem
: public ModeItem
143 RegisterViewItem(GroupingViewItem
* parent
,
144 const RegisterInfo
& regInfo
);
147 void setValue(const RegisterInfo
& regInfo
);
148 virtual void setMode(RegisterDisplay mode
);
149 virtual RegisterDisplay
mode() { return m_mode
; }
151 RegisterDisplay m_mode
; /* display mode */
157 RegisterViewItem::RegisterViewItem(GroupingViewItem
* parent
,
158 const RegisterInfo
& regInfo
) :
165 setText(0, m_reg
.regName
);
166 setMode(parent
->mode());
169 RegisterViewItem::~RegisterViewItem()
174 * We must be careful when converting the hex value because
175 * it may exceed this computer's long values.
177 inline int hexCharToDigit(char h
)
186 return h
- ('A' - 10);
190 return h
- ('a' - 10);
194 static QString
toBinary(QString hex
)
196 static const char digits
[16][8] = {
197 "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
198 "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
202 for (int i
= 2; i
< hex
.length(); i
++) {
203 int idx
= hexCharToDigit(hex
[i
].toLatin1());
205 // not a hex digit; no conversion
208 const char* bindigits
= digits
[idx
];
211 // remove leading zeros
212 switch (hexCharToDigit(hex
[2].toLatin1())) {
213 case 0: case 1: result
.remove(0, 3); break;
214 case 2: case 3: result
.remove(0, 2); break;
216 case 6: case 7: result
.remove(0, 1); break;
221 static QString
toOctal(QString hex
)
226 for (int i
= hex
.length()-1; i
>= 2; i
--) {
227 int idx
= hexCharToDigit(hex
[i
].toLatin1());
231 result
.insert(0, (v
& 7) + '0');
235 // an extra digit this round
236 result
.insert(0, v
+ '0');
241 result
.insert(0, v
+ '0');
246 static QString
toDecimal(QString hex
)
249 * We convert only numbers that are small enough for this computer's
250 * size of long integers.
252 if (hex
.length() > int(sizeof(unsigned long)*2+2)) /* count in leading "0x" */
256 unsigned long val
= hex
.toULong(&ok
, 0);
260 return QString().setNum(val
);
263 static QString
toBCD(const QString
& hex
)
268 static char* toRaw(const QString
& hex
, uint
& length
)
270 static uint testNum
=1;
271 static void* testVoid
=(void*)&testNum
;
272 static char* testChar
=(char*)testVoid
;
273 static bool littleendian
=(*testChar
==1);
275 length
=((hex
.length()-2)%2)+((hex
.length()-2)/2);
276 char* data
=new char[length
];
280 if (hex
.length()<=2) return 0;
281 for (int i
=hex
.length()-1; i
>=2; ) {
283 data
[j
/2]=hexCharToDigit(hex
[i
].toLatin1());
285 data
[j
/2]|=(hexCharToDigit(hex
[i
].toLatin1())<<4);
288 } else { // big endian
290 if (hex
.length()<=2) return 0;
291 for (int i
=2; i
<hex
.length(); ) {
293 data
[j
/2]=hexCharToDigit(hex
[i
].toLatin1())<<4;
295 data
[j
/2]|=hexCharToDigit(hex
[i
].toLatin1());
302 static long double extractNumber(const QString
& hex
)
305 char* data
=toRaw(hex
, length
);
307 if (length
==4) { // float
309 } else if (length
==8) { // double
310 val
=*((double*)data
);
311 } else if (length
==10) { // long double
312 val
=*((long double*)data
);
321 static QString
toFloat(const QString
& hex
, char p
)
324 if (hex
.length() <= 10)
326 else if (hex
.length() <= 18)
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
.isEmpty() && 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 QTreeWidgetItem
* header
= headerItem();
418 header
->setText(0, i18n("Register"));
419 header
->setText(1, i18n("Value"));
420 header
->setText(2, i18n("Decoded value"));
422 setAllColumnsShowFocus(true);
424 m_modemenu
= new QMenu("ERROR", this);
425 for (uint i
=0; i
<sizeof(menuitems
)/sizeof(MenuPair
); i
++) {
426 if (menuitems
[i
].isSeparator())
427 m_modemenu
->addSeparator();
429 QAction
* action
= m_modemenu
->addAction(i18n(menuitems
[i
].name
));
430 action
->setData(menuitems
[i
].mode
);
431 action
->setCheckable(true);
434 connect(m_modemenu
, SIGNAL(triggered(QAction
*)), SLOT(slotModeChange(QAction
*)));
436 new GroupingViewItem(this, i18n("GP and others"), "^$",
437 RegisterDisplay::nada
);
438 new GroupingViewItem(this, i18n("Flags"),
439 "(^eflags$|^fctrl$|^mxcsr$|^cr$|^fpscr$|^vscr$|^ftag$|^fstat$)",
440 RegisterDisplay::bits32
|RegisterDisplay::binary
);
441 new GroupingViewItem(this, i18n("x86/x87 segment"),
442 "(^cs$|^ss$|^ds$|^es$|^fs$|^gs$|^fiseg$|^foseg$)",
443 RegisterDisplay::nada
);
444 new GroupingViewItem(this, "x87", "^st.*",
445 RegisterDisplay::bits80
|RegisterDisplay::realE
);
446 new GroupingViewItem(this, "SSE", "^xmm.*",
447 RegisterDisplay::bits32
|RegisterDisplay::realE
);
448 new GroupingViewItem(this, "MMX", "^mm.*",
449 RegisterDisplay::bits32
|RegisterDisplay::realE
);
450 new GroupingViewItem(this, "POWER real", "^fpr.*",
451 RegisterDisplay::bits32
|RegisterDisplay::realE
);
452 new GroupingViewItem(this, "AltiVec", "^vr.*",
453 RegisterDisplay::bits32
|RegisterDisplay::realE
);
454 new GroupingViewItem(this, "MIPS VU", "^vu.*",
455 RegisterDisplay::bits32
|RegisterDisplay::realE
);
457 updateGroupVisibility();
458 setRootIsDecorated(true);
463 RegisterView::~RegisterView()
467 GroupingViewItem
* RegisterView::findMatchingGroup(const QString
& regName
)
469 for (int i
= 0; i
< topLevelItemCount(); i
++)
471 GroupingViewItem
* it
= static_cast<GroupingViewItem
*>(topLevelItem(i
));
472 if (it
->matchName(regName
))
475 // not better match found, so return "GP and others"
476 return static_cast<GroupingViewItem
*>(topLevelItem(0));
479 GroupingViewItem
* RegisterView::findGroup(const QString
& groupName
)
481 for (int i
= 0; i
< topLevelItemCount(); i
++)
483 QTreeWidgetItem
* it
= topLevelItem(i
);
484 if (it
->text(0) == groupName
)
485 return static_cast<GroupingViewItem
*>(it
);
487 // return that nothing was found.
491 // only show a group if it has subitems.
492 void RegisterView::updateGroupVisibility()
494 for(int i
= 0; i
< topLevelItemCount(); i
++)
496 QTreeWidgetItem
* item
= topLevelItem(i
);
497 item
->setHidden(item
->childCount() == 0);
501 void RegisterView::updateRegisters(const std::list
<RegisterInfo
>& regs
)
503 setUpdatesEnabled(false);
505 // mark all items as 'not found'
506 for (RegMap::iterator i
= m_registers
.begin(); i
!= m_registers
.end(); ++i
)
508 i
->second
->m_found
= false;
511 // parse register values
512 for (std::list
<RegisterInfo
>::const_iterator reg
= regs
.begin(); reg
!= regs
.end(); ++reg
)
514 // check if this is a new register
515 RegMap::iterator i
= m_registers
.find(reg
->regName
);
517 if (i
!= m_registers
.end())
519 RegisterViewItem
* it
= i
->second
;
521 if (it
->m_reg
.rawValue
!= reg
->rawValue
||
522 it
->m_reg
.cookedValue
!= reg
->cookedValue
)
524 it
->m_changes
= true;
527 it
->setForeground(0,Qt::red
);
528 it
->setForeground(1,Qt::red
);
529 it
->setForeground(2,Qt::red
);
533 * If there was a change last time, but not now, we
534 * must revert the color.
537 it
->m_changes
= false;
538 it
->setForeground(0,Qt::black
);
539 it
->setForeground(1,Qt::black
);
540 it
->setForeground(2,Qt::black
);
546 GroupingViewItem
* group
= findMatchingGroup(reg
->regName
);
547 m_registers
[reg
->regName
] =
548 new RegisterViewItem(group
, *reg
);
552 // remove all 'not found' items;
554 for (RegMap::iterator i
= m_registers
.begin(); i
!= m_registers
.end(); ++i
)
556 if (!i
->second
->m_found
) {
557 del
.push_back(i
->first
);
560 for (QStringList::Iterator i
= del
.begin(); i
!= del
.end(); ++i
)
562 RegMap::iterator it
= m_registers
.find(*i
);
564 m_registers
.erase(it
);
567 updateGroupVisibility();
568 setUpdatesEnabled(true);
572 void RegisterView::contextMenuEvent(QContextMenuEvent
* event
)
574 QTreeWidgetItem
*item
= itemAt(event
->pos());
577 RegisterDisplay mode
=static_cast<ModeItem
*>(item
)->mode();
579 foreach(QAction
* action
, m_modemenu
->actions())
581 action
->setChecked(mode
.contains(menuitems
[i
].mode
));
584 m_modemenu
->setTitle(item
->text(0));
585 m_modemenu
->popup(event
->globalPos());
591 void RegisterView::slotModeChange(QAction
* action
)
593 RegMap::iterator it
=m_registers
.find(m_modemenu
->title());
595 if (it
!= m_registers
.end())
598 view
= findGroup(m_modemenu
->title());
601 RegisterDisplay mode
= view
->mode();
602 mode
.changeFlag(action
->data().toInt());
607 void RegisterView::changeEvent(QEvent
* ev
)
609 switch (ev
->type()) {
610 case QEvent::ApplicationFontChange
:
611 case QEvent::FontChange
:
612 setFont(KGlobalSettings::fixedFont());
617 QTreeWidget::changeEvent(ev
);
620 #include "regwnd.moc"