LLDB  mainline
CommandObjectLog.cpp
Go to the documentation of this file.
1 //===-- CommandObjectLog.cpp ------------------------------------*- C++ -*-===//
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/Core/Module.h"
12 #include "lldb/Core/StreamFile.h"
13 #include "lldb/Host/OptionParser.h"
18 #include "lldb/Symbol/LineTable.h"
19 #include "lldb/Symbol/ObjectFile.h"
20 #include "lldb/Symbol/SymbolFile.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Utility/Args.h"
25 #include "lldb/Utility/FileSpec.h"
26 #include "lldb/Utility/Log.h"
28 #include "lldb/Utility/Stream.h"
29 #include "lldb/Utility/Timer.h"
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 static constexpr OptionDefinition g_log_options[] = {
35  // clang-format off
36  { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeFilename, "Set the destination file to log to." },
37  { LLDB_OPT_SET_1, false, "threadsafe", 't', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." },
38  { LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Enable verbose logging." },
39  { LLDB_OPT_SET_1, false, "sequence", 's', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." },
40  { LLDB_OPT_SET_1, false, "timestamp", 'T', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Prepend all log lines with a timestamp." },
41  { LLDB_OPT_SET_1, false, "pid-tid", 'p', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Prepend all log lines with the process and thread ID that generates the log line." },
42  { LLDB_OPT_SET_1, false, "thread-name",'n', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Prepend all log lines with the thread name for the thread that generates the log line." },
43  { LLDB_OPT_SET_1, false, "stack", 'S', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Append a stack backtrace to each log line." },
44  { LLDB_OPT_SET_1, false, "append", 'a', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Append to the log file instead of overwriting." },
45  { LLDB_OPT_SET_1, false, "file-function",'F',OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Prepend the names of files and function that generate the logs." },
46  // clang-format on
47 };
48 
50 public:
51  // Constructors and Destructors
53  : CommandObjectParsed(interpreter, "log enable",
54  "Enable logging for a single log channel.",
55  nullptr),
56  m_options() {
59  CommandArgumentData channel_arg;
60  CommandArgumentData category_arg;
61 
62  // Define the first (and only) variant of this arg.
63  channel_arg.arg_type = eArgTypeLogChannel;
64  channel_arg.arg_repetition = eArgRepeatPlain;
65 
66  // There is only one variant this argument could be; put it into the
67  // argument entry.
68  arg1.push_back(channel_arg);
69 
70  category_arg.arg_type = eArgTypeLogCategory;
71  category_arg.arg_repetition = eArgRepeatPlus;
72 
73  arg2.push_back(category_arg);
74 
75  // Push the data for the first argument into the m_arguments vector.
76  m_arguments.push_back(arg1);
77  m_arguments.push_back(arg2);
78  }
79 
80  ~CommandObjectLogEnable() override = default;
81 
82  Options *GetOptions() override { return &m_options; }
83 
84  class CommandOptions : public Options {
85  public:
86  CommandOptions() : Options(), log_file(), log_options(0) {}
87 
88  ~CommandOptions() override = default;
89 
90  Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
91  ExecutionContext *execution_context) override {
92  Status error;
93  const int short_option = m_getopt_table[option_idx].val;
94 
95  switch (short_option) {
96  case 'f':
97  log_file.SetFile(option_arg, FileSpec::Style::native);
98  FileSystem::Instance().Resolve(log_file);
99  break;
100  case 't':
101  log_options |= LLDB_LOG_OPTION_THREADSAFE;
102  break;
103  case 'v':
104  log_options |= LLDB_LOG_OPTION_VERBOSE;
105  break;
106  case 's':
107  log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE;
108  break;
109  case 'T':
110  log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP;
111  break;
112  case 'p':
114  break;
115  case 'n':
117  break;
118  case 'S':
119  log_options |= LLDB_LOG_OPTION_BACKTRACE;
120  break;
121  case 'a':
122  log_options |= LLDB_LOG_OPTION_APPEND;
123  break;
124  case 'F':
126  break;
127  default:
128  error.SetErrorStringWithFormat("unrecognized option '%c'",
129  short_option);
130  break;
131  }
132 
133  return error;
134  }
135 
136  void OptionParsingStarting(ExecutionContext *execution_context) override {
137  log_file.Clear();
138  log_options = 0;
139  }
140 
141  llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
142  return llvm::makeArrayRef(g_log_options);
143  }
144 
145  // Instance variables to hold the values for command options.
146 
149  };
150 
151 protected:
152  bool DoExecute(Args &args, CommandReturnObject &result) override {
153  if (args.GetArgumentCount() < 2) {
154  result.AppendErrorWithFormat(
155  "%s takes a log channel and one or more log types.\n",
156  m_cmd_name.c_str());
157  return false;
158  }
159 
160  // Store into a std::string since we're about to shift the channel off.
161  const std::string channel = args[0].ref;
162  args.Shift(); // Shift off the channel
163  char log_file[PATH_MAX];
164  if (m_options.log_file)
165  m_options.log_file.GetPath(log_file, sizeof(log_file));
166  else
167  log_file[0] = '\0';
168 
169  std::string error;
170  llvm::raw_string_ostream error_stream(error);
171  bool success =
172  GetDebugger().EnableLog(channel, args.GetArgumentArrayRef(), log_file,
173  m_options.log_options, error_stream);
174  result.GetErrorStream() << error_stream.str();
175 
176  if (success)
178  else
180  return result.Succeeded();
181  }
182 
184 };
185 
187 public:
188  // Constructors and Destructors
190  : CommandObjectParsed(interpreter, "log disable",
191  "Disable one or more log channel categories.",
192  nullptr) {
195  CommandArgumentData channel_arg;
196  CommandArgumentData category_arg;
197 
198  // Define the first (and only) variant of this arg.
199  channel_arg.arg_type = eArgTypeLogChannel;
200  channel_arg.arg_repetition = eArgRepeatPlain;
201 
202  // There is only one variant this argument could be; put it into the
203  // argument entry.
204  arg1.push_back(channel_arg);
205 
206  category_arg.arg_type = eArgTypeLogCategory;
207  category_arg.arg_repetition = eArgRepeatPlus;
208 
209  arg2.push_back(category_arg);
210 
211  // Push the data for the first argument into the m_arguments vector.
212  m_arguments.push_back(arg1);
213  m_arguments.push_back(arg2);
214  }
215 
216  ~CommandObjectLogDisable() override = default;
217 
218 protected:
219  bool DoExecute(Args &args, CommandReturnObject &result) override {
220  if (args.empty()) {
221  result.AppendErrorWithFormat(
222  "%s takes a log channel and one or more log types.\n",
223  m_cmd_name.c_str());
224  return false;
225  }
226 
227  const std::string channel = args[0].ref;
228  args.Shift(); // Shift off the channel
229  if (channel == "all") {
230  Log::DisableAllLogChannels();
232  } else {
233  std::string error;
234  llvm::raw_string_ostream error_stream(error);
235  if (Log::DisableLogChannel(channel, args.GetArgumentArrayRef(),
236  error_stream))
238  result.GetErrorStream() << error_stream.str();
239  }
240  return result.Succeeded();
241  }
242 };
243 
245 public:
246  // Constructors and Destructors
248  : CommandObjectParsed(interpreter, "log list",
249  "List the log categories for one or more log "
250  "channels. If none specified, lists them all.",
251  nullptr) {
253  CommandArgumentData channel_arg;
254 
255  // Define the first (and only) variant of this arg.
256  channel_arg.arg_type = eArgTypeLogChannel;
257  channel_arg.arg_repetition = eArgRepeatStar;
258 
259  // There is only one variant this argument could be; put it into the
260  // argument entry.
261  arg.push_back(channel_arg);
262 
263  // Push the data for the first argument into the m_arguments vector.
264  m_arguments.push_back(arg);
265  }
266 
267  ~CommandObjectLogList() override = default;
268 
269 protected:
270  bool DoExecute(Args &args, CommandReturnObject &result) override {
271  std::string output;
272  llvm::raw_string_ostream output_stream(output);
273  if (args.empty()) {
274  Log::ListAllLogChannels(output_stream);
276  } else {
277  bool success = true;
278  for (const auto &entry : args.entries())
279  success =
280  success && Log::ListChannelCategories(entry.ref, output_stream);
281  if (success)
283  }
284  result.GetOutputStream() << output_stream.str();
285  return result.Succeeded();
286  }
287 };
288 
290 public:
291  // Constructors and Destructors
293  : CommandObjectParsed(interpreter, "log timers",
294  "Enable, disable, dump, and reset LLDB internal "
295  "performance timers.",
296  "log timers < enable <depth> | disable | dump | "
297  "increment <bool> | reset >") {}
298 
299  ~CommandObjectLogTimer() override = default;
300 
301 protected:
302  bool DoExecute(Args &args, CommandReturnObject &result) override {
304 
305  if (args.GetArgumentCount() == 1) {
306  auto sub_command = args[0].ref;
307 
308  if (sub_command.equals_lower("enable")) {
309  Timer::SetDisplayDepth(UINT32_MAX);
311  } else if (sub_command.equals_lower("disable")) {
312  Timer::DumpCategoryTimes(&result.GetOutputStream());
313  Timer::SetDisplayDepth(0);
315  } else if (sub_command.equals_lower("dump")) {
316  Timer::DumpCategoryTimes(&result.GetOutputStream());
318  } else if (sub_command.equals_lower("reset")) {
319  Timer::ResetCategoryTimes();
321  }
322  } else if (args.GetArgumentCount() == 2) {
323  auto sub_command = args[0].ref;
324  auto param = args[1].ref;
325 
326  if (sub_command.equals_lower("enable")) {
327  uint32_t depth;
328  if (param.consumeInteger(0, depth)) {
329  result.AppendError(
330  "Could not convert enable depth to an unsigned integer.");
331  } else {
332  Timer::SetDisplayDepth(depth);
334  }
335  } else if (sub_command.equals_lower("increment")) {
336  bool success;
337  bool increment = OptionArgParser::ToBoolean(param, false, &success);
338  if (success) {
339  Timer::SetQuiet(!increment);
341  } else
342  result.AppendError("Could not convert increment value to boolean.");
343  }
344  }
345 
346  if (!result.Succeeded()) {
347  result.AppendError("Missing subcommand");
348  result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
349  }
350  return result.Succeeded();
351  }
352 };
353 
354 CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter)
355  : CommandObjectMultiword(interpreter, "log",
356  "Commands controlling LLDB internal logging.",
357  "log <subcommand> [<command-options>]") {
358  LoadSubCommand("enable",
359  CommandObjectSP(new CommandObjectLogEnable(interpreter)));
360  LoadSubCommand("disable",
361  CommandObjectSP(new CommandObjectLogDisable(interpreter)));
362  LoadSubCommand("list",
363  CommandObjectSP(new CommandObjectLogList(interpreter)));
364  LoadSubCommand("timers",
365  CommandObjectSP(new CommandObjectLogTimer(interpreter)));
366 }
367 
std::vector< CommandArgumentData > CommandArgumentEntry
A command line argument class.
Definition: Args.h:32
bool empty() const
Definition: Args.h:113
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
void Shift()
Shifts the first argument C string value of the array off the argument array.
Definition: Args.cpp:284
llvm::ArrayRef< ArgEntry > entries() const
Definition: Args.h:123
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
bool DoExecute(Args &args, CommandReturnObject &result) override
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.cpp:254
void OptionParsingStarting(ExecutionContext *execution_context) override
A file utility class.
Definition: FileSpec.h:55
llvm::ArrayRef< const char * > GetArgumentArrayRef() const
Gets the argument as an ArrayRef.
Definition: Args.h:165
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
#define LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION
Definition: Log.h:43
bool DoExecute(Args &args, CommandReturnObject &result) override
#define LLDB_LOG_OPTION_APPEND
Definition: Log.h:42
#define LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD
Definition: Log.h:39
CommandObjectLogList(CommandInterpreter &interpreter)
#define UINT32_MAX
Definition: lldb-defines.h:31
CommandObjectLogEnable(CommandInterpreter &interpreter)
#define LLDB_LOG_OPTION_PREPEND_THREAD_NAME
Definition: Log.h:40
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
static constexpr OptionDefinition g_log_options[]
CommandObjectLogTimer(CommandInterpreter &interpreter)
#define LLDB_LOG_OPTION_VERBOSE
Definition: Log.h:36
#define LLDB_LOG_OPTION_PREPEND_TIMESTAMP
Definition: Log.h:38
A command line option parsing protocol class.
Definition: Options.h:62
void void AppendError(llvm::StringRef in_string)
bool DoExecute(Args &args, CommandReturnObject &result) override
Options * GetOptions() override
#define LLDB_LOG_OPTION_PREPEND_SEQUENCE
Definition: Log.h:37
Definition: SBAddress.h:15
#define LLDB_LOG_OPTION_THREADSAFE
Definition: Log.h:35
#define PATH_MAX
bool DoExecute(Args &args, CommandReturnObject &result) override
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
Definition: Status.cpp:255
#define LLDB_OPT_SET_1
Definition: lldb-defines.h:111
CommandObjectLogDisable(CommandInterpreter &interpreter)
void SetStatus(lldb::ReturnStatus status)
An error handling class.
Definition: Status.h:44
#define LLDB_LOG_OPTION_BACKTRACE
Definition: Log.h:41