Allow to view memory dump in hex/ascii view.
[kdbg.git] / kdbg / memwindow.cpp
blobefb1d7de875843a59790fad9a30e092629871537
1 /*
2 * Copyright Johannes Sixt
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 "memwindow.h"
8 #include <QFontDatabase>
9 #include <QHeaderView>
10 #include <QMouseEvent>
11 #include <QList>
12 #include <klocale.h>
13 #include <kconfigbase.h>
14 #include <kconfiggroup.h>
15 #include "debugger.h"
17 const int COL_DUMP_ASCII = 9;
19 MemoryWindow::MemoryWindow(QWidget* parent) :
20 QWidget(parent),
21 m_debugger(0),
22 m_expression(this),
23 m_memory(this),
24 m_layout(QBoxLayout::TopToBottom, this),
25 m_format(MDTword | MDThex)
27 setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
29 m_expression.setEditable(true);
30 QSize minSize = m_expression.sizeHint();
31 m_expression.setMinimumSize(minSize);
32 m_expression.setInsertPolicy(QComboBox::NoInsert);
33 m_expression.setMaxCount(15);
35 m_memory.setColumnCount(10);
36 m_memory.setHeaderLabel(i18n("Address"));
37 for (int i = 1; i < 10; i++) {
38 m_memory.hideColumn(i);
39 m_memory.headerItem()->setText(i, QString());
41 m_memory.header()->setStretchLastSection(false);
43 m_memory.setSortingEnabled(false); /* don't sort */
44 m_memory.setAllColumnsShowFocus(true);
45 m_memory.setRootIsDecorated(false);
46 m_memory.header()->setSectionResizeMode(QHeaderView::ResizeToContents);
47 m_memory.header()->setSectionsClickable(false);
48 m_memory.header()->setSectionsMovable(false); // don't move columns
49 m_memory.setContextMenuPolicy(Qt::NoContextMenu); // defer to parent
51 // create layout
52 m_layout.setSpacing(2);
53 m_layout.addWidget(&m_expression, 0);
54 m_layout.addWidget(&m_memory, 10);
55 m_layout.activate();
57 connect(&m_expression, SIGNAL(activated(const QString&)),
58 this, SLOT(slotNewExpression(const QString&)));
59 connect(m_expression.lineEdit(), SIGNAL(returnPressed()),
60 this, SLOT(slotNewExpression()));
62 // the popup menu
63 QAction* pAction;
64 pAction = m_popup.addAction(i18n("B&ytes"));
65 pAction->setData(MDTbyte);
66 pAction = m_popup.addAction(i18n("Halfwords (&2 Bytes)"));
67 pAction->setData(MDThalfword);
68 pAction = m_popup.addAction(i18n("Words (&4 Bytes)"));
69 pAction->setData(MDTword);
70 pAction = m_popup.addAction(i18n("Giantwords (&8 Bytes)"));
71 pAction->setData(MDTgiantword);
72 m_popup.addSeparator();
73 pAction = m_popup.addAction(i18n("He&xadecimal"));
74 pAction->setData(MDThex);
75 pAction = m_popup.addAction(i18n("Signed &decimal"));
76 pAction->setData(MDTsigned);
77 pAction = m_popup.addAction(i18n("&Unsigned decimal"));
78 pAction->setData(MDTunsigned);
79 pAction = m_popup.addAction(i18n("&Octal"));
80 pAction->setData(MDToctal);
81 pAction = m_popup.addAction(i18n("&Binary"));
82 pAction->setData(MDTbinary);
83 pAction = m_popup.addAction(i18n("&Addresses"));
84 pAction->setData(MDTaddress);
85 pAction = m_popup.addAction(i18n("&Character"));
86 pAction->setData(MDTchar);
87 pAction = m_popup.addAction(i18n("&Floatingpoint"));
88 pAction->setData(MDTfloat);
89 pAction = m_popup.addAction(i18n("&Strings"));
90 pAction->setData(MDTstring);
91 pAction = m_popup.addAction(i18n("&Instructions"));
92 pAction->setData(MDTinsn);
93 connect(&m_popup, SIGNAL(triggered(QAction*)), this, SLOT(slotTypeChange(QAction*)));
96 MemoryWindow::~MemoryWindow()
100 void MemoryWindow::contextMenuEvent(QContextMenuEvent* ev)
102 m_popup.popup(ev->globalPos());
103 ev->accept();
106 void MemoryWindow::slotNewExpression()
108 slotNewExpression(m_expression.lineEdit()->text());
111 void MemoryWindow::slotNewExpression(const QString& newText)
113 QString text = newText.simplified();
115 // see if the string is in the list
116 // (note: must count downwards because of removeItem!)
117 for (int i = m_expression.count()-1; i >= 0; i--)
119 if (m_expression.itemText(i) == text) {
120 // yes it is!
121 // look up the format that was used last time for this expr
122 QMap<QString,unsigned>::iterator pFormat = m_formatCache.find(text);
123 if (pFormat != m_formatCache.end()) {
124 m_format = *pFormat;
125 m_debugger->setMemoryFormat(m_format);
127 // remove this text, will be inserted at the top
128 m_expression.removeItem(i);
131 m_expression.insertItem(0, text);
133 if (!text.isEmpty()) {
134 m_formatCache[text] = m_format;
137 displayNewExpression(text);
140 void MemoryWindow::displayNewExpression(const QString& expr)
142 m_debugger->setMemoryExpression(expr);
143 m_expression.setEditText(expr);
145 // clear memory dump if no dump wanted
146 if (expr.isEmpty()) {
147 m_memory.clear();
148 m_old_memory.clear();
152 void MemoryWindow::slotTypeChange(QAction* action)
154 int id = action->data().toInt();
156 m_old_memory.clear();
158 // compute new type
159 if (id & MDTsizemask)
160 m_format = (m_format & ~MDTsizemask) | id;
161 if (id & MDTformatmask)
162 m_format = (m_format & ~MDTformatmask) | id;
163 m_debugger->setMemoryFormat(m_format);
165 // change the format in the cache
166 QString expr = m_expression.currentText();
167 m_formatCache[expr.simplified()] = m_format;
169 // force redisplay
170 displayNewExpression(expr);
173 QString MemoryWindow::parseMemoryDumpLineToAscii(const QString& line)
175 QStringList hexdata = line.split("\t");
177 // Get the size of value from hex str representation length
178 // 0x00 = (4 - 2) / 2 -> 1 byte
179 // 0x0000 = (6 - 2) / 2 -> 2 half-word
180 // 0x00000000 = (10 - 2) / 2 -> 4 word
181 // 0x0000000000000000 = (18 - 2) / 2 -> 8 giant word
183 int len = (hexdata[0].length()-2) / 2;
184 QString dumpAscii;
185 for (const auto& hex: hexdata)
187 bool ok;
188 unsigned long long parsedValue = hex.toULongLong(&ok, 16);
189 if (ok) {
190 for (int s = 0; s < len; s++)
192 unsigned char b = parsedValue & 0xFF;
193 parsedValue >>= 8;
194 if (isprint(b)) {
195 dumpAscii += b;
196 } else {
197 dumpAscii += '.';
202 return dumpAscii;
205 void MemoryWindow::slotNewMemoryDump(const QString& msg, const std::list<MemoryDump>& memdump)
207 m_memory.clear();
208 if (!msg.isEmpty()) {
209 new QTreeWidgetItem(&m_memory, QStringList() << QString() << msg);
210 return;
212 bool showDumpAscii = (m_format & MDTformatmask) == MDThex;
214 std::list<MemoryDump>::const_iterator md = memdump.begin();
216 // show only needed columns
217 QStringList sl = md->dump.split( "\t" );
218 for (int i = COL_DUMP_ASCII-1; i > 0; i--)
219 m_memory.setColumnHidden(i, i > sl.count());
221 m_memory.setColumnHidden(COL_DUMP_ASCII, !showDumpAscii);
223 QMap<QString,QString> tmpMap;
225 for (; md != memdump.end(); ++md)
227 QString addr = md->address.asString() + " " + md->address.fnoffs;
228 QStringList sl = md->dump.split( "\t" );
230 // save memory
231 tmpMap[addr] = md->dump;
233 QTreeWidgetItem* line =
234 new QTreeWidgetItem(&m_memory, QStringList(addr) << sl);
236 if (showDumpAscii) {
237 QString dumpAscii = parseMemoryDumpLineToAscii(md->dump);
238 line->setText(COL_DUMP_ASCII, dumpAscii);
241 QStringList tmplist;
242 QMap<QString,QString>::Iterator pos = m_old_memory.find( addr );
244 if( pos != m_old_memory.end() )
245 tmplist = pos.value().split( "\t" );
247 for (int i = 0; i < sl.count(); i++)
249 bool changed =
250 i < tmplist.count() &&
251 sl[i] != tmplist[i];
252 line->setForeground(i+1, changed ? QBrush(QColor(Qt::red)) : palette().text());
256 m_old_memory.clear();
257 m_old_memory = tmpMap;
260 static const char MemoryGroup[] = "Memory";
261 static const char NumExprs[] = "NumExprs";
262 static const char ExpressionFmt[] = "Expression%d";
263 static const char FormatFmt[] = "Format%d";
264 static const char ColumnWidths[] = "ColumnWidths";
266 void MemoryWindow::saveProgramSpecific(KConfigBase* config)
268 KConfigGroup g = config->group(MemoryGroup);
270 int numEntries = m_expression.count();
271 g.writeEntry(NumExprs, numEntries);
272 QString exprEntry;
273 QString fmtEntry;
274 for (int i = 0; i < numEntries;) {
275 QString text = m_expression.itemText(i);
276 i++; /* entries are counted 1-based */
277 exprEntry.sprintf(ExpressionFmt, i);
278 fmtEntry.sprintf(FormatFmt, i);
279 g.writeEntry(exprEntry, text);
280 QMap<QString,unsigned>::iterator pFormat = m_formatCache.find(text);
281 unsigned fmt = pFormat != m_formatCache.end() ? *pFormat : MDTword | MDThex;
282 g.writeEntry(fmtEntry, fmt);
285 // column widths
286 QList<int> widths;
287 for (int i = 0; i < 2; i++) {
288 int w = m_memory.columnWidth(i);
289 widths.append(w);
291 g.writeEntry(ColumnWidths, widths);
294 void MemoryWindow::restoreProgramSpecific(KConfigBase* config)
296 KConfigGroup g = config->group(MemoryGroup);
298 int numEntries = g.readEntry(NumExprs, 0);
299 m_expression.clear();
301 QString exprEntry;
302 QString fmtEntry;
303 // entries are counted 1-based
304 for (int i = 1; i <= numEntries; i++) {
305 exprEntry.sprintf(ExpressionFmt, i);
306 fmtEntry.sprintf(FormatFmt, i);
307 QString expr = g.readEntry(exprEntry, QString());
308 unsigned fmt = g.readEntry(fmtEntry, MDTword | MDThex);
309 m_expression.addItem(expr);
310 m_formatCache[expr] = fmt & (MDTsizemask | MDTformatmask);
313 // initialize with top expression
314 if (numEntries > 0) {
315 m_expression.setCurrentIndex(0);
316 QString expr = m_expression.itemText(0);
317 m_format = m_formatCache[expr];
318 m_debugger->setMemoryFormat(m_format);
319 displayNewExpression(expr);
322 // column widths
323 QList<int> widths = g.readEntry(ColumnWidths, QList<int>());
324 QList<int>::iterator w = widths.begin();
325 for (int i = 0; i < 2 && w != widths.end(); ++i, ++w) {
326 m_memory.setColumnWidth(i, *w);
331 #include "memwindow.moc"