| /* |
| * Copyright (C) 2026 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "src/trace_processor/shell/traceconv_compat.h" |
| |
| #include <cstddef> |
| #include <string> |
| #include <string_view> |
| #include <vector> |
| |
| namespace perfetto::trace_processor::shell { |
| |
| bool InvokedAsTraceconv(const char* argv0) { |
| std::string_view name(argv0); |
| size_t slash = name.find_last_of("/\\"); |
| if (slash != std::string_view::npos) |
| name = name.substr(slash + 1); |
| constexpr std::string_view kExe = ".exe"; |
| if (name.size() >= kExe.size() && |
| name.substr(name.size() - kExe.size()) == kExe) { |
| name = name.substr(0, name.size() - kExe.size()); |
| } |
| // Match the bare tool name or the prebuilt cache form "traceconv-<sha>", but |
| // not unrelated tools that merely share the prefix (e.g. "traceconverter"). |
| return name == "traceconv" || name.rfind("traceconv-", 0) == 0; |
| } |
| |
| std::vector<std::string> RewriteTraceconvArgs(int argc, char** argv) { |
| // traceconv options that consume a following argument; used to find the MODE |
| // positional regardless of where options appear on the command line. |
| static constexpr const char* kFlagsWithArg[] = { |
| "-t", "--truncate", "--pid", |
| "--timestamps", "--symbol-paths", "--proguard-map", |
| "--output-dir"}; |
| |
| int mode_idx = -1; |
| for (int i = 1; i < argc; ++i) { |
| std::string_view arg(argv[i]); |
| if (!arg.empty() && arg[0] == '-') { |
| for (const char* f : kFlagsWithArg) { |
| if (arg == f) { |
| ++i; // Skip the flag's argument. |
| break; |
| } |
| } |
| continue; |
| } |
| mode_idx = i; |
| break; |
| } |
| if (mode_idx == -1) |
| return {}; |
| |
| std::string_view mode(argv[mode_idx]); |
| |
| // Map the traceconv MODE onto the new subcommand structure. Most modes just |
| // get a subcommand word inserted before them, but a few are renamed (and one |
| // gains a flag) because the underlying CLI moved: |
| // - util utilities: symbolize, deobfuscate, decompress_packets |
| // - "binary" was renamed to "util text_to_binary" |
| // - "java_heap_profile" became "convert profile --java-heap" |
| // - "bundle" is already a subcommand name, so it is left untouched |
| // - anything else is a convert format ('convert' validates it) |
| const char* subcommand = nullptr; |
| const char* replacement_mode = nullptr; // null => keep the original token |
| const char* extra_arg = nullptr; // inserted after the mode, if set |
| if (mode == "symbolize" || mode == "deobfuscate" || |
| mode == "decompress_packets") { |
| subcommand = "util"; |
| } else if (mode == "binary") { |
| subcommand = "util"; |
| replacement_mode = "text_to_binary"; |
| } else if (mode == "java_heap_profile") { |
| subcommand = "convert"; |
| replacement_mode = "profile"; |
| extra_arg = "--java-heap"; |
| } else if (mode != "bundle") { |
| subcommand = "convert"; |
| } |
| if (!subcommand) |
| return {}; |
| |
| std::vector<std::string> out; |
| out.reserve(static_cast<size_t>(argc) + 2); |
| for (int i = 0; i < mode_idx; ++i) |
| out.emplace_back(argv[i]); |
| out.emplace_back(subcommand); |
| out.emplace_back(replacement_mode ? replacement_mode : argv[mode_idx]); |
| if (extra_arg) |
| out.emplace_back(extra_arg); |
| for (int i = mode_idx + 1; i < argc; ++i) |
| out.emplace_back(argv[i]); |
| return out; |
| } |
| |
| } // namespace perfetto::trace_processor::shell |