@@ -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,15 +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
- uint64_t segmentStart = fetchExecSegment (M);
536
- /* Adjust the symbol to a value relative to the start of the load address
537
- to match up with registerNewMapping. */
538
- M->Adjust -= segmentStart;
539
- }
540
530
fetchSymbols (M);
541
531
542
532
std::sort (begin (), end ());
@@ -670,8 +660,7 @@ class PerfReader {
670
660
void emitSymbol (
671
661
Symbol &Sym, Map &M,
672
662
std::map<uint64_t , std::map<const char *, uint64_t >>::iterator Event,
673
- std::map<const char *, uint64_t > &SymEvents,
674
- uint64_t Adjust);
663
+ std::map<const char *, uint64_t > &SymEvents);
675
664
PyObject *complete ();
676
665
677
666
private:
@@ -851,13 +840,11 @@ static uint64_t getTimeFromSampleId(unsigned char *EndOfStruct,
851
840
void PerfReader::registerNewMapping (unsigned char *Buf, const char *Filename) {
852
841
perf_event_mmap_common *E = (perf_event_mmap_common *)Buf;
853
842
auto MapID = Maps.size ();
854
- // EXEC ELF objects aren't relocated. DYN ones are,
855
- // so if it's a DYN object adjust by subtracting the
856
- // map base.
857
- bool IsSO = IsSharedObject (BinaryCacheRoot + std::string (Filename));
843
+
858
844
uint64_t End = E->start + E->extent ;
859
- uint64_t Adjust = IsSO ? E->start - E->pgoff : 0 ;
860
- 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);
861
848
862
849
unsigned char *EndOfEvent = Buf + E->header .size ;
863
850
// FIXME: The first EventID is used for every event.
@@ -1025,24 +1012,25 @@ void PerfReader::emitMaps() {
1025
1012
if (AllUnderThreshold)
1026
1013
continue ;
1027
1014
1015
+ Map &M = Maps[MapID];
1028
1016
SymTabOutput Syms (Objdump, BinaryCacheRoot);
1029
- Syms.reset (&Maps[MapID] );
1017
+ Syms.reset (&M );
1030
1018
1031
- uint64_t Adjust = Maps[MapID]. Adjust ;
1019
+ uint64_t VAddrToPCOffset = M. VAddrToFileOffset + M. FileToPCOffset ;
1032
1020
1033
1021
// Accumulate the event totals for each symbol
1034
1022
auto Sym = Syms.begin ();
1035
1023
auto Event = MapEvents.begin ();
1036
1024
std::map<uint64_t , std::map<const char *, uint64_t >> SymToEventTotals;
1037
1025
while (Event != MapEvents.end () && Sym != Syms.end ()) {
1038
1026
// Skip events until we find one after the start of Sym
1039
- auto PC = Event->first - Adjust ;
1040
- if (PC < Sym->Start ) {
1027
+ auto VAddr = Event->first - VAddrToPCOffset ;
1028
+ if (VAddr < Sym->Start ) {
1041
1029
++Event;
1042
1030
continue ;
1043
1031
}
1044
1032
// Skip symbols until the event is before the end of Sym
1045
- if (PC >= Sym->End ) {
1033
+ if (VAddr >= Sym->End ) {
1046
1034
++Sym;
1047
1035
continue ;
1048
1036
}
@@ -1062,26 +1050,28 @@ void PerfReader::emitMaps() {
1062
1050
}
1063
1051
}
1064
1052
if (Keep)
1065
- emitSymbol (Sym, Maps[MapID] , MapEvents.lower_bound (Sym.Start ),
1066
- SymToEventTotals[Sym.Start ], Adjust );
1053
+ emitSymbol (Sym, M , MapEvents.lower_bound (Sym.Start + VAddrToPCOffset ),
1054
+ SymToEventTotals[Sym.Start ]);
1067
1055
}
1068
1056
}
1069
1057
}
1070
1058
1071
1059
void PerfReader::emitSymbol (
1072
1060
Symbol &Sym, Map &M,
1073
1061
std::map<uint64_t , std::map<const char *, uint64_t >>::iterator Event,
1074
- std::map<const char *, uint64_t > &SymEvents,
1075
- uint64_t Adjust) {
1062
+ std::map<const char *, uint64_t > &SymEvents) {
1063
+ uint64_t VAddrToPCOffset = M. VAddrToFileOffset + M. FileToPCOffset ;
1076
1064
ObjdumpOutput Dump (Objdump, BinaryCacheRoot);
1077
1065
Dump.reset (&M, Sym.Start , Sym.End );
1078
1066
1079
1067
emitFunctionStart (Sym.Name );
1068
+ assert (Sym.Start <= Event->first - VAddrToPCOffset &&
1069
+ Event->first - VAddrToPCOffset < Sym.End );
1080
1070
for (uint64_t I = Dump.next (); I < Sym.End ; I = Dump.next ()) {
1081
- auto PC = Event->first - Adjust ;
1071
+ auto VAddr = Event->first - VAddrToPCOffset ;
1082
1072
1083
1073
auto Text = Dump.getText ();
1084
- if (PC == I) {
1074
+ if (VAddr == I) {
1085
1075
emitLine (I, &Event->second , Text);
1086
1076
++Event;
1087
1077
} else {
0 commit comments