1e8d8bef9SDimitry Andric //===-- CommandObjectTraceStartIntelPT.cpp --------------------------------===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric 9e8d8bef9SDimitry Andric #include "CommandObjectTraceStartIntelPT.h" 10fe6060f1SDimitry Andric #include "TraceIntelPT.h" 11fe6060f1SDimitry Andric #include "TraceIntelPTConstants.h" 12e8d8bef9SDimitry Andric #include "lldb/Host/OptionParser.h" 13fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h" 14fe6060f1SDimitry Andric #include "lldb/Target/Process.h" 15e8d8bef9SDimitry Andric #include "lldb/Target/Trace.h" 16*bdd1243dSDimitry Andric #include <optional> 17e8d8bef9SDimitry Andric 18e8d8bef9SDimitry Andric using namespace lldb; 19e8d8bef9SDimitry Andric using namespace lldb_private; 20e8d8bef9SDimitry Andric using namespace lldb_private::trace_intel_pt; 21e8d8bef9SDimitry Andric using namespace llvm; 22e8d8bef9SDimitry Andric 23fe6060f1SDimitry Andric // CommandObjectThreadTraceStartIntelPT 24fe6060f1SDimitry Andric 25e8d8bef9SDimitry Andric #define LLDB_OPTIONS_thread_trace_start_intel_pt 26e8d8bef9SDimitry Andric #include "TraceIntelPTCommandOptions.inc" 27e8d8bef9SDimitry Andric 28fe6060f1SDimitry Andric Status CommandObjectThreadTraceStartIntelPT::CommandOptions::SetOptionValue( 29e8d8bef9SDimitry Andric uint32_t option_idx, llvm::StringRef option_arg, 30e8d8bef9SDimitry Andric ExecutionContext *execution_context) { 31e8d8bef9SDimitry Andric Status error; 32e8d8bef9SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 33e8d8bef9SDimitry Andric 34e8d8bef9SDimitry Andric switch (short_option) { 35e8d8bef9SDimitry Andric case 's': { 36*bdd1243dSDimitry Andric if (std::optional<uint64_t> bytes = 37753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression(option_arg)) 38753f127fSDimitry Andric m_ipt_trace_size = *bytes; 39e8d8bef9SDimitry Andric else 40753f127fSDimitry Andric error.SetErrorStringWithFormat("invalid bytes expression for '%s'", 41753f127fSDimitry Andric option_arg.str().c_str()); 42e8d8bef9SDimitry Andric break; 43e8d8bef9SDimitry Andric } 44fe6060f1SDimitry Andric case 't': { 45fe6060f1SDimitry Andric m_enable_tsc = true; 46fe6060f1SDimitry Andric break; 47fe6060f1SDimitry Andric } 48fe6060f1SDimitry Andric case 'p': { 49fe6060f1SDimitry Andric int64_t psb_period; 50fe6060f1SDimitry Andric if (option_arg.empty() || option_arg.getAsInteger(0, psb_period) || 51fe6060f1SDimitry Andric psb_period < 0) 52e8d8bef9SDimitry Andric error.SetErrorStringWithFormat("invalid integer value for option '%s'", 53e8d8bef9SDimitry Andric option_arg.str().c_str()); 54e8d8bef9SDimitry Andric else 55fe6060f1SDimitry Andric m_psb_period = psb_period; 56e8d8bef9SDimitry Andric break; 57e8d8bef9SDimitry Andric } 58e8d8bef9SDimitry Andric default: 59e8d8bef9SDimitry Andric llvm_unreachable("Unimplemented option"); 60e8d8bef9SDimitry Andric } 61e8d8bef9SDimitry Andric return error; 62e8d8bef9SDimitry Andric } 63e8d8bef9SDimitry Andric 64fe6060f1SDimitry Andric void CommandObjectThreadTraceStartIntelPT::CommandOptions:: 65fe6060f1SDimitry Andric OptionParsingStarting(ExecutionContext *execution_context) { 6681ad6265SDimitry Andric m_ipt_trace_size = kDefaultIptTraceSize; 67fe6060f1SDimitry Andric m_enable_tsc = kDefaultEnableTscValue; 68fe6060f1SDimitry Andric m_psb_period = kDefaultPsbPeriod; 69e8d8bef9SDimitry Andric } 70e8d8bef9SDimitry Andric 71e8d8bef9SDimitry Andric llvm::ArrayRef<OptionDefinition> 72fe6060f1SDimitry Andric CommandObjectThreadTraceStartIntelPT::CommandOptions::GetDefinitions() { 73*bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_trace_start_intel_pt_options); 74e8d8bef9SDimitry Andric } 75e8d8bef9SDimitry Andric 76fe6060f1SDimitry Andric bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads( 77fe6060f1SDimitry Andric Args &command, CommandReturnObject &result, 78fe6060f1SDimitry Andric llvm::ArrayRef<lldb::tid_t> tids) { 7981ad6265SDimitry Andric if (Error err = m_trace.Start(tids, m_options.m_ipt_trace_size, 80fe6060f1SDimitry Andric m_options.m_enable_tsc, m_options.m_psb_period)) 81fe6060f1SDimitry Andric result.SetError(Status(std::move(err))); 82fe6060f1SDimitry Andric else 83e8d8bef9SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 84fe6060f1SDimitry Andric 85fe6060f1SDimitry Andric return result.Succeeded(); 86fe6060f1SDimitry Andric } 87fe6060f1SDimitry Andric 88fe6060f1SDimitry Andric /// CommandObjectProcessTraceStartIntelPT 89fe6060f1SDimitry Andric 90fe6060f1SDimitry Andric #define LLDB_OPTIONS_process_trace_start_intel_pt 91fe6060f1SDimitry Andric #include "TraceIntelPTCommandOptions.inc" 92fe6060f1SDimitry Andric 93fe6060f1SDimitry Andric Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue( 94fe6060f1SDimitry Andric uint32_t option_idx, llvm::StringRef option_arg, 95fe6060f1SDimitry Andric ExecutionContext *execution_context) { 96fe6060f1SDimitry Andric Status error; 97fe6060f1SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 98fe6060f1SDimitry Andric 99fe6060f1SDimitry Andric switch (short_option) { 100fe6060f1SDimitry Andric case 's': { 101*bdd1243dSDimitry Andric if (std::optional<uint64_t> bytes = 102753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression(option_arg)) 103753f127fSDimitry Andric m_ipt_trace_size = *bytes; 104fe6060f1SDimitry Andric else 105753f127fSDimitry Andric error.SetErrorStringWithFormat("invalid bytes expression for '%s'", 106753f127fSDimitry Andric option_arg.str().c_str()); 107fe6060f1SDimitry Andric break; 108fe6060f1SDimitry Andric } 109fe6060f1SDimitry Andric case 'l': { 110*bdd1243dSDimitry Andric if (std::optional<uint64_t> bytes = 111753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression(option_arg)) 112753f127fSDimitry Andric m_process_buffer_size_limit = *bytes; 113fe6060f1SDimitry Andric else 114753f127fSDimitry Andric error.SetErrorStringWithFormat("invalid bytes expression for '%s'", 115753f127fSDimitry Andric option_arg.str().c_str()); 116fe6060f1SDimitry Andric break; 117fe6060f1SDimitry Andric } 118fe6060f1SDimitry Andric case 't': { 119fe6060f1SDimitry Andric m_enable_tsc = true; 120fe6060f1SDimitry Andric break; 121fe6060f1SDimitry Andric } 12281ad6265SDimitry Andric case 'c': { 12381ad6265SDimitry Andric m_per_cpu_tracing = true; 12481ad6265SDimitry Andric break; 12581ad6265SDimitry Andric } 126753f127fSDimitry Andric case 'd': { 127753f127fSDimitry Andric m_disable_cgroup_filtering = true; 128753f127fSDimitry Andric break; 129753f127fSDimitry Andric } 130fe6060f1SDimitry Andric case 'p': { 131fe6060f1SDimitry Andric int64_t psb_period; 132fe6060f1SDimitry Andric if (option_arg.empty() || option_arg.getAsInteger(0, psb_period) || 133fe6060f1SDimitry Andric psb_period < 0) 134fe6060f1SDimitry Andric error.SetErrorStringWithFormat("invalid integer value for option '%s'", 135fe6060f1SDimitry Andric option_arg.str().c_str()); 136fe6060f1SDimitry Andric else 137fe6060f1SDimitry Andric m_psb_period = psb_period; 138fe6060f1SDimitry Andric break; 139fe6060f1SDimitry Andric } 140fe6060f1SDimitry Andric default: 141fe6060f1SDimitry Andric llvm_unreachable("Unimplemented option"); 142fe6060f1SDimitry Andric } 143fe6060f1SDimitry Andric return error; 144fe6060f1SDimitry Andric } 145fe6060f1SDimitry Andric 146fe6060f1SDimitry Andric void CommandObjectProcessTraceStartIntelPT::CommandOptions:: 147fe6060f1SDimitry Andric OptionParsingStarting(ExecutionContext *execution_context) { 14881ad6265SDimitry Andric m_ipt_trace_size = kDefaultIptTraceSize; 149fe6060f1SDimitry Andric m_process_buffer_size_limit = kDefaultProcessBufferSizeLimit; 150fe6060f1SDimitry Andric m_enable_tsc = kDefaultEnableTscValue; 151fe6060f1SDimitry Andric m_psb_period = kDefaultPsbPeriod; 15281ad6265SDimitry Andric m_per_cpu_tracing = kDefaultPerCpuTracing; 153753f127fSDimitry Andric m_disable_cgroup_filtering = kDefaultDisableCgroupFiltering; 154fe6060f1SDimitry Andric } 155fe6060f1SDimitry Andric 156fe6060f1SDimitry Andric llvm::ArrayRef<OptionDefinition> 157fe6060f1SDimitry Andric CommandObjectProcessTraceStartIntelPT::CommandOptions::GetDefinitions() { 158*bdd1243dSDimitry Andric return llvm::ArrayRef(g_process_trace_start_intel_pt_options); 159fe6060f1SDimitry Andric } 160fe6060f1SDimitry Andric 161fe6060f1SDimitry Andric bool CommandObjectProcessTraceStartIntelPT::DoExecute( 162fe6060f1SDimitry Andric Args &command, CommandReturnObject &result) { 163753f127fSDimitry Andric if (Error err = m_trace.Start( 164753f127fSDimitry Andric m_options.m_ipt_trace_size, m_options.m_process_buffer_size_limit, 16581ad6265SDimitry Andric m_options.m_enable_tsc, m_options.m_psb_period, 166753f127fSDimitry Andric m_options.m_per_cpu_tracing, m_options.m_disable_cgroup_filtering)) 167fe6060f1SDimitry Andric result.SetError(Status(std::move(err))); 168fe6060f1SDimitry Andric else 169fe6060f1SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 170fe6060f1SDimitry Andric 171e8d8bef9SDimitry Andric return result.Succeeded(); 172e8d8bef9SDimitry Andric } 173753f127fSDimitry Andric 174*bdd1243dSDimitry Andric std::optional<uint64_t> 175753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression(llvm::StringRef size_expression) { 176753f127fSDimitry Andric if (size_expression.empty()) { 177*bdd1243dSDimitry Andric return std::nullopt; 178753f127fSDimitry Andric } 179753f127fSDimitry Andric const uint64_t kBytesMultiplier = 1; 180753f127fSDimitry Andric const uint64_t kKibiBytesMultiplier = 1024; 181753f127fSDimitry Andric const uint64_t kMebiBytesMultiplier = 1024 * 1024; 182753f127fSDimitry Andric 183753f127fSDimitry Andric DenseMap<StringRef, uint64_t> multipliers = { 184753f127fSDimitry Andric {"mib", kMebiBytesMultiplier}, {"mb", kMebiBytesMultiplier}, 185753f127fSDimitry Andric {"m", kMebiBytesMultiplier}, {"kib", kKibiBytesMultiplier}, 186753f127fSDimitry Andric {"kb", kKibiBytesMultiplier}, {"k", kKibiBytesMultiplier}, 187753f127fSDimitry Andric {"b", kBytesMultiplier}, {"", kBytesMultiplier}}; 188753f127fSDimitry Andric 189753f127fSDimitry Andric const auto non_digit_index = size_expression.find_first_not_of("0123456789"); 190753f127fSDimitry Andric if (non_digit_index == 0) { // expression starts from from non-digit char. 191*bdd1243dSDimitry Andric return std::nullopt; 192753f127fSDimitry Andric } 193753f127fSDimitry Andric 194753f127fSDimitry Andric const llvm::StringRef number_part = 195753f127fSDimitry Andric non_digit_index == llvm::StringRef::npos 196753f127fSDimitry Andric ? size_expression 197753f127fSDimitry Andric : size_expression.substr(0, non_digit_index); 198753f127fSDimitry Andric uint64_t parsed_number; 199753f127fSDimitry Andric if (number_part.getAsInteger(10, parsed_number)) { 200*bdd1243dSDimitry Andric return std::nullopt; 201753f127fSDimitry Andric } 202753f127fSDimitry Andric 203753f127fSDimitry Andric if (non_digit_index != llvm::StringRef::npos) { // if expression has units. 204753f127fSDimitry Andric const auto multiplier = size_expression.substr(non_digit_index).lower(); 205753f127fSDimitry Andric 206753f127fSDimitry Andric auto it = multipliers.find(multiplier); 207753f127fSDimitry Andric if (it == multipliers.end()) 208*bdd1243dSDimitry Andric return std::nullopt; 209753f127fSDimitry Andric 210753f127fSDimitry Andric return parsed_number * it->second; 211753f127fSDimitry Andric } else { 212753f127fSDimitry Andric return parsed_number; 213753f127fSDimitry Andric } 214753f127fSDimitry Andric } 215