Simpleperf: add branch stack feature in perf.data.

Also add the function to remove old perf.data.

Bug: 19483574

Change-Id: I605bb637674d4674f95503a160de8c530fe87812
diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp
index 9245d18..e5e239b 100644
--- a/simpleperf/cmd_dumprecord.cpp
+++ b/simpleperf/cmd_dumprecord.cpp
@@ -134,7 +134,7 @@
       {FEAT_EVENT_DESC, "event_desc"},
       {FEAT_CPU_TOPOLOGY, "cpu_topology"},
       {FEAT_NUMA_TOPOLOGY, "numa_topology"},
-      {FEAT_BRANCH_STACK, "branck_stack"},
+      {FEAT_BRANCH_STACK, "branch_stack"},
       {FEAT_PMU_MAPPINGS, "pmu_mappings"},
       {FEAT_GROUP_DESC, "group_desc"},
   };
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 7cd7ec8..2ceeed0 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -377,10 +377,17 @@
 }
 
 bool RecordCommand::DumpAdditionalFeatures() {
-  if (!record_file_writer_->WriteFeatureHeader(1)) {
+  size_t feature_count = (branch_sampling_ != 0 ? 2 : 1);
+  if (!record_file_writer_->WriteFeatureHeader(feature_count)) {
     return false;
   }
-  return DumpBuildIdFeature();
+  if (!DumpBuildIdFeature()) {
+    return false;
+  }
+  if (branch_sampling_ != 0 && !record_file_writer_->WriteBranchStackFeature()) {
+    return false;
+  }
+  return true;
 }
 
 bool RecordCommand::DumpBuildIdFeature() {
diff --git a/simpleperf/record_file.cpp b/simpleperf/record_file.cpp
index 360d842..2a7c6a1 100644
--- a/simpleperf/record_file.cpp
+++ b/simpleperf/record_file.cpp
@@ -35,6 +35,10 @@
 std::unique_ptr<RecordFileWriter> RecordFileWriter::CreateInstance(
     const std::string& filename, const perf_event_attr& event_attr,
     const std::vector<std::unique_ptr<EventFd>>& event_fds) {
+  // Remove old perf.data to avoid file ownership problems.
+  if (!RemovePossibleFile(filename)) {
+    return nullptr;
+  }
   FILE* fp = fopen(filename.c_str(), "web+");
   if (fp == nullptr) {
     PLOG(ERROR) << "failed to open record file '" << filename << "'";
@@ -191,16 +195,11 @@
     PLOG(ERROR) << "fflush() failed";
     return false;
   }
-  if (fseek(record_fp_, 0, SEEK_END) == -1) {
-    PLOG(ERROR) << "fseek() failed";
+  uint64_t file_size;
+  if (!SeekFileEnd(&file_size)) {
     return false;
   }
-  long file_size = ftell(record_fp_);
-  if (file_size == -1) {
-    PLOG(ERROR) << "ftell() failed";
-    return false;
-  }
-  size_t mmap_len = file_size;
+  size_t mmap_len = static_cast<size_t>(file_size);
   void* mmap_addr = mmap(nullptr, mmap_len, PROT_READ, MAP_SHARED, fileno(record_fp_), 0);
   if (mmap_addr == MAP_FAILED) {
     PLOG(ERROR) << "mmap() failed";
@@ -217,6 +216,20 @@
   return true;
 }
 
+bool RecordFileWriter::SeekFileEnd(uint64_t* file_end) {
+  if (fseek(record_fp_, 0, SEEK_END) == -1) {
+    PLOG(ERROR) << "fseek() failed";
+    return false;
+  }
+  long offset = ftell(record_fp_);
+  if (offset == -1) {
+    PLOG(ERROR) << "ftell() failed";
+    return false;
+  }
+  *file_end = static_cast<uint64_t>(offset);
+  return true;
+}
+
 bool RecordFileWriter::WriteFeatureHeader(size_t feature_count) {
   feature_count_ = feature_count;
   current_feature_index_ = 0;
@@ -232,17 +245,10 @@
 }
 
 bool RecordFileWriter::WriteBuildIdFeature(const std::vector<BuildIdRecord>& build_id_records) {
-  if (current_feature_index_ >= feature_count_) {
-    return false;
-  }
+  CHECK_LT(current_feature_index_, feature_count_);
   // Always write features at the end of the file.
-  if (fseek(record_fp_, 0, SEEK_END) == -1) {
-    PLOG(ERROR) << "fseek() failed";
-    return false;
-  }
-  long section_start = ftell(record_fp_);
-  if (section_start == -1) {
-    PLOG(ERROR) << "ftell() failed";
+  uint64_t start_offset;
+  if (!SeekFileEnd(&start_offset)) {
     return false;
   }
   for (auto& record : build_id_records) {
@@ -251,18 +257,41 @@
       return false;
     }
   }
-  long section_end = ftell(record_fp_);
-  if (section_end == -1) {
+  uint64_t end_offset;
+  if (!SeekFileEnd(&end_offset)) {
     return false;
   }
 
-  // Write feature section descriptor for build_id feature.
+  if (!ModifyFeatureSectionDescriptor(current_feature_index_, start_offset,
+                                      end_offset - start_offset)) {
+    return false;
+  }
+  ++current_feature_index_;
+  features_.push_back(FEAT_BUILD_ID);
+  return true;
+}
+
+bool RecordFileWriter::WriteBranchStackFeature() {
+  CHECK_LT(current_feature_index_, feature_count_);
+  uint64_t start_offset;
+  if (!SeekFileEnd(&start_offset)) {
+    return false;
+  }
+  if (!ModifyFeatureSectionDescriptor(current_feature_index_, start_offset, 0)) {
+    return false;
+  }
+  ++current_feature_index_;
+  features_.push_back(FEAT_BRANCH_STACK);
+  return true;
+}
+
+bool RecordFileWriter::ModifyFeatureSectionDescriptor(size_t feature_index, uint64_t offset,
+                                                      uint64_t size) {
   SectionDesc desc;
-  desc.offset = section_start;
-  desc.size = section_end - section_start;
+  desc.offset = offset;
+  desc.size = size;
   uint64_t feature_offset = data_section_offset_ + data_section_size_;
-  if (fseek(record_fp_, feature_offset + current_feature_index_ * sizeof(SectionDesc), SEEK_SET) ==
-      -1) {
+  if (fseek(record_fp_, feature_offset + feature_index * sizeof(SectionDesc), SEEK_SET) == -1) {
     PLOG(ERROR) << "fseek() failed";
     return false;
   }
@@ -270,8 +299,6 @@
     PLOG(ERROR) << "fwrite() failed";
     return false;
   }
-  ++current_feature_index_;
-  features_.push_back(FEAT_BUILD_ID);
   return true;
 }
 
diff --git a/simpleperf/record_file.h b/simpleperf/record_file.h
index 694486c..e217b3c 100644
--- a/simpleperf/record_file.h
+++ b/simpleperf/record_file.h
@@ -52,6 +52,7 @@
 
   bool WriteFeatureHeader(size_t feature_count);
   bool WriteBuildIdFeature(const std::vector<BuildIdRecord>& build_id_records);
+  bool WriteBranchStackFeature();
 
   // Normally, Close() should be called after writing. But if something
   // wrong happens and we need to finish in advance, the destructor
@@ -67,6 +68,8 @@
                              std::vector<std::string>* hit_user_files);
   bool WriteFileHeader();
   bool Write(const void* buf, size_t len);
+  bool SeekFileEnd(uint64_t* file_end);
+  bool ModifyFeatureSectionDescriptor(size_t feature_index, uint64_t offset, uint64_t size);
 
   const std::string filename_;
   FILE* record_fp_;
diff --git a/simpleperf/utils.cpp b/simpleperf/utils.cpp
index 5062504..783bc8f 100644
--- a/simpleperf/utils.cpp
+++ b/simpleperf/utils.cpp
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include <base/logging.h>
@@ -66,3 +67,18 @@
   }
   closedir(dir);
 }
+
+bool RemovePossibleFile(const std::string& filename) {
+  struct stat st;
+  if (stat(filename.c_str(), &st) == 0) {
+    if (!S_ISREG(st.st_mode)) {
+      LOG(ERROR) << filename << " is not a file.";
+      return false;
+    }
+    if (unlink(filename.c_str()) == -1) {
+      PLOG(ERROR) << "unlink(" << filename << ") failed";
+      return false;
+    }
+  }
+  return true;
+}
diff --git a/simpleperf/utils.h b/simpleperf/utils.h
index f54e698..43c09be 100644
--- a/simpleperf/utils.h
+++ b/simpleperf/utils.h
@@ -78,5 +78,6 @@
 
 void GetEntriesInDir(const std::string& dirpath, std::vector<std::string>* files,
                      std::vector<std::string>* subdirs);
+bool RemovePossibleFile(const std::string& filename);
 
 #endif  // SIMPLE_PERF_UTILS_H_