Invalidate process UID/GID-related command options on Windows.

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
This commit is contained in:
Zachary Turner 2014-07-07 23:54:51 +00:00
parent e7a8ccfaad
commit 28638911cd
9 changed files with 158 additions and 49 deletions

View 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
{

View File

@ -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_

View 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.

View 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

View 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." },

View 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));

View File

@ -7,6 +7,7 @@ add_lldb_library(lldbInterpreter
CommandObject.cpp
CommandObjectRegexCommand.cpp
CommandObjectScript.cpp
CommandOptionValidators.cpp
CommandReturnObject.cpp
OptionGroupArchitecture.cpp
OptionGroupBoolean.cpp

View File

@ -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.";
}

View 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)
{