35 #include <QHeaderView>
45 #define DEFAULT_SHOWHEXCODE true
56 while(buf[pos]==
' ' || buf[pos]==
'\t') pos++;
58 int digits = addr.
set(buf + pos);
59 if ((digits==0) || (buf[pos+digits] !=
':'))
return Addr(0);
66 return (c >=
'0' && c <=
'9') || (c >=
'a' && c <=
'f');
75 QString& code, QString& mnemonic, QString& operands)
82 while(buf[pos]==
' ' || buf[pos]==
'\t') pos++;
84 int digits = addr.
set(buf + pos);
86 if ((digits==0) || (buf[pos] !=
':'))
return false;
90 while(buf[pos]==
' ' || buf[pos]==
'\t') pos++;
98 if (buf[pos+2] ==
' ') {
104 if (buf[pos+4] ==
' ') {
112 if (buf[pos+8] !=
' ')
break;
115 if (pos <= start)
return false;
116 code = QString::fromLatin1(buf + start, pos - start - 1);
119 while(buf[pos]==
' ' || buf[pos]==
'\t') pos++;
123 while(buf[pos] && buf[pos]!=
' ' && buf[pos]!=
'\t') pos++;
124 mnemonic = QString::fromLatin1(buf + start, pos - start);
127 while(buf[pos]==
' '|| buf[pos]==
'\t') pos++;
130 int operandsLen = strlen(buf + pos);
133 if ((operandsLen>0) && (buf[pos + operandsLen - 1] ==
'\n'))
137 if (operandsLen > 50)
138 operands = QString::fromLatin1(buf + pos, 47) + QString(
"...");
140 operands = QString::fromLatin1(buf+pos, operandsLen);
142 if (0) qDebug(
"For 0x%s: Code '%s', Mnemonic '%s', Operands '%s'",
143 qPrintable(addr.
toString()), qPrintable(code),
144 qPrintable(mnemonic), qPrintable(operands));
162 _lastHexCodeWidth = 50;
164 _inSelectionUpdate =
false;
167 QStringList headerLabels;
168 headerLabels << tr(
"#" )
174 << tr(
"Assembly Instructions" )
175 << tr(
"Source Position" );
176 setHeaderLabels(headerLabels);
177 setRootIsDecorated(
false);
178 setAllColumnsShowFocus(
true);
179 setUniformRowHeights(
true);
181 setExpandsOnDoubleClick(
false);
184 sortByColumn(0, Qt::AscendingOrder);
185 header()->setSortIndicatorShown(
false);
193 setContextMenuPolicy(Qt::CustomContextMenu);
195 SIGNAL(customContextMenuRequested(
const QPoint &) ),
196 SLOT(
context(
const QPoint &)));
202 connect(header(), SIGNAL(sectionClicked(
int)),
211 return tr(
"<b>Annotated Machine Code</b>"
212 "<p>The annotated machine code list shows the "
213 "assembly instructions of the current selected "
214 "function together with (self) cost spent while "
215 "executing an instruction. If this is a call "
216 "instruction, lines with details on the "
217 "call happening are inserted into the source: "
218 "the cost spent inside of the call, the "
219 "number of calls happening, and the call destination.</p>"
220 "<p>The machine code shown is generated with "
221 "the 'objdump' utility from the 'binutils' package.</p>"
222 "<p>Select a line with call information to "
223 "make the destination function of this call current.</p>");
229 int c = columnAt(p.x());
237 QAction* activateFunctionAction = 0;
238 QAction* activateInstrAction = 0;
241 activateFunctionAction = popup.addAction(menuText);
242 popup.addSeparator();
245 QString menuText = tr(
"Go to Address %1").arg(instr->
name());
246 activateInstrAction = popup.addAction(menuText);
247 popup.addSeparator();
250 if ((c == 1) || (c == 2)) {
252 popup.addSeparator();
255 popup.addSeparator();
257 QAction* toggleHexAction =
new QAction(tr(
"Hex Code"), &popup);
258 toggleHexAction->setCheckable(
true);
259 toggleHexAction->setChecked(_showHexCode);
260 popup.addAction(toggleHexAction);
262 QAction* a = popup.exec(mapToGlobal(p + QPoint(0,header()->height())));
263 if (a == activateFunctionAction)
265 else if (a == activateInstrAction)
267 else if (a == toggleHexAction) {
268 _showHexCode = !_showHexCode;
271 _lastHexCodeWidth = columnWidth(4);
281 if (_inSelectionUpdate)
return;
330 if (item && ((event->key() == Qt::Key_Return) ||
331 (event->key() == Qt::Key_Space)))
335 QTreeView::keyPressEvent(event);
354 f = ((
TraceLine*)i)->functionSource()->function();
366 void InstrView::doUpdate(
int changeType,
bool)
386 for (
int i=0; i<topLevelItemCount(); i++) {
387 item = topLevelItem(i);
392 _inSelectionUpdate =
true;
393 setCurrentItem(item);
394 _inSelectionUpdate =
false;
398 for (
int j=0; i<item->childCount(); j++) {
399 item2 = item->child(j);
404 _inSelectionUpdate =
true;
405 setCurrentItem(item2);
406 _inSelectionUpdate =
false;
418 for (
int i=0; i<topLevelItemCount(); i++) {
419 item = topLevelItem(i);
420 for (
int j=0; i<item->childCount(); i++) {
421 item2 = item->child(j);
435 void InstrView::setColumnWidths()
437 #if QT_VERSION >= 0x050000
438 header()->setSectionResizeMode(4, QHeaderView::Interactive);
440 header()->setResizeMode(4, QHeaderView::Interactive);
443 setColumnWidth(4, _lastHexCodeWidth);
446 setColumnWidth(4, 0);
469 Addr addr1Low, addr1High, addr2Low, addr2High;
474 if (addr1Low != addr2Low)
return (addr1Low < addr2Low);
476 if (addr1Low == ij1->
instrTo()->
addr())
return true;
477 if (addr2Low == ij2->
instrTo()->
addr())
return false;
478 return (addr1High < addr2High);
485 Addr addr1Low, addr1High, addr2Low, addr2High;
490 if (addr1High != addr2High)
return (addr1High < addr2High);
492 if (addr1High == ij1->
instrTo()->
addr())
return true;
493 if (addr2High == ij2->
instrTo()->
addr())
return false;
494 return (addr1Low < addr2Low);
497 void InstrView::refresh()
499 int originalPosition = verticalScrollBar()->value();
502 setColumnWidth(0, 20);
503 setColumnWidth(1, 50);
505 setColumnWidth(3, 0);
506 setColumnWidth(4, 0);
507 setColumnWidth(5, 50);
508 setColumnWidth(6, 250);
511 #if QT_VERSION >= 0x050000
512 header()->setSectionResizeMode(4, QHeaderView::ResizeToContents);
514 header()->setResizeMode(4, QHeaderView::ResizeToContents);
541 TraceInstrMap::Iterator itStart, it, tmpIt, itEnd;
544 it = instrMap->begin();
545 itEnd = instrMap->end();
553 if (!instrMap || (it == itEnd)) {
555 tr(
"There is no instruction info in the profile data file."));
557 tr(
"Tip: For Callgrind, rerun with option"));
558 new InstrItem(
this,
this, 3, tr(
" --dump-instr=yes"));
559 new InstrItem(
this,
this, 4, tr(
"To see (conditional) jumps, additionally specify"));
560 new InstrItem(
this,
this, 5, tr(
" --collect-jumps=yes"));
574 _highList.append(ij);
582 if (it == itEnd)
break;
586 _lowListIter = _lowList.begin();
587 _highListIter = _highList.begin();
604 if (it == itEnd)
break;
605 if (!(*it).addr().isInRange( (*tmpIt).addr(),10000) )
break;
609 if (!fillInstrRange(f, itStart, ++tmpIt))
break;
610 if (it == itEnd)
break;
613 _lastHexCodeWidth = columnWidth(4);
617 #if QT_VERSION >= 0x050000
618 header()->setSectionResizeMode(2, QHeaderView::Interactive);
620 header()->setResizeMode(2, QHeaderView::Interactive);
622 setColumnWidth(2, 0);
627 verticalScrollBar()->setValue(originalPosition);
637 bool ignoreFrom,
bool ignoreTo)
639 Addr lowAddr, highAddr;
640 int iEnd = -1, iStart = -1;
642 if (0) qDebug(
"updateJumpArray(addr 0x%s, jump to %s)",
648 while(_lowListIter != _lowList.end()) {
654 if (lowAddr > addr)
break;
657 if (ignoreFrom && (lowAddr < ij->instrTo()->addr()))
break;
659 if (ignoreTo && (lowAddr < ij->instrFrom()->addr()))
break;
664 for(iStart=0;iStart<_arrowLevels;iStart++)
666 (_jump[iStart]->instrTo() == ij->
instrTo()))
break;
668 iStart = _arrowLevels;
671 if (iStart==_arrowLevels) {
672 for(iStart=0;iStart<_arrowLevels;iStart++)
673 if (_jump[iStart] == 0)
break;
674 if (iStart==_arrowLevels) {
676 _jump.resize(_arrowLevels);
678 if (0) qDebug(
" new start at %d for %s",
679 iStart, qPrintable(ij->
name()));
688 while(_highListIter != _highList.end()) {
695 else if (ignoreFrom)
break;
697 if (highAddr > addr)
break;
699 for(iEnd=0;iEnd<_arrowLevels;iEnd++)
700 if (_jump[iEnd] == ij)
break;
701 if (iEnd==_arrowLevels) {
702 qDebug() <<
"InstrView: no jump start for end at 0x"
708 qDebug(
" end %d (%s to %s)",
710 qPrintable(_jump[iEnd]->instrFrom()->name()),
711 qPrintable(_jump[iEnd]->instrTo()->name()));
713 if (0 && ij) qDebug(
"next end: %s to %s",
722 if (iEnd>=0) _jump[iEnd] = 0;
726 if (iEnd>=0) _jump[iEnd] = 0;
730 bool InstrView::searchFile(QString& dir,
TraceObject* o)
734 if (QDir::isAbsolutePath(dir)) {
735 return QFile::exists(dir +
'/' + filename);
738 QFileInfo fi(dir, filename);
740 dir = fi.absolutePath();
746 QFileInfo partFile(firstPart->
name());
747 if (QFileInfo(partFile.absolutePath(), filename).exists()) {
748 dir = partFile.absolutePath();
760 TraceInstrMap::Iterator it,
761 TraceInstrMap::Iterator itEnd)
763 Addr costAddr, nextCostAddr, objAddr, addr;
764 Addr dumpStartAddr, dumpEndAddr;
765 TraceInstrMap::Iterator costIt;
768 if (it == itEnd)
return false;
771 TraceInstrMap::Iterator tmpIt = itEnd;
773 nextCostAddr = (*it).addr();
774 dumpStartAddr = (nextCostAddr<20) ?
Addr(0) : nextCostAddr -20;
775 dumpEndAddr = (*tmpIt).addr() +20;
777 QString dir =
function->object()->directory();
778 if (!searchFile(dir, function->object())) {
780 tr(
"For annotated machine code, "
781 "the following object file is needed:"));
783 QString(
" '%1'").arg(function->object()->name()));
785 tr(
"This file can not be found."));
788 function->object()->setDirectory(dir);
791 QString objfile = dir +
'/' +
function->object()->shortName();
792 QStringList objdumpArgs = QStringList()
794 << QString(
"--start-address=0x%1").arg(dumpStartAddr.
toString())
795 << QString(
"--stop-address=0x%1").arg(dumpEndAddr.
toString())
797 QString objdumpCmd =
"objdump " + objdumpArgs.join(
" ");
799 if (1) qDebug(
"Running '%s'...", qPrintable(objdumpCmd));
803 objdump.start(
"objdump", objdumpArgs);
804 if (!objdump.waitForStarted() ||
805 !objdump.waitForFinished()) {
808 tr(
"There is an error trying to execute the command"));
810 QString(
" '%1'").arg(objdumpCmd));
812 tr(
"Check that you have installed 'objdump'."));
814 tr(
"This utility can be found in the 'binutils' package."));
822 bool inside =
false, skipLineWritten =
true;
824 int objdumpLineno = 0, dumpedLines = 0, noAssLines = 0;
828 QString code, cmd, args;
829 bool needObjAddr =
true, needCostAddr =
true;
842 readBytes=objdump.readLine(buf,
BUF_SIZE);
850 qDebug(
"ERROR: Line %d of '%s' too long\n",
851 objdumpLineno, qPrintable(objdumpCmd));
853 else if ((readBytes>0) && (buf[readBytes-1] ==
'\n'))
854 buf[readBytes-1] = 0;
857 if ((objAddr<dumpStartAddr) || (objAddr>dumpEndAddr))
859 if (objAddr != 0)
break;
862 if (0) qDebug() <<
"Got ObjAddr: 0x" << objAddr.
toString();
867 (nextCostAddr > 0) &&
868 ((objAddr ==
Addr(0)) || (objAddr >= nextCostAddr)) ) {
869 needCostAddr =
false;
878 costAddr = nextCostAddr;
879 nextCostAddr = (it == itEnd) ?
Addr(0) : (*it).addr();
881 if (0) qDebug() <<
"Got nextCostAddr: 0x" << nextCostAddr.
toString()
882 <<
", costAddr 0x" << costAddr.
toString();
886 if (objAddr == 0)
break;
888 if ((nextCostAddr==0) || (costAddr == 0) ||
889 (objAddr < nextCostAddr)) {
893 bool isAssemblyInstr =
parseLine(buf, addr, code, cmd, args);
894 Q_UNUSED(isAssemblyInstr);
895 assert(isAssemblyInstr && (objAddr == addr));
897 if (costAddr == objAddr) {
898 currInstr = &(*costIt);
906 if (0) qDebug() <<
"Dump Obj Addr: 0x" << addr.
toString()
907 <<
" [" << cmd <<
" " << args <<
"], cost (0x"
908 << costAddr.
toString() <<
", next 0x"
913 code = cmd = QString();
914 args = tr(
"(No Instruction)");
916 currInstr = &(*costIt);
920 if (0) qDebug() <<
"Dump Cost Addr: 0x" << addr.
toString()
921 <<
" (no ass), objAddr 0x" << objAddr.
toString();
926 if (currInstr) inside =
true;
929 if (0) qDebug() <<
"Check if 0x" << addr.
toString() <<
" is in ]0x"
935 if ( (addr > costAddr) &&
936 ((nextCostAddr==0) ||
943 if ( ((costAddr==0) || (addr > costAddr + 3*context)) &&
944 ((nextCostAddr==0) || (addr < nextCostAddr - 3*context)) ) {
948 (itEnd == function->instrMap()->end())) skipLineWritten=
true;
950 if (!skipLineWritten) {
951 skipLineWritten =
true;
953 code = cmd = QString();
954 args = QString(
"...");
960 skipLineWritten =
false;
963 ii =
new InstrItem(
this, 0, addr, inside,
964 code, cmd, args, currInstr);
968 if (0) qDebug() <<
"Dumped 0x" << addr.
toString() <<
" "
969 << (inside ?
"Inside " :
"Outside")
970 << (currInstr ?
"Cost" :
"");
973 if (!currInstr)
continue;
979 if (!first) first = ii;
986 ii->setExpanded(
true);
996 ii2 =
new InstrItem(
this, ii, addr, currInstr, ic);
1005 new InstrItem(
this, ii, addr, currInstr, ij);
1010 #if QT_VERSION >= 0x050000
1011 header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
1012 header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
1013 header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
1014 header()->setSectionResizeMode(5, QHeaderView::ResizeToContents);
1016 header()->setResizeMode(0, QHeaderView::ResizeToContents);
1017 header()->setResizeMode(1, QHeaderView::ResizeToContents);
1018 header()->setResizeMode(2, QHeaderView::ResizeToContents);
1019 header()->setResizeMode(5, QHeaderView::ResizeToContents);
1022 setSortingEnabled(
false);
1023 addTopLevelItems(items);
1025 setSortingEnabled(
true);
1027 sortByColumn(0, Qt::AscendingOrder);
1028 header()->setSortIndicatorShown(
false);
1031 #if QT_VERSION >= 0x050000
1032 header()->setSectionResizeMode(0, QHeaderView::Interactive);
1033 header()->setSectionResizeMode(1, QHeaderView::Interactive);
1034 header()->setSectionResizeMode(2, QHeaderView::Interactive);
1035 header()->setSectionResizeMode(5, QHeaderView::Interactive);
1037 header()->setResizeMode(0, QHeaderView::Interactive);
1038 header()->setResizeMode(1, QHeaderView::Interactive);
1039 header()->setResizeMode(2, QHeaderView::Interactive);
1040 header()->setResizeMode(5, QHeaderView::Interactive);
1044 if (item) first = item;
1046 scrollToItem(first);
1047 _inSelectionUpdate =
true;
1048 setCurrentItem(first);
1049 _inSelectionUpdate =
false;
1054 for (
int i=0; i<topLevelItemCount(); i++) {
1055 item1 = topLevelItem(i);
1057 updateJumpArray(ii->
addr(), ii,
true,
false);
1059 for (
int j=0; j<item1->childCount(); j++) {
1060 item2 = item1->child(j);
1063 updateJumpArray(ii->
addr(), ii2,
false,
true);
1072 setColumnWidth(3, 0);
1074 if (noAssLines > 1) {
1078 tr(
"There are %n cost line(s) without machine code.",
"", noAssLines));
1080 tr(
"This happens because the code of"));
1081 new InstrItem(
this,
this, 3, QString(
" %1").arg(objfile));
1083 tr(
"does not seem to match the profile data file."));
1086 tr(
"Are you using an old profile data file or is the above mentioned"));
1088 tr(
"ELF object from an updated installation/another machine?"));
1093 if (dumpedLines == 0) {
1096 tr(
"There seems to be an error trying to execute the command"));
1098 QString(
" '%1'").arg(objdumpCmd));
1100 tr(
"Check that the ELF object used in the command exists."));
1102 tr(
"Check that you have installed 'objdump'."));
1104 tr(
"This utility can be found in the 'binutils' package."));
1114 sortByColumn(col, Qt::AscendingOrder);
1118 sortByColumn(col, Qt::DescendingOrder);
1138 #include "instrview.moc"
QList< TraceInstrJump * > TraceInstrJumpList
static bool parseLine(const char *buf, Addr &addr, QString &code, QString &mnemonic, QString &operands)
Parses a line from objdump assembly output, returning false for a line without an assembly instructio...
void activatedSlot(QTreeWidgetItem *, int)
QString whatsThis() const
bool instrJumpHighLessThan(const TraceInstrJump *ij1, const TraceInstrJump *ij2)
SubCost subCost(EventType *)
Returns a sub cost.
TraceInstr * instr() const
InstrView(TraceItemView *parentView, QWidget *parent=0)
static bool isHexDigit(char c)
void addEventTypeMenu(QMenu *, bool withCost2=true)
TraceInstr * instrTo() const
const TraceInstrJumpList & instrJumps() const
ProfileContext::Type type() const
void setJumpArray(const QVector< TraceInstrJump * > &a)
void getInstrJumpAddresses(const TraceInstrJump *ij, Addr &low, Addr &high)
QMap< Addr, TraceInstr > TraceInstrMap
virtual void setValue(const QString &key, const QVariant &value, const QVariant &defaultValue=QVariant())
void restoreOptions(const QString &prefix, const QString &postfix)
Base class for cost items.
A call from an instruction of one function to another function.
Addresses are 64bit values like costs to be able to always load profile data produced on 64bit archit...
static ConfigGroup * group(const QString &group, const QString &optSuffix=QString())
Abstract Base Class for KCachegrind Views.
A object containing a text segment (shared lib/executable) with defined functions.
TracePartList parts() const
virtual QString name() const
Returns dynamic name info (without type)
void context(const QPoint &)
void keyPressEvent(QKeyEvent *event)
A code instruction address of the program.
QString prettyName() const
Similar to name, but prettyfied = more descriptive to humans.
void saveOptions(const QString &prefix, const QString &postfix)
const TraceInstrCallList & instrCalls() const
A source line of the program.
static QString shortenSymbol(const QString &)
A group of configuration settings.
virtual void selected(TraceItemView *sender, CostItem *)
Notification from child views.
virtual void activated(TraceItemView *sender, CostItem *)
TraceInstrMap * instrMap()
A Trace Part: All data read from a trace file, containing all costs that happened in a specified time...
A jump from an instruction to another inside of a function.
virtual QString name() const
Returns dynamic name info (without type)
Cost event counter, simple wrapper around a 64bit entity.
TraceFunction * called(bool skipCycle=false) const
#define DEFAULT_SHOWHEXCODE
bool instrJumpLowLessThan(const TraceInstrJump *ij1, const TraceInstrJump *ij2)
TraceInstr * instrFrom() const
void selectedSlot(QTreeWidgetItem *, QTreeWidgetItem *)
static Addr parseAddr(char *buf)
TraceInstrCall * instrCall() const
static int noCostInside()
TraceInstrJump * instrJump() const
QString shortName() const
virtual QVariant value(const QString &key, const QVariant &defaultValue) const