Clean up #includes.
[kdbg.git] / kdbg / regwnd.cpp
blobf8ec95be114d2cba6753f3d39585e8ab99088b4a
1 /*
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.
5 */
7 #include "regwnd.h"
8 #include "dbgdriver.h"
9 #include <Q3Header>
10 #include <QPixmap>
11 #include <kglobalsettings.h>
12 #include <klocale.h> /* i18n */
13 #include <kiconloader.h>
14 #include <Q3PopupMenu>
15 #include <QRegExp>
16 #include <QStringList>
17 #include <stdlib.h> /* strtoul */
19 /**
20 * Register display modes
22 class RegisterDisplay {
23 public:
24 enum BitSize {
25 bits8 = 0x10,
26 bits16 = 0x20,
27 bits32 = 0x30,
28 bits64 = 0x40,
29 bits80 = 0x50,
30 bits128 = 0x60,
31 bitsUnknown = 0x70
34 enum Format {
35 nada = 0x01,
36 binary = 0x02,
37 octal = 0x03,
38 decimal = 0x04,
39 hex = 0x05,
40 bcd = 0x06,
41 realE = 0x07,
42 realG = 0x08,
43 realF = 0x09
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);
50 return val;
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);
59 private:
60 uint mode;
61 static uint bitMap[];
64 // helper struct
65 struct MenuPair
67 const char* name;
68 uint mode;
69 bool isSeparator() { return name == 0; }
72 static MenuPair menuitems[] = {
73 // treat as
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 },
82 { 0, 0 },
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[] = {
92 0, 8, 16, 32,
93 64, 80, 128, /*default*/32,
96 class ModeItem : public Q3ListViewItem
98 public:
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
108 public:
109 GroupingViewItem(RegisterView* parent,
110 const QString& name, const QString& pattern,
111 RegisterDisplay mode) :
112 ModeItem(parent, name), matcher(pattern), gmode(mode)
114 setExpandable(true);
115 setOpen(true);
117 bool matchName(const QString& str) const
119 return matcher.exactMatch(str);
121 virtual void setMode(RegisterDisplay mode)
123 gmode=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; }
131 private:
132 QRegExp matcher;
133 RegisterDisplay gmode;
136 class RegisterViewItem : public ModeItem
138 public:
139 RegisterViewItem(GroupingViewItem* parent,
140 const RegisterInfo& regInfo);
141 ~RegisterViewItem();
143 void setValue(const RegisterInfo& regInfo);
144 virtual void setMode(RegisterDisplay mode);
145 virtual RegisterDisplay mode() { return m_mode; }
146 RegisterInfo m_reg;
147 RegisterDisplay m_mode; /* display mode */
148 bool m_changes;
149 bool m_found;
151 protected:
152 virtual void paintCell(QPainter*, const QColorGroup& cg,
153 int column, int width, int alignment);
158 RegisterViewItem::RegisterViewItem(GroupingViewItem* parent,
159 const RegisterInfo& regInfo) :
160 ModeItem(parent),
161 m_reg(regInfo),
162 m_changes(false),
163 m_found(true)
165 setValue(m_reg);
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)
180 if (h < '0')
181 return -1;
182 if (h <= '9')
183 return h - '0';
184 if (h < 'A')
185 return -1;
186 if (h <= 'F')
187 return h - ('A' - 10);
188 if (h < 'a')
189 return -1;
190 if (h <= 'f')
191 return h - ('a' - 10);
192 return -1;
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"
201 QString result;
203 for (int i = 2; i < hex.length(); i++) {
204 int idx = hexCharToDigit(hex[i].latin1());
205 if (idx < 0) {
206 // not a hex digit; no conversion
207 return hex;
209 const char* bindigits = digits[idx];
210 result += bindigits;
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;
216 case 4: case 5:
217 case 6: case 7: result.remove(0, 1); break;
219 return result;
222 static QString toOctal(QString hex)
224 QString result;
225 int shift = 0;
226 unsigned v = 0;
227 for (int i = hex.length()-1; i >= 2; i--) {
228 int idx = hexCharToDigit(hex[i].latin1());
229 if (idx < 0)
230 return hex;
231 v += idx << shift;
232 result.insert(0, (v & 7) + '0');
233 v >>= 3;
234 shift++;
235 if (shift == 3) {
236 // an extra digit this round
237 result.insert(0, v + '0');
238 shift = v = 0;
241 if (v != 0) {
242 result.insert(0, v + '0');
244 return "0" + result;
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" */
254 return hex;
256 const char* start = hex.latin1();
257 char* end;
258 unsigned long val = strtoul(start, &end, 0);
259 if (start == end)
260 return hex;
261 else
262 return QString().setNum(val);
265 static QString toBCD(const QString& hex)
267 return hex.right(2);
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];
280 if (littleendian) {
281 uint j=0;
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);
286 i--;j++;
288 } else { // big endian
289 uint j=0;
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());
294 i++;j++;
297 return data;
300 static long double extractNumber(const QString& hex)
302 uint length;
303 char* data=toRaw(hex, length);
304 long double val;
305 if (length==4) { // float
306 val=*((float*)data);
307 } else if (length==8) { // double
308 val=*((double*)data);
309 } else if (length==10) { // long double
310 val=*((long double*)data);
311 } else {
312 val=*((float*)data);
314 delete[] data;
316 return val;
319 static QString toFloat(const QString& hex, char p)
321 uint bits;
322 int prec=6;
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);
328 if (p=='e') {
329 prec+=7;
330 while (cooked.length()<prec) cooked=cooked.prepend(" ");
332 return cooked;
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');
346 default: return raw;
350 QString convertRaw(const RegisterInfo reg, RegisterDisplay mode)
352 QString cooked;
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;
360 else {
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;
377 else
379 cooked = reg.cookedValue;
381 if (cooked.at(0)!=' ' && cooked.at(0)!='-' && cooked.at(0)!='+')
382 cooked.prepend(" ");
383 return cooked;
386 void RegisterViewItem::setValue(const RegisterInfo& reg)
388 m_reg = reg;
390 setText(1, reg.rawValue);
391 QString cookedValue = convertRaw(reg, m_mode);
392 setText(2, cookedValue);
395 void RegisterViewItem::setMode(RegisterDisplay mode)
397 m_mode = 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)
406 if (m_changes) {
407 QColorGroup newcg = cg;
408 newcg.setColor(QColorGroup::Text, Qt::red);
409 Q3ListViewItem::paintCell(p, newcg, column, width, alignment);
410 } else {
411 Q3ListViewItem::paintCell(p, cg, column, width, alignment);
416 RegisterView::RegisterView(QWidget* parent) :
417 Q3ListView(parent)
419 setSorting(-1);
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();
444 else
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);
473 resize(200,300);
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))
486 return i;
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);
499 return 0;
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;
530 it->m_found = true;
531 if (it->m_reg.rawValue != reg->rawValue ||
532 it->m_reg.cookedValue != reg->cookedValue)
534 it->m_changes = true;
535 it->setValue(*reg);
536 repaintItem(it);
537 } else {
539 * If there was a change last time, but not now, we
540 * must revert the color.
542 if (it->m_changes) {
543 it->m_changes = false;
544 repaintItem(it);
548 else
550 GroupingViewItem* group = findMatchingGroup(reg->regName);
551 m_registers[reg->regName] =
552 new RegisterViewItem(group, *reg);
556 // remove all 'not found' items;
557 QStringList del;
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);
567 delete it->second;
568 m_registers.erase(it);
571 updateGroupVisibility();
572 setUpdatesEnabled(true);
573 triggerUpdate();
577 void RegisterView::rightButtonClicked(Q3ListViewItem* item, const QPoint& p, int)
579 if (item) {
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());
593 ModeItem* view;
594 if (it != m_registers.end())
595 view = it->second;
596 else
597 view = findGroup(m_modemenu->caption());
599 if (view) {
600 RegisterDisplay mode = view->mode();
601 mode.changeFlag(pcode);
602 view->setMode(mode);
606 void RegisterView::paletteChange(const QPalette& oldPal)
608 setFont(KGlobalSettings::fixedFont());
609 Q3ListView::paletteChange(oldPal);
612 #include "regwnd.moc"