1 // -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
4 // Copyright by Judin Max, Johannes Sixt, Daniel Kristjansson
5 // This file is under GPL, the GNU General Public Licence
8 #include <kglobalsettings.h>
9 #include <klocale.h> /* i18n */
10 #include <kiconloader.h>
11 #include <qfontdialog.h>
12 #include <qmessagebox.h>
15 #include <qstringlist.h>
16 #include <stdlib.h> /* strtoul */
18 #include "dbgdriver.h"
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 QListViewItem
100 ModeItem(QListView
* parent
, const QString
& name
) : QListViewItem(parent
, name
) {}
101 ModeItem(QListViewItem
* parent
) : QListViewItem(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
);
122 virtual void setMode(RegisterDisplay mode
)
125 QListViewItem
*it
=firstChild();
126 for (; 0!=it
; it
=it
->nextSibling()) {
127 (static_cast<ModeItem
*>(it
))->setMode(gmode
);
130 virtual RegisterDisplay
mode() { return gmode
; }
134 RegisterDisplay gmode
;
137 class RegisterViewItem
: public ModeItem
140 RegisterViewItem(GroupingViewItem
* parent
,
141 const RegisterInfo
& regInfo
);
144 void setValue(const RegisterInfo
& regInfo
);
145 virtual void setMode(RegisterDisplay mode
);
146 virtual RegisterDisplay
mode() { return m_mode
; }
148 RegisterDisplay m_mode
; /* display mode */
153 virtual void paintCell(QPainter
*, const QColorGroup
& cg
,
154 int column
, int width
, int alignment
);
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 (unsigned i
= 2; i
< hex
.length(); i
++) {
205 int idx
= hexCharToDigit(hex
[i
].latin1());
207 // not a hex digit; no conversion
210 const char* bindigits
= digits
[idx
];
213 // remove leading zeros
214 switch (hexCharToDigit(hex
[2].latin1())) {
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
].latin1());
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() > sizeof(unsigned long)*2+2) /* count in leading "0x" */
257 const char* start
= hex
.latin1();
259 unsigned long val
= strtoul(start
, &end
, 0);
263 return QString().setNum(val
);
266 static QString
toBCD(const QString
& hex
)
271 static char* toRaw(const QString
& hex
, uint
& length
)
273 static uint testNum
=1;
274 static void* testVoid
=(void*)&testNum
;
275 static char* testChar
=(char*)testVoid
;
276 static bool littleendian
=(*testChar
==1);
278 length
=((hex
.length()-2)%2)+((hex
.length()-2)/2);
279 char* data
=new char[length
];
283 if (hex
.length()<=2) return 0;
284 for (int i
=hex
.length()-1; i
>=2; ) {
285 if (j
%2==0) data
[j
/2]=hexCharToDigit(hex
[i
].latin1());
286 else data
[j
/2]|=(hexCharToDigit(hex
[i
].latin1())<<4);
289 } else { // big endian
291 if (hex
.length()<=2) return 0;
292 for (uint i
=2; i
<hex
.length(); ) {
293 if (j
%2==0) data
[j
/2]=hexCharToDigit(hex
[i
].latin1())<<4;
294 else data
[j
/2]|=hexCharToDigit(hex
[i
].latin1());
301 static long double extractNumber(const QString
& hex
)
304 char* data
=toRaw(hex
, length
);
306 if (length
==4) { // float
308 } else if (length
==8) { // double
309 val
=*((double*)data
);
310 } else if (length
==10) { // long double
311 val
=*((long double*)data
);
320 static QString
toFloat(const QString
& hex
, char p
)
324 if (hex
.length()<=10) { bits
=32; prec
=6; }
325 else if (hex
.length()<=18) { bits
=64; prec
=17; }
326 else { bits
=80; prec
=20; }
328 QString cooked
=QString::number(extractNumber(hex
), p
, prec
);
331 while (cooked
.length()<prec
) cooked
=cooked
.prepend(" ");
336 static QString
convertSingle(const QString
& raw
, const RegisterDisplay mode
)
338 switch (mode
.presentationFlag()) {
339 case RegisterDisplay::binary
: return toBinary(raw
);
340 case RegisterDisplay::octal
: return toOctal(raw
);
341 case RegisterDisplay::decimal
: return toDecimal(raw
);
342 case RegisterDisplay::hex
: return raw
;
343 case RegisterDisplay::bcd
: return toBCD(raw
);
344 case RegisterDisplay::realE
: return toFloat(raw
, 'e');
345 case RegisterDisplay::realG
: return toFloat(raw
, 'g');
346 case RegisterDisplay::realF
: return toFloat(raw
, 'f');
351 QString
convertRaw(const RegisterInfo reg
, RegisterDisplay mode
)
354 uint totalNibles
=0, nibles
=mode
.bits()>>2;
355 if (RegisterDisplay::nada
!=mode
.presentationFlag() &&
356 reg
.rawValue
.length() > 2 && reg
.rawValue
[0] == '0' && reg
.rawValue
[1] == 'x')
358 if ("uint128"==reg
.type
) totalNibles
=32;
359 else if ("uint64"==reg
.type
) totalNibles
=16;
360 else if (reg
.type
.isEmpty()) totalNibles
=nibles
;
362 return "don't know how to handle vector type <"+reg
.type
+">";
364 if (0==nibles
) nibles
=8; // default to 4 byte, 32 bits values
365 if (nibles
>totalNibles
) totalNibles
=nibles
; // minimum one value
367 QString raw
=reg
.rawValue
.right(reg
.rawValue
.length()-2); // clip off "0x"
368 while (raw
.length()<totalNibles
) raw
.prepend("0"); // pad out to totalNibles
370 QString separator
=","; // locale-specific?
371 for (int nib
=totalNibles
-nibles
; nib
>=0; nib
-=nibles
) {
372 QString qstr
=convertSingle(raw
.mid(nib
, nibles
).prepend("0x"), mode
);
374 if (nib
==int(totalNibles
-nibles
)) cooked
=qstr
+cooked
;
375 else cooked
=qstr
+separator
+cooked
;
380 cooked
= reg
.cookedValue
;
382 if (cooked
.at(0)!=' ' && cooked
.at(0)!='-' && cooked
.at(0)!='+')
387 void RegisterViewItem::setValue(const RegisterInfo
& reg
)
391 setText(1, reg
.rawValue
);
392 QString cookedValue
= convertRaw(reg
, m_mode
);
393 setText(2, cookedValue
);
396 void RegisterViewItem::setMode(RegisterDisplay mode
)
400 QString cookedValue
= convertRaw(m_reg
, mode
);
401 setText(2, cookedValue
);
404 void RegisterViewItem::paintCell(QPainter
* p
, const QColorGroup
& cg
,
405 int column
, int width
, int alignment
)
408 QColorGroup newcg
= cg
;
409 newcg
.setColor(QColorGroup::Text
, red
);
410 QListViewItem::paintCell(p
, newcg
, column
, width
, alignment
);
412 QListViewItem::paintCell(p
, cg
, column
, width
, alignment
);
417 RegisterView::RegisterView(QWidget
* parent
, const char* name
) :
418 QListView(parent
, name
)
421 setFont(KGlobalSettings::fixedFont());
423 QPixmap iconRegs
= BarIcon("regs.xpm");
424 QPixmap iconWatchcoded
= BarIcon("watchcoded.xpm");
425 QPixmap iconWatch
= BarIcon("watch.xpm");
427 addColumn(QIconSet(iconRegs
), i18n("Register"));
428 addColumn(QIconSet(iconWatchcoded
), i18n("Value"));
429 addColumn(QIconSet(iconWatch
), i18n("Decoded value"));
431 setColumnAlignment(0,AlignLeft
);
432 setColumnAlignment(1,AlignLeft
);
433 setColumnAlignment(2,AlignLeft
);
435 setAllColumnsShowFocus( true );
436 header()->setClickEnabled(false);
438 connect(this, SIGNAL(contextMenuRequested(QListViewItem
*, const QPoint
&, int)),
439 SLOT(rightButtonClicked(QListViewItem
*,const QPoint
&,int)));
441 m_modemenu
= new QPopupMenu(this, "ERROR");
442 for (uint i
=0; i
<sizeof(menuitems
)/sizeof(MenuPair
); i
++) {
443 if (menuitems
[i
].isSeparator())
444 m_modemenu
->insertSeparator();
446 m_modemenu
->insertItem(i18n(menuitems
[i
].name
), menuitems
[i
].mode
);
448 connect(m_modemenu
,SIGNAL(activated(int)),SLOT(slotModeChange(int)));
450 new GroupingViewItem(this, "MIPS VU", "^vu.*",
451 RegisterDisplay::bits32
|RegisterDisplay::realE
);
452 new GroupingViewItem(this, "AltiVec", "^vr.*",
453 RegisterDisplay::bits32
|RegisterDisplay::realE
);
454 new GroupingViewItem(this, "POWER real", "^fpr.*",
455 RegisterDisplay::bits32
|RegisterDisplay::realE
);
456 new GroupingViewItem(this, "MMX", "^mm.*",
457 RegisterDisplay::bits32
|RegisterDisplay::realE
);
458 new GroupingViewItem(this, "SSE", "^xmm.*",
459 RegisterDisplay::bits32
|RegisterDisplay::realE
);
460 new GroupingViewItem(this, "x87", "^st.*",
461 RegisterDisplay::bits80
|RegisterDisplay::realE
);
462 new GroupingViewItem(this, i18n("x86/x87 segment"),
463 "(^cs$|^ss$|^ds$|^es$|^fs$|^gs$|^fiseg$|^foseg$)",
464 RegisterDisplay::nada
);
465 new GroupingViewItem(this, i18n("Flags"),
466 "(^eflags$|^fctrl$|^mxcsr$|^cr$|^fpscr$|^vscr$|^ftag$|^fstat$)",
467 RegisterDisplay::bits32
|RegisterDisplay::binary
);
468 new GroupingViewItem(this, i18n("GP and others"), "^$",
469 RegisterDisplay::nada
);
471 updateGroupVisibility();
472 setRootIsDecorated(true);
477 RegisterView::~RegisterView()
481 GroupingViewItem
* RegisterView::findMatchingGroup(const QString
& regName
)
483 for (QListViewItem
* it
= firstChild(); it
!= 0; it
= it
->nextSibling())
485 GroupingViewItem
* i
= static_cast<GroupingViewItem
*>(it
);
486 if (i
->matchName(regName
))
489 // not better match found, so return "GP and others"
490 return static_cast<GroupingViewItem
*>(firstChild());
493 GroupingViewItem
* RegisterView::findGroup(const QString
& groupName
)
495 for (QListViewItem
* it
= firstChild(); it
!= 0; it
= it
->nextSibling())
497 if (it
->text(0) == groupName
)
498 return static_cast<GroupingViewItem
*>(it
);
503 void RegisterView::updateGroupVisibility()
505 for (QListViewItem
* it
= firstChild(); it
!= 0; it
= it
->nextSibling())
507 it
->setVisible(it
->childCount() > 0);
511 void RegisterView::updateRegisters(QList
<RegisterInfo
>& regs
)
513 setUpdatesEnabled(false);
515 // mark all items as 'not found'
516 for (RegMap::iterator i
= m_registers
.begin(); i
!= m_registers
.end(); ++i
)
518 i
->second
->m_found
= false;
521 // parse register values
522 // must iterate last to first, since QListView inserts at the top
523 for (RegisterInfo
* reg
= regs
.last(); reg
!= 0; reg
= regs
.prev())
525 // check if this is a new register
526 RegMap::iterator i
= m_registers
.find(reg
->regName
);
528 if (i
!= m_registers
.end())
530 RegisterViewItem
* it
= i
->second
;
532 if (it
->m_reg
.rawValue
!= reg
->rawValue
||
533 it
->m_reg
.cookedValue
!= reg
->cookedValue
)
535 it
->m_changes
= true;
540 * If there was a change last time, but not now, we
541 * must revert the color.
544 it
->m_changes
= false;
551 GroupingViewItem
* group
= findMatchingGroup(reg
->regName
);
552 m_registers
[reg
->regName
] =
553 new RegisterViewItem(group
, *reg
);
557 // remove all 'not found' items;
559 for (RegMap::iterator i
= m_registers
.begin(); i
!= m_registers
.end(); ++i
)
561 if (!i
->second
->m_found
) {
562 del
.push_back(i
->first
);
565 for (QStringList::Iterator i
= del
.begin(); i
!= del
.end(); ++i
)
567 RegMap::iterator it
= m_registers
.find(*i
);
569 m_registers
.erase(it
);
572 updateGroupVisibility();
573 setUpdatesEnabled(true);
578 void RegisterView::rightButtonClicked(QListViewItem
* item
, const QPoint
& p
, int)
581 RegisterDisplay mode
=static_cast<ModeItem
*>(item
)->mode();
582 for (unsigned int i
= 0; i
<sizeof(menuitems
)/sizeof(MenuPair
); i
++) {
583 m_modemenu
->setItemChecked(menuitems
[i
].mode
,
584 mode
.contains(menuitems
[i
].mode
));
586 m_modemenu
->setCaption(item
->text(0));
587 m_modemenu
->popup(p
);
591 void RegisterView::slotModeChange(int pcode
)
593 RegMap::iterator it
=m_registers
.find(m_modemenu
->caption());
595 if (it
!= m_registers
.end())
598 view
= findGroup(m_modemenu
->caption());
601 RegisterDisplay mode
= view
->mode();
602 mode
.changeFlag(pcode
);
607 void RegisterView::paletteChange(const QPalette
& oldPal
)
609 setFont(KGlobalSettings::fixedFont());
610 QListView::paletteChange(oldPal
);
613 #include "regwnd.moc"