* synced up.
*
\*===----------------------------------------------------------------------===*/
+#include <string.h>
#ifdef _MSC_VER
#define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop))
(uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129)
// The version number of the raw binary format.
-#define MEMPROF_RAW_VERSION 2ULL
+#define MEMPROF_RAW_VERSION 3ULL
+
+#define MEMPROF_BUILDID_MAX_SIZE 32ULL
namespace llvm {
namespace memprof {
uint64_t StackOffset;
});
-
// A struct describing the information necessary to describe a /proc/maps
// segment entry for a particular binary/library identified by its build id.
PACKED(struct SegmentEntry {
uint64_t Start;
uint64_t End;
uint64_t Offset;
- // This field is unused until sanitizer procmaps support for build ids for
- // Linux-Elf is implemented.
- uint8_t BuildId[32] = {0};
+ uint64_t BuildIdSize;
+ uint8_t BuildId[MEMPROF_BUILDID_MAX_SIZE] = {0};
- SegmentEntry(uint64_t S, uint64_t E, uint64_t O) :
- Start(S), End(E), Offset(O) {}
+ // This constructor is only used in tests so don't set the BuildId.
+ SegmentEntry(uint64_t S, uint64_t E, uint64_t O)
+ : Start(S), End(E), Offset(O), BuildIdSize(0) {}
SegmentEntry(const SegmentEntry& S) {
Start = S.Start;
End = S.End;
Offset = S.Offset;
+ BuildIdSize = S.BuildIdSize;
+ memcpy(BuildId, S.BuildId, S.BuildIdSize);
}
SegmentEntry& operator=(const SegmentEntry& S) {
Start = S.Start;
End = S.End;
Offset = S.Offset;
+ BuildIdSize = S.BuildIdSize;
+ memcpy(BuildId, S.BuildId, S.BuildIdSize);
return *this;
}
bool operator==(const SegmentEntry& S) const {
- return Start == S.Start &&
- End == S.End &&
- Offset == S.Offset;
+ return Start == S.Start && End == S.End && Offset == S.Offset &&
+ BuildIdSize == S.BuildIdSize &&
+ memcmp(BuildId, S.BuildId, S.BuildIdSize) == 0;
}
});
#include "sanitizer_common/sanitizer_allocator_checks.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_allocator_report.h"
+#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_file.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
-#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include <sched.h>
// memprof_rawprofile.h.
char *Buffer = nullptr;
- MemoryMappingLayout Layout(/*cache_enabled=*/true);
- u64 BytesSerialized = SerializeToRawProfile(MIBMap, Layout, Buffer);
+ __sanitizer::ListOfModules Modules;
+ Modules.init();
+ u64 BytesSerialized = SerializeToRawProfile(MIBMap, Modules, Buffer);
CHECK(Buffer && BytesSerialized && "could not serialize to buffer");
report_file.Write(Buffer, BytesSerialized);
}
}
} // namespace
-u64 SegmentSizeBytes(MemoryMappingLayoutBase &Layout) {
+u64 SegmentSizeBytes(__sanitizer::ListOfModules &Modules) {
u64 NumSegmentsToRecord = 0;
- MemoryMappedSegment segment;
- for (Layout.Reset(); Layout.Next(&segment);)
- if (segment.IsReadable() && segment.IsExecutable())
- NumSegmentsToRecord++;
+ for (const auto &Module : Modules) {
+ for (const auto &Segment : Module.ranges()) {
+ if (Segment.executable)
+ NumSegmentsToRecord++;
+ }
+ }
return sizeof(u64) // A header which stores the number of records.
+ sizeof(SegmentEntry) * NumSegmentsToRecord;
// Start
// End
// Offset
-// BuildID 32B
+// UuidSize
+// Uuid 32B
// ----------
// ...
-void SerializeSegmentsToBuffer(MemoryMappingLayoutBase &Layout,
+void SerializeSegmentsToBuffer(__sanitizer::ListOfModules &Modules,
const u64 ExpectedNumBytes, char *&Buffer) {
char *Ptr = Buffer;
// Reserve space for the final count.
Ptr += sizeof(u64);
u64 NumSegmentsRecorded = 0;
- MemoryMappedSegment segment;
-
- for (Layout.Reset(); Layout.Next(&segment);) {
- if (segment.IsReadable() && segment.IsExecutable()) {
- // TODO: Record segment.uuid when it is implemented for Linux-Elf.
- SegmentEntry Entry(segment.start, segment.end, segment.offset);
- memcpy(Ptr, &Entry, sizeof(SegmentEntry));
- Ptr += sizeof(SegmentEntry);
- NumSegmentsRecorded++;
+
+ for (const auto &Module : Modules) {
+ for (const auto &Segment : Module.ranges()) {
+ if (Segment.executable) {
+ SegmentEntry Entry(Segment.beg, Segment.end, Module.base_address());
+ CHECK(Module.uuid_size() <= MEMPROF_BUILDID_MAX_SIZE);
+ Entry.BuildIdSize = Module.uuid_size();
+ memcpy(Entry.BuildId, Module.uuid(), Module.uuid_size());
+ memcpy(Ptr, &Entry, sizeof(SegmentEntry));
+ Ptr += sizeof(SegmentEntry);
+ NumSegmentsRecorded++;
+ }
}
}
-
// Store the number of segments we recorded in the space we reserved.
*((u64 *)Buffer) = NumSegmentsRecorded;
CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
// ----------
// Optional Padding Bytes
// ...
-u64 SerializeToRawProfile(MIBMapTy &MIBMap, MemoryMappingLayoutBase &Layout,
+u64 SerializeToRawProfile(MIBMapTy &MIBMap, __sanitizer::ListOfModules &Modules,
char *&Buffer) {
// Each section size is rounded up to 8b since the first entry in each section
// is a u64 which holds the number of entries in the section by convention.
- const u64 NumSegmentBytes = RoundUpTo(SegmentSizeBytes(Layout), 8);
+ const u64 NumSegmentBytes = RoundUpTo(SegmentSizeBytes(Modules), 8);
Vector<u64> StackIds;
MIBMap.ForEach(RecordStackId, reinterpret_cast<void *>(&StackIds));
sizeof(Header) + NumSegmentBytes + NumMIBInfoBytes};
Ptr = WriteBytes(header, Ptr);
- SerializeSegmentsToBuffer(Layout, NumSegmentBytes, Ptr);
+ SerializeSegmentsToBuffer(Modules, NumSegmentBytes, Ptr);
Ptr += NumSegmentBytes;
SerializeMIBInfoToBuffer(MIBMap, StackIds, NumMIBInfoBytes, Ptr);
#define MEMPROF_RAWPROFILE_H_
#include "memprof_mibmap.h"
-#include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_common.h"
namespace __memprof {
// Serialize the in-memory representation of the memprof profile to the raw
// binary format. The format itself is documented memprof_rawprofile.cpp.
-u64 SerializeToRawProfile(MIBMapTy &BlockCache, MemoryMappingLayoutBase &Layout,
- char *&Buffer);
+u64 SerializeToRawProfile(MIBMapTy &BlockCache,
+ __sanitizer::ListOfModules &Modules, char *&Buffer);
} // namespace __memprof
#endif // MEMPROF_RAWPROFILE_H_
* synced up.
*
\*===----------------------------------------------------------------------===*/
+#include <string.h>
#ifdef _MSC_VER
#define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop))
(uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129)
// The version number of the raw binary format.
-#define MEMPROF_RAW_VERSION 2ULL
+#define MEMPROF_RAW_VERSION 3ULL
+
+#define MEMPROF_BUILDID_MAX_SIZE 32ULL
namespace llvm {
namespace memprof {
uint64_t StackOffset;
});
-
// A struct describing the information necessary to describe a /proc/maps
// segment entry for a particular binary/library identified by its build id.
PACKED(struct SegmentEntry {
uint64_t Start;
uint64_t End;
uint64_t Offset;
- // This field is unused until sanitizer procmaps support for build ids for
- // Linux-Elf is implemented.
- uint8_t BuildId[32] = {0};
+ uint64_t BuildIdSize;
+ uint8_t BuildId[MEMPROF_BUILDID_MAX_SIZE] = {0};
- SegmentEntry(uint64_t S, uint64_t E, uint64_t O) :
- Start(S), End(E), Offset(O) {}
+ // This constructor is only used in tests so don't set the BuildId.
+ SegmentEntry(uint64_t S, uint64_t E, uint64_t O)
+ : Start(S), End(E), Offset(O), BuildIdSize(0) {}
SegmentEntry(const SegmentEntry& S) {
Start = S.Start;
End = S.End;
Offset = S.Offset;
+ BuildIdSize = S.BuildIdSize;
+ memcpy(BuildId, S.BuildId, S.BuildIdSize);
}
SegmentEntry& operator=(const SegmentEntry& S) {
Start = S.Start;
End = S.End;
Offset = S.Offset;
+ BuildIdSize = S.BuildIdSize;
+ memcpy(BuildId, S.BuildId, S.BuildIdSize);
return *this;
}
bool operator==(const SegmentEntry& S) const {
- return Start == S.Start &&
- End == S.End &&
- Offset == S.Offset;
+ return Start == S.Start && End == S.End && Offset == S.Offset &&
+ BuildIdSize == S.BuildIdSize &&
+ memcmp(BuildId, S.BuildId, S.BuildIdSize) == 0;
}
});
}
std::string getBuildIdString(const SegmentEntry &Entry) {
- constexpr size_t Size = sizeof(Entry.BuildId) / sizeof(uint8_t);
- constexpr uint8_t Zeros[Size] = {0};
// If the build id is unset print a helpful string instead of all zeros.
- if (memcmp(Entry.BuildId, Zeros, Size) == 0)
+ if (Entry.BuildIdSize == 0)
return "<None>";
std::string Str;
raw_string_ostream OS(Str);
- for (size_t I = 0; I < Size; I++) {
+ for (size_t I = 0; I < Entry.BuildIdSize; I++) {
OS << format_hex_no_prefix(Entry.BuildId[I], 2);
}
return OS.str();
INPUTS["inline"]="INLINE"
INPUTS["multi"]="MULTI"
INPUTS["pic"]="BASIC;-pie"
+INPUTS["buildid"]="BASIC;-Wl,-build-id=sha1"
for name in "${!INPUTS[@]}"; do
IFS=";" read -r src flags <<< "${INPUTS[$name]}"
CHECK: MemprofProfile:
CHECK-NEXT: Summary:
-CHECK-NEXT: Version: 2
+CHECK-NEXT: Version: 3
CHECK-NEXT: NumSegments: {{[0-9]+}}
CHECK-NEXT: NumMibInfo: 2
CHECK-NEXT: NumAllocFunctions: 1
CHECK-NEXT: NumStackOffsets: 2
CHECK-NEXT: Segments:
CHECK-NEXT: -
-CHECK-NEXT: BuildId: <None>
-CHECK-NEXT: Start: 0x{{[0-9]+}}
-CHECK-NEXT: End: 0x{{[0-9]+}}
-CHECK-NEXT: Offset: 0x{{[0-9]+}}
+CHECK-NEXT: BuildId: {{[[:xdigit:]]+}}
+CHECK-NEXT: Start: 0x{{[[:xdigit:]]+}}
+CHECK-NEXT: End: 0x{{[[:xdigit:]]+}}
+CHECK-NEXT: Offset: 0x{{[[:xdigit:]]+}}
CHECK-NEXT: -
CHECK: Records:
--- /dev/null
+REQUIRES: x86_64-linux
+
+To update the inputs used below run Inputs/update_memprof_inputs.sh /path/to/updated/clang
+RUN: llvm-readelf --notes %p/Inputs/buildid.memprofexe > %t1.txt
+RUN: llvm-profdata show --memory %p/Inputs/buildid.memprofraw --profiled-binary %p/Inputs/buildid.memprofexe -o - > %t2.txt
+RUN: cat %t1.txt %t2.txt | FileCheck %s
+
+COM: First extract the id from the llvm-readelf output.
+CHECK: Build ID: [[ID:[[:xdigit:]]+]]
+
+COM: Then match it with the profdata output.
+CHECK: BuildId: {{.*}}[[ID]]
CHECK: MemprofProfile:
CHECK-NEXT: Summary:
-CHECK-NEXT: Version: 2
+CHECK-NEXT: Version: 3
CHECK-NEXT: NumSegments: {{[0-9]+}}
CHECK-NEXT: NumMibInfo: 2
CHECK-NEXT: NumAllocFunctions: 2
CHECK-NEXT: NumStackOffsets: 1
CHECK-NEXT: Segments:
CHECK-NEXT: -
-CHECK-NEXT: BuildId: <None>
-CHECK-NEXT: Start: 0x{{[0-9]+}}
-CHECK-NEXT: End: 0x{{[0-9]+}}
-CHECK-NEXT: Offset: 0x{{[0-9]+}}
+CHECK-NEXT: BuildId: {{[[:xdigit:]]+}}
+CHECK-NEXT: Start: 0x{{[[:xdigit:]]+}}
+CHECK-NEXT: End: 0x{{[[:xdigit:]]+}}
+CHECK-NEXT: Offset: 0x{{[[:xdigit:]]+}}
CHECK-NEXT: -
CHECK: Records:
CHECK: MemprofProfile:
CHECK-NEXT: Summary:
-CHECK-NEXT: Version: 2
+CHECK-NEXT: Version: 3
CHECK-NEXT: NumSegments: {{[0-9]+}}
CHECK-NEXT: NumMibInfo: 2
CHECK-NEXT: NumAllocFunctions: 1