Merge with version 2.0.
[kdbg.git] / kdbg / regwnd.cpp
blob92d38a50c2dfd7437c02351cbbfdee1468966180
1 // -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // $Id$
4 // Copyright by Judin Max, Johannes Sixt, Daniel Kristjansson
5 // This file is under GPL, the GNU General Public Licence
7 #include <qheader.h>
8 #include <kglobalsettings.h>
9 #include <klocale.h> /* i18n */
10 #include <kiconloader.h>
11 #include <qfontdialog.h>
12 #include <qmessagebox.h>
13 #include <qpopupmenu.h>
14 #include <qregexp.h>
15 #include <qstringlist.h>
16 #include <stdlib.h> /* strtoul */
17 #include "regwnd.h"
18 #include "dbgdriver.h"
20 /**
21 * Register display modes
23 class RegisterDisplay {
24 public:
25 enum BitSize {
26 bits8 = 0x10,
27 bits16 = 0x20,
28 bits32 = 0x30,
29 bits64 = 0x40,
30 bits80 = 0x50,
31 bits128 = 0x60,
32 bitsUnknown = 0x70
35 enum Format {
36 nada = 0x01,
37 binary = 0x02,
38 octal = 0x03,
39 decimal = 0x04,
40 hex = 0x05,
41 bcd = 0x06,
42 realE = 0x07,
43 realG = 0x08,
44 realF = 0x09
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);
51 return val;
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);
60 private:
61 uint mode;
62 static uint bitMap[];
65 // helper struct
66 struct MenuPair
68 const char* name;
69 uint mode;
70 bool isSeparator() { return name == 0; }
73 static MenuPair menuitems[] = {
74 // treat as
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 },
83 { 0, 0 },
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[] = {
93 0, 8, 16, 32,
94 64, 80, 128, /*default*/32,
97 class ModeItem : public QListViewItem
99 public:
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
109 public:
110 GroupingViewItem(RegisterView* parent,
111 const QString& name, const QString& pattern,
112 RegisterDisplay mode) :
113 ModeItem(parent, name), matcher(pattern), gmode(mode)
115 setExpandable(true);
116 setOpen(true);
118 bool matchName(const QString& str) const
120 return matcher.exactMatch(str);
122 virtual void setMode(RegisterDisplay mode)
124 gmode=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; }
132 private:
133 QRegExp matcher;
134 RegisterDisplay gmode;
137 class RegisterViewItem : public ModeItem
139 public:
140 RegisterViewItem(GroupingViewItem* parent,
141 const RegisterInfo& regInfo);
142 ~RegisterViewItem();
144 void setValue(const RegisterInfo& regInfo);
145 virtual void setMode(RegisterDisplay mode);
146 virtual RegisterDisplay mode() { return m_mode; }
147 RegisterInfo m_reg;
148 RegisterDisplay m_mode; /* display mode */
149 bool m_changes;
150 bool m_found;
152 protected:
153 virtual void paintCell(QPainter*, const QColorGroup& cg,
154 int column, int width, int alignment);
159 RegisterViewItem::RegisterViewItem(GroupingViewItem* parent,
160 const RegisterInfo& regInfo) :
161 ModeItem(parent),
162 m_reg(regInfo),
163 m_changes(false),
164 m_found(true)
166 setValue(m_reg);
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)
181 if (h < '0')
182 return -1;
183 if (h <= '9')
184 return h - '0';
185 if (h < 'A')
186 return -1;
187 if (h <= 'F')
188 return h - ('A' - 10);
189 if (h < 'a')
190 return -1;
191 if (h <= 'f')
192 return h - ('a' - 10);
193 return -1;
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"
202 QString result;
204 for (unsigned i = 2; i < hex.length(); i++) {
205 int idx = hexCharToDigit(hex[i].latin1());
206 if (idx < 0) {
207 // not a hex digit; no conversion
208 return hex;
210 const char* bindigits = digits[idx];
211 result += bindigits;
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;
217 case 4: case 5:
218 case 6: case 7: result.remove(0, 1); break;
220 return result;
223 static QString toOctal(QString hex)
225 QString result;
226 int shift = 0;
227 unsigned v = 0;
228 for (int i = hex.length()-1; i >= 2; i--) {
229 int idx = hexCharToDigit(hex[i].latin1());
230 if (idx < 0)
231 return hex;
232 v += idx << shift;
233 result.insert(0, (v & 7) + '0');
234 v >>= 3;
235 shift++;
236 if (shift == 3) {
237 // an extra digit this round
238 result.insert(0, v + '0');
239 shift = v = 0;
242 if (v != 0) {
243 result.insert(0, v + '0');
245 return "0" + result;
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" */
255 return hex;
257 const char* start = hex.latin1();
258 char* end;
259 unsigned long val = strtoul(start, &end, 0);
260 if (start == end)
261 return hex;
262 else
263 return QString().setNum(val);
266 static QString toBCD(const QString& hex)
268 return hex.right(2);
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];
281 if (littleendian) {
282 uint j=0;
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);
287 i--;j++;
289 } else { // big endian
290 uint j=0;
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());
295 i++;j++;
298 return data;
301 static long double extractNumber(const QString& hex)
303 uint length;
304 char* data=toRaw(hex, length);
305 long double val;
306 if (length==4) { // float
307 val=*((float*)data);
308 } else if (length==8) { // double
309 val=*((double*)data);
310 } else if (length==10) { // long double
311 val=*((long double*)data);
312 } else {
313 val=*((float*)data);
315 delete[] data;
317 return val;
320 static QString toFloat(const QString& hex, char p)
322 uint bits;
323 uint prec=6;
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);
329 if (p=='e') {
330 prec+=7;
331 while (cooked.length()<prec) cooked=cooked.prepend(" ");
333 return cooked;
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');
347 default: return raw;
351 QString convertRaw(const RegisterInfo reg, RegisterDisplay mode)
353 QString cooked;
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;
361 else {
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;
378 else
380 cooked = reg.cookedValue;
382 if (cooked.at(0)!=' ' && cooked.at(0)!='-' && cooked.at(0)!='+')
383 cooked.prepend(" ");
384 return cooked;
387 void RegisterViewItem::setValue(const RegisterInfo& reg)
389 m_reg = reg;
391 setText(1, reg.rawValue);
392 QString cookedValue = convertRaw(reg, m_mode);
393 setText(2, cookedValue);
396 void RegisterViewItem::setMode(RegisterDisplay mode)
398 m_mode = 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)
407 if (m_changes) {
408 QColorGroup newcg = cg;
409 newcg.setColor(QColorGroup::Text, red);
410 QListViewItem::paintCell(p, newcg, column, width, alignment);
411 } else {
412 QListViewItem::paintCell(p, cg, column, width, alignment);
417 RegisterView::RegisterView(QWidget* parent, const char* name) :
418 QListView(parent, name)
420 setSorting(-1);
421 setFont(KGlobalSettings::fixedFont());
423 QPixmap iconRegs = UserIcon("regs.xpm");
424 QPixmap iconWatchcoded = UserIcon("watchcoded.xpm");
425 QPixmap iconWatch = UserIcon("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();
445 else
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);
474 resize(200,300);
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))
487 return i;
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);
500 return 0;
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;
531 it->m_found = true;
532 if (it->m_reg.rawValue != reg->rawValue ||
533 it->m_reg.cookedValue != reg->cookedValue)
535 it->m_changes = true;
536 it->setValue(*reg);
537 repaintItem(it);
538 } else {
540 * If there was a change last time, but not now, we
541 * must revert the color.
543 if (it->m_changes) {
544 it->m_changes = false;
545 repaintItem(it);
549 else
551 GroupingViewItem* group = findMatchingGroup(reg->regName);
552 m_registers[reg->regName] =
553 new RegisterViewItem(group, *reg);
557 // remove all 'not found' items;
558 QStringList del;
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);
568 delete it->second;
569 m_registers.erase(it);
572 updateGroupVisibility();
573 setUpdatesEnabled(true);
574 triggerUpdate();
578 void RegisterView::rightButtonClicked(QListViewItem* item, const QPoint& p, int)
580 if (item) {
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());
594 ModeItem* view;
595 if (it != m_registers.end())
596 view = it->second;
597 else
598 view = findGroup(m_modemenu->caption());
600 if (view) {
601 RegisterDisplay mode = view->mode();
602 mode.changeFlag(pcode);
603 view->setMode(mode);
607 void RegisterView::paletteChange(const QPalette& oldPal)
609 setFont(KGlobalSettings::fixedFont());
610 QListView::paletteChange(oldPal);
613 #include "regwnd.moc"