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');
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;
119 while(buf[pos]==
' ' || buf[pos]==
'\t') pos++;
123 while(buf[pos] && buf[pos]!=
' ' && buf[pos]!=
'\t') pos++;
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)
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;
168 headerLabels <<
tr(
"#" )
174 <<
tr(
"Assembly Instructions" )
175 <<
tr(
"Source Position" );
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>");
237 QAction* activateFunctionAction = 0;
238 QAction* activateInstrAction = 0;
241 activateFunctionAction = popup.
addAction(menuText);
246 activateInstrAction = popup.
addAction(menuText);
250 if ((c == 1) || (c == 2)) {
263 if (a == activateFunctionAction)
265 else if (a == activateInstrAction)
267 else if (a == toggleHexAction) {
268 _showHexCode = !_showHexCode;
281 if (_inSelectionUpdate)
return;
330 if (item && ((event->
key() == Qt::Key_Return) ||
331 (event->
key() == Qt::Key_Space)))
357 void InstrView::doUpdate(
int changeType,
bool)
388 _inSelectionUpdate =
true;
390 _inSelectionUpdate =
false;
395 item2 = item->
child(j);
400 _inSelectionUpdate =
true;
402 _inSelectionUpdate =
false;
417 item2 = item->
child(j);
431 void InstrView::setColumnWidths()
433 #if QT_VERSION >= 0x050000
434 header()->setSectionResizeMode(4, QHeaderView::Interactive);
465 Addr addr1Low, addr1High, addr2Low, addr2High;
470 if (addr1Low != addr2Low)
return (addr1Low < addr2Low);
472 if (addr1Low == ij1->
instrTo()->
addr())
return true;
473 if (addr2Low == ij2->
instrTo()->
addr())
return false;
474 return (addr1High < addr2High);
481 Addr addr1Low, addr1High, addr2Low, addr2High;
486 if (addr1High != addr2High)
return (addr1High < addr2High);
488 if (addr1High == ij1->
instrTo()->
addr())
return true;
489 if (addr2High == ij2->
instrTo()->
addr())
return false;
490 return (addr1Low < addr2Low);
493 void InstrView::refresh()
507 #if QT_VERSION >= 0x050000
508 header()->setSectionResizeMode(4, QHeaderView::ResizeToContents);
540 it = instrMap->
begin();
541 itEnd = instrMap->
end();
549 if (!instrMap || (it == itEnd)) {
551 tr(
"There is no instruction info in the profile data file."));
553 tr(
"Tip: For Callgrind, rerun with option"));
554 new InstrItem(
this,
this, 3,
tr(
" --dump-instr=yes"));
555 new InstrItem(
this,
this, 4,
tr(
"To see (conditional) jumps, additionally specify"));
556 new InstrItem(
this,
this, 5,
tr(
" --collect-jumps=yes"));
578 if (it == itEnd)
break;
582 _lowListIter = _lowList.
begin();
583 _highListIter = _highList.
begin();
600 if (it == itEnd)
break;
601 if (!(*it).addr().isInRange( (*tmpIt).addr(),10000) )
break;
605 if (!fillInstrRange(f, itStart, ++tmpIt))
break;
606 if (it == itEnd)
break;
613 #if QT_VERSION >= 0x050000
614 header()->setSectionResizeMode(2, QHeaderView::Interactive);
633 bool ignoreFrom,
bool ignoreTo)
635 Addr lowAddr, highAddr;
636 int iEnd = -1, iStart = -1;
638 if (0) qDebug(
"updateJumpArray(addr 0x%s, jump to %s)",
644 while(_lowListIter != _lowList.
end()) {
650 if (lowAddr > addr)
break;
653 if (ignoreFrom && (lowAddr < ij->instrTo()->addr()))
break;
655 if (ignoreTo && (lowAddr < ij->instrFrom()->addr()))
break;
660 for(iStart=0;iStart<_arrowLevels;iStart++)
662 (_jump[iStart]->instrTo() == ij->
instrTo()))
break;
664 iStart = _arrowLevels;
667 if (iStart==_arrowLevels) {
668 for(iStart=0;iStart<_arrowLevels;iStart++)
669 if (_jump[iStart] == 0)
break;
670 if (iStart==_arrowLevels) {
672 _jump.
resize(_arrowLevels);
674 if (0) qDebug(
" new start at %d for %s",
675 iStart, qPrintable(ij->
name()));
684 while(_highListIter != _highList.
end()) {
691 else if (ignoreFrom)
break;
693 if (highAddr > addr)
break;
695 for(iEnd=0;iEnd<_arrowLevels;iEnd++)
696 if (_jump[iEnd] == ij)
break;
697 if (iEnd==_arrowLevels) {
698 qDebug() <<
"InstrView: no jump start for end at 0x"
704 qDebug(
" end %d (%s to %s)",
706 qPrintable(_jump[iEnd]->instrFrom()->
name()),
707 qPrintable(_jump[iEnd]->instrTo()->
name()));
709 if (0 && ij) qDebug(
"next end: %s to %s",
718 if (iEnd>=0) _jump[iEnd] = 0;
722 if (iEnd>=0) _jump[iEnd] = 0;
736 dir = fi.absolutePath();
743 if (
QFileInfo(partFile.absolutePath(), filename).exists()) {
744 dir = partFile.absolutePath();
759 Addr costAddr, nextCostAddr, objAddr, addr;
760 Addr dumpStartAddr, dumpEndAddr;
764 if (it == itEnd)
return false;
769 nextCostAddr = (*it).addr();
770 dumpStartAddr = (nextCostAddr<20) ?
Addr(0) : nextCostAddr -20;
771 dumpEndAddr = (*tmpIt).addr() +20;
773 QString dir =
function->object()->directory();
774 if (!searchFile(dir, function->object())) {
776 tr(
"For annotated machine code, "
777 "the following object file is needed:"));
779 QString(
" '%1'").arg(function->object()->name()));
781 tr(
"This file can not be found."));
784 function->object()->setDirectory(dir);
787 QString objfile = dir +
'/' +
function->object()->shortName();
793 QString objdumpCmd =
"objdump " + objdumpArgs.
join(
" ");
795 if (1) qDebug(
"Running '%s'...", qPrintable(objdumpCmd));
799 objdump.
start(
"objdump", objdumpArgs);
804 tr(
"There is an error trying to execute the command"));
806 QString(
" '%1'").arg(objdumpCmd));
808 tr(
"Check that you have installed 'objdump'."));
810 tr(
"This utility can be found in the 'binutils' package."));
818 bool inside =
false, skipLineWritten =
true;
820 int objdumpLineno = 0, dumpedLines = 0, noAssLines = 0;
825 bool needObjAddr =
true, needCostAddr =
true;
846 qDebug(
"ERROR: Line %d of '%s' too long\n",
847 objdumpLineno, qPrintable(objdumpCmd));
849 else if ((readBytes>0) && (buf[readBytes-1] ==
'\n'))
850 buf[readBytes-1] = 0;
853 if ((objAddr<dumpStartAddr) || (objAddr>dumpEndAddr))
855 if (objAddr != 0)
break;
858 if (0) qDebug() <<
"Got ObjAddr: 0x" << objAddr.
toString();
863 (nextCostAddr > 0) &&
864 ((objAddr ==
Addr(0)) || (objAddr >= nextCostAddr)) ) {
865 needCostAddr =
false;
874 costAddr = nextCostAddr;
875 nextCostAddr = (it == itEnd) ?
Addr(0) : (*it).addr();
877 if (0) qDebug() <<
"Got nextCostAddr: 0x" << nextCostAddr.
toString()
878 <<
", costAddr 0x" << costAddr.
toString();
882 if (objAddr == 0)
break;
884 if ((nextCostAddr==0) || (costAddr == 0) ||
885 (objAddr < nextCostAddr)) {
889 bool isAssemblyInstr =
parseLine(buf, addr, code, cmd, args);
890 Q_UNUSED(isAssemblyInstr);
891 assert(isAssemblyInstr && (objAddr == addr));
893 if (costAddr == objAddr) {
894 currInstr = &(*costIt);
902 if (0) qDebug() <<
"Dump Obj Addr: 0x" << addr.
toString()
903 <<
" [" << cmd <<
" " << args <<
"], cost (0x"
904 << costAddr.
toString() <<
", next 0x"
910 args =
tr(
"(No Instruction)");
912 currInstr = &(*costIt);
916 if (0) qDebug() <<
"Dump Cost Addr: 0x" << addr.
toString()
917 <<
" (no ass), objAddr 0x" << objAddr.
toString();
922 if (currInstr) inside =
true;
925 if (0) qDebug() <<
"Check if 0x" << addr.
toString() <<
" is in ]0x"
931 if ( (addr > costAddr) &&
932 ((nextCostAddr==0) ||
939 if ( ((costAddr==0) || (addr > costAddr + 3*context)) &&
940 ((nextCostAddr==0) || (addr < nextCostAddr - 3*context)) ) {
944 (itEnd == function->instrMap()->end())) skipLineWritten=
true;
946 if (!skipLineWritten) {
947 skipLineWritten =
true;
956 skipLineWritten =
false;
959 ii =
new InstrItem(
this, 0, addr, inside,
960 code, cmd, args, currInstr);
964 if (0) qDebug() <<
"Dumped 0x" << addr.
toString() <<
" "
965 << (inside ?
"Inside " :
"Outside")
966 << (currInstr ?
"Cost" :
"");
969 if (!currInstr)
continue;
975 if (!first) first = ii;
992 ii2 =
new InstrItem(
this, ii, addr, currInstr, ic);
1001 new InstrItem(
this, ii, addr, currInstr, ij);
1006 #if QT_VERSION >= 0x050000
1007 header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
1008 header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
1009 header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
1010 header()->setSectionResizeMode(5, QHeaderView::ResizeToContents);
1027 #if QT_VERSION >= 0x050000
1028 header()->setSectionResizeMode(0, QHeaderView::Interactive);
1029 header()->setSectionResizeMode(1, QHeaderView::Interactive);
1030 header()->setSectionResizeMode(2, QHeaderView::Interactive);
1031 header()->setSectionResizeMode(5, QHeaderView::Interactive);
1040 if (item) first = item;
1043 _inSelectionUpdate =
true;
1045 _inSelectionUpdate =
false;
1053 updateJumpArray(ii->
addr(), ii,
true,
false);
1056 item2 = item1->
child(j);
1059 updateJumpArray(ii->
addr(), ii2,
false,
true);
1070 if (noAssLines > 1) {
1074 tr(
"There are %n cost line(s) without machine code.",
"", noAssLines));
1076 tr(
"This happens because the code of"));
1079 tr(
"does not seem to match the profile data file."));
1082 tr(
"Are you using an old profile data file or is the above mentioned"));
1084 tr(
"ELF object from an updated installation/another machine?"));
1089 if (dumpedLines == 0) {
1092 tr(
"There seems to be an error trying to execute the command"));
1094 QString(
" '%1'").arg(objdumpCmd));
1096 tr(
"Check that the ELF object used in the command exists."));
1098 tr(
"Check that you have installed 'objdump'."));
1100 tr(
"This utility can be found in the 'binutils' package."));
1134 #include "instrview.moc"
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)
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.
QString join(const QString &separator) const
void sortByColumn(int column, Qt::SortOrder order)
QString tr(const char *sourceText, const char *disambiguation, int n)
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
const char * name() const
int columnWidth(int column) const
void setColumnWidth(int column, int width)
int count(const T &value) const
void append(const T &value)
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.
void setItemDelegate(QAbstractItemDelegate *delegate)
QString prettyName() const
Similar to name, but prettyfied = more descriptive to humans.
void saveOptions(const QString &prefix, const QString &postfix)
void setAllColumnsShowFocus(bool enable)
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.
bool waitForStarted(int msecs)
virtual void activated(TraceItemView *sender, CostItem *)
TraceInstrMap * instrMap()
void setExpandsOnDoubleClick(bool enable)
void setSortingEnabled(bool enable)
A Trace Part: All data read from a trace file, containing all costs that happened in a specified time...
bool isAbsolutePath(const QString &path)
A jump from an instruction to another inside of a function.
char * toString(const T &value)
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
void setText(int column, const QString &text)
QString fromLatin1(const char *str, int size)
#define DEFAULT_SHOWHEXCODE
bool instrJumpLowLessThan(const TraceInstrJump *ij1, const TraceInstrJump *ij2)
TraceInstr * instrFrom() const
void selectedSlot(QTreeWidgetItem *, QTreeWidgetItem *)
static Addr parseAddr(char *buf)
virtual void keyPressEvent(QKeyEvent *event)
TraceInstrCall * instrCall() const
void setRootIsDecorated(bool show)
static int noCostInside()
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
TraceInstrJump * instrJump() const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
void start(const QString &program, const QStringList &arguments, QFlags< QIODevice::OpenModeFlag > mode)
int columnAt(int x) const
QString shortName() const
qint64 readLine(char *data, qint64 maxSize)
virtual QVariant value(const QString &key, const QVariant &defaultValue) const
bool waitForFinished(int msecs)