37
37
// if the mmap's event total is < 1% of the total in all counters,
38
38
// then discard the mmap [1].
39
39
//
40
- // load symbol data by calling "nm " and parsing the result.
40
+ // load symbol data by calling "objdump -t " and parsing the result.
41
41
// for all PCs we have events for, in sorted order:
42
42
// find the symbol this PC is part of -> Sym
43
43
// look up all PCs between Sym.Start and Sym.End and emit data
50
50
// invoked, and its samples will continue until the perf wrapper tool exits.
51
51
// This means that it will often take one or two samples in intermediate
52
52
// binaries like "perf", "bash", or libaries such as libdl. We don't care about
53
- // these, and these binaries and libraries are very large to nm and objdump.
53
+ // these, and these binaries and libraries are very large to objdump.
54
54
//
55
55
// So we have a threshold - if a binary contains < 1% of all samples, don't
56
56
// bother importing it.
@@ -361,7 +361,7 @@ static const char* sw_event_names[PERF_COUNT_SW_MAX] = {
361
361
};
362
362
363
363
// ===----------------------------------------------------------------------===//
364
- // Readers for nm and objdump output
364
+ // Readers for objdump output
365
365
// ===----------------------------------------------------------------------===//
366
366
367
367
struct Map {
@@ -380,19 +380,15 @@ struct Symbol {
380
380
}
381
381
};
382
382
383
- class NmOutput : public std ::vector<Symbol> {
383
+ class SymTabOutput : public std ::vector<Symbol> {
384
384
public:
385
- std::string Nm , BinaryCacheRoot;
385
+ std::string Objdump , BinaryCacheRoot;
386
386
387
- NmOutput (std::string Nm , std::string BinaryCacheRoot)
388
- : Nm(Nm ), BinaryCacheRoot(BinaryCacheRoot) {}
387
+ SymTabOutput (std::string Objdump , std::string BinaryCacheRoot)
388
+ : Objdump(Objdump ), BinaryCacheRoot(BinaryCacheRoot) {}
389
389
390
- void fetchSymbols (Map *M, bool Dynamic) {
391
- std::string D = " -D" ;
392
- if (!Dynamic)
393
- // Don't fetch the dynamic symbols - instead fetch static ones.
394
- D = " " ;
395
- std::string Cmd = Nm + " " + D + " -S --defined-only " +
390
+ void fetchSymbols (Map *M) {
391
+ std::string Cmd = Objdump + " -t -T -C " +
396
392
BinaryCacheRoot + std::string (M->Filename ) +
397
393
#ifdef _WIN32
398
394
" 2> NUL" ;
@@ -408,38 +404,65 @@ class NmOutput : public std::vector<Symbol> {
408
404
if (Len == -1 )
409
405
break ;
410
406
411
- std::vector<std::string> SplittedLine;
412
- if (splitLine (std::string (Line), SplittedLine) < 4 )
413
- continue ;
407
+ std::stringstream SS (Line);
414
408
415
- const std::string& One = SplittedLine[0 ];
416
- const std::string& Two = SplittedLine[1 ];
417
- const std::string& Three = SplittedLine[2 ];
418
- std::string& Four = SplittedLine[3 ];
409
+ std::string Start;
410
+ if (!std::getline (SS, Start, ' ' ))
411
+ continue ;
412
+ char * EndPtr = NULL ;
413
+ uint64_t NStart = strtoull (Start.c_str (), &EndPtr, 16 );
414
+ if (EndPtr == Start.c_str ())
415
+ continue ;
419
416
420
- char *EndPtr = NULL ;
421
- uint64_t Start = strtoull (One.c_str (), &EndPtr, 16 );
422
- if (EndPtr == One.c_str ())
417
+ char GlobLoc; // Local -> 'l', Global -> 'g', Neither -> ' '
418
+ if (!SS.get (GlobLoc))
423
419
continue ;
424
- uint64_t Extent = strtoull (Two. c_str (), &EndPtr, 16 );
425
- if (EndPtr == Two. c_str ( ))
420
+ char Weak; // Weak?
421
+ if (!SS. get (Weak ))
426
422
continue ;
427
- if (Three.length () != 1 )
423
+ char Space;
424
+ if (!SS.get (Space)) // Constructor. Not supported yet.
428
425
continue ;
429
- switch (Three.front ()) {
430
- default :
426
+ if (!SS.get (Space)) // Warning. Not supported yet.
431
427
continue ;
432
- case ' T' :
433
- case ' t' : // Text section
434
- case ' V' :
435
- case ' v' : // Weak object
436
- case ' W' :
437
- case ' w' : // Weak object (not tagged as such)
438
- break ;
439
- }
440
- if (Four.back () == ' \n ' )
441
- Four.pop_back ();
442
- push_back ({Start, Start + Extent, Four});
428
+ char IFunc; // Indirect reference to another symbol.
429
+ if (!SS.get (IFunc))
430
+ continue ;
431
+ char Debug; // Debugging (d) or dynamic (D) symbol.
432
+ if (!SS.get (Debug))
433
+ continue ;
434
+ char FileFunc; // Name of function (F), file (f) or object (O).
435
+ if (!SS.get (FileFunc))
436
+ continue ;
437
+ if (FileFunc != ' F' )
438
+ continue ;
439
+ if (!SS.get (Space))
440
+ continue ;
441
+
442
+ std::string Section;
443
+ if (!std::getline (SS, Section, ' \t ' ))
444
+ continue ;
445
+ if (Section != " .text" )
446
+ continue ;
447
+
448
+ std::string Extent;
449
+ if (!std::getline (SS, Extent, ' ' ))
450
+ continue ;
451
+ uint64_t NExtent = strtoull (Extent.c_str (), &EndPtr, 16 );
452
+ if (EndPtr == Extent.c_str ())
453
+ continue ;
454
+
455
+ std::string Func;
456
+ while (std::getline (SS, Func, ' ' ) && Func.empty ()); // Skip spaces.
457
+ if (Func.empty ())
458
+ continue ;
459
+ // Note Func includes the symbol table visibility if any.
460
+ std::string FuncRest;
461
+ if (std::getline (SS, FuncRest)) // Read the rest line if any.
462
+ Func += std::string (" " ) + FuncRest;
463
+ if (Func.back () == ' \n ' )
464
+ Func.pop_back ();
465
+ push_back ({NStart, NStart + NExtent, Func});
443
466
}
444
467
if (Line)
445
468
free (Line);
@@ -455,8 +478,7 @@ class NmOutput : public std::vector<Symbol> {
455
478
void reset (Map *M) {
456
479
clear ();
457
480
// Fetch both dynamic and static symbols, sort and unique them.
458
- fetchSymbols (M, true );
459
- fetchSymbols (M, false );
481
+ fetchSymbols (M);
460
482
461
483
std::sort (begin (), end ());
462
484
auto NewEnd = std::unique (begin (), end ());
@@ -568,8 +590,8 @@ class ObjdumpOutput {
568
590
569
591
class PerfReader {
570
592
public:
571
- PerfReader (const std::string &Filename, std::string Nm ,
572
- std::string Objdump, std::string BinaryCacheRoot);
593
+ PerfReader (const std::string &Filename, std::string Objdump ,
594
+ std::string BinaryCacheRoot);
573
595
~PerfReader ();
574
596
575
597
void readHeader ();
@@ -613,13 +635,12 @@ class PerfReader {
613
635
PyObject *Functions, *TopLevelCounters;
614
636
std::vector<PyObject*> Lines;
615
637
616
- std::string Nm, Objdump, BinaryCacheRoot;
638
+ std::string Objdump, BinaryCacheRoot;
617
639
};
618
640
619
- PerfReader::PerfReader (const std::string &Filename,
620
- std::string Nm, std::string Objdump,
641
+ PerfReader::PerfReader (const std::string &Filename, std::string Objdump,
621
642
std::string BinaryCacheRoot)
622
- : Nm(Nm), Objdump(Objdump), BinaryCacheRoot(BinaryCacheRoot) {
643
+ : Objdump(Objdump), BinaryCacheRoot(BinaryCacheRoot) {
623
644
TopLevelCounters = PyDict_New ();
624
645
Functions = PyDict_New ();
625
646
#ifdef _WIN32
@@ -934,7 +955,7 @@ void PerfReader::emitMaps() {
934
955
935
956
uint64_t Adjust = Maps[MapID].Adjust ;
936
957
937
- NmOutput Syms (Nm , BinaryCacheRoot);
958
+ SymTabOutput Syms (Objdump , BinaryCacheRoot);
938
959
Syms.reset (&Maps[MapID]);
939
960
940
961
// Accumulate the event totals for each symbol
@@ -1008,14 +1029,13 @@ PyObject *PerfReader::complete() {
1008
1029
#ifndef STANDALONE
1009
1030
static PyObject *cPerf_importPerf (PyObject *self, PyObject *args) {
1010
1031
const char *Fname;
1011
- const char *Nm = " nm" ;
1012
1032
const char *Objdump = " objdump" ;
1013
1033
const char *BinaryCacheRoot = " " ;
1014
- if (!PyArg_ParseTuple (args, " s|sss " , &Fname, &Nm , &Objdump, &BinaryCacheRoot))
1034
+ if (!PyArg_ParseTuple (args, " s|ss " , &Fname, &Objdump, &BinaryCacheRoot))
1015
1035
return NULL ;
1016
1036
1017
1037
try {
1018
- PerfReader P (Fname, Nm, Objdump, BinaryCacheRoot);
1038
+ PerfReader P (Fname, Objdump, BinaryCacheRoot);
1019
1039
P.readHeader ();
1020
1040
P.readAttrs ();
1021
1041
P.readDataStream ();
@@ -1066,7 +1086,7 @@ PyMODINIT_FUNC initcPerf(void) {
1066
1086
int main (int argc, char **argv) {
1067
1087
Py_Initialize ();
1068
1088
if (argc < 2 ) return -1 ;
1069
- PerfReader P (argv[1 ], " nm " , " objdump" , " " );
1089
+ PerfReader P (argv[1 ], " objdump" , " " );
1070
1090
P.readHeader ();
1071
1091
P.readAttrs ();
1072
1092
P.readDataStream ();
0 commit comments