213 lines · cpp
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-exception6//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 18using namespace lldb;19using namespace lldb_private;20using namespace lldb_private::trace_intel_pt;21using namespace llvm;22 23// CommandObjectThreadTraceStartIntelPT24 25#define LLDB_OPTIONS_thread_trace_start_intel_pt26#include "TraceIntelPTCommandOptions.inc"27 28Status 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 else40 error = Status::FromErrorStringWithFormat(41 "invalid bytes expression for '%s'", 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 = Status::FromErrorStringWithFormat(53 "invalid integer value for option '%s'", option_arg.str().c_str());54 else55 m_psb_period = psb_period;56 break;57 }58 default:59 llvm_unreachable("Unimplemented option");60 }61 return error;62}63 64void 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 71llvm::ArrayRef<OptionDefinition>72CommandObjectThreadTraceStartIntelPT::CommandOptions::GetDefinitions() {73 return llvm::ArrayRef(g_thread_trace_start_intel_pt_options);74}75 76bool 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(std::move(err));82 else83 result.SetStatus(eReturnStatusSuccessFinishResult);84 85 return result.Succeeded();86}87 88/// CommandObjectProcessTraceStartIntelPT89 90#define LLDB_OPTIONS_process_trace_start_intel_pt91#include "TraceIntelPTCommandOptions.inc"92 93Status 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 else105 error = Status::FromErrorStringWithFormat(106 "invalid bytes expression for '%s'", 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 else114 error = Status::FromErrorStringWithFormat(115 "invalid bytes expression for '%s'", 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 = Status::FromErrorStringWithFormat(135 "invalid integer value for option '%s'", option_arg.str().c_str());136 else137 m_psb_period = psb_period;138 break;139 }140 default:141 llvm_unreachable("Unimplemented option");142 }143 return error;144}145 146void 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 156llvm::ArrayRef<OptionDefinition>157CommandObjectProcessTraceStartIntelPT::CommandOptions::GetDefinitions() {158 return llvm::ArrayRef(g_process_trace_start_intel_pt_options);159}160 161void 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(std::move(err));168 else169 result.SetStatus(eReturnStatusSuccessFinishResult);170}171 172std::optional<uint64_t>173ParsingUtils::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::npos194 ? size_expression195 : 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