Home | History | Annotate | Download | only in Commands
      1 //===-- CommandObjectLog.cpp ------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "lldb/lldb-python.h"
     11 
     12 #include "CommandObjectLog.h"
     13 
     14 // C Includes
     15 // C++ Includes
     16 // Other libraries and framework includes
     17 // Project includes
     18 #include "lldb/lldb-private-log.h"
     19 
     20 #include "lldb/Interpreter/Args.h"
     21 #include "lldb/Core/Debugger.h"
     22 #include "lldb/Host/FileSpec.h"
     23 #include "lldb/Core/Log.h"
     24 #include "lldb/Core/Module.h"
     25 #include "lldb/Interpreter/Options.h"
     26 #include "lldb/Core/RegularExpression.h"
     27 #include "lldb/Core/Stream.h"
     28 #include "lldb/Core/StreamFile.h"
     29 #include "lldb/Core/Timer.h"
     30 
     31 #include "lldb/Core/Debugger.h"
     32 #include "lldb/Interpreter/CommandInterpreter.h"
     33 #include "lldb/Interpreter/CommandReturnObject.h"
     34 
     35 #include "lldb/Symbol/LineTable.h"
     36 #include "lldb/Symbol/ObjectFile.h"
     37 #include "lldb/Symbol/SymbolFile.h"
     38 #include "lldb/Symbol/SymbolVendor.h"
     39 
     40 #include "lldb/Target/Process.h"
     41 #include "lldb/Target/Target.h"
     42 
     43 using namespace lldb;
     44 using namespace lldb_private;
     45 
     46 
     47 class CommandObjectLogEnable : public CommandObjectParsed
     48 {
     49 public:
     50     //------------------------------------------------------------------
     51     // Constructors and Destructors
     52     //------------------------------------------------------------------
     53     CommandObjectLogEnable(CommandInterpreter &interpreter) :
     54         CommandObjectParsed (interpreter,
     55                              "log enable",
     56                              "Enable logging for a single log channel.",
     57                              NULL),
     58         m_options (interpreter)
     59     {
     60 
     61         CommandArgumentEntry arg1;
     62         CommandArgumentEntry arg2;
     63         CommandArgumentData channel_arg;
     64         CommandArgumentData category_arg;
     65 
     66         // Define the first (and only) variant of this arg.
     67         channel_arg.arg_type = eArgTypeLogChannel;
     68         channel_arg.arg_repetition = eArgRepeatPlain;
     69 
     70         // There is only one variant this argument could be; put it into the argument entry.
     71         arg1.push_back (channel_arg);
     72 
     73         category_arg.arg_type = eArgTypeLogCategory;
     74         category_arg.arg_repetition = eArgRepeatPlus;
     75 
     76         arg2.push_back (category_arg);
     77 
     78         // Push the data for the first argument into the m_arguments vector.
     79         m_arguments.push_back (arg1);
     80         m_arguments.push_back (arg2);
     81     }
     82 
     83     virtual
     84     ~CommandObjectLogEnable()
     85     {
     86     }
     87 
     88     Options *
     89     GetOptions ()
     90     {
     91         return &m_options;
     92     }
     93 
     94 //    int
     95 //    HandleArgumentCompletion (Args &input,
     96 //                              int &cursor_index,
     97 //                              int &cursor_char_position,
     98 //                              OptionElementVector &opt_element_vector,
     99 //                              int match_start_point,
    100 //                              int max_return_elements,
    101 //                              bool &word_complete,
    102 //                              StringList &matches)
    103 //    {
    104 //        std::string completion_str (input.GetArgumentAtIndex(cursor_index));
    105 //        completion_str.erase (cursor_char_position);
    106 //
    107 //        if (cursor_index == 1)
    108 //        {
    109 //            //
    110 //            Log::AutoCompleteChannelName (completion_str.c_str(), matches);
    111 //        }
    112 //        return matches.GetSize();
    113 //    }
    114 //
    115 
    116     class CommandOptions : public Options
    117     {
    118     public:
    119 
    120         CommandOptions (CommandInterpreter &interpreter) :
    121             Options (interpreter),
    122             log_file (),
    123             log_options (0)
    124         {
    125         }
    126 
    127 
    128         virtual
    129         ~CommandOptions ()
    130         {
    131         }
    132 
    133         virtual Error
    134         SetOptionValue (uint32_t option_idx, const char *option_arg)
    135         {
    136             Error error;
    137             const int short_option = m_getopt_table[option_idx].val;
    138 
    139             switch (short_option)
    140             {
    141             case 'f':  log_file.SetFile(option_arg, true);                    break;
    142             case 't':  log_options |= LLDB_LOG_OPTION_THREADSAFE;             break;
    143             case 'v':  log_options |= LLDB_LOG_OPTION_VERBOSE;                break;
    144             case 'g':  log_options |= LLDB_LOG_OPTION_DEBUG;                  break;
    145             case 's':  log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE;       break;
    146             case 'T':  log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP;      break;
    147             case 'p':  log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break;
    148             case 'n':  log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME;    break;
    149             case 'S':  log_options |= LLDB_LOG_OPTION_BACKTRACE;              break;
    150             default:
    151                 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
    152                 break;
    153             }
    154 
    155             return error;
    156         }
    157 
    158         void
    159         OptionParsingStarting ()
    160         {
    161             log_file.Clear();
    162             log_options = 0;
    163         }
    164 
    165         const OptionDefinition*
    166         GetDefinitions ()
    167         {
    168             return g_option_table;
    169         }
    170 
    171         // Options table: Required for subclasses of Options.
    172 
    173         static OptionDefinition g_option_table[];
    174 
    175         // Instance variables to hold the values for command options.
    176 
    177         FileSpec log_file;
    178         uint32_t log_options;
    179     };
    180 
    181 protected:
    182     virtual bool
    183     DoExecute (Args& args,
    184              CommandReturnObject &result)
    185     {
    186         if (args.GetArgumentCount() < 2)
    187         {
    188             result.AppendErrorWithFormat("%s takes a log channel and one or more log types.\n", m_cmd_name.c_str());
    189         }
    190         else
    191         {
    192             std::string channel(args.GetArgumentAtIndex(0));
    193             args.Shift ();  // Shift off the channel
    194             char log_file[PATH_MAX];
    195             if (m_options.log_file)
    196                 m_options.log_file.GetPath(log_file, sizeof(log_file));
    197             else
    198                 log_file[0] = '\0';
    199             bool success = m_interpreter.GetDebugger().EnableLog (channel.c_str(),
    200                                                                   args.GetConstArgumentVector(),
    201                                                                   log_file,
    202                                                                   m_options.log_options,
    203                                                                   result.GetErrorStream());
    204             if (success)
    205                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
    206             else
    207                 result.SetStatus (eReturnStatusFailed);
    208         }
    209         return result.Succeeded();
    210     }
    211 
    212     CommandOptions m_options;
    213 };
    214 
    215 OptionDefinition
    216 CommandObjectLogEnable::CommandOptions::g_option_table[] =
    217 {
    218 { LLDB_OPT_SET_1, false, "file",       'f', required_argument, NULL, 0, eArgTypeFilename,   "Set the destination file to log to."},
    219 { LLDB_OPT_SET_1, false, "threadsafe", 't', no_argument,       NULL, 0, eArgTypeNone,        "Enable thread safe logging to avoid interweaved log lines." },
    220 { LLDB_OPT_SET_1, false, "verbose",    'v', no_argument,       NULL, 0, eArgTypeNone,       "Enable verbose logging." },
    221 { LLDB_OPT_SET_1, false, "debug",      'g', no_argument,       NULL, 0, eArgTypeNone,       "Enable debug logging." },
    222 { LLDB_OPT_SET_1, false, "sequence",   's', no_argument,       NULL, 0, eArgTypeNone,       "Prepend all log lines with an increasing integer sequence id." },
    223 { LLDB_OPT_SET_1, false, "timestamp",  'T', no_argument,       NULL, 0, eArgTypeNone,       "Prepend all log lines with a timestamp." },
    224 { LLDB_OPT_SET_1, false, "pid-tid",    'p', no_argument,       NULL, 0, eArgTypeNone,       "Prepend all log lines with the process and thread ID that generates the log line." },
    225 { LLDB_OPT_SET_1, false, "thread-name",'n', no_argument,       NULL, 0, eArgTypeNone,       "Prepend all log lines with the thread name for the thread that generates the log line." },
    226 { LLDB_OPT_SET_1, false, "stack",      'S', no_argument,       NULL, 0, eArgTypeNone,       "Append a stack backtrace to each log line." },
    227 { 0, false, NULL,                       0,  0,                 NULL, 0, eArgTypeNone,       NULL }
    228 };
    229 
    230 class CommandObjectLogDisable : public CommandObjectParsed
    231 {
    232 public:
    233     //------------------------------------------------------------------
    234     // Constructors and Destructors
    235     //------------------------------------------------------------------
    236     CommandObjectLogDisable(CommandInterpreter &interpreter) :
    237         CommandObjectParsed (interpreter,
    238                              "log disable",
    239                              "Disable one or more log channel categories.",
    240                              NULL)
    241     {
    242         CommandArgumentEntry arg1;
    243         CommandArgumentEntry arg2;
    244         CommandArgumentData channel_arg;
    245         CommandArgumentData category_arg;
    246 
    247         // Define the first (and only) variant of this arg.
    248         channel_arg.arg_type = eArgTypeLogChannel;
    249         channel_arg.arg_repetition = eArgRepeatPlain;
    250 
    251         // There is only one variant this argument could be; put it into the argument entry.
    252         arg1.push_back (channel_arg);
    253 
    254         category_arg.arg_type = eArgTypeLogCategory;
    255         category_arg.arg_repetition = eArgRepeatPlus;
    256 
    257         arg2.push_back (category_arg);
    258 
    259         // Push the data for the first argument into the m_arguments vector.
    260         m_arguments.push_back (arg1);
    261         m_arguments.push_back (arg2);
    262     }
    263 
    264     virtual
    265     ~CommandObjectLogDisable()
    266     {
    267     }
    268 
    269 protected:
    270     virtual bool
    271     DoExecute (Args& args,
    272              CommandReturnObject &result)
    273     {
    274         const size_t argc = args.GetArgumentCount();
    275         if (argc == 0)
    276         {
    277             result.AppendErrorWithFormat("%s takes a log channel and one or more log types.\n", m_cmd_name.c_str());
    278         }
    279         else
    280         {
    281             Log::Callbacks log_callbacks;
    282 
    283             std::string channel(args.GetArgumentAtIndex(0));
    284             args.Shift ();  // Shift off the channel
    285             if (Log::GetLogChannelCallbacks (ConstString(channel.c_str()), log_callbacks))
    286             {
    287                 log_callbacks.disable (args.GetConstArgumentVector(), &result.GetErrorStream());
    288                 result.SetStatus(eReturnStatusSuccessFinishNoResult);
    289             }
    290             else if (channel == "all")
    291             {
    292                 Log::DisableAllLogChannels(&result.GetErrorStream());
    293             }
    294             else
    295             {
    296                 LogChannelSP log_channel_sp (LogChannel::FindPlugin(channel.c_str()));
    297                 if (log_channel_sp)
    298                 {
    299                     log_channel_sp->Disable(args.GetConstArgumentVector(), &result.GetErrorStream());
    300                     result.SetStatus(eReturnStatusSuccessFinishNoResult);
    301                 }
    302                 else
    303                     result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
    304             }
    305         }
    306         return result.Succeeded();
    307     }
    308 };
    309 
    310 class CommandObjectLogList : public CommandObjectParsed
    311 {
    312 public:
    313     //------------------------------------------------------------------
    314     // Constructors and Destructors
    315     //------------------------------------------------------------------
    316     CommandObjectLogList(CommandInterpreter &interpreter) :
    317         CommandObjectParsed (interpreter,
    318                              "log list",
    319                              "List the log categories for one or more log channels.  If none specified, lists them all.",
    320                              NULL)
    321     {
    322         CommandArgumentEntry arg;
    323         CommandArgumentData channel_arg;
    324 
    325         // Define the first (and only) variant of this arg.
    326         channel_arg.arg_type = eArgTypeLogChannel;
    327         channel_arg.arg_repetition = eArgRepeatStar;
    328 
    329         // There is only one variant this argument could be; put it into the argument entry.
    330         arg.push_back (channel_arg);
    331 
    332         // Push the data for the first argument into the m_arguments vector.
    333         m_arguments.push_back (arg);
    334     }
    335 
    336     virtual
    337     ~CommandObjectLogList()
    338     {
    339     }
    340 
    341 protected:
    342     virtual bool
    343     DoExecute (Args& args,
    344              CommandReturnObject &result)
    345     {
    346         const size_t argc = args.GetArgumentCount();
    347         if (argc == 0)
    348         {
    349             Log::ListAllLogChannels (&result.GetOutputStream());
    350             result.SetStatus(eReturnStatusSuccessFinishResult);
    351         }
    352         else
    353         {
    354             for (size_t i=0; i<argc; ++i)
    355             {
    356                 Log::Callbacks log_callbacks;
    357 
    358                 std::string channel(args.GetArgumentAtIndex(i));
    359                 if (Log::GetLogChannelCallbacks (ConstString(channel.c_str()), log_callbacks))
    360                 {
    361                     log_callbacks.list_categories (&result.GetOutputStream());
    362                     result.SetStatus(eReturnStatusSuccessFinishResult);
    363                 }
    364                 else if (channel == "all")
    365                 {
    366                     Log::ListAllLogChannels (&result.GetOutputStream());
    367                     result.SetStatus(eReturnStatusSuccessFinishResult);
    368                 }
    369                 else
    370                 {
    371                     LogChannelSP log_channel_sp (LogChannel::FindPlugin(channel.c_str()));
    372                     if (log_channel_sp)
    373                     {
    374                         log_channel_sp->ListCategories(&result.GetOutputStream());
    375                         result.SetStatus(eReturnStatusSuccessFinishNoResult);
    376                     }
    377                     else
    378                         result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
    379                 }
    380             }
    381         }
    382         return result.Succeeded();
    383     }
    384 };
    385 
    386 class CommandObjectLogTimer : public CommandObjectParsed
    387 {
    388 public:
    389     //------------------------------------------------------------------
    390     // Constructors and Destructors
    391     //------------------------------------------------------------------
    392     CommandObjectLogTimer(CommandInterpreter &interpreter) :
    393         CommandObjectParsed (interpreter,
    394                            "log timers",
    395                            "Enable, disable, dump, and reset LLDB internal performance timers.",
    396                            "log timers < enable <depth> | disable | dump | increment <bool> | reset >")
    397     {
    398     }
    399 
    400     virtual
    401     ~CommandObjectLogTimer()
    402     {
    403     }
    404 
    405 protected:
    406     virtual bool
    407     DoExecute (Args& args,
    408              CommandReturnObject &result)
    409     {
    410         const size_t argc = args.GetArgumentCount();
    411         result.SetStatus(eReturnStatusFailed);
    412 
    413         if (argc == 1)
    414         {
    415             const char *sub_command = args.GetArgumentAtIndex(0);
    416 
    417             if (strcasecmp(sub_command, "enable") == 0)
    418             {
    419                 Timer::SetDisplayDepth (UINT32_MAX);
    420                 result.SetStatus(eReturnStatusSuccessFinishNoResult);
    421             }
    422             else if (strcasecmp(sub_command, "disable") == 0)
    423             {
    424                 Timer::DumpCategoryTimes (&result.GetOutputStream());
    425                 Timer::SetDisplayDepth (0);
    426                 result.SetStatus(eReturnStatusSuccessFinishResult);
    427             }
    428             else if (strcasecmp(sub_command, "dump") == 0)
    429             {
    430                 Timer::DumpCategoryTimes (&result.GetOutputStream());
    431                 result.SetStatus(eReturnStatusSuccessFinishResult);
    432             }
    433             else if (strcasecmp(sub_command, "reset") == 0)
    434             {
    435                 Timer::ResetCategoryTimes ();
    436                 result.SetStatus(eReturnStatusSuccessFinishResult);
    437             }
    438 
    439         }
    440         else if (argc == 2)
    441         {
    442             const char *sub_command = args.GetArgumentAtIndex(0);
    443 
    444             if (strcasecmp(sub_command, "enable") == 0)
    445             {
    446                 bool success;
    447                 uint32_t depth = Args::StringToUInt32(args.GetArgumentAtIndex(1), 0, 0, &success);
    448                 if (success)
    449                 {
    450                     Timer::SetDisplayDepth (depth);
    451                     result.SetStatus(eReturnStatusSuccessFinishNoResult);
    452                 }
    453                 else
    454                     result.AppendError("Could not convert enable depth to an unsigned integer.");
    455             }
    456             if (strcasecmp(sub_command, "increment") == 0)
    457             {
    458                 bool success;
    459                 bool increment = Args::StringToBoolean(args.GetArgumentAtIndex(1), false, &success);
    460                 if (success)
    461                 {
    462                     Timer::SetQuiet (!increment);
    463                     result.SetStatus(eReturnStatusSuccessFinishNoResult);
    464                 }
    465                 else
    466                     result.AppendError("Could not convert increment value to boolean.");
    467             }
    468         }
    469 
    470         if (!result.Succeeded())
    471         {
    472             result.AppendError("Missing subcommand");
    473             result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
    474         }
    475         return result.Succeeded();
    476     }
    477 };
    478 
    479 //----------------------------------------------------------------------
    480 // CommandObjectLog constructor
    481 //----------------------------------------------------------------------
    482 CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) :
    483     CommandObjectMultiword (interpreter,
    484                             "log",
    485                             "A set of commands for operating on logs.",
    486                             "log <command> [<command-options>]")
    487 {
    488     LoadSubCommand ("enable",  CommandObjectSP (new CommandObjectLogEnable (interpreter)));
    489     LoadSubCommand ("disable", CommandObjectSP (new CommandObjectLogDisable (interpreter)));
    490     LoadSubCommand ("list",    CommandObjectSP (new CommandObjectLogList (interpreter)));
    491     LoadSubCommand ("timers",  CommandObjectSP (new CommandObjectLogTimer (interpreter)));
    492 }
    493 
    494 //----------------------------------------------------------------------
    495 // Destructor
    496 //----------------------------------------------------------------------
    497 CommandObjectLog::~CommandObjectLog()
    498 {
    499 }
    500 
    501 
    502 
    503 
    504