@@ -178,30 +178,6 @@ void Assert(bool Expr, const char *ExprStr, const char *File, int Line) {
178
178
throw std::logic_error (Str);
179
179
}
180
180
181
- // Returns true if the ELF file given by filename
182
- // is a shared object (DYN).
183
- bool IsSharedObject (const std::string &Fname) {
184
- // We replicate the first part of an ELF header here
185
- // so as not to rely on <elf.h>.
186
- struct PartialElfHeader {
187
- unsigned char e_ident[16 ];
188
- uint16_t e_type;
189
- };
190
- const int ET_DYN = 3 ;
191
-
192
- FILE *stream = fopen (Fname.c_str (), " r" );
193
- if (stream == NULL )
194
- return false ;
195
-
196
- PartialElfHeader H;
197
- auto NumRead = fread (&H, 1 , sizeof (H), stream);
198
- assert (NumRead == sizeof (H));
199
-
200
- fclose (stream);
201
-
202
- return H.e_type == ET_DYN;
203
- }
204
-
205
181
// ===----------------------------------------------------------------------===//
206
182
// Perf structures. Taken from https://lwn.net/Articles/644919/
207
183
// ===----------------------------------------------------------------------===//
@@ -360,9 +336,20 @@ static const char* sw_event_names[PERF_COUNT_SW_MAX] = {
360
336
// ===----------------------------------------------------------------------===//
361
337
362
338
struct Map {
363
- uint64_t Start, End, Adjust;
364
- bool isSO;
339
+ Map (uint64_t Start, uint64_t End, const char *Filename)
340
+ : Start(Start), End(End), Filename(Filename) {}
341
+
342
+ uint64_t Start, End;
365
343
const char *Filename;
344
+
345
+ // Mapping-related adjustments. Here FileOffset(func) is the offset of func
346
+ // in the ELF file, VAddr(func) is the virtual address associated with this
347
+ // symbol (in case of executable and shared object ELF files, st_value field
348
+ // of a symbol table's entry is symbol's virtual address) and &func is the
349
+ // actual memory address after relocations took place in the address space of
350
+ // the process being profiled.
351
+ uint64_t FileToPCOffset; // FileOffset(func) + FileToPCOffset == &func
352
+ uint64_t VAddrToFileOffset; // VAddr(func) + VAddrToFileOffset == FileOffset(func)
366
353
};
367
354
368
355
struct EventDesc {
@@ -389,7 +376,7 @@ class SymTabOutput : public std::vector<Symbol> {
389
376
SymTabOutput (std::string Objdump, std::string BinaryCacheRoot)
390
377
: Objdump(Objdump), BinaryCacheRoot(BinaryCacheRoot) {}
391
378
392
- uint64_t fetchExecSegment (Map *M) {
379
+ void fetchExecSegment (Map *M, uint64_t *FileOffset, uint64_t *VAddr ) {
393
380
std::string Cmd = Objdump + " -p -C " +
394
381
BinaryCacheRoot + std::string (M->Filename ) +
395
382
#ifdef _WIN32
@@ -401,7 +388,7 @@ class SymTabOutput : public std::vector<Symbol> {
401
388
402
389
char *Line = nullptr , *PrevLine = nullptr ;
403
390
size_t LineLen = 0 ;
404
- uint64_t offset = 0 ;
391
+ *FileOffset = *VAddr = 0 ;
405
392
while (true ) {
406
393
if (PrevLine)
407
394
free (PrevLine);
@@ -411,17 +398,22 @@ class SymTabOutput : public std::vector<Symbol> {
411
398
if (Len == -1 )
412
399
break ;
413
400
414
- char * pos;
415
- if ((pos = strstr (Line, " flags r-x" )) == NULL
416
- && (pos = strstr (Line, " flags rwx" )) == NULL )
401
+ if (!strstr (Line, " flags r-x" ) && !strstr (Line, " flags rwx" ))
417
402
continue ;
418
403
419
404
/* Format is weird.. but we did find the section so punt. */
420
- if ((pos = strstr (PrevLine, " vaddr " )) == NULL )
405
+ const char *OFFSET_LABEL = " off " ;
406
+ const char *VADDR_LABEL = " vaddr " ;
407
+ char *pos_offset = strstr (PrevLine, OFFSET_LABEL);
408
+ char *pos_vaddr = strstr (PrevLine, VADDR_LABEL);
409
+ if (!pos_offset || !pos_vaddr)
421
410
break ;
422
411
423
- pos += 6 ;
424
- offset = strtoull (pos, NULL , 16 );
412
+ pos_offset += strlen (OFFSET_LABEL);
413
+ pos_vaddr += strlen (VADDR_LABEL);
414
+ *FileOffset = strtoull (pos_offset, NULL , 16 );
415
+ *VAddr = strtoull (pos_vaddr, NULL , 16 );
416
+
425
417
break ;
426
418
}
427
419
if (Line)
@@ -435,7 +427,6 @@ class SymTabOutput : public std::vector<Symbol> {
435
427
fclose (Stream);
436
428
wait (NULL );
437
429
#endif
438
- return offset;
439
430
}
440
431
441
432
void fetchSymbols (Map *M) {
@@ -528,16 +519,14 @@ class SymTabOutput : public std::vector<Symbol> {
528
519
529
520
void reset (Map *M) {
530
521
clear ();
522
+
523
+ // Take possible difference between "offset" and "virtual address" of
524
+ // the executable segment into account.
525
+ uint64_t FileOffset, VAddr;
526
+ fetchExecSegment (M, &FileOffset, &VAddr);
527
+ M->VAddrToFileOffset = FileOffset - VAddr;
528
+
531
529
// Fetch both dynamic and static symbols, sort and unique them.
532
- /* If we're a relocatable object then take the actual start of the text
533
- segment into account. */
534
- if (M->isSO )
535
- {
536
- uint64_t segmentStart = fetchExecSegment (M);
537
- /* Adjust the symbol to a value relative to the start of the load address
538
- to match up with registerNewMapping. */
539
- M->Adjust -= segmentStart;
540
- }
541
530
fetchSymbols (M);
542
531
543
532
std::sort (begin (), end ());
@@ -671,8 +660,7 @@ class PerfReader {
671
660
void emitSymbol (
672
661
Symbol &Sym, Map &M,
673
662
std::map<uint64_t , std::map<const char *, uint64_t >>::iterator Event,
674
- std::map<const char *, uint64_t > &SymEvents,
675
- uint64_t Adjust);
663
+ std::map<const char *, uint64_t > &SymEvents);
676
664
PyObject *complete ();
677
665
678
666
private:
@@ -852,13 +840,11 @@ static uint64_t getTimeFromSampleId(unsigned char *EndOfStruct,
852
840
void PerfReader::registerNewMapping (unsigned char *Buf, const char *Filename) {
853
841
perf_event_mmap_common *E = (perf_event_mmap_common *)Buf;
854
842
auto MapID = Maps.size ();
855
- // EXEC ELF objects aren't relocated. DYN ones are,
856
- // so if it's a DYN object adjust by subtracting the
857
- // map base.
858
- bool IsSO = IsSharedObject (BinaryCacheRoot + std::string (Filename));
843
+
859
844
uint64_t End = E->start + E->extent ;
860
- uint64_t Adjust = IsSO ? E->start - E->pgoff : 0 ;
861
- Maps.push_back ({E->start , End, Adjust, IsSO, Filename});
845
+ Map NewMapping (E->start , End, Filename);
846
+ NewMapping.FileToPCOffset = E->start - E->pgoff ;
847
+ Maps.push_back (NewMapping);
862
848
863
849
unsigned char *EndOfEvent = Buf + E->header .size ;
864
850
// FIXME: The first EventID is used for every event.
@@ -1026,24 +1012,25 @@ void PerfReader::emitMaps() {
1026
1012
if (AllUnderThreshold)
1027
1013
continue ;
1028
1014
1015
+ Map &M = Maps[MapID];
1029
1016
SymTabOutput Syms (Objdump, BinaryCacheRoot);
1030
- Syms.reset (&Maps[MapID] );
1017
+ Syms.reset (&M );
1031
1018
1032
- uint64_t Adjust = Maps[MapID]. Adjust ;
1019
+ uint64_t VAddrToPCOffset = M. VAddrToFileOffset + M. FileToPCOffset ;
1033
1020
1034
1021
// Accumulate the event totals for each symbol
1035
1022
auto Sym = Syms.begin ();
1036
1023
auto Event = MapEvents.begin ();
1037
1024
std::map<uint64_t , std::map<const char *, uint64_t >> SymToEventTotals;
1038
1025
while (Event != MapEvents.end () && Sym != Syms.end ()) {
1039
1026
// Skip events until we find one after the start of Sym
1040
- auto PC = Event->first - Adjust ;
1041
- if (PC < Sym->Start ) {
1027
+ auto VAddr = Event->first - VAddrToPCOffset ;
1028
+ if (VAddr < Sym->Start ) {
1042
1029
++Event;
1043
1030
continue ;
1044
1031
}
1045
1032
// Skip symbols until the event is before the end of Sym
1046
- if (PC >= Sym->End ) {
1033
+ if (VAddr >= Sym->End ) {
1047
1034
++Sym;
1048
1035
continue ;
1049
1036
}
@@ -1063,26 +1050,28 @@ void PerfReader::emitMaps() {
1063
1050
}
1064
1051
}
1065
1052
if (Keep)
1066
- emitSymbol (Sym, Maps[MapID] , MapEvents.lower_bound (Sym.Start ),
1067
- SymToEventTotals[Sym.Start ], Adjust );
1053
+ emitSymbol (Sym, M , MapEvents.lower_bound (Sym.Start + VAddrToPCOffset ),
1054
+ SymToEventTotals[Sym.Start ]);
1068
1055
}
1069
1056
}
1070
1057
}
1071
1058
1072
1059
void PerfReader::emitSymbol (
1073
1060
Symbol &Sym, Map &M,
1074
1061
std::map<uint64_t , std::map<const char *, uint64_t >>::iterator Event,
1075
- std::map<const char *, uint64_t > &SymEvents,
1076
- uint64_t Adjust) {
1062
+ std::map<const char *, uint64_t > &SymEvents) {
1063
+ uint64_t VAddrToPCOffset = M. VAddrToFileOffset + M. FileToPCOffset ;
1077
1064
ObjdumpOutput Dump (Objdump, BinaryCacheRoot);
1078
1065
Dump.reset (&M, Sym.Start , Sym.End );
1079
1066
1080
1067
emitFunctionStart (Sym.Name );
1068
+ assert (Sym.Start <= Event->first - VAddrToPCOffset &&
1069
+ Event->first - VAddrToPCOffset < Sym.End );
1081
1070
for (uint64_t I = Dump.next (); I < Sym.End ; I = Dump.next ()) {
1082
- auto PC = Event->first - Adjust ;
1071
+ auto VAddr = Event->first - VAddrToPCOffset ;
1083
1072
1084
1073
auto Text = Dump.getText ();
1085
- if (PC == I) {
1074
+ if (VAddr == I) {
1086
1075
emitLine (I, &Event->second , Text);
1087
1076
++Event;
1088
1077
} else {
0 commit comments