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