summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--simpleperf/cmd_record.cpp105
-rw-r--r--simpleperf/cmd_record_test.cpp9
2 files changed, 79 insertions, 35 deletions
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index b4d9328a..60677a7c 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -1887,59 +1887,94 @@ void RecordCommand::CollectHitFileInfo(const SampleRecord& r) {
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);
- return true;
- }
+ 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;
}
- } 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 (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.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, "");
+ }
+ }
+ 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;
}
- 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 efaebc6f..612a9302 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::Realpath;
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, exclude_perf_option) {
}
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 @@ TEST(record_cmd, ParseAddrFilterOption) {
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");