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