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"
16bdd1243dSDimitry 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
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)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': {
36bdd1243dSDimitry 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::
OptionParsingStarting(ExecutionContext * execution_context)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>
GetDefinitions()72fe6060f1SDimitry Andric CommandObjectThreadTraceStartIntelPT::CommandOptions::GetDefinitions() {
73bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_trace_start_intel_pt_options);
74e8d8bef9SDimitry Andric }
75e8d8bef9SDimitry Andric
DoExecuteOnThreads(Args & command,CommandReturnObject & result,llvm::ArrayRef<lldb::tid_t> tids)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
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)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': {
101bdd1243dSDimitry 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': {
110bdd1243dSDimitry 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::
OptionParsingStarting(ExecutionContext * execution_context)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>
GetDefinitions()157fe6060f1SDimitry Andric CommandObjectProcessTraceStartIntelPT::CommandOptions::GetDefinitions() {
158bdd1243dSDimitry Andric return llvm::ArrayRef(g_process_trace_start_intel_pt_options);
159fe6060f1SDimitry Andric }
160fe6060f1SDimitry Andric
DoExecute(Args & command,CommandReturnObject & result)161*297eecfbSDimitry Andric void 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);
170e8d8bef9SDimitry Andric }
171753f127fSDimitry Andric
172bdd1243dSDimitry Andric std::optional<uint64_t>
ParseUserFriendlySizeExpression(llvm::StringRef size_expression)173753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression(llvm::StringRef size_expression) {
174753f127fSDimitry Andric if (size_expression.empty()) {
175bdd1243dSDimitry Andric return std::nullopt;
176753f127fSDimitry Andric }
177753f127fSDimitry Andric const uint64_t kBytesMultiplier = 1;
178753f127fSDimitry Andric const uint64_t kKibiBytesMultiplier = 1024;
179753f127fSDimitry Andric const uint64_t kMebiBytesMultiplier = 1024 * 1024;
180753f127fSDimitry Andric
181753f127fSDimitry Andric DenseMap<StringRef, uint64_t> multipliers = {
182753f127fSDimitry Andric {"mib", kMebiBytesMultiplier}, {"mb", kMebiBytesMultiplier},
183753f127fSDimitry Andric {"m", kMebiBytesMultiplier}, {"kib", kKibiBytesMultiplier},
184753f127fSDimitry Andric {"kb", kKibiBytesMultiplier}, {"k", kKibiBytesMultiplier},
185753f127fSDimitry Andric {"b", kBytesMultiplier}, {"", kBytesMultiplier}};
186753f127fSDimitry Andric
187753f127fSDimitry Andric const auto non_digit_index = size_expression.find_first_not_of("0123456789");
188753f127fSDimitry Andric if (non_digit_index == 0) { // expression starts from from non-digit char.
189bdd1243dSDimitry Andric return std::nullopt;
190753f127fSDimitry Andric }
191753f127fSDimitry Andric
192753f127fSDimitry Andric const llvm::StringRef number_part =
193753f127fSDimitry Andric non_digit_index == llvm::StringRef::npos
194753f127fSDimitry Andric ? size_expression
195753f127fSDimitry Andric : size_expression.substr(0, non_digit_index);
196753f127fSDimitry Andric uint64_t parsed_number;
197753f127fSDimitry Andric if (number_part.getAsInteger(10, parsed_number)) {
198bdd1243dSDimitry Andric return std::nullopt;
199753f127fSDimitry Andric }
200753f127fSDimitry Andric
201753f127fSDimitry Andric if (non_digit_index != llvm::StringRef::npos) { // if expression has units.
202753f127fSDimitry Andric const auto multiplier = size_expression.substr(non_digit_index).lower();
203753f127fSDimitry Andric
204753f127fSDimitry Andric auto it = multipliers.find(multiplier);
205753f127fSDimitry Andric if (it == multipliers.end())
206bdd1243dSDimitry Andric return std::nullopt;
207753f127fSDimitry Andric
208753f127fSDimitry Andric return parsed_number * it->second;
209753f127fSDimitry Andric } else {
210753f127fSDimitry Andric return parsed_number;
211753f127fSDimitry Andric }
212753f127fSDimitry Andric }
213