brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.0 KiB · 0c01da0 Raw
601 lines · cpp
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-exception6//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 24using namespace lldb;25using namespace lldb_private;26 27#define LLDB_OPTIONS_log_enable28#include "CommandOptions.inc"29 30#define LLDB_OPTIONS_log_dump31#include "CommandOptions.inc"32 33/// Common completion logic for log enable/disable.34static 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(channel);39  } else if (arg_index >= 1) { // We got: log enable/disable channel x[tab]40    llvm::StringRef channel = request.GetParsedLine().GetArgumentAtIndex(0);41    Log::ForEachChannelCategory(42        channel, [&request](llvm::StringRef name, llvm::StringRef desc) {43          request.TryCompleteCurrentArg(name, desc);44        });45  }46}47 48class CommandObjectLogEnable : public CommandObjectParsed {49public:50  // Constructors and Destructors51  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 the65    // argument entry.66    arg1.push_back(channel_arg);67 68    category_arg.arg_type = eArgTypeLogCategory;69    category_arg.arg_repetition = eArgRepeatPlus;70 71    arg2.push_back(category_arg);72 73    // Push the data for the first argument into the m_arguments vector.74    m_arguments.push_back(arg1);75    m_arguments.push_back(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(option_arg, FileSpec::Style::native);96        FileSystem::Instance().Resolve(log_file);97        break;98      case 'h':99        handler = (LogHandlerKind)OptionArgParser::ToOptionEnum(100            option_arg, GetDefinitions()[option_idx].enum_values, 0, error);101        if (!error.Success())102          return Status::FromErrorStringWithFormatv(103              "unrecognized value for log handler '{0}'", option_arg);104        break;105      case 'b':106        return buffer_size.SetValueFromString(option_arg,107                                              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  void157  HandleArgumentCompletion(CompletionRequest &request,158                           OptionElementVector &opt_element_vector) override {159    CompleteEnableDisable(request);160  }161 162protected:163  void DoExecute(Args &args, CommandReturnObject &result) override {164    if (args.GetArgumentCount() < 2) {165      result.AppendErrorWithFormat(166          "%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          "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("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          "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 channel195    char log_file[PATH_MAX];196    if (m_options.log_file)197      m_options.log_file.GetPath(log_file, sizeof(log_file));198    else199      log_file[0] = '\0';200 201    std::string error;202    llvm::raw_string_ostream error_stream(error);203    bool success = GetDebugger().EnableLog(204        channel, args.GetArgumentArrayRef(), log_file, m_options.log_options,205        m_options.buffer_size.GetCurrentValue(), m_options.handler,206        error_stream);207    result.GetErrorStream() << error;208 209    if (success)210      result.SetStatus(eReturnStatusSuccessFinishNoResult);211    else212      result.SetStatus(eReturnStatusFailed);213  }214 215  CommandOptions m_options;216};217 218class CommandObjectLogDisable : public CommandObjectParsed {219public:220  // Constructors and Destructors221  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 the235    // argument entry.236    arg1.push_back(channel_arg);237 238    category_arg.arg_type = eArgTypeLogCategory;239    category_arg.arg_repetition = eArgRepeatPlus;240 241    arg2.push_back(category_arg);242 243    // Push the data for the first argument into the m_arguments vector.244    m_arguments.push_back(arg1);245    m_arguments.push_back(arg2);246  }247 248  ~CommandObjectLogDisable() override = default;249 250  void251  HandleArgumentCompletion(CompletionRequest &request,252                           OptionElementVector &opt_element_vector) override {253    CompleteEnableDisable(request);254  }255 256protected:257  void DoExecute(Args &args, CommandReturnObject &result) override {258    if (args.empty()) {259      result.AppendErrorWithFormat(260          "%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 channel267    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, args.GetArgumentArrayRef(),274                                 error_stream))275        result.SetStatus(eReturnStatusSuccessFinishNoResult);276      result.GetErrorStream() << error;277    }278  }279};280 281class CommandObjectLogList : public CommandObjectParsed {282public:283  // Constructors and Destructors284  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(eArgTypeLogChannel, eArgRepeatStar);290  }291 292  ~CommandObjectLogList() override = default;293 294  void295  HandleArgumentCompletion(CompletionRequest &request,296                           OptionElementVector &opt_element_vector) override {297    for (llvm::StringRef channel : Log::ListChannels())298      request.TryCompleteCurrentArg(channel);299  }300 301protected: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(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(entry.ref(), output_stream);313      if (success)314        result.SetStatus(eReturnStatusSuccessFinishResult);315    }316    result.GetOutputStream() << output;317  }318};319class CommandObjectLogDump : public CommandObjectParsed {320public:321  CommandObjectLogDump(CommandInterpreter &interpreter)322      : CommandObjectParsed(interpreter, "log dump",323                            "dump circular buffer logs", nullptr) {324    AddSimpleArgumentList(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(option_arg, FileSpec::Style::native);345        FileSystem::Instance().Resolve(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  void366  HandleArgumentCompletion(CompletionRequest &request,367                           OptionElementVector &opt_element_vector) override {368    CompleteEnableDisable(request);369  }370 371protected:372  void DoExecute(Args &args, CommandReturnObject &result) override {373    if (args.empty()) {374      result.AppendErrorWithFormat(375          "%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          m_options.log_file, flags, lldb::eFilePermissionsFileDefault, false);387      if (!file) {388        result.AppendErrorWithFormat("Unable to open log file '%s': %s",389                                     m_options.log_file.GetPath().c_str(),390                                     llvm::toString(file.takeError()).c_str());391        return;392      }393      stream_up = std::make_unique<llvm::raw_fd_ostream>(394          (*file)->GetDescriptor(), /*shouldClose=*/true);395    } else {396      stream_up = std::make_unique<llvm::raw_fd_ostream>(397          GetDebugger().GetOutputFileSP()->GetDescriptor(),398          /*shouldClose=*/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, *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 415class CommandObjectLogTimerEnable : public CommandObjectParsed {416public:417  // Constructors and Destructors418  CommandObjectLogTimerEnable(CommandInterpreter &interpreter)419      : CommandObjectParsed(interpreter, "log timers enable",420                            "enable LLDB internal performance timers",421                            "log timers enable <depth>") {422    AddSimpleArgumentList(eArgTypeCount, eArgRepeatOptional);423  }424 425  ~CommandObjectLogTimerEnable() override = default;426 427protected: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(0, depth)) {437        result.AppendError(438            "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("Missing subcommand");447      result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());448    }449  }450};451 452class CommandObjectLogTimerDisable : public CommandObjectParsed {453public:454  // Constructors and Destructors455  CommandObjectLogTimerDisable(CommandInterpreter &interpreter)456      : CommandObjectParsed(interpreter, "log timers disable",457                            "disable LLDB internal performance timers",458                            nullptr) {}459 460  ~CommandObjectLogTimerDisable() override = default;461 462protected:463  void DoExecute(Args &args, CommandReturnObject &result) override {464    Timer::DumpCategoryTimes(result.GetOutputStream());465    Timer::SetDisplayDepth(0);466    result.SetStatus(eReturnStatusSuccessFinishResult);467 468    if (!result.Succeeded()) {469      result.AppendError("Missing subcommand");470      result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());471    }472  }473};474 475class CommandObjectLogTimerDump : public CommandObjectParsed {476public:477  // Constructors and Destructors478  CommandObjectLogTimerDump(CommandInterpreter &interpreter)479      : CommandObjectParsed(interpreter, "log timers dump",480                            "dump LLDB internal performance timers", nullptr) {}481 482  ~CommandObjectLogTimerDump() override = default;483 484protected:485  void DoExecute(Args &args, CommandReturnObject &result) override {486    Timer::DumpCategoryTimes(result.GetOutputStream());487    result.SetStatus(eReturnStatusSuccessFinishResult);488 489    if (!result.Succeeded()) {490      result.AppendError("Missing subcommand");491      result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());492    }493  }494};495 496class CommandObjectLogTimerReset : public CommandObjectParsed {497public:498  // Constructors and Destructors499  CommandObjectLogTimerReset(CommandInterpreter &interpreter)500      : CommandObjectParsed(interpreter, "log timers reset",501                            "reset LLDB internal performance timers", nullptr) {502  }503 504  ~CommandObjectLogTimerReset() override = default;505 506protected:507  void DoExecute(Args &args, CommandReturnObject &result) override {508    Timer::ResetCategoryTimes();509    result.SetStatus(eReturnStatusSuccessFinishResult);510 511    if (!result.Succeeded()) {512      result.AppendError("Missing subcommand");513      result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());514    }515  }516};517 518class CommandObjectLogTimerIncrement : public CommandObjectParsed {519public:520  // Constructors and Destructors521  CommandObjectLogTimerIncrement(CommandInterpreter &interpreter)522      : CommandObjectParsed(interpreter, "log timers increment",523                            "increment LLDB internal performance timers",524                            "log timers increment <bool>") {525    AddSimpleArgumentList(eArgTypeBoolean);526  }527 528  ~CommandObjectLogTimerIncrement() override = default;529 530  void531  HandleArgumentCompletion(CompletionRequest &request,532                           OptionElementVector &opt_element_vector) override {533    request.TryCompleteCurrentArg("true");534    request.TryCompleteCurrentArg("false");535  }536 537protected: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(args[0].ref(), false, &success);545 546      if (success) {547        Timer::SetQuiet(!increment);548        result.SetStatus(eReturnStatusSuccessFinishNoResult);549      } else550        result.AppendError("could not convert increment value to boolean");551    }552 553    if (!result.Succeeded()) {554      result.AppendError("Missing subcommand");555      result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());556    }557  }558};559 560class CommandObjectLogTimer : public CommandObjectMultiword {561public: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("enable", CommandObjectSP(569                                 new CommandObjectLogTimerEnable(interpreter)));570    LoadSubCommand("disable", CommandObjectSP(new CommandObjectLogTimerDisable(571                                  interpreter)));572    LoadSubCommand("dump",573                   CommandObjectSP(new CommandObjectLogTimerDump(interpreter)));574    LoadSubCommand(575        "reset", CommandObjectSP(new CommandObjectLogTimerReset(interpreter)));576    LoadSubCommand(577        "increment",578        CommandObjectSP(new CommandObjectLogTimerIncrement(interpreter)));579  }580 581  ~CommandObjectLogTimer() override = default;582};583 584CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter)585    : CommandObjectMultiword(interpreter, "log",586                             "Commands controlling LLDB internal logging.",587                             "log <subcommand> [<command-options>]") {588  LoadSubCommand("enable",589                 CommandObjectSP(new CommandObjectLogEnable(interpreter)));590  LoadSubCommand("disable",591                 CommandObjectSP(new CommandObjectLogDisable(interpreter)));592  LoadSubCommand("list",593                 CommandObjectSP(new CommandObjectLogList(interpreter)));594  LoadSubCommand("dump",595                 CommandObjectSP(new CommandObjectLogDump(interpreter)));596  LoadSubCommand("timers",597                 CommandObjectSP(new CommandObjectLogTimer(interpreter)));598}599 600CommandObjectLog::~CommandObjectLog() = default;601