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