Merge "simpleperf: fix arch in RegSet."
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index b4d9328..60677a7 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -1887,59 +1887,94 @@
 
 namespace simpleperf {
 
+static bool ConsumeStr(const char*& p, const char* s) {
+  if (strncmp(p, s, strlen(s)) == 0) {
+    p += strlen(s);
+    return true;
+  }
+  return false;
+}
+
+static bool ConsumeAddr(const char*& p, uint64_t* addr) {
+  errno = 0;
+  char* end;
+  *addr = strtoull(p, &end, 0);
+  if (errno == 0 && p != end) {
+    p = end;
+    return true;
+  }
+  return false;
+}
+
 // To reduce function length, not all format errors are checked.
 static bool ParseOneAddrFilter(const std::string& s, std::vector<AddrFilter>* filters) {
-  std::vector<std::string> args = android::base::Split(s, " -@");
-  std::unique_ptr<ElfFile> elf;
+  std::vector<std::string> args = android::base::Split(s, " ");
+  if (args.size() != 2) {
+    return false;
+  }
+
   uint64_t addr1;
   uint64_t addr2;
   uint64_t off1;
   uint64_t off2;
   std::string path;
 
-  if (args[0] == "start" || args[0] == "stop") {
-    if (args.size() >= 2 && ParseUint(args[1], &addr1)) {
-      if (args.size() == 2) {
-        // start <kernel_addr>  || stop <kernel_addr>
-        filters->emplace_back(
-            args[0] == "start" ? AddrFilter::KERNEL_START : AddrFilter::KERNEL_STOP, addr1, 0, "");
-        return true;
-      }
-      if (auto elf = ElfFile::Open(args[2]);
-          elf && elf->VaddrToOff(addr1, &off1) && Realpath(args[2], &path)) {
-        // start <vaddr>@<file_path> || stop <vaddr>@<file_path>
-        filters->emplace_back(args[0] == "start" ? AddrFilter::FILE_START : AddrFilter::FILE_STOP,
-                              off1, 0, path);
+  if (auto p = s.data(); ConsumeStr(p, "start") && ConsumeAddr(p, &addr1)) {
+    if (*p == '\0') {
+      // start <kernel_addr>
+      filters->emplace_back(AddrFilter::KERNEL_START, addr1, 0, "");
+      return true;
+    }
+    if (ConsumeStr(p, "@") && *p != '\0') {
+      // start <vaddr>@<file_path>
+      if (auto elf = ElfFile::Open(p); elf && elf->VaddrToOff(addr1, &off1) && Realpath(p, &path)) {
+        filters->emplace_back(AddrFilter::FILE_START, off1, 0, path);
         return true;
       }
     }
-  } else if (args[0] == "filter") {
-    if (args.size() == 2) {
-      // filter <file_path>
-      if (auto elf = ElfFile::Open(args[1]); elf) {
-        for (const ElfSegment& seg : elf->GetProgramHeader()) {
-          if (seg.is_executable) {
-            filters->emplace_back(AddrFilter::FILE_RANGE, seg.file_offset, seg.file_size, args[1]);
-          }
-        }
+  }
+  if (auto p = s.data(); ConsumeStr(p, "stop") && ConsumeAddr(p, &addr1)) {
+    if (*p == '\0') {
+      // stop <kernel_addr>
+      filters->emplace_back(AddrFilter::KERNEL_STOP, addr1, 0, "");
+      return true;
+    }
+    if (ConsumeStr(p, "@") && *p != '\0') {
+      // stop <vaddr>@<file_path>
+      if (auto elf = ElfFile::Open(p); elf && elf->VaddrToOff(addr1, &off1) && Realpath(p, &path)) {
+        filters->emplace_back(AddrFilter::FILE_STOP, off1, 0, path);
         return true;
       }
-    } else if (args.size() >= 3 && ParseUint(args[1], &addr1) && ParseUint(args[2], &addr2) &&
-               addr1 < addr2) {
-      if (args.size() == 3) {
-        // filter <kernel_addr_start>-<kernel_addr_end>
-        filters->emplace_back(AddrFilter::KERNEL_RANGE, addr1, addr2 - addr1, "");
-        return true;
-      }
-      if (auto elf = ElfFile::Open(args[3]); elf && elf->VaddrToOff(addr1, &off1) &&
-                                             elf->VaddrToOff(addr2, &off2) &&
-                                             Realpath(args[3], &path)) {
-        // filter <vaddr_start>-<vaddr_end>@<file_path>
+    }
+  }
+  if (auto p = s.data(); ConsumeStr(p, "filter") && ConsumeAddr(p, &addr1) && ConsumeStr(p, "-") &&
+                         ConsumeAddr(p, &addr2)) {
+    if (*p == '\0') {
+      // filter <kernel_addr_start>-<kernel_addr_end>
+      filters->emplace_back(AddrFilter::KERNEL_RANGE, addr1, addr2 - addr1, "");
+      return true;
+    }
+    if (ConsumeStr(p, "@") && *p != '\0') {
+      // filter <vaddr_start>-<vaddr_end>@<file_path>
+      if (auto elf = ElfFile::Open(p); elf && elf->VaddrToOff(addr1, &off1) &&
+                                       elf->VaddrToOff(addr2, &off2) && Realpath(p, &path)) {
         filters->emplace_back(AddrFilter::FILE_RANGE, off1, off2 - off1, path);
         return true;
       }
     }
   }
+  if (auto p = s.data(); ConsumeStr(p, "filter") && *p != '\0') {
+    // filter <file_path>
+    path = android::base::Trim(p);
+    if (auto elf = ElfFile::Open(path); elf) {
+      for (const ElfSegment& seg : elf->GetProgramHeader()) {
+        if (seg.is_executable) {
+          filters->emplace_back(AddrFilter::FILE_RANGE, seg.file_offset, seg.file_size, path);
+        }
+      }
+      return true;
+    }
+  }
   return false;
 }
 
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index efaebc6..612a930 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -29,6 +29,7 @@
 #include <android-base/properties.h>
 #endif
 
+#include <filesystem>
 #include <map>
 #include <memory>
 #include <regex>
@@ -51,6 +52,7 @@
 using android::base::StringPrintf;
 using namespace simpleperf;
 using namespace PerfFileFormat;
+namespace fs = std::filesystem;
 
 static std::unique_ptr<Command> RecordCmd() {
   return CreateCommandInstance("record");
@@ -969,6 +971,7 @@
 }
 
 TEST(record_cmd, tp_filter_option) {
+  TEST_REQUIRE_HOST_ROOT();
   TEST_REQUIRE_TRACEPOINT_EVENTS();
   // Test string operands both with quotes and without quotes.
   for (const auto& filter :
@@ -1008,6 +1011,12 @@
   ASSERT_EQ(option_to_str("start 0x400502@" + path + ",stop 0x400527@" + path),
             "start 0x502@" + path + ",stop 0x527@" + path);
 
+  // Test '-' in file path. Create a temporary file with '-' in name.
+  TemporaryDir tmpdir;
+  fs::path tmpfile = fs::path(tmpdir.path) / "elf-with-hyphen";
+  ASSERT_TRUE(fs::copy_file(path, tmpfile));
+  ASSERT_EQ(option_to_str("filter " + tmpfile.string()), "filter 0x0/0x73c@" + tmpfile.string());
+
   // Test kernel filters.
   ASSERT_EQ(option_to_str("filter 0x12345678-0x1234567a"), "filter 0x12345678/0x2");
   ASSERT_EQ(option_to_str("start 0x12345678,stop 0x1234567a"), "start 0x12345678,stop 0x1234567a");