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" 10e8d8bef9SDimitry Andric 11fe6060f1SDimitry Andric #include "TraceIntelPT.h" 12fe6060f1SDimitry Andric #include "TraceIntelPTConstants.h" 13e8d8bef9SDimitry Andric #include "lldb/Host/OptionParser.h" 14fe6060f1SDimitry Andric #include "lldb/Target/Process.h" 15e8d8bef9SDimitry Andric #include "lldb/Target/Trace.h" 16e8d8bef9SDimitry Andric 17e8d8bef9SDimitry Andric using namespace lldb; 18e8d8bef9SDimitry Andric using namespace lldb_private; 19e8d8bef9SDimitry Andric using namespace lldb_private::trace_intel_pt; 20e8d8bef9SDimitry Andric using namespace llvm; 21e8d8bef9SDimitry Andric 22fe6060f1SDimitry Andric // CommandObjectThreadTraceStartIntelPT 23fe6060f1SDimitry Andric 24e8d8bef9SDimitry Andric #define LLDB_OPTIONS_thread_trace_start_intel_pt 25e8d8bef9SDimitry Andric #include "TraceIntelPTCommandOptions.inc" 26e8d8bef9SDimitry Andric 27fe6060f1SDimitry Andric Status CommandObjectThreadTraceStartIntelPT::CommandOptions::SetOptionValue( 28e8d8bef9SDimitry Andric uint32_t option_idx, llvm::StringRef option_arg, 29e8d8bef9SDimitry Andric ExecutionContext *execution_context) { 30e8d8bef9SDimitry Andric Status error; 31e8d8bef9SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 32e8d8bef9SDimitry Andric 33e8d8bef9SDimitry Andric switch (short_option) { 34e8d8bef9SDimitry Andric case 's': { 35*753f127fSDimitry Andric if (Optional<uint64_t> bytes = 36*753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression(option_arg)) 37*753f127fSDimitry Andric m_ipt_trace_size = *bytes; 38e8d8bef9SDimitry Andric else 39*753f127fSDimitry Andric error.SetErrorStringWithFormat("invalid bytes expression for '%s'", 40*753f127fSDimitry Andric option_arg.str().c_str()); 41e8d8bef9SDimitry Andric break; 42e8d8bef9SDimitry Andric } 43fe6060f1SDimitry Andric case 't': { 44fe6060f1SDimitry Andric m_enable_tsc = true; 45fe6060f1SDimitry Andric break; 46fe6060f1SDimitry Andric } 47fe6060f1SDimitry Andric case 'p': { 48fe6060f1SDimitry Andric int64_t psb_period; 49fe6060f1SDimitry Andric if (option_arg.empty() || option_arg.getAsInteger(0, psb_period) || 50fe6060f1SDimitry Andric psb_period < 0) 51e8d8bef9SDimitry Andric error.SetErrorStringWithFormat("invalid integer value for option '%s'", 52e8d8bef9SDimitry Andric option_arg.str().c_str()); 53e8d8bef9SDimitry Andric else 54fe6060f1SDimitry Andric m_psb_period = psb_period; 55e8d8bef9SDimitry Andric break; 56e8d8bef9SDimitry Andric } 57e8d8bef9SDimitry Andric default: 58e8d8bef9SDimitry Andric llvm_unreachable("Unimplemented option"); 59e8d8bef9SDimitry Andric } 60e8d8bef9SDimitry Andric return error; 61e8d8bef9SDimitry Andric } 62e8d8bef9SDimitry Andric 63fe6060f1SDimitry Andric void CommandObjectThreadTraceStartIntelPT::CommandOptions:: 64fe6060f1SDimitry Andric OptionParsingStarting(ExecutionContext *execution_context) { 6581ad6265SDimitry Andric m_ipt_trace_size = kDefaultIptTraceSize; 66fe6060f1SDimitry Andric m_enable_tsc = kDefaultEnableTscValue; 67fe6060f1SDimitry Andric m_psb_period = kDefaultPsbPeriod; 68e8d8bef9SDimitry Andric } 69e8d8bef9SDimitry Andric 70e8d8bef9SDimitry Andric llvm::ArrayRef<OptionDefinition> 71fe6060f1SDimitry Andric CommandObjectThreadTraceStartIntelPT::CommandOptions::GetDefinitions() { 72e8d8bef9SDimitry Andric return llvm::makeArrayRef(g_thread_trace_start_intel_pt_options); 73e8d8bef9SDimitry Andric } 74e8d8bef9SDimitry Andric 75fe6060f1SDimitry Andric bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads( 76fe6060f1SDimitry Andric Args &command, CommandReturnObject &result, 77fe6060f1SDimitry Andric llvm::ArrayRef<lldb::tid_t> tids) { 7881ad6265SDimitry Andric if (Error err = m_trace.Start(tids, m_options.m_ipt_trace_size, 79fe6060f1SDimitry Andric m_options.m_enable_tsc, m_options.m_psb_period)) 80fe6060f1SDimitry Andric result.SetError(Status(std::move(err))); 81fe6060f1SDimitry Andric else 82e8d8bef9SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 83fe6060f1SDimitry Andric 84fe6060f1SDimitry Andric return result.Succeeded(); 85fe6060f1SDimitry Andric } 86fe6060f1SDimitry Andric 87fe6060f1SDimitry Andric /// CommandObjectProcessTraceStartIntelPT 88fe6060f1SDimitry Andric 89fe6060f1SDimitry Andric #define LLDB_OPTIONS_process_trace_start_intel_pt 90fe6060f1SDimitry Andric #include "TraceIntelPTCommandOptions.inc" 91fe6060f1SDimitry Andric 92fe6060f1SDimitry Andric Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue( 93fe6060f1SDimitry Andric uint32_t option_idx, llvm::StringRef option_arg, 94fe6060f1SDimitry Andric ExecutionContext *execution_context) { 95fe6060f1SDimitry Andric Status error; 96fe6060f1SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 97fe6060f1SDimitry Andric 98fe6060f1SDimitry Andric switch (short_option) { 99fe6060f1SDimitry Andric case 's': { 100*753f127fSDimitry Andric if (Optional<uint64_t> bytes = 101*753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression(option_arg)) 102*753f127fSDimitry Andric m_ipt_trace_size = *bytes; 103fe6060f1SDimitry Andric else 104*753f127fSDimitry Andric error.SetErrorStringWithFormat("invalid bytes expression for '%s'", 105*753f127fSDimitry Andric option_arg.str().c_str()); 106fe6060f1SDimitry Andric break; 107fe6060f1SDimitry Andric } 108fe6060f1SDimitry Andric case 'l': { 109*753f127fSDimitry Andric if (Optional<uint64_t> bytes = 110*753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression(option_arg)) 111*753f127fSDimitry Andric m_process_buffer_size_limit = *bytes; 112fe6060f1SDimitry Andric else 113*753f127fSDimitry Andric error.SetErrorStringWithFormat("invalid bytes expression for '%s'", 114*753f127fSDimitry Andric option_arg.str().c_str()); 115fe6060f1SDimitry Andric break; 116fe6060f1SDimitry Andric } 117fe6060f1SDimitry Andric case 't': { 118fe6060f1SDimitry Andric m_enable_tsc = true; 119fe6060f1SDimitry Andric break; 120fe6060f1SDimitry Andric } 12181ad6265SDimitry Andric case 'c': { 12281ad6265SDimitry Andric m_per_cpu_tracing = true; 12381ad6265SDimitry Andric break; 12481ad6265SDimitry Andric } 125*753f127fSDimitry Andric case 'd': { 126*753f127fSDimitry Andric m_disable_cgroup_filtering = true; 127*753f127fSDimitry Andric break; 128*753f127fSDimitry Andric } 129fe6060f1SDimitry Andric case 'p': { 130fe6060f1SDimitry Andric int64_t psb_period; 131fe6060f1SDimitry Andric if (option_arg.empty() || option_arg.getAsInteger(0, psb_period) || 132fe6060f1SDimitry Andric psb_period < 0) 133fe6060f1SDimitry Andric error.SetErrorStringWithFormat("invalid integer value for option '%s'", 134fe6060f1SDimitry Andric option_arg.str().c_str()); 135fe6060f1SDimitry Andric else 136fe6060f1SDimitry Andric m_psb_period = psb_period; 137fe6060f1SDimitry Andric break; 138fe6060f1SDimitry Andric } 139fe6060f1SDimitry Andric default: 140fe6060f1SDimitry Andric llvm_unreachable("Unimplemented option"); 141fe6060f1SDimitry Andric } 142fe6060f1SDimitry Andric return error; 143fe6060f1SDimitry Andric } 144fe6060f1SDimitry Andric 145fe6060f1SDimitry Andric void CommandObjectProcessTraceStartIntelPT::CommandOptions:: 146fe6060f1SDimitry Andric OptionParsingStarting(ExecutionContext *execution_context) { 14781ad6265SDimitry Andric m_ipt_trace_size = kDefaultIptTraceSize; 148fe6060f1SDimitry Andric m_process_buffer_size_limit = kDefaultProcessBufferSizeLimit; 149fe6060f1SDimitry Andric m_enable_tsc = kDefaultEnableTscValue; 150fe6060f1SDimitry Andric m_psb_period = kDefaultPsbPeriod; 15181ad6265SDimitry Andric m_per_cpu_tracing = kDefaultPerCpuTracing; 152*753f127fSDimitry Andric m_disable_cgroup_filtering = kDefaultDisableCgroupFiltering; 153fe6060f1SDimitry Andric } 154fe6060f1SDimitry Andric 155fe6060f1SDimitry Andric llvm::ArrayRef<OptionDefinition> 156fe6060f1SDimitry Andric CommandObjectProcessTraceStartIntelPT::CommandOptions::GetDefinitions() { 157fe6060f1SDimitry Andric return llvm::makeArrayRef(g_process_trace_start_intel_pt_options); 158fe6060f1SDimitry Andric } 159fe6060f1SDimitry Andric 160fe6060f1SDimitry Andric bool CommandObjectProcessTraceStartIntelPT::DoExecute( 161fe6060f1SDimitry Andric Args &command, CommandReturnObject &result) { 162*753f127fSDimitry Andric if (Error err = m_trace.Start( 163*753f127fSDimitry Andric m_options.m_ipt_trace_size, m_options.m_process_buffer_size_limit, 16481ad6265SDimitry Andric m_options.m_enable_tsc, m_options.m_psb_period, 165*753f127fSDimitry Andric m_options.m_per_cpu_tracing, m_options.m_disable_cgroup_filtering)) 166fe6060f1SDimitry Andric result.SetError(Status(std::move(err))); 167fe6060f1SDimitry Andric else 168fe6060f1SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 169fe6060f1SDimitry Andric 170e8d8bef9SDimitry Andric return result.Succeeded(); 171e8d8bef9SDimitry Andric } 172*753f127fSDimitry Andric 173*753f127fSDimitry Andric Optional<uint64_t> 174*753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression(llvm::StringRef size_expression) { 175*753f127fSDimitry Andric if (size_expression.empty()) { 176*753f127fSDimitry Andric return llvm::None; 177*753f127fSDimitry Andric } 178*753f127fSDimitry Andric const uint64_t kBytesMultiplier = 1; 179*753f127fSDimitry Andric const uint64_t kKibiBytesMultiplier = 1024; 180*753f127fSDimitry Andric const uint64_t kMebiBytesMultiplier = 1024 * 1024; 181*753f127fSDimitry Andric 182*753f127fSDimitry Andric DenseMap<StringRef, uint64_t> multipliers = { 183*753f127fSDimitry Andric {"mib", kMebiBytesMultiplier}, {"mb", kMebiBytesMultiplier}, 184*753f127fSDimitry Andric {"m", kMebiBytesMultiplier}, {"kib", kKibiBytesMultiplier}, 185*753f127fSDimitry Andric {"kb", kKibiBytesMultiplier}, {"k", kKibiBytesMultiplier}, 186*753f127fSDimitry Andric {"b", kBytesMultiplier}, {"", kBytesMultiplier}}; 187*753f127fSDimitry Andric 188*753f127fSDimitry Andric const auto non_digit_index = size_expression.find_first_not_of("0123456789"); 189*753f127fSDimitry Andric if (non_digit_index == 0) { // expression starts from from non-digit char. 190*753f127fSDimitry Andric return llvm::None; 191*753f127fSDimitry Andric } 192*753f127fSDimitry Andric 193*753f127fSDimitry Andric const llvm::StringRef number_part = 194*753f127fSDimitry Andric non_digit_index == llvm::StringRef::npos 195*753f127fSDimitry Andric ? size_expression 196*753f127fSDimitry Andric : size_expression.substr(0, non_digit_index); 197*753f127fSDimitry Andric uint64_t parsed_number; 198*753f127fSDimitry Andric if (number_part.getAsInteger(10, parsed_number)) { 199*753f127fSDimitry Andric return llvm::None; 200*753f127fSDimitry Andric } 201*753f127fSDimitry Andric 202*753f127fSDimitry Andric if (non_digit_index != llvm::StringRef::npos) { // if expression has units. 203*753f127fSDimitry Andric const auto multiplier = size_expression.substr(non_digit_index).lower(); 204*753f127fSDimitry Andric 205*753f127fSDimitry Andric auto it = multipliers.find(multiplier); 206*753f127fSDimitry Andric if (it == multipliers.end()) 207*753f127fSDimitry Andric return llvm::None; 208*753f127fSDimitry Andric 209*753f127fSDimitry Andric return parsed_number * it->second; 210*753f127fSDimitry Andric } else { 211*753f127fSDimitry Andric return parsed_number; 212*753f127fSDimitry Andric } 213*753f127fSDimitry Andric } 214