@@ -178,30 +178,6 @@ void Assert(bool Expr, const char *ExprStr, const char *File, int Line) {
178178 throw std::logic_error (Str);
179179}
180180
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-
205181// ===----------------------------------------------------------------------===//
206182// Perf structures. Taken from https://lwn.net/Articles/644919/
207183// ===----------------------------------------------------------------------===//
@@ -360,9 +336,20 @@ static const char* sw_event_names[PERF_COUNT_SW_MAX] = {
360336// ===----------------------------------------------------------------------===//
361337
362338struct 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;
365343 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)
366353};
367354
368355struct EventDesc {
@@ -389,7 +376,7 @@ class SymTabOutput : public std::vector<Symbol> {
389376 SymTabOutput (std::string Objdump, std::string BinaryCacheRoot)
390377 : Objdump(Objdump), BinaryCacheRoot(BinaryCacheRoot) {}
391378
392- uint64_t fetchExecSegment (Map *M) {
379+ void fetchExecSegment (Map *M, uint64_t *FileOffset, uint64_t *VAddr ) {
393380 std::string Cmd = Objdump + " -p -C " +
394381 BinaryCacheRoot + std::string (M->Filename ) +
395382#ifdef _WIN32
@@ -401,7 +388,7 @@ class SymTabOutput : public std::vector<Symbol> {
401388
402389 char *Line = nullptr , *PrevLine = nullptr ;
403390 size_t LineLen = 0 ;
404- uint64_t offset = 0 ;
391+ *FileOffset = *VAddr = 0 ;
405392 while (true ) {
406393 if (PrevLine)
407394 free (PrevLine);
@@ -411,17 +398,22 @@ class SymTabOutput : public std::vector<Symbol> {
411398 if (Len == -1 )
412399 break ;
413400
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" ))
417402 continue ;
418403
419404 /* 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)
421410 break ;
422411
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+
425417 break ;
426418 }
427419 if (Line)
@@ -435,7 +427,6 @@ class SymTabOutput : public std::vector<Symbol> {
435427 fclose (Stream);
436428 wait (NULL );
437429#endif
438- return offset;
439430 }
440431
441432 void fetchSymbols (Map *M) {
@@ -528,15 +519,14 @@ class SymTabOutput : public std::vector<Symbol> {
528519
529520 void reset (Map *M) {
530521 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+
531529 // 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- }
540530 fetchSymbols (M);
541531
542532 std::sort (begin (), end ());
@@ -670,8 +660,7 @@ class PerfReader {
670660 void emitSymbol (
671661 Symbol &Sym, Map &M,
672662 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);
675664 PyObject *complete ();
676665
677666private:
@@ -851,13 +840,11 @@ static uint64_t getTimeFromSampleId(unsigned char *EndOfStruct,
851840void PerfReader::registerNewMapping (unsigned char *Buf, const char *Filename) {
852841 perf_event_mmap_common *E = (perf_event_mmap_common *)Buf;
853842 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+
858844 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);
861848
862849 unsigned char *EndOfEvent = Buf + E->header .size ;
863850 // FIXME: The first EventID is used for every event.
@@ -1025,24 +1012,25 @@ void PerfReader::emitMaps() {
10251012 if (AllUnderThreshold)
10261013 continue ;
10271014
1015+ Map &M = Maps[MapID];
10281016 SymTabOutput Syms (Objdump, BinaryCacheRoot);
1029- Syms.reset (&Maps[MapID] );
1017+ Syms.reset (&M );
10301018
1031- uint64_t Adjust = Maps[MapID]. Adjust ;
1019+ uint64_t VAddrToPCOffset = M. VAddrToFileOffset + M. FileToPCOffset ;
10321020
10331021 // Accumulate the event totals for each symbol
10341022 auto Sym = Syms.begin ();
10351023 auto Event = MapEvents.begin ();
10361024 std::map<uint64_t , std::map<const char *, uint64_t >> SymToEventTotals;
10371025 while (Event != MapEvents.end () && Sym != Syms.end ()) {
10381026 // 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 ) {
10411029 ++Event;
10421030 continue ;
10431031 }
10441032 // Skip symbols until the event is before the end of Sym
1045- if (PC >= Sym->End ) {
1033+ if (VAddr >= Sym->End ) {
10461034 ++Sym;
10471035 continue ;
10481036 }
@@ -1062,26 +1050,28 @@ void PerfReader::emitMaps() {
10621050 }
10631051 }
10641052 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 ]);
10671055 }
10681056 }
10691057}
10701058
10711059void PerfReader::emitSymbol (
10721060 Symbol &Sym, Map &M,
10731061 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 ;
10761064 ObjdumpOutput Dump (Objdump, BinaryCacheRoot);
10771065 Dump.reset (&M, Sym.Start , Sym.End );
10781066
10791067 emitFunctionStart (Sym.Name );
1068+ assert (Sym.Start <= Event->first - VAddrToPCOffset &&
1069+ Event->first - VAddrToPCOffset < Sym.End );
10801070 for (uint64_t I = Dump.next (); I < Sym.End ; I = Dump.next ()) {
1081- auto PC = Event->first - Adjust ;
1071+ auto VAddr = Event->first - VAddrToPCOffset ;
10821072
10831073 auto Text = Dump.getText ();
1084- if (PC == I) {
1074+ if (VAddr == I) {
10851075 emitLine (I, &Event->second , Text);
10861076 ++Event;
10871077 } else {
0 commit comments