1 | //===-- CommandObjectLog.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 "CommandObjectLog.h" |
10 | #include "lldb/Core/Debugger.h" |
11 | #include "lldb/Host/OptionParser.h" |
12 | #include "lldb/Interpreter/CommandOptionArgumentTable.h" |
13 | #include "lldb/Interpreter/CommandReturnObject.h" |
14 | #include "lldb/Interpreter/OptionArgParser.h" |
15 | #include "lldb/Interpreter/OptionValueEnumeration.h" |
16 | #include "lldb/Interpreter/OptionValueUInt64.h" |
17 | #include "lldb/Interpreter/Options.h" |
18 | #include "lldb/Utility/Args.h" |
19 | #include "lldb/Utility/FileSpec.h" |
20 | #include "lldb/Utility/Log.h" |
21 | #include "lldb/Utility/Stream.h" |
22 | #include "lldb/Utility/Timer.h" |
23 | |
24 | using namespace lldb; |
25 | using namespace lldb_private; |
26 | |
27 | #define LLDB_OPTIONS_log_enable |
28 | #include "CommandOptions.inc" |
29 | |
30 | #define LLDB_OPTIONS_log_dump |
31 | #include "CommandOptions.inc" |
32 | |
33 | /// Common completion logic for log enable/disable. |
34 | static void CompleteEnableDisable(CompletionRequest &request) { |
35 | size_t arg_index = request.GetCursorIndex(); |
36 | if (arg_index == 0) { // We got: log enable/disable x[tab] |
37 | for (llvm::StringRef channel : Log::ListChannels()) |
38 | request.TryCompleteCurrentArg(completion: channel); |
39 | } else if (arg_index >= 1) { // We got: log enable/disable channel x[tab] |
40 | llvm::StringRef channel = request.GetParsedLine().GetArgumentAtIndex(idx: 0); |
41 | Log::ForEachChannelCategory( |
42 | channel, lambda: [&request](llvm::StringRef name, llvm::StringRef desc) { |
43 | request.TryCompleteCurrentArg(completion: name, description: desc); |
44 | }); |
45 | } |
46 | } |
47 | |
48 | class CommandObjectLogEnable : public CommandObjectParsed { |
49 | public: |
50 | // Constructors and Destructors |
51 | CommandObjectLogEnable(CommandInterpreter &interpreter) |
52 | : CommandObjectParsed(interpreter, "log enable", |
53 | "Enable logging for a single log channel.", |
54 | nullptr) { |
55 | CommandArgumentEntry arg1; |
56 | CommandArgumentEntry arg2; |
57 | CommandArgumentData channel_arg; |
58 | CommandArgumentData category_arg; |
59 | |
60 | // Define the first (and only) variant of this arg. |
61 | channel_arg.arg_type = eArgTypeLogChannel; |
62 | channel_arg.arg_repetition = eArgRepeatPlain; |
63 | |
64 | // There is only one variant this argument could be; put it into the |
65 | // argument entry. |
66 | arg1.push_back(x: channel_arg); |
67 | |
68 | category_arg.arg_type = eArgTypeLogCategory; |
69 | category_arg.arg_repetition = eArgRepeatPlus; |
70 | |
71 | arg2.push_back(x: category_arg); |
72 | |
73 | // Push the data for the first argument into the m_arguments vector. |
74 | m_arguments.push_back(x: arg1); |
75 | m_arguments.push_back(x: arg2); |
76 | } |
77 | |
78 | ~CommandObjectLogEnable() override = default; |
79 | |
80 | Options *GetOptions() override { return &m_options; } |
81 | |
82 | class CommandOptions : public Options { |
83 | public: |
84 | CommandOptions() = default; |
85 | |
86 | ~CommandOptions() override = default; |
87 | |
88 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
89 | ExecutionContext *execution_context) override { |
90 | Status error; |
91 | const int short_option = m_getopt_table[option_idx].val; |
92 | |
93 | switch (short_option) { |
94 | case 'f': |
95 | log_file.SetFile(path: option_arg, style: FileSpec::Style::native); |
96 | FileSystem::Instance().Resolve(file_spec&: log_file); |
97 | break; |
98 | case 'h': |
99 | handler = (LogHandlerKind)OptionArgParser::ToOptionEnum( |
100 | s: option_arg, enum_values: GetDefinitions()[option_idx].enum_values, fail_value: 0, error); |
101 | if (!error.Success()) |
102 | return Status::FromErrorStringWithFormatv( |
103 | format: "unrecognized value for log handler '{0}'", args&: option_arg); |
104 | break; |
105 | case 'b': |
106 | return buffer_size.SetValueFromString(value: option_arg, |
107 | op: eVarSetOperationAssign); |
108 | case 'v': |
109 | log_options |= LLDB_LOG_OPTION_VERBOSE; |
110 | break; |
111 | case 's': |
112 | log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; |
113 | break; |
114 | case 'T': |
115 | log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; |
116 | break; |
117 | case 'p': |
118 | log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD; |
119 | break; |
120 | case 'n': |
121 | log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; |
122 | break; |
123 | case 'S': |
124 | log_options |= LLDB_LOG_OPTION_BACKTRACE; |
125 | break; |
126 | case 'a': |
127 | log_options |= LLDB_LOG_OPTION_APPEND; |
128 | break; |
129 | case 'F': |
130 | log_options |= LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION; |
131 | break; |
132 | default: |
133 | llvm_unreachable("Unimplemented option"); |
134 | } |
135 | |
136 | return error; |
137 | } |
138 | |
139 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
140 | log_file.Clear(); |
141 | buffer_size.Clear(); |
142 | handler = eLogHandlerStream; |
143 | log_options = 0; |
144 | } |
145 | |
146 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
147 | return llvm::ArrayRef(g_log_enable_options); |
148 | } |
149 | |
150 | FileSpec log_file; |
151 | OptionValueUInt64 buffer_size; |
152 | LogHandlerKind handler = eLogHandlerStream; |
153 | uint32_t log_options = 0; |
154 | }; |
155 | |
156 | void |
157 | HandleArgumentCompletion(CompletionRequest &request, |
158 | OptionElementVector &opt_element_vector) override { |
159 | CompleteEnableDisable(request); |
160 | } |
161 | |
162 | protected: |
163 | void DoExecute(Args &args, CommandReturnObject &result) override { |
164 | if (args.GetArgumentCount() < 2) { |
165 | result.AppendErrorWithFormat( |
166 | format: "%s takes a log channel and one or more log types.\n", |
167 | m_cmd_name.c_str()); |
168 | return; |
169 | } |
170 | |
171 | if (m_options.handler == eLogHandlerCircular && |
172 | m_options.buffer_size.GetCurrentValue() == 0) { |
173 | result.AppendError( |
174 | in_string: "the circular buffer handler requires a non-zero buffer size.\n"); |
175 | return; |
176 | } |
177 | |
178 | if ((m_options.handler != eLogHandlerCircular && |
179 | m_options.handler != eLogHandlerStream) && |
180 | m_options.buffer_size.GetCurrentValue() != 0) { |
181 | result.AppendError(in_string: "a buffer size can only be specified for the circular " |
182 | "and stream buffer handler.\n"); |
183 | return; |
184 | } |
185 | |
186 | if (m_options.handler != eLogHandlerStream && m_options.log_file) { |
187 | result.AppendError( |
188 | in_string: "a file name can only be specified for the stream handler.\n"); |
189 | return; |
190 | } |
191 | |
192 | // Store into a std::string since we're about to shift the channel off. |
193 | const std::string channel = std::string(args[0].ref()); |
194 | args.Shift(); // Shift off the channel |
195 | char log_file[PATH_MAX]; |
196 | if (m_options.log_file) |
197 | m_options.log_file.GetPath(path: log_file, max_path_length: sizeof(log_file)); |
198 | else |
199 | log_file[0] = '\0'; |
200 | |
201 | std::string error; |
202 | llvm::raw_string_ostream error_stream(error); |
203 | bool success = GetDebugger().EnableLog( |
204 | channel, categories: args.GetArgumentArrayRef(), log_file, log_options: m_options.log_options, |
205 | buffer_size: m_options.buffer_size.GetCurrentValue(), log_handler_kind: m_options.handler, |
206 | error_stream); |
207 | result.GetErrorStream() << error; |
208 | |
209 | if (success) |
210 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
211 | else |
212 | result.SetStatus(eReturnStatusFailed); |
213 | } |
214 | |
215 | CommandOptions m_options; |
216 | }; |
217 | |
218 | class CommandObjectLogDisable : public CommandObjectParsed { |
219 | public: |
220 | // Constructors and Destructors |
221 | CommandObjectLogDisable(CommandInterpreter &interpreter) |
222 | : CommandObjectParsed(interpreter, "log disable", |
223 | "Disable one or more log channel categories.", |
224 | nullptr) { |
225 | CommandArgumentEntry arg1; |
226 | CommandArgumentEntry arg2; |
227 | CommandArgumentData channel_arg; |
228 | CommandArgumentData category_arg; |
229 | |
230 | // Define the first (and only) variant of this arg. |
231 | channel_arg.arg_type = eArgTypeLogChannel; |
232 | channel_arg.arg_repetition = eArgRepeatPlain; |
233 | |
234 | // There is only one variant this argument could be; put it into the |
235 | // argument entry. |
236 | arg1.push_back(x: channel_arg); |
237 | |
238 | category_arg.arg_type = eArgTypeLogCategory; |
239 | category_arg.arg_repetition = eArgRepeatPlus; |
240 | |
241 | arg2.push_back(x: category_arg); |
242 | |
243 | // Push the data for the first argument into the m_arguments vector. |
244 | m_arguments.push_back(x: arg1); |
245 | m_arguments.push_back(x: arg2); |
246 | } |
247 | |
248 | ~CommandObjectLogDisable() override = default; |
249 | |
250 | void |
251 | HandleArgumentCompletion(CompletionRequest &request, |
252 | OptionElementVector &opt_element_vector) override { |
253 | CompleteEnableDisable(request); |
254 | } |
255 | |
256 | protected: |
257 | void DoExecute(Args &args, CommandReturnObject &result) override { |
258 | if (args.empty()) { |
259 | result.AppendErrorWithFormat( |
260 | format: "%s takes a log channel and one or more log types.\n", |
261 | m_cmd_name.c_str()); |
262 | return; |
263 | } |
264 | |
265 | const std::string channel = std::string(args[0].ref()); |
266 | args.Shift(); // Shift off the channel |
267 | if (channel == "all") { |
268 | Log::DisableAllLogChannels(); |
269 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
270 | } else { |
271 | std::string error; |
272 | llvm::raw_string_ostream error_stream(error); |
273 | if (Log::DisableLogChannel(channel, categories: args.GetArgumentArrayRef(), |
274 | error_stream)) |
275 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
276 | result.GetErrorStream() << error; |
277 | } |
278 | } |
279 | }; |
280 | |
281 | class CommandObjectLogList : public CommandObjectParsed { |
282 | public: |
283 | // Constructors and Destructors |
284 | CommandObjectLogList(CommandInterpreter &interpreter) |
285 | : CommandObjectParsed(interpreter, "log list", |
286 | "List the log categories for one or more log " |
287 | "channels. If none specified, lists them all.", |
288 | nullptr) { |
289 | AddSimpleArgumentList(arg_type: eArgTypeLogChannel, repetition_type: eArgRepeatStar); |
290 | } |
291 | |
292 | ~CommandObjectLogList() override = default; |
293 | |
294 | void |
295 | HandleArgumentCompletion(CompletionRequest &request, |
296 | OptionElementVector &opt_element_vector) override { |
297 | for (llvm::StringRef channel : Log::ListChannels()) |
298 | request.TryCompleteCurrentArg(completion: channel); |
299 | } |
300 | |
301 | protected: |
302 | void DoExecute(Args &args, CommandReturnObject &result) override { |
303 | std::string output; |
304 | llvm::raw_string_ostream output_stream(output); |
305 | if (args.empty()) { |
306 | Log::ListAllLogChannels(stream&: output_stream); |
307 | result.SetStatus(eReturnStatusSuccessFinishResult); |
308 | } else { |
309 | bool success = true; |
310 | for (const auto &entry : args.entries()) |
311 | success = |
312 | success && Log::ListChannelCategories(channel: entry.ref(), stream&: output_stream); |
313 | if (success) |
314 | result.SetStatus(eReturnStatusSuccessFinishResult); |
315 | } |
316 | result.GetOutputStream() << output; |
317 | } |
318 | }; |
319 | class CommandObjectLogDump : public CommandObjectParsed { |
320 | public: |
321 | CommandObjectLogDump(CommandInterpreter &interpreter) |
322 | : CommandObjectParsed(interpreter, "log dump", |
323 | "dump circular buffer logs", nullptr) { |
324 | AddSimpleArgumentList(arg_type: eArgTypeLogChannel); |
325 | } |
326 | |
327 | ~CommandObjectLogDump() override = default; |
328 | |
329 | Options *GetOptions() override { return &m_options; } |
330 | |
331 | class CommandOptions : public Options { |
332 | public: |
333 | CommandOptions() = default; |
334 | |
335 | ~CommandOptions() override = default; |
336 | |
337 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
338 | ExecutionContext *execution_context) override { |
339 | Status error; |
340 | const int short_option = m_getopt_table[option_idx].val; |
341 | |
342 | switch (short_option) { |
343 | case 'f': |
344 | log_file.SetFile(path: option_arg, style: FileSpec::Style::native); |
345 | FileSystem::Instance().Resolve(file_spec&: log_file); |
346 | break; |
347 | default: |
348 | llvm_unreachable("Unimplemented option"); |
349 | } |
350 | |
351 | return error; |
352 | } |
353 | |
354 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
355 | log_file.Clear(); |
356 | } |
357 | |
358 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
359 | return llvm::ArrayRef(g_log_dump_options); |
360 | } |
361 | |
362 | FileSpec log_file; |
363 | }; |
364 | |
365 | void |
366 | HandleArgumentCompletion(CompletionRequest &request, |
367 | OptionElementVector &opt_element_vector) override { |
368 | CompleteEnableDisable(request); |
369 | } |
370 | |
371 | protected: |
372 | void DoExecute(Args &args, CommandReturnObject &result) override { |
373 | if (args.empty()) { |
374 | result.AppendErrorWithFormat( |
375 | format: "%s takes a log channel and one or more log types.\n", |
376 | m_cmd_name.c_str()); |
377 | return; |
378 | } |
379 | |
380 | std::unique_ptr<llvm::raw_ostream> stream_up; |
381 | if (m_options.log_file) { |
382 | const File::OpenOptions flags = File::eOpenOptionWriteOnly | |
383 | File::eOpenOptionCanCreate | |
384 | File::eOpenOptionTruncate; |
385 | llvm::Expected<FileUP> file = FileSystem::Instance().Open( |
386 | file_spec: m_options.log_file, options: flags, permissions: lldb::eFilePermissionsFileDefault, should_close_fd: false); |
387 | if (!file) { |
388 | result.AppendErrorWithFormat(format: "Unable to open log file '%s': %s", |
389 | m_options.log_file.GetPath().c_str(), |
390 | llvm::toString(E: file.takeError()).c_str()); |
391 | return; |
392 | } |
393 | stream_up = std::make_unique<llvm::raw_fd_ostream>( |
394 | args: (*file)->GetDescriptor(), /*shouldClose=*/args: true); |
395 | } else { |
396 | stream_up = std::make_unique<llvm::raw_fd_ostream>( |
397 | args: GetDebugger().GetOutputFileSP()->GetDescriptor(), |
398 | /*shouldClose=*/args: false); |
399 | } |
400 | |
401 | const std::string channel = std::string(args[0].ref()); |
402 | std::string error; |
403 | llvm::raw_string_ostream error_stream(error); |
404 | if (Log::DumpLogChannel(channel, output_stream&: *stream_up, error_stream)) { |
405 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
406 | } else { |
407 | result.SetStatus(eReturnStatusFailed); |
408 | result.GetErrorStream() << error; |
409 | } |
410 | } |
411 | |
412 | CommandOptions m_options; |
413 | }; |
414 | |
415 | class CommandObjectLogTimerEnable : public CommandObjectParsed { |
416 | public: |
417 | // Constructors and Destructors |
418 | CommandObjectLogTimerEnable(CommandInterpreter &interpreter) |
419 | : CommandObjectParsed(interpreter, "log timers enable", |
420 | "enable LLDB internal performance timers", |
421 | "log timers enable <depth>") { |
422 | AddSimpleArgumentList(arg_type: eArgTypeCount, repetition_type: eArgRepeatOptional); |
423 | } |
424 | |
425 | ~CommandObjectLogTimerEnable() override = default; |
426 | |
427 | protected: |
428 | void DoExecute(Args &args, CommandReturnObject &result) override { |
429 | result.SetStatus(eReturnStatusFailed); |
430 | |
431 | if (args.GetArgumentCount() == 0) { |
432 | Timer::SetDisplayDepth(UINT32_MAX); |
433 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
434 | } else if (args.GetArgumentCount() == 1) { |
435 | uint32_t depth; |
436 | if (args[0].ref().consumeInteger(Radix: 0, Result&: depth)) { |
437 | result.AppendError( |
438 | in_string: "Could not convert enable depth to an unsigned integer."); |
439 | } else { |
440 | Timer::SetDisplayDepth(depth); |
441 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
442 | } |
443 | } |
444 | |
445 | if (!result.Succeeded()) { |
446 | result.AppendError(in_string: "Missing subcommand"); |
447 | result.AppendErrorWithFormat(format: "Usage: %s\n", m_cmd_syntax.c_str()); |
448 | } |
449 | } |
450 | }; |
451 | |
452 | class CommandObjectLogTimerDisable : public CommandObjectParsed { |
453 | public: |
454 | // Constructors and Destructors |
455 | CommandObjectLogTimerDisable(CommandInterpreter &interpreter) |
456 | : CommandObjectParsed(interpreter, "log timers disable", |
457 | "disable LLDB internal performance timers", |
458 | nullptr) {} |
459 | |
460 | ~CommandObjectLogTimerDisable() override = default; |
461 | |
462 | protected: |
463 | void DoExecute(Args &args, CommandReturnObject &result) override { |
464 | Timer::DumpCategoryTimes(s&: result.GetOutputStream()); |
465 | Timer::SetDisplayDepth(0); |
466 | result.SetStatus(eReturnStatusSuccessFinishResult); |
467 | |
468 | if (!result.Succeeded()) { |
469 | result.AppendError(in_string: "Missing subcommand"); |
470 | result.AppendErrorWithFormat(format: "Usage: %s\n", m_cmd_syntax.c_str()); |
471 | } |
472 | } |
473 | }; |
474 | |
475 | class CommandObjectLogTimerDump : public CommandObjectParsed { |
476 | public: |
477 | // Constructors and Destructors |
478 | CommandObjectLogTimerDump(CommandInterpreter &interpreter) |
479 | : CommandObjectParsed(interpreter, "log timers dump", |
480 | "dump LLDB internal performance timers", nullptr) {} |
481 | |
482 | ~CommandObjectLogTimerDump() override = default; |
483 | |
484 | protected: |
485 | void DoExecute(Args &args, CommandReturnObject &result) override { |
486 | Timer::DumpCategoryTimes(s&: result.GetOutputStream()); |
487 | result.SetStatus(eReturnStatusSuccessFinishResult); |
488 | |
489 | if (!result.Succeeded()) { |
490 | result.AppendError(in_string: "Missing subcommand"); |
491 | result.AppendErrorWithFormat(format: "Usage: %s\n", m_cmd_syntax.c_str()); |
492 | } |
493 | } |
494 | }; |
495 | |
496 | class CommandObjectLogTimerReset : public CommandObjectParsed { |
497 | public: |
498 | // Constructors and Destructors |
499 | CommandObjectLogTimerReset(CommandInterpreter &interpreter) |
500 | : CommandObjectParsed(interpreter, "log timers reset", |
501 | "reset LLDB internal performance timers", nullptr) { |
502 | } |
503 | |
504 | ~CommandObjectLogTimerReset() override = default; |
505 | |
506 | protected: |
507 | void DoExecute(Args &args, CommandReturnObject &result) override { |
508 | Timer::ResetCategoryTimes(); |
509 | result.SetStatus(eReturnStatusSuccessFinishResult); |
510 | |
511 | if (!result.Succeeded()) { |
512 | result.AppendError(in_string: "Missing subcommand"); |
513 | result.AppendErrorWithFormat(format: "Usage: %s\n", m_cmd_syntax.c_str()); |
514 | } |
515 | } |
516 | }; |
517 | |
518 | class CommandObjectLogTimerIncrement : public CommandObjectParsed { |
519 | public: |
520 | // Constructors and Destructors |
521 | CommandObjectLogTimerIncrement(CommandInterpreter &interpreter) |
522 | : CommandObjectParsed(interpreter, "log timers increment", |
523 | "increment LLDB internal performance timers", |
524 | "log timers increment <bool>") { |
525 | AddSimpleArgumentList(arg_type: eArgTypeBoolean); |
526 | } |
527 | |
528 | ~CommandObjectLogTimerIncrement() override = default; |
529 | |
530 | void |
531 | HandleArgumentCompletion(CompletionRequest &request, |
532 | OptionElementVector &opt_element_vector) override { |
533 | request.TryCompleteCurrentArg(completion: "true"); |
534 | request.TryCompleteCurrentArg(completion: "false"); |
535 | } |
536 | |
537 | protected: |
538 | void DoExecute(Args &args, CommandReturnObject &result) override { |
539 | result.SetStatus(eReturnStatusFailed); |
540 | |
541 | if (args.GetArgumentCount() == 1) { |
542 | bool success; |
543 | bool increment = |
544 | OptionArgParser::ToBoolean(s: args[0].ref(), fail_value: false, success_ptr: &success); |
545 | |
546 | if (success) { |
547 | Timer::SetQuiet(!increment); |
548 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
549 | } else |
550 | result.AppendError(in_string: "Could not convert increment value to boolean."); |
551 | } |
552 | |
553 | if (!result.Succeeded()) { |
554 | result.AppendError(in_string: "Missing subcommand"); |
555 | result.AppendErrorWithFormat(format: "Usage: %s\n", m_cmd_syntax.c_str()); |
556 | } |
557 | } |
558 | }; |
559 | |
560 | class CommandObjectLogTimer : public CommandObjectMultiword { |
561 | public: |
562 | CommandObjectLogTimer(CommandInterpreter &interpreter) |
563 | : CommandObjectMultiword(interpreter, "log timers", |
564 | "Enable, disable, dump, and reset LLDB internal " |
565 | "performance timers.", |
566 | "log timers < enable <depth> | disable | dump | " |
567 | "increment <bool> | reset >") { |
568 | LoadSubCommand(cmd_name: "enable", command_obj: CommandObjectSP( |
569 | new CommandObjectLogTimerEnable(interpreter))); |
570 | LoadSubCommand(cmd_name: "disable", command_obj: CommandObjectSP(new CommandObjectLogTimerDisable( |
571 | interpreter))); |
572 | LoadSubCommand(cmd_name: "dump", |
573 | command_obj: CommandObjectSP(new CommandObjectLogTimerDump(interpreter))); |
574 | LoadSubCommand( |
575 | cmd_name: "reset", command_obj: CommandObjectSP(new CommandObjectLogTimerReset(interpreter))); |
576 | LoadSubCommand( |
577 | cmd_name: "increment", |
578 | command_obj: CommandObjectSP(new CommandObjectLogTimerIncrement(interpreter))); |
579 | } |
580 | |
581 | ~CommandObjectLogTimer() override = default; |
582 | }; |
583 | |
584 | CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) |
585 | : CommandObjectMultiword(interpreter, "log", |
586 | "Commands controlling LLDB internal logging.", |
587 | "log <subcommand> [<command-options>]") { |
588 | LoadSubCommand(cmd_name: "enable", |
589 | command_obj: CommandObjectSP(new CommandObjectLogEnable(interpreter))); |
590 | LoadSubCommand(cmd_name: "disable", |
591 | command_obj: CommandObjectSP(new CommandObjectLogDisable(interpreter))); |
592 | LoadSubCommand(cmd_name: "list", |
593 | command_obj: CommandObjectSP(new CommandObjectLogList(interpreter))); |
594 | LoadSubCommand(cmd_name: "dump", |
595 | command_obj: CommandObjectSP(new CommandObjectLogDump(interpreter))); |
596 | LoadSubCommand(cmd_name: "timers", |
597 | command_obj: CommandObjectSP(new CommandObjectLogTimer(interpreter))); |
598 | } |
599 | |
600 | CommandObjectLog::~CommandObjectLog() = default; |
601 |
Definitions
- CompleteEnableDisable
- CommandObjectLogEnable
- CommandObjectLogEnable
- ~CommandObjectLogEnable
- GetOptions
- CommandOptions
- CommandOptions
- ~CommandOptions
- SetOptionValue
- OptionParsingStarting
- GetDefinitions
- HandleArgumentCompletion
- DoExecute
- CommandObjectLogDisable
- CommandObjectLogDisable
- ~CommandObjectLogDisable
- HandleArgumentCompletion
- DoExecute
- CommandObjectLogList
- CommandObjectLogList
- ~CommandObjectLogList
- HandleArgumentCompletion
- DoExecute
- CommandObjectLogDump
- CommandObjectLogDump
- ~CommandObjectLogDump
- GetOptions
- CommandOptions
- CommandOptions
- ~CommandOptions
- SetOptionValue
- OptionParsingStarting
- GetDefinitions
- HandleArgumentCompletion
- DoExecute
- CommandObjectLogTimerEnable
- CommandObjectLogTimerEnable
- ~CommandObjectLogTimerEnable
- DoExecute
- CommandObjectLogTimerDisable
- CommandObjectLogTimerDisable
- ~CommandObjectLogTimerDisable
- DoExecute
- CommandObjectLogTimerDump
- CommandObjectLogTimerDump
- ~CommandObjectLogTimerDump
- DoExecute
- CommandObjectLogTimerReset
- CommandObjectLogTimerReset
- ~CommandObjectLogTimerReset
- DoExecute
- CommandObjectLogTimerIncrement
- CommandObjectLogTimerIncrement
- ~CommandObjectLogTimerIncrement
- HandleArgumentCompletion
- DoExecute
- CommandObjectLogTimer
- CommandObjectLogTimer
- ~CommandObjectLogTimer
- CommandObjectLog
Improve your Profiling and Debugging skills
Find out more