diff options
-rw-r--r-- | simpleperf/cmd_record.cpp | 105 | ||||
-rw-r--r-- | simpleperf/cmd_record_test.cpp | 9 |
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"); |