3
4
#include <qstringlist.h>
5
6
#include <qtextstream.h>
6
#include <qsortedlist.h>
7
#include <q3sortedlist.h>
9
#include <qvaluelist.h>
10
#include <q3valuelist.h>
10
12
#include <stdlib.h>
11
#include <ktempfile.h>
12
#include <kinstance.h>
13
#include <ktemporaryfile.h>
14
#include <kcomponentdata.h>
13
15
#include <kstandarddirs.h>
14
16
#include <kcmdlineargs.h>
18
20
/* Options passed to cplus_demangle (in 2nd parameter). */
48
50
bool operator<(const Entry &e) { return total_size > e.total_size; }
51
QIntDict<Entry> *entryDict = 0;
52
QIntDict<char> *symbolDict = 0;
53
QIntDict<char> *formatDict = 0;
54
QSortedList<Entry> *entryList = 0;
55
QStrList *excludes = 0;
53
Q3IntDict<Entry> *entryDict = 0;
54
Q3IntDict<char> *symbolDict = 0;
55
Q3IntDict<char> *formatDict = 0;
56
Q3SortedList<Entry> *entryList = 0;
57
Q3StrList *excludes = 0;
57
59
const char * const unknown = "<unknown>";
58
60
const char * const excluded = "<excluded>";
68
70
int fromHex(const char *str);
69
void parseLine(const QCString &_line, char operation);
71
void parseLine(const QString &_line, char operation);
72
74
int fromHex(const char *str)
79
81
// [address0][address1] .... [address] + base size
80
void parseLine(const QCString &_line, char operation)
82
void parseLine(const QString &_line, char operation)
82
84
char *line= (char *) _line.data();
83
85
const char *cols[200];
165
167
void collectDupes()
167
QIntDict<Entry> dupeDict;
168
QIntDictIterator<Entry> it(*entryDict);
169
Q3IntDict<Entry> dupeDict;
170
Q3IntDictIterator<Entry> it(*entryDict);
169
171
for(;it.current();)
171
173
Entry *entry = it.current();
245
247
void lookupUnknownSymbols(const char *appname)
248
KTempFile outputFile;
249
inputFile.setAutoDelete(true);
250
outputFile.setAutoDelete(true);
251
FILE *fInputFile = inputFile.fstream();
252
QIntDict<char> oldDict = *symbolDict;
253
QIntDictIterator<char> it(oldDict);
249
KTemporaryFile inputFile;
250
KTemporaryFile outputFile;
253
QTextStream str ( &inputFile );
254
Q3IntDict<char> oldDict = *symbolDict;
255
Q3IntDictIterator<char> it(oldDict);
254
256
for(;it.current(); ++it)
256
fprintf(fInputFile, "%08lx\n", it.currentKey());
259
temp.sprintf("%08lx\n", it.currentKey());
260
264
command.sprintf("addr2line -e %s -f -C -s < %s > %s", appname,
261
QFile::encodeName(KProcess::quote(inputFile.name())).data(),
262
QFile::encodeName(KProcess::quote(outputFile.name())).data());
265
QFile::encodeName(KShell::quoteArg(inputFile.fileName())).data(),
266
QFile::encodeName(KShell::quoteArg(outputFile.fileName())).data());
263
267
system(command.data());
264
fInputFile = fopen(QFile::encodeName(outputFile.name()), "r");
268
FILE *fInputFile = fopen(QFile::encodeName(outputFile.fileName()), "r");
267
271
fprintf(stderr, "Error opening temp file.\n");
270
QIntDictIterator<char> it2(oldDict);
274
Q3IntDictIterator<char> it2(oldDict);
271
275
char buffer1[1024];
272
276
char buffer2[1024];
273
277
for(;it2.current(); ++it2)
282
286
if (!fgets(buffer2, 1023, fInputFile)) continue;
283
287
buffer1[strlen(buffer1)-1]=0;
284
288
buffer2[strlen(buffer2)-1]=0;
286
290
symbol.sprintf("%s(%s)", buffer2, buffer1);
287
291
if(*buffer1 != '?')
288
292
symbolDict->replace(it2.currentKey(),qstrdup(symbol.data()));
311
315
char *str = formatDict->find(addr);
312
316
if (str) return str;
313
QCString s = symbolDict->find(addr);
317
QByteArray s = symbolDict->find(addr);
316
320
fprintf(stderr, "Error!\n");
324
328
end = s.findRev(')');
325
329
if ((start > 0) && (end > start))
327
QCString symbol = s.mid(start+1, end-start-1);
331
QByteArray symbol = s.mid(start+1, end-start-1);
329
333
if (symbol.find(')') == -1)
330
334
res = cplus_demangle(symbol.data(), DMGL_PARAMS | DMGL_AUTO | DMGL_ANSI );
390
394
int address; // backtrace
393
typedef QValueList < TreeEntry > TreeList;
397
typedef Q3ValueList < TreeEntry > TreeList;
394
398
TreeList *subentries () const;
395
399
mutable TreeList *_subentries;
396
400
TreeEntry (int adr = 0, int size = 0, int count = 0, TreeList * sub = NULL );
398
402
bool operator < (const TreeEntry &) const;
401
typedef QValueList < TreeEntry > TreeList;
405
typedef Q3ValueList < TreeEntry > TreeList;
403
407
inline TreeEntry::TreeEntry (int adr, int size, int count, TreeList * sub)
404
408
: address (adr), total_size (size), total_count (count), _subentries (sub)
523
527
dumpTree (*it, 0, indent, file);
526
void createTree (const QCString & treefile, int threshold, int maxdepth)
530
void createTree (const QString & treefile, int threshold, int maxdepth)
528
FILE * file = fopen (treefile, "w");
532
FILE * file = fopen (treefile.toLocal8Bit(), "w");
529
533
if (file == NULL)
531
535
fprintf (stderr, "Can't write tree file.\n");
558
562
excludes->sort();
561
static KCmdLineOptions options[] =
564
{ "exclude <file>", "File containing symbols to exclude from output", 0},
566
{ "exe <file>", "Executable to use for looking up unknown symbols", 0},
567
{ "+<trace-log>", "Log file to investigate", 0},
569
{"tree <file>", "File to write allocations tree", 0},
571
{"treethreshold <value>",
572
"Don't print subtrees which allocated less than <value> memory", 0},
574
{"treedepth <value>",
575
"Don't print subtrees that are deeper than <value>", 0},
579
565
int main(int argc, char *argv[])
581
KInstance instance("kmtrace");
583
KCmdLineArgs::init(argc, argv, "kmtrace", "KDE Memory leak tracer", "v1.0");
567
KComponentData componentData("kmtrace");
569
KCmdLineArgs::init(argc, argv, "kmtrace", 0, ki18n("kmtrace"), "v1.0", ki18n("KDE Memory leak tracer"));
572
KCmdLineOptions options;
576
options.add("exclude <file>", ki18n("File containing symbols to exclude from output"));
580
options.add("exe <file>", ki18n("Executable to use for looking up unknown symbols"));
582
options.add("+<trace-log>", ki18n("Log file to investigate"));
586
options.add("tree <file>", ki18n("File to write allocations tree"));
590
options.add("treethreshold <value>", ki18n("Do not print subtrees which allocated less than <value> memory"));
594
options.add("treedepth <value>", ki18n("Do not print subtrees that are deeper than <value>"));
585
596
KCmdLineArgs::addCmdLineOptions(options);
589
600
(void) args->count();
590
601
const char *logfile;
591
602
if(args->count())
592
logfile = args->arg(0);
603
logfile = args->arg(0).toLocal8Bit();
594
605
logfile = "ktrace.out";
596
QCString exe = args->getOption("exe");
599
excludes = new QStrList;
601
exclude = QFile::encodeName(locate("data", "kmtrace/kde.excludes"));
607
QString exe = args->getOption("exe");
610
excludes = new Q3StrList;
612
exclude = QFile::encodeName(KStandardDirs::locate("data", "kmtrace/kde.excludes"));
602
613
if(!exclude.isEmpty())
603
614
readExcludeFile(exclude);
605
exclude = args->getOption("exclude");
616
exclude = args->getOption("exclude").toLocal8Bit().data();
606
617
if (!exclude.isEmpty())
608
619
fprintf(stderr, "Reading %s\n", exclude.data());
619
entryDict = new QIntDict<Entry>(9973);
620
symbolDict = new QIntDict<char>(9973);
621
formatDict = new QIntDict<char>(9973);
622
entryList = new QSortedList<Entry>;
630
entryDict = new Q3IntDict<Entry>(9973);
631
symbolDict = new Q3IntDict<char>(9973);
632
formatDict = new Q3IntDict<char>(9973);
633
entryList = new Q3SortedList<Entry>;
624
635
fprintf(stderr, "Running\n");
626
637
char line2[1024];
627
638
while(!feof(stream))
637
648
else if (line2[0] == '#')
639
QCString app(line2+1);
650
QByteArray app(line2+1);
640
651
if(exe.isEmpty())
642
exe = app.stripWhiteSpace();
643
654
fprintf(stderr, "ktrace.out: malloc trace of %s\n", exe.data());
645
else if(!app.contains(exe.data()))
656
else if(!app.contains(exe.toLocal8Bit().data()))
647
658
fprintf(stderr, "trace file was for application '%s', not '%s'\n", app.data(), exe.data());
651
662
else if (line2[0] == '@')
653
664
else if (line2[0] == '[')
654
665
line = line + ' ' + line2;
655
666
else if (line2[0] == '+')
668
679
line = line + ' ' + line2;
669
680
parseLine(line, '-');
672
683
else if (line2[0] == '<')
675
686
// First part of realloc (free)
676
QCString reline = line + ' ' + line2;
687
QString reline = line + ' ' + line2;
677
688
parseLine(reline, '-');
679
690
else if (line2[0] == '>')
682
693
// Second part of realloc (alloc)
683
694
line = line + ' ' + line2;
684
695
parseLine(line, '+');
689
char *addr = index(line2,'[');
700
const char *addr = index(line2,'[');
692
line = line + ' ' + addr;
703
line = line + QChar(' ') + addr;
707
718
lookupSymbols(stream);
708
719
fprintf(stderr, "Looking up unknown symbols...\n");
709
lookupUnknownSymbols(exe);
720
lookupUnknownSymbols(exe.toLocal8Bit());
710
721
fprintf(stderr, "Printing...\n");
712
QCString treeFile = args->getOption ("tree");
723
QString treeFile = args->getOption ("tree");
713
724
if (!treeFile.isEmpty ())
715
726
fprintf (stderr, "Creating allocation tree...\n");