Invalidate process UID/GID-related command options on Windows.
authorZachary Turner <zturner@google.com>
Mon, 7 Jul 2014 23:54:51 +0000 (23:54 +0000)
committerZachary Turner <zturner@google.com>
Mon, 7 Jul 2014 23:54:51 +0000 (23:54 +0000)
Windows uses a different process security model and does not have
a concept of process UID or GID.  This patch makes these options
invalid on Windows.  Attempting to specify these options when the
current platform is Windows will generate an error.

Reviewed by: Jim Ingham
Differential Revision: http://reviews.llvm.org/D4373

llvm-svn: 212500

lldb/include/lldb/Host/OptionParser.h
lldb/include/lldb/Interpreter/CommandOptionValidators.h [new file with mode: 0644]
lldb/include/lldb/Interpreter/Options.h
lldb/include/lldb/lldb-private-types.h
lldb/source/Commands/CommandObjectPlatform.cpp
lldb/source/Interpreter/Args.cpp
lldb/source/Interpreter/CMakeLists.txt
lldb/source/Interpreter/CommandOptionValidators.cpp [new file with mode: 0644]
lldb/source/Interpreter/Options.cpp

index ca83eeb..5aa7db5 100644 (file)
@@ -16,18 +16,17 @@ struct option;
 
 namespace lldb_private {
 
-typedef struct Option
+struct OptionDefinition;
+
+struct Option
 {
-    // name of long option
-    const char *name;
-    // one of no_argument, required_argument, and optional_argument:
-    // whether option takes an argument
-    int has_arg;
+    // The definition of the option that this refers to.
+    const OptionDefinition *definition;
     // if not NULL, set *flag to val when option found
     int *flag;
     // if flag not NULL, value to set *flag to; else return value
     int val;
-} Option;
+};
 
 class OptionParser
 {
diff --git a/lldb/include/lldb/Interpreter/CommandOptionValidators.h b/lldb/include/lldb/Interpreter/CommandOptionValidators.h
new file mode 100644 (file)
index 0000000..eef8881
--- /dev/null
@@ -0,0 +1,30 @@
+//===-- CommandOptionValidators.h -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CommandOptionValidators_h_
+#define liblldb_CommandOptionValidators_h_
+
+#include "lldb/lldb-private-types.h"
+
+namespace lldb_private {
+
+class Platform;
+class ExecutionContext;
+
+class PosixPlatformCommandOptionValidator : public OptionValidator
+{
+    virtual bool IsValid(Platform &platform, ExecutionContext &target) const;
+    virtual const char* ShortConditionString() const;
+    virtual const char* LongConditionString() const;
+};
+
+} // namespace lldb_private
+
+
+#endif  // liblldb_CommandOptionValidators_h_
index 2b4ac11..6ecf08d 100644 (file)
@@ -159,7 +159,7 @@ public:
 
     void
     OutputFormattedUsageText (Stream &strm,
-                              const char *text,
+                              const OptionDefinition &option_def,
                               uint32_t output_max_columns);
 
     void
@@ -301,6 +301,12 @@ public:
                                     int max_return_elements,
                                     bool &word_complete,
                                     StringList &matches);
+
+    CommandInterpreter&
+    GetInterpreter()
+    {
+        return m_interpreter;
+    }
     
 protected:
     // This is a set of options expressed as indexes into the options table for this Option.
index 060efac..a7d6db2 100644 (file)
@@ -16,6 +16,9 @@
 
 namespace lldb_private
 {
+    class Platform;
+    class ExecutionContext;
+
     //----------------------------------------------------------------------
     // Every register is described in detail including its name, alternate
     // name (optional), encoding, size in bytes and the default display
@@ -55,11 +58,12 @@ namespace lldb_private
     struct OptionValidator
     {
         virtual ~OptionValidator() { }
-        virtual bool IsValid() const = 0;
-        virtual const char * ValidConditionString() const = 0;
+        virtual bool IsValid(Platform &platform, ExecutionContext &target) const = 0;
+        virtual const char * ShortConditionString() const = 0;
+        virtual const char * LongConditionString() const = 0;
     };
     
-    typedef struct
+    struct OptionDefinition
     {
         uint32_t usage_mask;                     // Used to mark options that can be used together.  If (1 << n & usage_mask) != 0
                                                  // then this option belongs to option set n.
@@ -73,7 +77,7 @@ namespace lldb_private
         lldb::CommandArgumentType argument_type; // Type of argument this option takes
         const char *usage_text;                  // Full text explaining what this options does and what (if any) argument to
                                                  // pass it.
-    } OptionDefinition;
+    };
 
 } // namespace lldb_private
 
index 96ebd51..9998dbd 100644 (file)
@@ -21,6 +21,7 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Interpreter/Args.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandOptionValidators.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Interpreter/OptionGroupFile.h"
 #include "lldb/Interpreter/OptionGroupPlatform.h"
@@ -1644,6 +1645,11 @@ protected:
     CommandOptions m_options;
 };
 
+namespace
+{
+    PosixPlatformCommandOptionValidator g_posix_validator;
+}
+
 OptionDefinition
 CommandObjectPlatformProcessList::CommandOptions::g_option_table[] =
 {
@@ -1654,10 +1660,10 @@ CommandObjectPlatformProcessList::CommandOptions::g_option_table[] =
 { LLDB_OPT_SET_5            , true , "contains"   , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName      , "Find processes with executable basenames that contain a string." },
 { LLDB_OPT_SET_6            , true , "regex"      , 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "Find processes with executable basenames that match a regular expression." },
 { LLDB_OPT_SET_FROM_TO(2, 6), false, "parent"     , 'P', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePid              , "Find processes that have a matching parent process ID." },
-{ LLDB_OPT_SET_FROM_TO(2, 6), false, "uid"        , 'u', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching user ID." },
-{ LLDB_OPT_SET_FROM_TO(2, 6), false, "euid"       , 'U', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching effective user ID." },
-{ LLDB_OPT_SET_FROM_TO(2, 6), false, "gid"        , 'g', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching group ID." },
-{ LLDB_OPT_SET_FROM_TO(2, 6), false, "egid"       , 'G', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching effective group ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "uid"        , 'u', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching user ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "euid"       , 'U', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching effective user ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "gid"        , 'g', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching group ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "egid"       , 'G', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger  , "Find processes that have a matching effective group ID." },
 { LLDB_OPT_SET_FROM_TO(2, 6), false, "arch"       , 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeArchitecture     , "Find processes that have a matching architecture." },
 { LLDB_OPT_SET_FROM_TO(1, 6), false, "show-args"  , 'A', OptionParser::eNoArgument      , NULL, NULL, 0, eArgTypeNone             , "Show process arguments instead of the process executable basename." },
 { LLDB_OPT_SET_FROM_TO(1, 6), false, "verbose"    , 'v', OptionParser::eNoArgument      , NULL, NULL, 0, eArgTypeNone             , "Enable verbose output." },
index facddcd..0b8f3e1 100644 (file)
@@ -20,6 +20,7 @@
 #include "lldb/Core/StreamString.h"
 #include "lldb/DataFormatters/FormatManager.h"
 #include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Target/Process.h"
 //#include "lldb/Target/RegisterContext.h"
@@ -627,14 +628,14 @@ Args::ParseOptions (Options &options)
         return error;
     }
 
-    for (int i=0; long_options[i].name != nullptr; ++i)
+    for (int i=0; long_options[i].definition != nullptr; ++i)
     {
         if (long_options[i].flag == nullptr)
         {
             if (isprint8(long_options[i].val))
             {
                 sstr << (char)long_options[i].val;
-                switch (long_options[i].has_arg)
+                switch (long_options[i].definition->option_has_arg)
                 {
                 default:
                 case OptionParser::eNoArgument:                       break;
@@ -673,7 +674,7 @@ Args::ParseOptions (Options &options)
         if (long_options_index == -1)
         {
             for (int i=0;
-                 long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
+                 long_options[i].definition || long_options[i].flag || long_options[i].val;
                  ++i)
             {
                 if (long_options[i].val == val)
@@ -686,8 +687,18 @@ Args::ParseOptions (Options &options)
         // Call the callback with the option
         if (long_options_index >= 0)
         {
-            error = options.SetOptionValue(long_options_index,
-                                           long_options[long_options_index].has_arg == OptionParser::eNoArgument ? nullptr : OptionParser::GetOptionArgument());
+            const OptionDefinition *def = long_options[long_options_index].definition;
+            CommandInterpreter &interpreter = options.GetInterpreter();
+            OptionValidator *validator = def->validator;
+            if (validator && !validator->IsValid(*interpreter.GetPlatform(true), interpreter.GetExecutionContext()))
+            {
+                error.SetErrorStringWithFormat("Option \"%s\" invalid.  %s", def->long_option, def->validator->LongConditionString());
+            }
+            else
+            {
+                error = options.SetOptionValue(long_options_index,
+                                               (def->option_has_arg == OptionParser::eNoArgument) ? nullptr : OptionParser::GetOptionArgument());
+            }
         }
         else
         {
@@ -1222,7 +1233,7 @@ Args::FindArgumentIndexForOption (Option *long_options, int long_options_index)
     char short_buffer[3];
     char long_buffer[255];
     ::snprintf (short_buffer, sizeof (short_buffer), "-%c", long_options[long_options_index].val);
-    ::snprintf (long_buffer, sizeof (long_buffer),  "--%s", long_options[long_options_index].name);
+    ::snprintf (long_buffer, sizeof (long_buffer),  "--%s", long_options[long_options_index].definition->long_option);
     size_t end = GetArgumentCount ();
     size_t idx = 0;
     while (idx < end)
@@ -1278,12 +1289,12 @@ Args::ParseAliasOptions (Options &options,
         return;
     }
 
-    for (i = 0; long_options[i].name != nullptr; ++i)
+    for (i = 0; long_options[i].definition != nullptr; ++i)
     {
         if (long_options[i].flag == nullptr)
         {
             sstr << (char) long_options[i].val;
-            switch (long_options[i].has_arg)
+            switch (long_options[i].definition->option_has_arg)
             {
                 default:
                 case OptionParser::eNoArgument:
@@ -1328,7 +1339,7 @@ Args::ParseAliasOptions (Options &options,
         if (long_options_index == -1)
         {
             for (int j = 0;
-                 long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val;
+                 long_options[j].definition || long_options[j].flag || long_options[j].val;
                  ++j)
             {
                 if (long_options[j].val == val)
@@ -1344,8 +1355,10 @@ Args::ParseAliasOptions (Options &options,
         {
             StreamString option_str;
             option_str.Printf ("-%c", val);
+            const OptionDefinition *def = long_options[long_options_index].definition;
+            int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
 
-            switch (long_options[long_options_index].has_arg)
+            switch (has_arg)
             {
             case OptionParser::eNoArgument:
                 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), 
@@ -1410,7 +1423,7 @@ Args::ParseAliasOptions (Options &options,
                         raw_input_string.erase (pos, strlen (tmp_arg));
                 }
                 ReplaceArgumentAtIndex (idx, "");
-                if ((long_options[long_options_index].has_arg != OptionParser::eNoArgument)
+                if ((long_options[long_options_index].definition->option_has_arg != OptionParser::eNoArgument)
                     && (OptionParser::GetOptionArgument() != nullptr)
                     && (idx+1 < GetArgumentCount())
                     && (strcmp (OptionParser::GetOptionArgument(), GetArgumentAtIndex(idx+1)) == 0))
@@ -1453,12 +1466,12 @@ Args::ParseArgsForCompletion
     // to suppress error messages.
 
     sstr << ":";
-    for (int i = 0; long_options[i].name != nullptr; ++i)
+    for (int i = 0; long_options[i].definition != nullptr; ++i)
     {
         if (long_options[i].flag == nullptr)
         {
             sstr << (char) long_options[i].val;
-            switch (long_options[i].has_arg)
+            switch (long_options[i].definition->option_has_arg)
             {
                 default:
                 case OptionParser::eNoArgument:
@@ -1555,7 +1568,7 @@ Args::ParseArgsForCompletion
         if (long_options_index == -1)
         {
             for (int j = 0;
-                 long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val;
+                 long_options[j].definition || long_options[j].flag || long_options[j].val;
                  ++j)
             {
                 if (long_options[j].val == val)
@@ -1581,7 +1594,9 @@ Args::ParseArgsForCompletion
                 }
             }
 
-            switch (long_options[long_options_index].has_arg)
+            const OptionDefinition *def = long_options[long_options_index].definition;
+            int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
+            switch (has_arg)
             {
             case OptionParser::eNoArgument:
                 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, 0));
index 27597fc..52f89bb 100644 (file)
@@ -7,6 +7,7 @@ add_lldb_library(lldbInterpreter
   CommandObject.cpp
   CommandObjectRegexCommand.cpp
   CommandObjectScript.cpp
+  CommandOptionValidators.cpp
   CommandReturnObject.cpp
   OptionGroupArchitecture.cpp
   OptionGroupBoolean.cpp
diff --git a/lldb/source/Interpreter/CommandOptionValidators.cpp b/lldb/source/Interpreter/CommandOptionValidators.cpp
new file mode 100644 (file)
index 0000000..c9f3e3b
--- /dev/null
@@ -0,0 +1,39 @@
+//===-- CommandOptionValidators.cpp -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Interpreter/CommandOptionValidators.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/Platform.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool PosixPlatformCommandOptionValidator::IsValid(Platform &platform, ExecutionContext &target) const
+{
+    llvm::Triple::OSType os = platform.GetSystemArchitecture().GetTriple().getOS();
+    switch (os)
+    {
+    // Are there any other platforms that are not POSIX-compatible?
+    case llvm::Triple::Win32:
+        return false;
+    default:
+        return true;
+    }
+}
+
+const char* PosixPlatformCommandOptionValidator::ShortConditionString() const 
+{ 
+    return "POSIX"; 
+}
+
+const char* PosixPlatformCommandOptionValidator::LongConditionString() const 
+{ 
+    return "Option only valid for POSIX-compliant hosts."; 
+}
index 0aa8aae..a8766f5 100644 (file)
@@ -277,8 +277,7 @@ Options::GetLongOptions ()
         {
             const int short_opt = opt_defs[i].short_option;
 
-            m_getopt_table[i].name    = opt_defs[i].long_option;
-            m_getopt_table[i].has_arg = opt_defs[i].option_has_arg;
+            m_getopt_table[i].definition = &opt_defs[i];
             m_getopt_table[i].flag    = nullptr;
             m_getopt_table[i].val     = short_opt;
 
@@ -297,7 +296,7 @@ Options::GetLongOptions ()
                                 opt_defs[i].long_option,
                                 short_opt,
                                 pos->second,
-                                m_getopt_table[pos->second].name,
+                                m_getopt_table[pos->second].definition->long_option,
                                 opt_defs[i].long_option);
                 else
                     Host::SystemLog (Host::eSystemLogError, "option[%u] --%s has a short option 0x%x that conflicts with option[%u] --%s, short option won't be used for --%s\n",
@@ -305,17 +304,16 @@ Options::GetLongOptions ()
                                 opt_defs[i].long_option,
                                 short_opt,
                                 pos->second,
-                                m_getopt_table[pos->second].name,
+                                m_getopt_table[pos->second].definition->long_option,
                                 opt_defs[i].long_option);
             }
         }
 
         //getopt_long_only requires a NULL final entry in the table:
 
-        m_getopt_table[i].name    = nullptr;
-        m_getopt_table[i].has_arg = 0;
-        m_getopt_table[i].flag    = nullptr;
-        m_getopt_table[i].val     = 0;
+        m_getopt_table[i].definition    = nullptr;
+        m_getopt_table[i].flag          = nullptr;
+        m_getopt_table[i].val           = 0;
     }
 
     if (m_getopt_table.empty())
@@ -336,18 +334,29 @@ void
 Options::OutputFormattedUsageText
 (
     Stream &strm,
-    const char *text,
+    const OptionDefinition &option_def,
     uint32_t output_max_columns
 )
 {
-    int len = strlen (text);
+    std::string actual_text;
+    if (option_def.validator)
+    {
+        const char *condition = option_def.validator->ShortConditionString();
+        if (condition)
+        {
+            actual_text = "[";
+            actual_text.append(condition);
+            actual_text.append("] ");
+        }
+    }
+    actual_text.append(option_def.usage_text);
 
     // Will it all fit on one line?
 
-    if (static_cast<uint32_t>(len + strm.GetIndentLevel()) < output_max_columns)
+    if (static_cast<uint32_t>(actual_text.length() + strm.GetIndentLevel()) < output_max_columns)
     {
         // Output it as a single line.
-        strm.Indent (text);
+        strm.Indent (actual_text.c_str());
         strm.EOL();
     }
     else
@@ -357,13 +366,13 @@ Options::OutputFormattedUsageText
         int text_width = output_max_columns - strm.GetIndentLevel() - 1;
         int start = 0;
         int end = start;
-        int final_end = strlen (text);
+        int final_end = actual_text.length();
         int sub_len;
 
         while (end < final_end)
         {
             // Don't start the 'text' on a space, since we're already outputting the indentation.
-            while ((start < final_end) && (text[start] == ' '))
+            while ((start < final_end) && (actual_text[start] == ' '))
                 start++;
 
             end = start + text_width;
@@ -373,7 +382,7 @@ Options::OutputFormattedUsageText
             {
                 // If we're not at the end of the text, make sure we break the line on white space.
                 while (end > start
-                       && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
+                       && actual_text[end] != ' ' && actual_text[end] != '\t' && actual_text[end] != '\n')
                     end--;
             }
 
@@ -383,7 +392,7 @@ Options::OutputFormattedUsageText
             strm.Indent();
             assert (start < final_end);
             assert (start + sub_len <= final_end);
-            strm.Write(text + start, sub_len);
+            strm.Write(actual_text.c_str() + start, sub_len);
             start = end + 1;
         }
         strm.EOL();
@@ -630,7 +639,7 @@ Options::GenerateOptionUsage
     strm.Printf ("\n\n");
 
     // Now print out all the detailed information about the various options:  long form, short form and help text:
-    //   --long_name <argument>  ( -short <argument> )
+    //   -short <argument> ( --long_name <argument> )
     //   help text
 
     // This variable is used to keep track of which options' info we've printed out, because some options can be in
@@ -683,7 +692,7 @@ Options::GenerateOptionUsage
         
         if (opt_defs[i].usage_text)
             OutputFormattedUsageText (strm,
-                                      opt_defs[i].usage_text,
+                                      opt_defs[i],
                                       screen_width);
         if (opt_defs[i].enum_values != nullptr)
         {