diff --git a/src/perf_data_handler.cc b/src/perf_data_handler.cc index b5bc75d5..e5840bbe 100644 --- a/src/perf_data_handler.cc +++ b/src/perf_data_handler.cc @@ -7,10 +7,15 @@ #include "src/perf_data_handler.h" +#include + #include +#include #include +#include #include #include +#include #include #include #include @@ -196,6 +201,10 @@ class Normalizer { // finds the build ID according to the filename from the mmap. BuildId GetBuildId(const quipper::PerfDataProto_MMapEvent* mmap); + void ConvertMmapFromKsymbol( + const quipper::PerfDataProto_KsymbolEvent& ksymbol_event, uint32_t prot, + quipper::PerfDataProto_MMapEvent* mmap); + // Copy the parent's mmaps/comm if they exist. Otherwise, items // will be lazily populated. void UpdateMapsWithMMapEvent(const quipper::PerfDataProto_MMapEvent* mmap); @@ -214,6 +223,9 @@ class Normalizer { // records to parse potential samples. void HandleSpeAuxtrace(const quipper::PerfDataProto::PerfEvent& event_proto); + // Handles the ksymbol event in event_proto. + void HandleKsymbol(const quipper::PerfDataProto::PerfEvent& event_proto); + // Handles the perf LOST event or LOST_SAMPLE event. void HandleLost(const quipper::PerfDataProto::PerfEvent& event_proto); @@ -449,6 +461,8 @@ void Normalizer::Normalize() { } else if (event_proto.has_auxtrace_error_event()) { LOG(WARNING) << "auxtrace_error event: " << event_proto.auxtrace_error_event().msg(); + } else if (event_proto.has_ksymbol_event()) { + HandleKsymbol(event_proto); } } @@ -535,7 +549,7 @@ void Normalizer::HandleSample( context.branch_stack.resize(sample.branch_stack_size()); for (int i = 0; i < sample.branch_stack_size(); ++i) { stat_.branch_stack_ips += 2; - auto entry = sample.branch_stack(i); + const auto& entry = sample.branch_stack(i); // from context.branch_stack[i].from.ip = entry.from_ip(); context.branch_stack[i].from.mapping = @@ -714,6 +728,25 @@ static bool IsVirtualMapping(const std::string& map_name) { HasPrefixString(map_name, "[anon:"); } +void Normalizer::ConvertMmapFromKsymbol( + const quipper::PerfDataProto_KsymbolEvent& ksymbol_event, uint32_t prot, + quipper::PerfDataProto_MMapEvent* mmap) { + uint32_t pid = 1; + uint32_t tid = 1; + uint32_t flags = 0; + uint64_t pgoff = 0; + mmap->set_pid(pid); + mmap->set_tid(tid); + mmap->set_flags(flags); + mmap->set_pgoff(pgoff); + mmap->set_prot(prot); + mmap->set_start(ksymbol_event.addr()); + mmap->set_len(ksymbol_event.len()); + // TODO(go/gwp-bpf-name-breakdown): Need to do post-processing on `filename`. + mmap->set_filename(ksymbol_event.name()); + *mmap->mutable_sample_info() = ksymbol_event.sample_info(); +} + void Normalizer::UpdateMapsWithMMapEvent( const quipper::PerfDataProto_MMapEvent* mmap) { if (mmap->len() == 0) { @@ -920,6 +953,18 @@ void Normalizer::HandleSpeAuxtrace( } } +void Normalizer::HandleKsymbol( + const quipper::PerfDataProto::PerfEvent& event_proto) { + quipper::PerfDataProto_MMapEvent mmap; + if (event_proto.ksymbol_event().ksym_type() == + quipper::PERF_RECORD_KSYMBOL_TYPE_BPF && + event_proto.ksymbol_event().flags() == 0) { + uint32_t prot = PROT_EXEC | PROT_READ; + ConvertMmapFromKsymbol(event_proto.ksymbol_event(), prot, &mmap); + UpdateMapsWithMMapEvent(&mmap); + } +} + } // namespace // Finds needle in haystack starting at cursor. It then returns the index diff --git a/src/perf_data_handler_test.cc b/src/perf_data_handler_test.cc index 248967eb..c3039669 100644 --- a/src/perf_data_handler_test.cc +++ b/src/perf_data_handler_test.cc @@ -131,6 +131,14 @@ class TestPerfDataHandler : public PerfDataHandler { } } + void CheckNotEmptyFilenames() { + EXPECT_EQ(1, seen_filenames_.size()); + for (auto const& filename : seen_filenames_) { + EXPECT_TRUE(expected_filename_to_build_id_.find(filename) != + expected_filename_to_build_id_.end()); + } + } + const std::vector>& SeenAddrMappings() const { return seen_addr_mappings_; } @@ -550,6 +558,31 @@ TEST(PerfDataHandlerTest, SpeAuxtraceIntoSamples) { EXPECT_EQ(sample_events[1].pid(), 2); } +TEST(PerfDataHandlerTest, KsymbolIntoMappings) { + quipper::PerfDataProto proto; + std::string mock_filename = "bpf_prog_bec4c5629f7c7e2d_netcg_bind4"; + + // File attrs are required for sample event processing. + uint64_t file_attr_id = 0; + auto* file_attr = proto.add_file_attrs(); + file_attr->add_ids(file_attr_id); + + // Add a ksymbol event. + auto* ksymbol_event = proto.add_events()->mutable_ksymbol_event(); + ksymbol_event->set_addr(0x1000); + ksymbol_event->set_len(0x500); + ksymbol_event->set_ksym_type(quipper::PERF_RECORD_KSYMBOL_TYPE_BPF); + ksymbol_event->set_flags(0); + ksymbol_event->set_name(mock_filename); + + std::unordered_map expected_filename_to_build_id; + expected_filename_to_build_id[mock_filename] = ""; + TestPerfDataHandler handler(std::vector{}, + expected_filename_to_build_id); + PerfDataHandler::Process(proto, &handler); + handler.CheckSeenFilenames(); +} + } // namespace perftools int main(int argc, char** argv) {